Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,13 @@ jobs:
done
exit 1
- run: zig build test-all -Doptimize=ReleaseSafe --summary all

nix:
name: nix build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: DeterminateSystems/nix-installer-action@v22
- run: nix flake check
- run: nix build -L
- run: nix run . -- version
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
zig-out/
.zig-cache/
result
result-*
57 changes: 54 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
# boo
<div align="center">
<h1>boo</h1>

Sessions that haunt your terminal. A GNU `screen` style terminal
multiplexer built on [libghostty](https://github.com/ghostty-org/ghostty)
Sessions that haunt your terminal.

[Install](#install) | [Usage](#usage) | [Automation](#automation) | [Architecture](#architecture)

[![ci](https://github.com/coder/boo/actions/workflows/ci.yml/badge.svg)](https://github.com/coder/boo/actions/workflows/ci.yml)
[![release](https://img.shields.io/github/v/release/coder/boo)](https://github.com/coder/boo/releases/latest)
[![license](https://img.shields.io/github/license/coder/boo)](./LICENSE)
[![discord](https://img.shields.io/discord/747933592273027093?label=discord)](https://discord.gg/coder)

</div>

A GNU `screen` style terminal multiplexer built on
[libghostty](https://github.com/ghostty-org/ghostty)
(`libghostty-vt`), written in Zig.

Every session's output is parsed through Ghostty's terminal emulation
Expand Down Expand Up @@ -37,6 +49,8 @@ exactly as a human would see it.

## Install

### Install script

```sh
curl -fsSL https://raw.githubusercontent.com/coder/boo/main/install.sh | sh
```
Expand All @@ -48,6 +62,19 @@ Pre-built binaries for Linux (x86_64, aarch64; fully static) and macOS
install location (default: `/usr/local/bin` when writable, otherwise
`~/.local/bin`).

### Nix

With [flakes](https://wiki.nixos.org/wiki/Flakes) enabled:

```sh
nix run github:coder/boo # try it without installing
nix profile add github:coder/boo # install into your profile
```

Or add `github:coder/boo` as an input to your own flake and reference
`packages.<system>.default` from your NixOS, nix-darwin, or Home
Manager configuration.

## Building

Requires [Zig](https://ziglang.org) 0.15.2.
Expand All @@ -62,6 +89,9 @@ zig build test-all # everything
The libghostty dependency is fetched and built from source
automatically (pinned in `build.zig.zon`).

With Nix, `nix develop` opens a shell with the right Zig version, and
`nix build` builds the package to `./result/bin/boo`.

## Usage

```sh
Expand Down Expand Up @@ -172,6 +202,27 @@ This is a young project, not a drop-in GNU screen replacement:
- No status line, monitoring, or copy mode yet.
- Sessions run with `TERM=xterm-256color`.

## Support

Feel free to [open an issue](https://github.com/coder/boo/issues/new)
if you have questions, run into bugs, or have a feature request.

[Join the Coder Discord](https://discord.gg/coder) to chat with the
community.

## Contributing

Contributions are welcome:

1. Fork and clone the repository.
2. Make your change and cover it with tests.
3. Run `zig build test-all` and
`zig fmt build.zig build.zig.zon src test`.
4. Open a pull request against `main`.

CI runs formatting checks, unit tests, and PTY integration tests on
Linux and macOS, plus a Nix build.

## License

[MIT](LICENSE). Ghostty itself is MIT licensed.
61 changes: 61 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

110 changes: 110 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
{
description = "Sessions that haunt your terminal. A GNU screen style terminal multiplexer built on libghostty.";

inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};

outputs =
{
self,
nixpkgs,
flake-utils,
}:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) lib;
zig = pkgs.zig_0_15;

# Single source of truth for the version is build.zig.zon.
version = builtins.head (
builtins.match ''.*\.version = "([^"]+)".*'' (builtins.readFile ./build.zig.zon)
);

# Zig package cache containing every dependency pinned in
# build.zig.zon (libghostty and its transitive dependencies).
# Pre-fetched as a fixed-output derivation so the sandboxed
# build below needs no network access. When dependencies in
# build.zig.zon change, update outputHash (set it to
# lib.fakeHash, build, and copy the hash from the error).
deps = pkgs.stdenvNoCC.mkDerivation {
pname = "boo-deps";
inherit version;
src = ./.;

nativeBuildInputs = [ zig ];

dontConfigure = true;
dontBuild = true;
dontFixup = true;

installPhase = ''
export ZIG_GLOBAL_CACHE_DIR="$TMPDIR/zig-cache"
# Dependency hosts intermittently fail; retry like CI
# does. Zig resumes from its cache, so completed fetches
# are not repeated and the output stays reproducible.
for i in 1 2 3 4 5; do
zig build --fetch=all && break
if [ "$i" = 5 ]; then exit 1; fi
echo "fetch attempt $i failed; retrying in 10s" >&2
sleep 10
done
mv "$ZIG_GLOBAL_CACHE_DIR/p" "$out"
'';

impureEnvVars = lib.fetchers.proxyImpureEnvVars;
SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
outputHashMode = "recursive";
outputHashAlgo = "sha256";
outputHash = "sha256-2dZHdZoAap25va9ka2SN5QqoQ2xcZITJKNzwfOGmvus=";
};

boo = pkgs.stdenv.mkDerivation {
pname = "boo";
inherit version;
src = ./.;

nativeBuildInputs = [ zig.hook ];

# zig.hook builds with --release=safe, matching the
# optimization mode of the published release binaries.
#
# The dependency cache is copied, not symlinked: some
# ghostty build steps run helper executables with a working
# directory inside the package cache and locate their
# outputs via relative paths, which resolve incorrectly
# through a symlink into the store.
postConfigure = ''
cp -r --no-preserve=mode ${deps} "$ZIG_GLOBAL_CACHE_DIR/p"
'';

# Runs `zig build test` (unit tests; no TTY required). The
# PTY integration tests stay in CI via `zig build test-all`.
doCheck = true;

meta = {
description = "Sessions that haunt your terminal. A GNU screen style terminal multiplexer built on libghostty";
homepage = "https://github.com/coder/boo";
license = lib.licenses.mit;
mainProgram = "boo";
platforms = lib.platforms.linux ++ lib.platforms.darwin;
};
};
in
{
packages = {
default = boo;
inherit boo;
};

devShells.default = pkgs.mkShell {
packages = [ zig ];
};

formatter = pkgs.nixfmt-tree;
}
);
}
Loading