T01: crate, window, check script, CI
This commit is contained in:
11 files changed
+8339
No files matched your search
@@ -0,0 +1,33 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
macos:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: "1.95"
|
||||
components: clippy, rustfmt
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- run: scripts/check.sh
|
||||
|
||||
platforms:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-24.04, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: "1.95"
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- run: cargo test --quiet
|
||||
- run: cargo build
|
||||
@@ -0,0 +1,3 @@
|
||||
/target
|
||||
/Otty.app
|
||||
.DS_Store
|
||||
@@ -0,0 +1,35 @@
|
||||
# AGENTS.md
|
||||
|
||||
ELYTerminal. A terminal on GPUI and Ely components. `PRD.md` says what it does; `TASKS.md` says how far it is.
|
||||
|
||||
## Stack
|
||||
|
||||
- Rust 1.95, edition 2024. One binary crate, `elyterminal`.
|
||||
- Ely (`ely-gpui-component`) from git.zacharyzhang.com, pinned by rev. gpui and gpui_platform from crates.io's `gpui-pre`, the exact version Ely pins, under their crate names through `package`.
|
||||
- `alacritty_terminal` 0.26: grid, parser, pseudo-terminal, event loop.
|
||||
- `serde`, `serde_json`: settings. `dirs`: the config folder. `log`, `env_logger`: logs to stderr.
|
||||
|
||||
## Commands
|
||||
|
||||
- `cargo run` opens the app. `RUST_LOG=elyterminal=debug cargo run` logs more.
|
||||
- `scripts/check.sh`: fmt, clippy `-D warnings`, tests, the 500-line rule.
|
||||
|
||||
## Layout
|
||||
|
||||
- `src/main.rs`: start, window.
|
||||
|
||||
## Rules
|
||||
|
||||
- Files stay at or under 500 lines. Comments are one short line, and rare.
|
||||
- Fail fast. No silent fallbacks. An error names its owner and what failed.
|
||||
- Log every state change on a key path with `log`: spawn, exit, folder change, settings load and save, blur path.
|
||||
- No dead code, no versioned names, no compatibility shims.
|
||||
- Colors, sizes and radii come from Ely's theme. Gaps use gpui's rem helpers.
|
||||
- No credential in any file. Pushes pass the token as an `http.extraHeader` on the command line.
|
||||
|
||||
## Decisions
|
||||
|
||||
- 2026-10-14: ELYTerminal owns its terminal engine on `alacritty_terminal`. Ely's `Terminal` lacks mouse reporting, IME, kitty keys and style settings, and a library widget should not carry an app's engine.
|
||||
- 2026-10-14: the working directory comes from OSC 7, read by a tap on the pty reader, sent by injected shell integration. vte drops OSC 7.
|
||||
- 2026-10-14: Git through the `git` command line, not libgit2.
|
||||
- 2026-10-14: license MIT, as Ely.
|
||||
Generated
+7966
File diff suppressed because it is too large.
Load diff
+23
@@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "elyterminal"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
rust-version = "1.95"
|
||||
license = "MIT"
|
||||
description = "A terminal on GPUI and Ely."
|
||||
repository = "https://git.zacharyzhang.com/ZacharyZhang-NY/ELYTerminal"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
ely-gpui-component = { git = "https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components.git", rev = "12512217bd9bc652ed6bbf10461b00cc26c01c21" }
|
||||
env_logger = "0.11"
|
||||
gpui = { package = "gpui-pre", version = "=0.3.8", default-features = false }
|
||||
gpui_platform = { package = "gpui-pre-platform", version = "=0.3.8", features = ["font-kit"] }
|
||||
log = "0.4"
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(feature, values("cargo-clippy"))'] }
|
||||
|
||||
[lints.clippy]
|
||||
all = { level = "warn", priority = -1 }
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 ELYTerminal contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,125 @@
|
||||
# ELYTerminal PRD
|
||||
|
||||
A terminal for macOS, Windows and Linux. Rust, GPUI, Ely components. It draws a terminal as well as Ghostty does, shows every setting on screen, and makes no noise.
|
||||
|
||||
Chapters run in build order. `TASKS.md` follows them line by line.
|
||||
|
||||
## 1. Product
|
||||
|
||||
- One window. Sessions on the left, the terminal in the middle, Git or Files on the right.
|
||||
- Every setting has a control in the settings window. No setting lives only in a file.
|
||||
- Silent: no sound, no bell, no notifications, no update checks, no telemetry, no tips, no onboarding.
|
||||
- Clean: no subtitle, no tagline, no logging options, no status bar, no badges that do not carry state.
|
||||
- Built-in themes, each shown as a small preview, Catppuccin among them. A theme colors the terminal and the chrome.
|
||||
- The window background blurs on macOS, Windows, Wayland and X11.
|
||||
|
||||
## 2. Foundation
|
||||
|
||||
- One binary crate, `elyterminal`, edition 2024, Rust 1.95.
|
||||
- Ely from git.zacharyzhang.com by pinned rev. gpui, gpui_platform from crates.io `gpui-pre` at the exact version Ely pins.
|
||||
- `alacritty_terminal` 0.26 for the grid, the parser and the pseudo-terminal, as Ely uses it.
|
||||
- Logs through `log` to stderr, `RUST_LOG` sets the level. No log setting in the app.
|
||||
- CI on Gitea Actions: macOS builds, tests and lints; Ubuntu and Windows build and test.
|
||||
- Private repo `ELYTerminal` on git.zacharyzhang.com. No credential in any file or commit.
|
||||
|
||||
## 3. Settings model and storage
|
||||
|
||||
- One JSON file, `settings.json`, in the platform config folder (`dirs::config_dir()/ELYTerminal`).
|
||||
- Every field has a default. A missing file means defaults. A missing field means its default.
|
||||
- A file that does not parse, or a value out of range, stops the start with an error naming the file and the field. The app never overwrites a file it could not read.
|
||||
- Writes go to a temp file in the same folder, then rename. One writer: the app's settings entity.
|
||||
- Fields: see chapter 10.
|
||||
|
||||
## 4. Themes
|
||||
|
||||
- Built in: Ely Dark, Ely Light, Catppuccin Mocha, Catppuccin Macchiato, Catppuccin Frappé, Catppuccin Latte, Tokyo Night, Dracula, Nord, Gruvbox Dark, Rosé Pine, Solarized Light, One Light, Kanagawa Wave.
|
||||
- A theme holds background, foreground, cursor, cursor text, selection background and foreground, and the 16 ANSI colors. Values come from the theme's upstream files (iTerm2-Color-Schemes' Ghostty export, or Ely's palette).
|
||||
- A theme maps onto Ely's `Palette` through `Theme::set_palette`, so panels, inputs and lists wear the theme.
|
||||
- Dark mode: one theme, or a second theme for when the system is dark.
|
||||
|
||||
## 5. Terminal engine
|
||||
|
||||
Ghostty is the bar for what the terminal does. ELYTerminal owns its engine on `alacritty_terminal`; Ely's `Terminal` is a gallery widget without mouse reporting, IME, kitty keys or style settings.
|
||||
|
||||
- PTY: alacritty's `tty` and event loop. The pty is wrapped so its reader passes bytes through an OSC 7 scanner. The scanner reports the working directory.
|
||||
- Shell integration for zsh, bash, fish and PowerShell, injected at launch as Ghostty does: each prompt sends OSC 7 and a title. A shell without integration reports nothing, and the panels say so.
|
||||
- Grid: colors (named, 256, truecolor, OSC 4/10/11/12), bold, dim, italic, underline (single, double, curly, dotted, dashed), strikethrough, inverse, hidden, wide characters, combining marks.
|
||||
- Box drawing (U+2500–U+257F) and block elements (U+2580–U+259F) painted as geometry, so lines join across cells.
|
||||
- Cursor: block, bar, underline, hollow block; blinking per setting and per DECSCUSR; hollow when the window is not focused.
|
||||
- Keys: xterm encoding with modifiers, application cursor and keypad modes, Option as Alt on macOS, the kitty keyboard protocol as the program sets its flags.
|
||||
- IME: marked text drawn at the cursor; committed text sent to the program.
|
||||
- Mouse: select by character, word (double press) and line (triple press); Shift extends; mouse reporting (X10, normal, button, any; SGR and UTF-8); wheel scrolls back, or reports, or sends arrows on the alternate screen.
|
||||
- Clipboard: copy, paste (bracketed when asked), copy on select per setting, OSC 52 writes.
|
||||
- Links: OSC 8 and plain URLs; Cmd-press (Ctrl-press off macOS) opens them.
|
||||
- Focus reporting, title (OSC 0/2), scrollback limit per setting, find in scrollback (Ely's `FindWidget`).
|
||||
- Bell: no sound. The session row marks it until the session is shown.
|
||||
|
||||
## 6. Main window and layout
|
||||
|
||||
- Ely's `ColumnShell`: sessions column, terminal column, right column. The window opens with blur when the setting is on.
|
||||
- The sessions column and the right column toggle and keep their state in settings.
|
||||
- The title shows the active session's title. Nothing else in the title bar.
|
||||
|
||||
## 7. Sessions panel
|
||||
|
||||
- A list of sessions. Each row: title, then the working directory, home as `~`.
|
||||
- New session (+ and Cmd-T), close (row's ×, Cmd-W), select (press, Cmd-1…9, Ctrl-Tab and Ctrl-Shift-Tab).
|
||||
- A session whose program ends closes its row. The last row closing closes the window.
|
||||
- A bell in a hidden session marks its row.
|
||||
|
||||
## 8. Right panel: Files
|
||||
|
||||
- A switch at the top: Git, Files.
|
||||
- Files shows the active session's working directory as a tree, folders first, Git status colors on names.
|
||||
- Double press: a folder opens, a file opens in the system's default app.
|
||||
- It reloads when the session reports a new directory and at each prompt.
|
||||
|
||||
## 9. Right panel: Git
|
||||
|
||||
- Through the `git` command line. No libgit2.
|
||||
- Shows the branch, staged and unstaged changes, a commit message field and Commit, and recent commits.
|
||||
- Stage and unstage a file. Press a file to see its diff in Ely's `DiffViewer`.
|
||||
- Outside a repository it says so. A failed git command shows its error.
|
||||
- It reloads at each prompt and on directory change.
|
||||
|
||||
## 10. Settings window
|
||||
|
||||
Cmd-, opens it. Categories on the left, rows on the right, Ely's settings components. Changes apply at once to every session and save.
|
||||
|
||||
- General
|
||||
- Shell: a path; empty runs the login shell.
|
||||
- Start in: Home, or the active session's folder.
|
||||
- Appearance
|
||||
- Theme: a grid of previews.
|
||||
- Separate dark theme: a switch; when on, a second grid for dark mode.
|
||||
- Font family: a list of installed fonts. Font size. Line height. Ligatures.
|
||||
- Cursor: style (block, bar, underline, hollow), blink, with a live preview.
|
||||
- Background opacity: a slider. Background blur: a switch.
|
||||
- Padding: horizontal and vertical.
|
||||
- Terminal
|
||||
- Scrollback lines.
|
||||
- Option as Alt: off, left, right, both (macOS only).
|
||||
- Copy on select.
|
||||
|
||||
## 11. Background blur
|
||||
|
||||
- macOS: gpui's `WindowBackgroundAppearance::Blurred` (NSVisualEffectView).
|
||||
- Windows: gpui's `Blurred` (acrylic accent).
|
||||
- Wayland: gpui's `Blurred` speaks `org_kde_kwin_blur`; ELYTerminal adds `ext_background_effect_v1` on the window's surface, which GNOME 51 and Plasma 6.7 support.
|
||||
- X11: ELYTerminal sets `_KDE_NET_WM_BLUR_BEHIND_REGION` (CARDINAL, 32) on the window, as Ghostty does; removes it when blur turns off.
|
||||
- A compositor with neither protocol shows transparency without blur. The app logs which path it took.
|
||||
|
||||
## 12. Menus and shortcuts
|
||||
|
||||
- macOS menu bar: ELYTerminal (Settings, Quit), Shell (New Session, Close Session), Edit (Copy, Paste, Select All, Find), View (Toggle Sessions, Toggle Right Panel, Bigger, Smaller, Reset Size), Window.
|
||||
- The same shortcuts on Windows and Linux with Ctrl-Shift for terminal-colliding keys.
|
||||
|
||||
## 13. Acceptance
|
||||
|
||||
- Each chapter's tasks ticked in `TASKS.md` with a passing review in `tasks/reviews.md`.
|
||||
- `scripts/check.sh` passes: fmt, clippy with `-D warnings`, tests, no file over 500 lines.
|
||||
- CI green on macOS, Ubuntu and Windows.
|
||||
|
||||
## Deferred
|
||||
|
||||
Splits, tabs inside a session, profiles, key rebinding, kitty graphics, sixel, OSC 133 prompt marks, session restore, push and pull, discard changes, quick terminal.
|
||||
@@ -0,0 +1,62 @@
|
||||
# Tasks
|
||||
|
||||
Progress truth. Top to bottom, one at a time. A task is ticked only after its codex review passes; rounds go in `tasks/reviews.md`, three at most.
|
||||
|
||||
## 2. Foundation
|
||||
|
||||
- [ ] T01 Repo, crate, window: git, `.gitignore`, `Cargo.toml` with Ely pinned, `main.rs` opens one window through Ely, logging, `scripts/check.sh`, CI workflow, private Gitea repo, first push.
|
||||
|
||||
## 3. Settings model and storage
|
||||
|
||||
- [ ] T02 `Settings` with defaults and ranges; load (missing file, missing field, bad file, bad value) and atomic save; tests.
|
||||
|
||||
## 4. Themes
|
||||
|
||||
- [ ] T03 Built-in themes from upstream files; mapping onto Ely's `Palette`; dark-mode choice; tests.
|
||||
|
||||
## 5. Terminal engine
|
||||
|
||||
- [ ] T04 PTY: spawn through alacritty's event loop, OSC 7 tap on the reader, child id, events to the app; tests.
|
||||
- [ ] T05 Shell integration for zsh, bash, fish, PowerShell, injected at launch; tests that zsh and bash report their folder.
|
||||
- [ ] T06 Terminal view: frame from the grid, colors and styles, wide and combining cells, cursor shapes and blink, font, line height, padding, resize.
|
||||
- [ ] T07 Box drawing and block elements painted as geometry; tests.
|
||||
- [ ] T08 Keys: xterm encoding, modes, Option as Alt, kitty keyboard protocol, IME; tests.
|
||||
- [ ] T09 Mouse: selection, mouse reporting, wheel and scrollback, clipboard, copy on select, OSC 52, links; tests.
|
||||
- [ ] T10 Focus reporting, title, silent bell, scrollback limit, find.
|
||||
|
||||
## 6. Main window and layout
|
||||
|
||||
- [ ] T11 `ColumnShell` with sessions, terminal and right columns; toggles kept in settings; window title.
|
||||
|
||||
## 7. Sessions panel
|
||||
|
||||
- [ ] T12 Sessions: new, close, select, keys, titles and folders, ended programs, bell marks.
|
||||
|
||||
## 8. Right panel: Files
|
||||
|
||||
- [ ] T13 Git/Files switch; file tree of the session's folder with Git colors; open; reload on folder and prompt.
|
||||
|
||||
## 9. Right panel: Git
|
||||
|
||||
- [ ] T14 Git through the command line: status, branch, stage, unstage, commit, log, diff; tests on a temp repo.
|
||||
- [ ] T15 Git panel: branch, changes, stage and unstage, commit, recent commits, diff view, errors.
|
||||
|
||||
## 10. Settings window
|
||||
|
||||
- [ ] T16 Settings window: categories, General rows, live apply and save.
|
||||
- [ ] T17 Appearance: theme grids with previews, font, cursor with preview, opacity, blur, padding.
|
||||
- [ ] T18 Terminal rows: scrollback, Option as Alt, copy on select.
|
||||
|
||||
## 11. Background blur
|
||||
|
||||
- [ ] T19 macOS and Windows: `Blurred` or `Transparent` or `Opaque` from settings, applied live.
|
||||
- [ ] T20 Wayland: `ext_background_effect_v1` on the window's surface.
|
||||
- [ ] T21 X11: `_KDE_NET_WM_BLUR_BEHIND_REGION` on the window.
|
||||
|
||||
## 12. Menus and shortcuts
|
||||
|
||||
- [ ] T22 macOS menu bar; key bindings on all platforms.
|
||||
|
||||
## 13. Acceptance
|
||||
|
||||
- [ ] T23 End-to-end checks, README, acceptance table, CI green on three platforms.
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
# Pre-review gate: build rules plus house rules.
|
||||
set -eu
|
||||
cargo fmt --check
|
||||
cargo clippy --all-targets -- -D warnings
|
||||
cargo test --quiet
|
||||
fail=0
|
||||
files=$(git ls-files -co --exclude-standard '*.rs')
|
||||
multi=$(awk 'FNR==1{prev=0} /^[[:space:]]*\/\// {if(prev) print FILENAME":"FNR; prev=1; next} {prev=0}' $files)
|
||||
[ -z "$multi" ] || { echo "multi-line comments:"; echo "$multi"; fail=1; }
|
||||
for f in $(git ls-files -co --exclude-standard); do
|
||||
case "$f" in *.rs|*.md|*.sh|*.zsh|*.bash|*.fish|*.ps1|*.toml|*.yml) ;; *) continue ;; esac
|
||||
n=$(wc -l < "$f")
|
||||
[ "$n" -le 500 ] || { echo "$f has $n lines"; fail=1; }
|
||||
done
|
||||
exit $fail
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
use ely_gpui_component::{
|
||||
Assets,
|
||||
primitives::FocusScope,
|
||||
theme::{ActiveTheme, Mode, Theme},
|
||||
};
|
||||
use gpui::{
|
||||
App, AppContext, Bounds, Context, FocusHandle, IntoElement, Render, Styled, TitlebarOptions,
|
||||
Window, WindowBounds, WindowOptions, px, size,
|
||||
};
|
||||
|
||||
struct Workspace {
|
||||
focus: FocusHandle,
|
||||
}
|
||||
|
||||
impl Render for Workspace {
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
FocusScope::new(&self.focus)
|
||||
.root()
|
||||
.size_full()
|
||||
.bg(cx.theme().colors.bg)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("elyterminal=info"))
|
||||
.init();
|
||||
gpui_platform::application()
|
||||
.with_assets(Assets)
|
||||
.run(|cx: &mut App| {
|
||||
ely_gpui_component::init(cx).expect("Ely failed to start");
|
||||
Theme::set_mode_now(Mode::Dark, cx);
|
||||
let bounds = Bounds::centered(None, size(px(1200.0), px(760.0)), cx);
|
||||
let options = WindowOptions {
|
||||
window_bounds: Some(WindowBounds::Windowed(bounds)),
|
||||
titlebar: Some(TitlebarOptions {
|
||||
title: Some("ELYTerminal".into()),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
cx.open_window(options, |window, cx| {
|
||||
cx.new(|cx| {
|
||||
let focus = cx.focus_handle();
|
||||
window.focus(&focus, cx);
|
||||
Workspace { focus }
|
||||
})
|
||||
})
|
||||
.expect("the main window failed to open");
|
||||
log::info!("app: main window open");
|
||||
cx.activate(true);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# Reviews
|
||||
|
||||
Each task gets at most three codex rounds. Each round: the commit, the verdict, the findings and what was done.
|
||||
Reference in new issue
Block a user