T22: Edit's Copy, Paste and Select All are Ely's text input actions, which Ely a2cb531 exports and the terminal handles too, so the menu reaches find and every field; Select All counts a space under a combining mark as a character; comments cut to one short line; the Ely pin moves to a2cb531; AGENTS.md says gpui draws a shot window only while macOS shows it
CI / platforms (windows-latest) (push) Failing after 7s
CI / macos (push) Failing after 8m50s
CI / platforms (ubuntu-24.04) (push) Canceled after 0s

This commit is contained in:
ZacharyZhang-NY committed 2026-10-15 10:15:53 -04:00
1 parent 5ee67bd406
commit 37220a72d4
11 files changed
+56 -39

No files matched your search

+5 -7
View File
@@ -1,11 +1,9 @@
use ely_gpui_component::forms::{Copy, Paste, SelectAll};
use gpui::{App, InteractiveElement, KeyBinding, Menu, MenuItem, OsAction, actions};
use crate::{
settings::window::OpenSettings,
term::{
input::{Copy, Find, Paste, SelectAll},
zoom,
},
term::{input::Find, zoom},
workspace::{CloseSession, NewSession, TogglePanel, ToggleSessions},
};
@@ -14,7 +12,7 @@ actions!(
[Quit, Bigger, Smaller, ResetSize, Minimize, Zoom]
);
/// The menu bar the PRD lists; macOS draws it and names the first menu after the app.
/// The PRD's menu bar.
pub fn menus() -> Vec<Menu> {
let menu = |name: &str, items| Menu {
name: name.to_string().into(),
@@ -69,7 +67,7 @@ pub fn menus() -> Vec<Menu> {
]
}
/// Ghostty's keys for Quit and the font's size, Cmd on macOS and Ctrl elsewhere, Cmd-M to minimize; what they do; then the menus, which show the keys bound by now.
/// Binds app commands before building their menus.
pub fn init(cx: &mut App) {
let (quit, modifier) = if cfg!(target_os = "macos") {
("cmd-q", "cmd")
@@ -97,7 +95,7 @@ pub fn init(cx: &mut App) {
cx.set_menus(menus());
}
/// Minimize and Zoom on a window's root: only a window answers them.
/// Minimize and Zoom, which only a window answers.
pub fn window_actions<E: InteractiveElement>(root: E) -> E {
root.on_action(|_: &Minimize, window, _| {
log::info!("window: minimized");
+3 -2
View File
@@ -1,6 +1,7 @@
use std::ops::Range;
use alacritty_terminal::{grid::Scroll, term::TermMode};
use ely_gpui_component::forms::{Copy, Paste, SelectAll};
use gpui::{
App, Bounds, Context, EntityInputHandler, KeyBinding, KeyDownEvent, KeyUpEvent, Keystroke,
NoAction, Pixels, Point, UTF16Selection, Window, actions,
@@ -11,7 +12,7 @@ use super::{
view::TerminalView,
};
actions!(elyterminal, [Copy, Paste, Find, FindNewer, SelectAll]);
actions!(elyterminal, [Find, FindNewer]);
/// The key context a terminal's root sets.
pub const CONTEXT: &str = "Terminal";
@@ -19,7 +20,7 @@ pub const CONTEXT: &str = "Terminal";
/// The key context of a terminal's find box.
pub const FIND: &str = "TerminalFind";
/// Copy, paste, select all and find; Ely's focus keys go to the terminal's listeners instead.
/// The terminal's keys; Ely's focus keys reach its listeners.
pub fn bind_keys(cx: &mut App) {
let (copy, paste, all, find) = if cfg!(target_os = "macos") {
("cmd-c", "cmd-v", "cmd-a", "cmd-f")
+25 -10
View File
@@ -298,7 +298,7 @@ impl TerminalView {
(!text.is_empty()).then_some(text)
}
/// Selects the history and the screen, blanks around them left out; copy on select takes the text.
/// Selects all text; copy on select takes it.
pub(super) fn select_all(&mut self, cx: &mut Context<Self>) {
{
let mut term = self.pty.term.lock();
@@ -367,13 +367,17 @@ impl TerminalView {
}
}
/// Ghostty's select all: the first cell holding more than a space or tab, through history and screen, to the last.
/// Ghostty's select all: first to last non-blank cell.
fn everything<T>(term: &Term<T>) -> Option<Selection> {
let grid = term.grid();
let cells = (grid.topmost_line().0..=grid.bottommost_line().0).flat_map(|line| {
(0..grid.columns()).map(move |column| Cell::new(Line(line), Column(column)))
});
let inked = |cell: &Cell| !matches!(grid[*cell].c, ' ' | '\t');
let inked = |point: &Cell| {
let cell = &grid[*point];
let marked = cell.zerowidth().is_some_and(|marks| !marks.is_empty());
marked || !matches!(cell.c, ' ' | '\t')
};
let first = cells.clone().find(inked)?;
let last = cells.rev().find(inked)?;
let mut all = Selection::new(SelectionType::Simple, first, Side::Left);
@@ -391,14 +395,25 @@ mod tests {
use super::*;
/// What select all copies after `bytes`.
fn all(bytes: &[u8]) -> Option<String> {
let mut term = Term::new(Config::default(), &TermSize::new(10, 3), VoidListener);
let mut parser: Processor = Processor::new();
parser.advance(&mut term, bytes);
term.selection = everything(&term);
term.selection_to_string()
}
#[test]
fn everything_runs_from_the_first_character_in_the_history_to_the_last() {
let mut term = Term::new(Config::default(), &TermSize::new(10, 3), VoidListener);
assert!(everything(&term).is_none(), "a blank grid selects nothing");
let mut parser: Processor = Processor::new();
parser.advance(&mut term, b"\r\n one\r\n\r\ntwo six\t\r\n\r\n");
term.selection = everything(&term);
let text = term.selection_to_string().expect("a selection");
assert_eq!(text, "one\n\ntwo six");
assert_eq!(all(b""), None, "a blank grid selects nothing");
let text = all(b"\r\n one\r\n\r\ntwo six\t\r\n\r\n");
assert_eq!(text.as_deref(), Some("one\n\ntwo six"));
let mark = all(" \u{301}".as_bytes());
assert_eq!(mark.as_deref(), Some(" \u{301}"), "a mark on a space");
let last = all("text \u{301}".as_bytes());
assert_eq!(last.as_deref(), Some("text \u{301}"), "a mark ends it");
let link = all(b"\x1b]8;;http://a\x07 \x1b]8;;\x07text");
assert_eq!(link.as_deref(), Some("text"), "a linked space is blank");
}
}
+6 -3
View File
@@ -6,7 +6,10 @@ use alacritty_terminal::{
term::{ClipboardType, TermMode},
vte::ansi::CursorShape,
};
use ely_gpui_component::theme::ActiveTheme;
use ely_gpui_component::{
forms::{Copy, Paste, SelectAll},
theme::ActiveTheme,
};
use futures::StreamExt;
use gpui::{
Bounds, Context, EventEmitter, FocusHandle, Focusable, Font, FontFeatures, FontId, FontStyle,
@@ -18,7 +21,7 @@ use super::{
find::Finder,
frame::frame,
ink::Ink,
input::{self, Copy, Find, Paste, SelectAll},
input::{self, Find},
mouse::MouseMode,
paint::{self, Look},
pointer::Pointer,
@@ -269,7 +272,7 @@ pub fn load_font(font: &Font, system: &TextSystem) -> anyhow::Result<FontId> {
Ok(id)
}
/// The font, cell and metrics the settings give at `points` and this window's scale.
/// Font, cell and metrics at `points` on this window.
fn look(settings: &Settings, points: f32, ink: &Ink, window: &Window) -> anyhow::Result<Look> {
let font = Font {
family: settings.font_family.clone().into(),
+4 -4
View File
@@ -2,18 +2,18 @@ use gpui::{App, Global};
use crate::settings::{FONT_SIZE, SettingsStore};
/// Points the terminal's font stands above the Size setting, below it when negative; Bigger and Smaller move it, nothing saves it.
/// Unsaved font-size offset.
#[derive(Default)]
pub struct Enlarged(f32);
impl Global for Enlarged {}
/// The size the terminal draws its font at: the setting, moved, inside the range.
/// The font size the terminal draws.
pub fn size(cx: &App) -> f32 {
shown(SettingsStore::get(cx).font_size, cx.global::<Enlarged>().0)
}
/// Moves the font `by` points, or back to the setting when `by` is none.
/// Moves the font `by` points; none resets it.
pub fn step(by: Option<f32>, cx: &mut App) {
let setting = SettingsStore::get(cx).font_size;
let enlarged = by.map_or(0.0, |by| moved(setting, cx.global::<Enlarged>().0, by));
@@ -28,7 +28,7 @@ fn shown(setting: f32, enlarged: f32) -> f32 {
(setting + enlarged).clamp(*FONT_SIZE.start(), *FONT_SIZE.end())
}
/// What `enlarged` becomes once the font moves `by` points from where it shows.
/// The offset after moving `by` from the shown size.
fn moved(setting: f32, enlarged: f32, by: f32) -> f32 {
shown(shown(setting, enlarged) + by, 0.0) - setting
}