From c316d271a286100aeb6ef217ff9c0de023d594ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Thu, 15 Oct 2026 19:04:41 -0400 Subject: [PATCH] T26: on Windows and Linux, which have no menu bar, a gear just inside the right toggle opens Settings; it sends OpenSettings through Window::dispatch_action, since App::dispatch_action inside the window's own click handler fails with only gpui's log line --- AGENTS.md | 2 +- PRD.md | 2 +- README.md | 2 +- TASKS.md | 2 +- src/workspace.rs | 20 +++++++++++++++++--- tasks/acceptance.md | 1 + 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index b52c3b0..2767a8e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -68,7 +68,7 @@ ELYTerminal. A terminal on GPUI and Ely components. `PRD.md` says what it does; - 2026-10-14: a key's release goes out only when the terminal saw its press, so a key a binding takes sends no release, as in kitty. - 2026-10-14: find opens on Cmd-F (Ctrl-Shift-F off macOS) beside the grid, outside the `Terminal` key context, so its keys never reach the program. Matches wash in Ely's `warning` color, the current one stronger; the newest is current first, Enter steps older and Shift-Enter newer. Shift-Enter binds under `TerminalFind > ElyInput`, the context of Ely's text input, whose own Shift-Enter binding takes the key. Find reads the grid as it shows: combining marks ride their cells, hidden cells are blank, wrapped rows join, words are Unicode; alacritty's own search reads no marks and knows only ASCII word edges. New output, a resize and a settings change search again; the current match stays the same occurrence: its line kept, grown or cut at its end, held under the same line above or in its place, before such a line elsewhere, nearest where scrolling moved it; else the nearest by line, then column. Searching and following take one pass over the text and the matches. - 2026-10-14: the program hears focus in and out under mode 1004 when the terminal's focus or the window's activation changes. The window wears the program's title, the app's name while it names none. A bell is logged and makes no sound. A full reset, `ESC c`, empties alacritty's title and sends only `CursorBlinkingChange`, in the parser's order, synchronized updates too; on that event the view replays the title through `set_options`, which sends it. -- 2026-10-14: the title bar is transparent, as Ghostty's: the content runs under it, Ely's column headers drag the window, and the terminal's header shows the program's title. macOS draws its traffic lights at Ely's origin; elsewhere Ely draws the controls, so windows ask for client decorations, which only Linux reads, and Ely's `ResizeBorder` gives the edges. Cmd-B and Cmd-Alt-B (Ctrl-Shift-B and Ctrl-Shift-Alt-B off macOS) toggle the sessions and right columns, kept in the settings. A button at each end of the title bar does the same: `PanelLeft` leads the first column, right after the traffic lights, and `PanelRight` ends the last, before the window buttons Ely draws on Windows and Linux, so neither moves when a column hides; its tooltip says Hide or Show. The Git and Files switch tops the right column, centered below the title bar: on Windows the caption buttons left the last header no room for it. +- 2026-10-14: the title bar is transparent, as Ghostty's: the content runs under it, Ely's column headers drag the window, and the terminal's header shows the program's title. macOS draws its traffic lights at Ely's origin; elsewhere Ely draws the controls, so windows ask for client decorations, which only Linux reads, and Ely's `ResizeBorder` gives the edges. Cmd-B and Cmd-Alt-B (Ctrl-Shift-B and Ctrl-Shift-Alt-B off macOS) toggle the sessions and right columns, kept in the settings. A button at each end of the title bar does the same: `PanelLeft` leads the first column, right after the traffic lights, and `PanelRight` ends the last, before the window buttons Ely draws on Windows and Linux, so neither moves when a column hides; its tooltip says Hide or Show. On Windows and Linux, which have no menu bar, a gear just inside `PanelRight` opens Settings, as Ctrl-, does. It sends `OpenSettings` through `Window::dispatch_action`, which waits for the click to finish: `App::dispatch_action` updates the active window at once, which fails inside that window's own handler, and only gpui's log says so. The Git and Files switch tops the right column, centered below the title bar: on Windows the caption buttons left the last header no room for it. - 2026-10-14: session keys are Ghostty's: Cmd-T, Cmd-W, Cmd-1 to Cmd-8, Cmd-9 for the last, Ctrl-Tab and Ctrl-Shift-Tab; off macOS Ctrl-Shift-T, Ctrl-Shift-W and Alt with the digits. A digit past the last session goes on to the program. A new session runs the Shell setting in home or in the shown session's folder, as Start in says. A session whose program ends closes its row; the last row closes the window, and with no window left the app quits. A bell in a hidden session marks its row until it is shown. A hidden terminal hears no mouse release, so hiding it ends its mouse gesture as releases would: the selection drag ends, and the program hears each held button come up. A row's title is the program's, or the app's name while it names none. - 2026-10-14: Files shows the shown session's folder in Ely's `Tree`, not `FileTree`, which takes every path up front and drops empty folders. A folder is read off the main thread when it first opens; the root and the open folders are read again whenever the session reports a folder, so at each prompt. Git's marks come from `git status --porcelain=v2 -z -- .`, run with `--no-optional-locks`, so it never holds `index.lock` against the user's own git, and under the user's `status.showUntrackedFiles`, so a home folder kept in git stays quick. An untracked folder marks what it holds. On macOS, whose file systems ignore Unicode forms, a name keeps its form on disk and meets Git's mark in composed form, as git's `core.precomposeunicode` writes it. A label built from a path shows each control character as its picture, `␊` for a newline: gpui shapes no newline, and a file may be named with one. A name not in UTF-8 keeps its bytes: its label shows it lossily, and its tree key adds the bytes after a NUL, which no path holds, so no two names share a key. A program without shell integration gets a line in the right column until it reports a folder. - 2026-10-14: git runs in English with `--literal-pathspecs` and without optional locks. Paths stay git's bytes until shown, so a name not in UTF-8 still names its own file; off Unix git writes UTF-8. Status reads porcelain v2. Paths to stage and unstage go in on stdin, NUL-ended (`--pathspec-from-file`), so any name and any count pass; an empty list is refused, since git would take it as the whole tree. Unstaging is `git reset`, which works before the first commit, and a staged rename unstages with its old path; a copy is a new file, its source no part of it. A diff is git's own, without external tools or text converters, a conflict against HEAD, our side, so a file we deleted reads as new; it is read into Ely's stretches; a binary file has none, and an untracked folder none either. Without an index git exits 1 for a difference and a failure alike; only a difference prints. What git warns of while it works goes to the log. The log needs a commit at HEAD: git refuses it before the first. diff --git a/PRD.md b/PRD.md index 4938169..afaa6df 100644 --- a/PRD.md +++ b/PRD.md @@ -88,7 +88,7 @@ Ghostty is the bar for what the terminal does. ELYTerminal owns its engine on `a ## 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. +Cmd-, opens it; on Windows and Linux, which have no menu bar, so does a gear in the title bar. 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. diff --git a/README.md b/README.md index 959ebce..e637c84 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ The app writes its log to stderr. `RUST_LOG=elyterminal=debug` writes more; `tra - The terminal runs on `alacritty_terminal`: 256 colors and truecolor, bold, dim, italic, five underline styles, wide characters and combining marks. Box drawing, block elements and powerline shapes are drawn as geometry, so lines join across cells. Keys follow xterm and the kitty keyboard protocol; input methods compose at the cursor; programs can track the mouse; pastes are bracketed when a program asks; OSC 8 and plain links open with the link press below; find searches the scrollback. - Shell integration for zsh, bash, fish and PowerShell: each prompt reports its folder and title. - Sessions: new, close and switch. A bell marks a hidden session's row and makes no sound. -- A button at each end of the title bar hides or shows its side column; the window opens as it was left. +- A button at each end of the title bar hides or shows its side column; the window opens as it was left. On Windows and Linux a gear beside the right one opens Settings. - Files shows the session's folder as a tree with Git's marks. - Git shows the branch, stages, unstages, discards, commits, lists recent commits and opens diffs, all through the `git` command line. - Themes: Ely Dark, Ely Light, Catppuccin Mocha, Macchiato, Frappé and Latte, Tokyo Night, Dracula, Nord, Gruvbox Dark, Rosé Pine, Solarized Light, One Light and Kanagawa Wave. A second theme can take over while the system is dark. diff --git a/TASKS.md b/TASKS.md index cceb293..a095996 100644 --- a/TASKS.md +++ b/TASKS.md @@ -71,4 +71,4 @@ Progress truth. Top to bottom, one at a time. A task is ticked only after its co ## 16. The title bar on Windows -- [ ] T26 On Windows every title bar control takes its press, Ely's window buttons too: in Ely, window buttons and header items occlude the drag region; the Git and Files switch moves below the title bar, centered; release v0.1.1 with the three builds. +- [ ] T26 On Windows every title bar control takes its press, Ely's window buttons too: in Ely, window buttons and header items occlude the drag region; the Git and Files switch moves below the title bar, centered; on Windows and Linux a gear in the title bar opens Settings; release v0.1.1 with the three builds. diff --git a/src/workspace.rs b/src/workspace.rs index 9becd4d..faf8564 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -18,7 +18,7 @@ use crate::{ git::panel::{Acted, GitPanel}, menus, sessions::{self, Session}, - settings::{PanelTab, Settings, SettingsStore, StartIn}, + settings::{PanelTab, Settings, SettingsStore, StartIn, window::OpenSettings}, term::{ Events, Launch, Pty, TerminalEvent, TerminalView, config, shell::{ShellIntegration, launch}, @@ -356,6 +356,20 @@ impl Render for Workspace { tip(settings.show_panel, "Git and Files"), |settings| settings.show_panel = !settings.show_panel, ); + // No menu bar off macOS: a gear opens Settings. + let gear = (!cfg!(target_os = "macos")).then(|| { + IconButton::new("open-settings", IconName::Settings) + .variant(ButtonVariant::Ghost) + .size(ControlSize::Sm) + .tooltip("Settings") + .on_click(|_, window, cx| window.dispatch_action(Box::new(OpenSettings), cx)) + }); + let end = div() + .flex() + .items_center() + .gap_2() + .children(gear) + .child(right); let mut shell = ColumnShell::new("workspace").glass(); let shown = self .sessions @@ -424,7 +438,7 @@ impl Render for Workspace { shell = shell.column(terminal).column( ShellColumn::new("panel") .width(width) - .action(right) + .action(end) // Below the title bar, clear of Windows' caption buttons. .child(div().flex().justify_center().px_2().pt_2().child(switch)) .children(quiet.then(caption)) @@ -432,7 +446,7 @@ impl Render for Workspace { .child(body(tab == PanelTab::Files).child(self.files.clone())), ); } else { - shell = shell.column(terminal.action(right)); + shell = shell.column(terminal.action(end)); } // The context sits above the focus root, so its keys work wherever focus is. div() diff --git a/tasks/acceptance.md b/tasks/acceptance.md index 6e77779..7f419c2 100644 --- a/tasks/acceptance.md +++ b/tasks/acceptance.md @@ -106,6 +106,7 @@ What no check reached: no one has looked at the window on Windows, which CI buil | PRD line | Task | Evidence | Status | |---|---|---|---| | Cmd-, opens it; categories left, rows right; changes apply at once and save | T16 | T16 review | Pass | +| On Windows and Linux, a gear in the title bar opens it too | T26 | on X11 under Xvfb with xfwm4, xdotool's click on the gear, just inside the right toggle, opened the 900×640 Settings window ("settings: the window opens"), after a click on + opened a session; sent through `App::dispatch_action`, the same click had opened nothing; the owner has not yet clicked it on Windows | Partial | | General: Shell, Start in | T16 | `settings::tests` | Pass | | Appearance: theme grids, dark theme, font, size, line height, ligatures, cursor and preview, opacity, blur, padding | T17 | T17 review | Pass | | Terminal: scrollback, Option as Alt (macOS), copy on select | T18 | T18 review | Pass |