diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index ad7318d529..4674893693 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -476,19 +476,14 @@ impl AppContext { pub fn spawn_on_main( &self, - f: impl FnOnce(&mut MainThread) -> F + Send + 'static, + f: impl FnOnce(MainThread) -> F + Send + 'static, ) -> Task where F: Future + 'static, R: Send + 'static, { - let this = self.this.upgrade().unwrap(); - self.executor.spawn_on_main(move || { - let cx = &mut *this.lock(); - cx.update(|cx| { - f(unsafe { mem::transmute::<&mut AppContext, &mut MainThread>(cx) }) - }) - }) + let cx = self.to_async(); + self.executor.spawn_on_main(move || f(MainThread(cx))) } pub fn spawn(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task diff --git a/crates/gpui2/src/app/model_context.rs b/crates/gpui2/src/app/model_context.rs index 0b84cbe93e..35237d91cf 100644 --- a/crates/gpui2/src/app/model_context.rs +++ b/crates/gpui2/src/app/model_context.rs @@ -1,10 +1,15 @@ use crate::{ - AppContext, AsyncAppContext, Context, Effect, EntityId, EventEmitter, Handle, Reference, - Subscription, Task, WeakHandle, + AppContext, AsyncAppContext, Context, Effect, EntityId, EventEmitter, Handle, MainThread, + Reference, Subscription, Task, WeakHandle, }; use derive_more::{Deref, DerefMut}; use futures::FutureExt; -use std::{any::TypeId, future::Future, marker::PhantomData}; +use std::{ + any::TypeId, + borrow::{Borrow, BorrowMut}, + future::Future, + marker::PhantomData, +}; #[derive(Deref, DerefMut)] pub struct ModelContext<'a, T> { @@ -174,6 +179,18 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> { let this = self.weak_handle(); self.app.spawn(|cx| f(this, cx)) } + + pub fn spawn_on_main( + &self, + f: impl FnOnce(WeakHandle, MainThread) -> Fut + Send + 'static, + ) -> Task + where + Fut: Future + 'static, + R: Send + 'static, + { + let this = self.weak_handle(); + self.app.spawn_on_main(|cx| f(this, cx)) + } } impl<'a, T: EventEmitter + Send + Sync + 'static> ModelContext<'a, T> { @@ -204,3 +221,15 @@ impl<'a, T: 'static> Context for ModelContext<'a, T> { self.app.update_entity(handle, update) } } + +impl Borrow for ModelContext<'_, T> { + fn borrow(&self) -> &AppContext { + &self.app + } +} + +impl BorrowMut for ModelContext<'_, T> { + fn borrow_mut(&mut self) -> &mut AppContext { + &mut self.app + } +} diff --git a/crates/gpui2/src/color.rs b/crates/gpui2/src/color.rs index f6ea2549ec..608ef6ab08 100644 --- a/crates/gpui2/src/color.rs +++ b/crates/gpui2/src/color.rs @@ -203,6 +203,16 @@ impl Hsla { } } +// impl From for Rgba { +// fn from(value: Hsla) -> Self { +// let h = value.h; +// let s = value.s; +// let l = value.l; + +// let c = (1 - |2L - 1|) X s +// } +// } + impl From for Hsla { fn from(color: Rgba) -> Self { let r = color.r; diff --git a/crates/gpui2/src/geometry.rs b/crates/gpui2/src/geometry.rs index 45b6af9444..eedf8bbb2c 100644 --- a/crates/gpui2/src/geometry.rs +++ b/crates/gpui2/src/geometry.rs @@ -1,5 +1,5 @@ use core::fmt::Debug; -use derive_more::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign}; +use derive_more::{Add, AddAssign, Div, DivAssign, Mul, Neg, Sub, SubAssign}; use refineable::Refineable; use serde_derive::{Deserialize, Serialize}; use std::{ @@ -131,7 +131,7 @@ impl Clone for Point { } } -#[derive(Refineable, Default, Clone, Copy, PartialEq, Div, Hash)] +#[derive(Refineable, Default, Clone, Copy, PartialEq, Div, Hash, Serialize, Deserialize)] #[refineable(debug)] #[repr(C)] pub struct Size { @@ -660,8 +660,9 @@ impl Copy for Corners where T: Copy + Clone + Default + Debug {} AddAssign, Sub, SubAssign, - Div, Neg, + Div, + DivAssign, PartialEq, PartialOrd, Serialize, @@ -670,6 +671,34 @@ impl Copy for Corners where T: Copy + Clone + Default + Debug {} #[repr(transparent)] pub struct Pixels(pub(crate) f32); +impl std::ops::Div for Pixels { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + Self(self.0 / rhs.0) + } +} + +impl std::ops::DivAssign for Pixels { + fn div_assign(&mut self, rhs: Self) { + self.0 /= rhs.0; + } +} + +impl std::ops::RemAssign for Pixels { + fn rem_assign(&mut self, rhs: Self) { + self.0 %= rhs.0; + } +} + +impl std::ops::Rem for Pixels { + type Output = Self; + + fn rem(self, rhs: Self) -> Self { + Self(self.0 % rhs.0) + } +} + impl Mul for Pixels { type Output = Pixels; @@ -703,6 +732,14 @@ impl MulAssign for Pixels { impl Pixels { pub const MAX: Pixels = Pixels(f32::MAX); + pub fn as_usize(&self) -> usize { + self.0 as usize + } + + pub fn as_isize(&self) -> isize { + self.0 as isize + } + pub fn floor(&self) -> Self { Self(self.0.floor()) } @@ -714,6 +751,10 @@ impl Pixels { pub fn scale(&self, factor: f32) -> ScaledPixels { ScaledPixels(self.0 * factor) } + + pub fn pow(&self, exponent: f32) -> Self { + Self(self.0.powf(exponent)) + } } impl Mul for Pixels { diff --git a/crates/terminal2/src/mappings/colors.rs b/crates/terminal2/src/mappings/colors.rs index f89413c49c..99b66b9e14 100644 --- a/crates/terminal2/src/mappings/colors.rs +++ b/crates/terminal2/src/mappings/colors.rs @@ -1,9 +1,9 @@ // todo!() -// use alacritty_terminal::{ansi::Color as AnsiColor, term::color::Rgb as AlacRgb}; +use alacritty_terminal::term::color::Rgb as AlacRgb; // use gpui2::color::Color; // use theme2::TerminalStyle; -// ///Converts a 2, 8, or 24 bit color ANSI color to the GPUI equivalent +///Converts a 2, 8, or 24 bit color ANSI color to the GPUI equivalent // pub fn convert_color(alac_color: &AnsiColor, style: &TerminalStyle) -> Color { // match alac_color { // //Named and theme defined colors @@ -45,9 +45,10 @@ // } // } -// ///Converts an 8 bit ANSI color to it's GPUI equivalent. -// ///Accepts usize for compatibility with the alacritty::Colors interface, -// ///Other than that use case, should only be called with values in the [0,255] range +/// TODO: Move this +///Converts an 8 bit ANSI color to it's GPUI equivalent. +///Accepts usize for compatibility with the alacritty::Colors interface, +///Other than that use case, should only be called with values in the [0,255] range // pub fn get_color_at_index(index: &usize, style: &TerminalStyle) -> Color { // match index { // //0-15 are the same as the named colors above @@ -96,14 +97,14 @@ // _ => Color::new(0, 0, 0, 255), // } // } -// ///Generates the rgb channels in [0, 5] for a given index into the 6x6x6 ANSI color cube -// ///See: [8 bit ansi color](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit). -// /// -// ///Wikipedia gives a formula for calculating the index for a given color: -// /// -// ///index = 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5) -// /// -// ///This function does the reverse, calculating the r, g, and b components from a given index. +///Generates the rgb channels in [0, 5] for a given index into the 6x6x6 ANSI color cube +///See: [8 bit ansi color](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit). +/// +///Wikipedia gives a formula for calculating the index for a given color: +/// +///index = 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5) +/// +///This function does the reverse, calculating the r, g, and b components from a given index. // fn rgb_for_index(i: &u8) -> (u8, u8, u8) { // debug_assert!((&16..=&231).contains(&i)); // let i = i - 16; @@ -112,11 +113,16 @@ // let b = (i % 36) % 6; // (r, g, b) // } +use gpui2::Rgba; -// //Convenience method to convert from a GPUI color to an alacritty Rgb -// pub fn to_alac_rgb(color: Color) -> AlacRgb { -// AlacRgb::new(color.r, color.g, color.g) -// } +//Convenience method to convert from a GPUI color to an alacritty Rgb +pub fn to_alac_rgb(color: impl Into) -> AlacRgb { + let color = color.into(); + let r = ((color.r * color.a) * 255.) as u8; + let g = ((color.g * color.a) * 255.) as u8; + let b = ((color.b * color.a) * 255.) as u8; + AlacRgb::new(r, g, b) +} // #[cfg(test)] // mod tests { diff --git a/crates/terminal2/src/mappings/keys.rs b/crates/terminal2/src/mappings/keys.rs index 5a18e0ac2d..0009d39e13 100644 --- a/crates/terminal2/src/mappings/keys.rs +++ b/crates/terminal2/src/mappings/keys.rs @@ -1,9 +1,9 @@ /// The mappings defined in this file where created from reading the alacritty source use alacritty_terminal::term::TermMode; -use gpui2::keymap_matcher::Keystroke; +use gpui2::Keystroke; #[derive(Debug, PartialEq, Eq)] -pub enum Modifiers { +enum AlacModifiers { None, Alt, Ctrl, @@ -12,179 +12,184 @@ pub enum Modifiers { Other, } -impl Modifiers { +impl AlacModifiers { fn new(ks: &Keystroke) -> Self { - match (ks.alt, ks.ctrl, ks.shift, ks.cmd) { - (false, false, false, false) => Modifiers::None, - (true, false, false, false) => Modifiers::Alt, - (false, true, false, false) => Modifiers::Ctrl, - (false, false, true, false) => Modifiers::Shift, - (false, true, true, false) => Modifiers::CtrlShift, - _ => Modifiers::Other, + match ( + ks.modifiers.alt, + ks.modifiers.control, + ks.modifiers.shift, + ks.modifiers.command, + ) { + (false, false, false, false) => AlacModifiers::None, + (true, false, false, false) => AlacModifiers::Alt, + (false, true, false, false) => AlacModifiers::Ctrl, + (false, false, true, false) => AlacModifiers::Shift, + (false, true, true, false) => AlacModifiers::CtrlShift, + _ => AlacModifiers::Other, } } fn any(&self) -> bool { match &self { - Modifiers::None => false, - Modifiers::Alt => true, - Modifiers::Ctrl => true, - Modifiers::Shift => true, - Modifiers::CtrlShift => true, - Modifiers::Other => true, + AlacModifiers::None => false, + AlacModifiers::Alt => true, + AlacModifiers::Ctrl => true, + AlacModifiers::Shift => true, + AlacModifiers::CtrlShift => true, + AlacModifiers::Other => true, } } } pub fn to_esc_str(keystroke: &Keystroke, mode: &TermMode, alt_is_meta: bool) -> Option { - let modifiers = Modifiers::new(keystroke); + let modifiers = AlacModifiers::new(keystroke); // Manual Bindings including modifiers let manual_esc_str = match (keystroke.key.as_ref(), &modifiers) { //Basic special keys - ("tab", Modifiers::None) => Some("\x09".to_string()), - ("escape", Modifiers::None) => Some("\x1b".to_string()), - ("enter", Modifiers::None) => Some("\x0d".to_string()), - ("enter", Modifiers::Shift) => Some("\x0d".to_string()), - ("backspace", Modifiers::None) => Some("\x7f".to_string()), + ("tab", AlacModifiers::None) => Some("\x09".to_string()), + ("escape", AlacModifiers::None) => Some("\x1b".to_string()), + ("enter", AlacModifiers::None) => Some("\x0d".to_string()), + ("enter", AlacModifiers::Shift) => Some("\x0d".to_string()), + ("backspace", AlacModifiers::None) => Some("\x7f".to_string()), //Interesting escape codes - ("tab", Modifiers::Shift) => Some("\x1b[Z".to_string()), - ("backspace", Modifiers::Alt) => Some("\x1b\x7f".to_string()), - ("backspace", Modifiers::Shift) => Some("\x7f".to_string()), - ("home", Modifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => { + ("tab", AlacModifiers::Shift) => Some("\x1b[Z".to_string()), + ("backspace", AlacModifiers::Alt) => Some("\x1b\x7f".to_string()), + ("backspace", AlacModifiers::Shift) => Some("\x7f".to_string()), + ("home", AlacModifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => { Some("\x1b[1;2H".to_string()) } - ("end", Modifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => { + ("end", AlacModifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => { Some("\x1b[1;2F".to_string()) } - ("pageup", Modifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => { + ("pageup", AlacModifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => { Some("\x1b[5;2~".to_string()) } - ("pagedown", Modifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => { + ("pagedown", AlacModifiers::Shift) if mode.contains(TermMode::ALT_SCREEN) => { Some("\x1b[6;2~".to_string()) } - ("home", Modifiers::None) if mode.contains(TermMode::APP_CURSOR) => { + ("home", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => { Some("\x1bOH".to_string()) } - ("home", Modifiers::None) if !mode.contains(TermMode::APP_CURSOR) => { + ("home", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => { Some("\x1b[H".to_string()) } - ("end", Modifiers::None) if mode.contains(TermMode::APP_CURSOR) => { + ("end", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => { Some("\x1bOF".to_string()) } - ("end", Modifiers::None) if !mode.contains(TermMode::APP_CURSOR) => { + ("end", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => { Some("\x1b[F".to_string()) } - ("up", Modifiers::None) if mode.contains(TermMode::APP_CURSOR) => { + ("up", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => { Some("\x1bOA".to_string()) } - ("up", Modifiers::None) if !mode.contains(TermMode::APP_CURSOR) => { + ("up", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => { Some("\x1b[A".to_string()) } - ("down", Modifiers::None) if mode.contains(TermMode::APP_CURSOR) => { + ("down", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => { Some("\x1bOB".to_string()) } - ("down", Modifiers::None) if !mode.contains(TermMode::APP_CURSOR) => { + ("down", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => { Some("\x1b[B".to_string()) } - ("right", Modifiers::None) if mode.contains(TermMode::APP_CURSOR) => { + ("right", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => { Some("\x1bOC".to_string()) } - ("right", Modifiers::None) if !mode.contains(TermMode::APP_CURSOR) => { + ("right", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => { Some("\x1b[C".to_string()) } - ("left", Modifiers::None) if mode.contains(TermMode::APP_CURSOR) => { + ("left", AlacModifiers::None) if mode.contains(TermMode::APP_CURSOR) => { Some("\x1bOD".to_string()) } - ("left", Modifiers::None) if !mode.contains(TermMode::APP_CURSOR) => { + ("left", AlacModifiers::None) if !mode.contains(TermMode::APP_CURSOR) => { Some("\x1b[D".to_string()) } - ("back", Modifiers::None) => Some("\x7f".to_string()), - ("insert", Modifiers::None) => Some("\x1b[2~".to_string()), - ("delete", Modifiers::None) => Some("\x1b[3~".to_string()), - ("pageup", Modifiers::None) => Some("\x1b[5~".to_string()), - ("pagedown", Modifiers::None) => Some("\x1b[6~".to_string()), - ("f1", Modifiers::None) => Some("\x1bOP".to_string()), - ("f2", Modifiers::None) => Some("\x1bOQ".to_string()), - ("f3", Modifiers::None) => Some("\x1bOR".to_string()), - ("f4", Modifiers::None) => Some("\x1bOS".to_string()), - ("f5", Modifiers::None) => Some("\x1b[15~".to_string()), - ("f6", Modifiers::None) => Some("\x1b[17~".to_string()), - ("f7", Modifiers::None) => Some("\x1b[18~".to_string()), - ("f8", Modifiers::None) => Some("\x1b[19~".to_string()), - ("f9", Modifiers::None) => Some("\x1b[20~".to_string()), - ("f10", Modifiers::None) => Some("\x1b[21~".to_string()), - ("f11", Modifiers::None) => Some("\x1b[23~".to_string()), - ("f12", Modifiers::None) => Some("\x1b[24~".to_string()), - ("f13", Modifiers::None) => Some("\x1b[25~".to_string()), - ("f14", Modifiers::None) => Some("\x1b[26~".to_string()), - ("f15", Modifiers::None) => Some("\x1b[28~".to_string()), - ("f16", Modifiers::None) => Some("\x1b[29~".to_string()), - ("f17", Modifiers::None) => Some("\x1b[31~".to_string()), - ("f18", Modifiers::None) => Some("\x1b[32~".to_string()), - ("f19", Modifiers::None) => Some("\x1b[33~".to_string()), - ("f20", Modifiers::None) => Some("\x1b[34~".to_string()), + ("back", AlacModifiers::None) => Some("\x7f".to_string()), + ("insert", AlacModifiers::None) => Some("\x1b[2~".to_string()), + ("delete", AlacModifiers::None) => Some("\x1b[3~".to_string()), + ("pageup", AlacModifiers::None) => Some("\x1b[5~".to_string()), + ("pagedown", AlacModifiers::None) => Some("\x1b[6~".to_string()), + ("f1", AlacModifiers::None) => Some("\x1bOP".to_string()), + ("f2", AlacModifiers::None) => Some("\x1bOQ".to_string()), + ("f3", AlacModifiers::None) => Some("\x1bOR".to_string()), + ("f4", AlacModifiers::None) => Some("\x1bOS".to_string()), + ("f5", AlacModifiers::None) => Some("\x1b[15~".to_string()), + ("f6", AlacModifiers::None) => Some("\x1b[17~".to_string()), + ("f7", AlacModifiers::None) => Some("\x1b[18~".to_string()), + ("f8", AlacModifiers::None) => Some("\x1b[19~".to_string()), + ("f9", AlacModifiers::None) => Some("\x1b[20~".to_string()), + ("f10", AlacModifiers::None) => Some("\x1b[21~".to_string()), + ("f11", AlacModifiers::None) => Some("\x1b[23~".to_string()), + ("f12", AlacModifiers::None) => Some("\x1b[24~".to_string()), + ("f13", AlacModifiers::None) => Some("\x1b[25~".to_string()), + ("f14", AlacModifiers::None) => Some("\x1b[26~".to_string()), + ("f15", AlacModifiers::None) => Some("\x1b[28~".to_string()), + ("f16", AlacModifiers::None) => Some("\x1b[29~".to_string()), + ("f17", AlacModifiers::None) => Some("\x1b[31~".to_string()), + ("f18", AlacModifiers::None) => Some("\x1b[32~".to_string()), + ("f19", AlacModifiers::None) => Some("\x1b[33~".to_string()), + ("f20", AlacModifiers::None) => Some("\x1b[34~".to_string()), // NumpadEnter, Action::Esc("\n".into()); //Mappings for caret notation keys - ("a", Modifiers::Ctrl) => Some("\x01".to_string()), //1 - ("A", Modifiers::CtrlShift) => Some("\x01".to_string()), //1 - ("b", Modifiers::Ctrl) => Some("\x02".to_string()), //2 - ("B", Modifiers::CtrlShift) => Some("\x02".to_string()), //2 - ("c", Modifiers::Ctrl) => Some("\x03".to_string()), //3 - ("C", Modifiers::CtrlShift) => Some("\x03".to_string()), //3 - ("d", Modifiers::Ctrl) => Some("\x04".to_string()), //4 - ("D", Modifiers::CtrlShift) => Some("\x04".to_string()), //4 - ("e", Modifiers::Ctrl) => Some("\x05".to_string()), //5 - ("E", Modifiers::CtrlShift) => Some("\x05".to_string()), //5 - ("f", Modifiers::Ctrl) => Some("\x06".to_string()), //6 - ("F", Modifiers::CtrlShift) => Some("\x06".to_string()), //6 - ("g", Modifiers::Ctrl) => Some("\x07".to_string()), //7 - ("G", Modifiers::CtrlShift) => Some("\x07".to_string()), //7 - ("h", Modifiers::Ctrl) => Some("\x08".to_string()), //8 - ("H", Modifiers::CtrlShift) => Some("\x08".to_string()), //8 - ("i", Modifiers::Ctrl) => Some("\x09".to_string()), //9 - ("I", Modifiers::CtrlShift) => Some("\x09".to_string()), //9 - ("j", Modifiers::Ctrl) => Some("\x0a".to_string()), //10 - ("J", Modifiers::CtrlShift) => Some("\x0a".to_string()), //10 - ("k", Modifiers::Ctrl) => Some("\x0b".to_string()), //11 - ("K", Modifiers::CtrlShift) => Some("\x0b".to_string()), //11 - ("l", Modifiers::Ctrl) => Some("\x0c".to_string()), //12 - ("L", Modifiers::CtrlShift) => Some("\x0c".to_string()), //12 - ("m", Modifiers::Ctrl) => Some("\x0d".to_string()), //13 - ("M", Modifiers::CtrlShift) => Some("\x0d".to_string()), //13 - ("n", Modifiers::Ctrl) => Some("\x0e".to_string()), //14 - ("N", Modifiers::CtrlShift) => Some("\x0e".to_string()), //14 - ("o", Modifiers::Ctrl) => Some("\x0f".to_string()), //15 - ("O", Modifiers::CtrlShift) => Some("\x0f".to_string()), //15 - ("p", Modifiers::Ctrl) => Some("\x10".to_string()), //16 - ("P", Modifiers::CtrlShift) => Some("\x10".to_string()), //16 - ("q", Modifiers::Ctrl) => Some("\x11".to_string()), //17 - ("Q", Modifiers::CtrlShift) => Some("\x11".to_string()), //17 - ("r", Modifiers::Ctrl) => Some("\x12".to_string()), //18 - ("R", Modifiers::CtrlShift) => Some("\x12".to_string()), //18 - ("s", Modifiers::Ctrl) => Some("\x13".to_string()), //19 - ("S", Modifiers::CtrlShift) => Some("\x13".to_string()), //19 - ("t", Modifiers::Ctrl) => Some("\x14".to_string()), //20 - ("T", Modifiers::CtrlShift) => Some("\x14".to_string()), //20 - ("u", Modifiers::Ctrl) => Some("\x15".to_string()), //21 - ("U", Modifiers::CtrlShift) => Some("\x15".to_string()), //21 - ("v", Modifiers::Ctrl) => Some("\x16".to_string()), //22 - ("V", Modifiers::CtrlShift) => Some("\x16".to_string()), //22 - ("w", Modifiers::Ctrl) => Some("\x17".to_string()), //23 - ("W", Modifiers::CtrlShift) => Some("\x17".to_string()), //23 - ("x", Modifiers::Ctrl) => Some("\x18".to_string()), //24 - ("X", Modifiers::CtrlShift) => Some("\x18".to_string()), //24 - ("y", Modifiers::Ctrl) => Some("\x19".to_string()), //25 - ("Y", Modifiers::CtrlShift) => Some("\x19".to_string()), //25 - ("z", Modifiers::Ctrl) => Some("\x1a".to_string()), //26 - ("Z", Modifiers::CtrlShift) => Some("\x1a".to_string()), //26 - ("@", Modifiers::Ctrl) => Some("\x00".to_string()), //0 - ("[", Modifiers::Ctrl) => Some("\x1b".to_string()), //27 - ("\\", Modifiers::Ctrl) => Some("\x1c".to_string()), //28 - ("]", Modifiers::Ctrl) => Some("\x1d".to_string()), //29 - ("^", Modifiers::Ctrl) => Some("\x1e".to_string()), //30 - ("_", Modifiers::Ctrl) => Some("\x1f".to_string()), //31 - ("?", Modifiers::Ctrl) => Some("\x7f".to_string()), //127 + ("a", AlacModifiers::Ctrl) => Some("\x01".to_string()), //1 + ("A", AlacModifiers::CtrlShift) => Some("\x01".to_string()), //1 + ("b", AlacModifiers::Ctrl) => Some("\x02".to_string()), //2 + ("B", AlacModifiers::CtrlShift) => Some("\x02".to_string()), //2 + ("c", AlacModifiers::Ctrl) => Some("\x03".to_string()), //3 + ("C", AlacModifiers::CtrlShift) => Some("\x03".to_string()), //3 + ("d", AlacModifiers::Ctrl) => Some("\x04".to_string()), //4 + ("D", AlacModifiers::CtrlShift) => Some("\x04".to_string()), //4 + ("e", AlacModifiers::Ctrl) => Some("\x05".to_string()), //5 + ("E", AlacModifiers::CtrlShift) => Some("\x05".to_string()), //5 + ("f", AlacModifiers::Ctrl) => Some("\x06".to_string()), //6 + ("F", AlacModifiers::CtrlShift) => Some("\x06".to_string()), //6 + ("g", AlacModifiers::Ctrl) => Some("\x07".to_string()), //7 + ("G", AlacModifiers::CtrlShift) => Some("\x07".to_string()), //7 + ("h", AlacModifiers::Ctrl) => Some("\x08".to_string()), //8 + ("H", AlacModifiers::CtrlShift) => Some("\x08".to_string()), //8 + ("i", AlacModifiers::Ctrl) => Some("\x09".to_string()), //9 + ("I", AlacModifiers::CtrlShift) => Some("\x09".to_string()), //9 + ("j", AlacModifiers::Ctrl) => Some("\x0a".to_string()), //10 + ("J", AlacModifiers::CtrlShift) => Some("\x0a".to_string()), //10 + ("k", AlacModifiers::Ctrl) => Some("\x0b".to_string()), //11 + ("K", AlacModifiers::CtrlShift) => Some("\x0b".to_string()), //11 + ("l", AlacModifiers::Ctrl) => Some("\x0c".to_string()), //12 + ("L", AlacModifiers::CtrlShift) => Some("\x0c".to_string()), //12 + ("m", AlacModifiers::Ctrl) => Some("\x0d".to_string()), //13 + ("M", AlacModifiers::CtrlShift) => Some("\x0d".to_string()), //13 + ("n", AlacModifiers::Ctrl) => Some("\x0e".to_string()), //14 + ("N", AlacModifiers::CtrlShift) => Some("\x0e".to_string()), //14 + ("o", AlacModifiers::Ctrl) => Some("\x0f".to_string()), //15 + ("O", AlacModifiers::CtrlShift) => Some("\x0f".to_string()), //15 + ("p", AlacModifiers::Ctrl) => Some("\x10".to_string()), //16 + ("P", AlacModifiers::CtrlShift) => Some("\x10".to_string()), //16 + ("q", AlacModifiers::Ctrl) => Some("\x11".to_string()), //17 + ("Q", AlacModifiers::CtrlShift) => Some("\x11".to_string()), //17 + ("r", AlacModifiers::Ctrl) => Some("\x12".to_string()), //18 + ("R", AlacModifiers::CtrlShift) => Some("\x12".to_string()), //18 + ("s", AlacModifiers::Ctrl) => Some("\x13".to_string()), //19 + ("S", AlacModifiers::CtrlShift) => Some("\x13".to_string()), //19 + ("t", AlacModifiers::Ctrl) => Some("\x14".to_string()), //20 + ("T", AlacModifiers::CtrlShift) => Some("\x14".to_string()), //20 + ("u", AlacModifiers::Ctrl) => Some("\x15".to_string()), //21 + ("U", AlacModifiers::CtrlShift) => Some("\x15".to_string()), //21 + ("v", AlacModifiers::Ctrl) => Some("\x16".to_string()), //22 + ("V", AlacModifiers::CtrlShift) => Some("\x16".to_string()), //22 + ("w", AlacModifiers::Ctrl) => Some("\x17".to_string()), //23 + ("W", AlacModifiers::CtrlShift) => Some("\x17".to_string()), //23 + ("x", AlacModifiers::Ctrl) => Some("\x18".to_string()), //24 + ("X", AlacModifiers::CtrlShift) => Some("\x18".to_string()), //24 + ("y", AlacModifiers::Ctrl) => Some("\x19".to_string()), //25 + ("Y", AlacModifiers::CtrlShift) => Some("\x19".to_string()), //25 + ("z", AlacModifiers::Ctrl) => Some("\x1a".to_string()), //26 + ("Z", AlacModifiers::CtrlShift) => Some("\x1a".to_string()), //26 + ("@", AlacModifiers::Ctrl) => Some("\x00".to_string()), //0 + ("[", AlacModifiers::Ctrl) => Some("\x1b".to_string()), //27 + ("\\", AlacModifiers::Ctrl) => Some("\x1c".to_string()), //28 + ("]", AlacModifiers::Ctrl) => Some("\x1d".to_string()), //29 + ("^", AlacModifiers::Ctrl) => Some("\x1e".to_string()), //30 + ("_", AlacModifiers::Ctrl) => Some("\x1f".to_string()), //31 + ("?", AlacModifiers::Ctrl) => Some("\x7f".to_string()), //127 _ => None, }; if manual_esc_str.is_some() { @@ -232,12 +237,12 @@ pub fn to_esc_str(keystroke: &Keystroke, mode: &TermMode, alt_is_meta: bool) -> } } - let alt_meta_binding = if alt_is_meta && modifiers == Modifiers::Alt && keystroke.key.is_ascii() - { - Some(format!("\x1b{}", keystroke.key)) - } else { - None - }; + let alt_meta_binding = + if alt_is_meta && modifiers == AlacModifiers::Alt && keystroke.key.is_ascii() { + Some(format!("\x1b{}", keystroke.key)) + } else { + None + }; if alt_meta_binding.is_some() { return alt_meta_binding; @@ -259,13 +264,13 @@ pub fn to_esc_str(keystroke: &Keystroke, mode: &TermMode, alt_is_meta: bool) -> /// from: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-PC-Style-Function-Keys fn modifier_code(keystroke: &Keystroke) -> u32 { let mut modifier_code = 0; - if keystroke.shift { + if keystroke.modifiers.shift { modifier_code |= 1; } - if keystroke.alt { + if keystroke.modifiers.alt { modifier_code |= 1 << 1; } - if keystroke.ctrl { + if keystroke.modifiers.control { modifier_code |= 1 << 2; } modifier_code + 1 @@ -273,7 +278,7 @@ fn modifier_code(keystroke: &Keystroke) -> u32 { #[cfg(test)] mod test { - use gpui2::keymap_matcher::Keystroke; + use gpui2::Modifiers; use super::*; @@ -327,11 +332,13 @@ mod test { #[test] fn test_plain_inputs() { let ks = Keystroke { - ctrl: false, - alt: false, - shift: false, - cmd: false, - function: false, + modifiers: Modifiers { + control: false, + alt: false, + shift: false, + command: false, + function: false, + }, key: "🖖🏻".to_string(), //2 char string ime_key: None, }; diff --git a/crates/terminal2/src/mappings/mouse.rs b/crates/terminal2/src/mappings/mouse.rs index 26697d2f06..28ad510fcd 100644 --- a/crates/terminal2/src/mappings/mouse.rs +++ b/crates/terminal2/src/mappings/mouse.rs @@ -1,52 +1,15 @@ -use std::cmp::{max, min}; +use std::cmp::{self, max, min}; use std::iter::repeat; use alacritty_terminal::grid::Dimensions; /// Most of the code, and specifically the constants, in this are copied from Alacritty, /// with modifications for our circumstances -use alacritty_terminal::index::{Column as GridCol, Line as GridLine, Point, Side}; +use alacritty_terminal::index::{Column as GridCol, Line as GridLine, Point as AlacPoint, Side}; use alacritty_terminal::term::TermMode; -use gpui2::platform; -use gpui2::scene::MouseScrollWheel; -use gpui2::{ - geometry::vector::Vector2F, - platform::{MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent}, -}; +use gpui2::{px, Modifiers, MouseButton, MouseMoveEvent, Pixels, Point, ScrollWheelEvent}; use crate::TerminalSize; -struct Modifiers { - ctrl: bool, - shift: bool, - alt: bool, -} - -impl Modifiers { - fn from_moved(e: &MouseMovedEvent) -> Self { - Modifiers { - ctrl: e.ctrl, - shift: e.shift, - alt: e.alt, - } - } - - fn from_button(e: &MouseButtonEvent) -> Self { - Modifiers { - ctrl: e.ctrl, - shift: e.shift, - alt: e.alt, - } - } - - fn from_scroll(scroll: &ScrollWheelEvent) -> Self { - Modifiers { - ctrl: scroll.ctrl, - shift: scroll.shift, - alt: scroll.alt, - } - } -} - enum MouseFormat { SGR, Normal(bool), @@ -65,7 +28,7 @@ impl MouseFormat { } #[derive(Debug)] -enum MouseButton { +enum AlacMouseButton { LeftButton = 0, MiddleButton = 1, RightButton = 2, @@ -78,56 +41,61 @@ enum MouseButton { Other = 99, } -impl MouseButton { - fn from_move(e: &MouseMovedEvent) -> Self { +impl AlacMouseButton { + fn from_move(e: &MouseMoveEvent) -> Self { match e.pressed_button { Some(b) => match b { - platform::MouseButton::Left => MouseButton::LeftMove, - platform::MouseButton::Middle => MouseButton::MiddleMove, - platform::MouseButton::Right => MouseButton::RightMove, - platform::MouseButton::Navigate(_) => MouseButton::Other, + gpui2::MouseButton::Left => AlacMouseButton::LeftMove, + gpui2::MouseButton::Middle => AlacMouseButton::MiddleMove, + gpui2::MouseButton::Right => AlacMouseButton::RightMove, + gpui2::MouseButton::Navigate(_) => AlacMouseButton::Other, }, - None => MouseButton::NoneMove, + None => AlacMouseButton::NoneMove, } } - fn from_button(e: &MouseButtonEvent) -> Self { - match e.button { - platform::MouseButton::Left => MouseButton::LeftButton, - platform::MouseButton::Right => MouseButton::MiddleButton, - platform::MouseButton::Middle => MouseButton::RightButton, - platform::MouseButton::Navigate(_) => MouseButton::Other, + fn from_button(e: MouseButton) -> Self { + match e { + gpui2::MouseButton::Left => AlacMouseButton::LeftButton, + gpui2::MouseButton::Right => AlacMouseButton::MiddleButton, + gpui2::MouseButton::Middle => AlacMouseButton::RightButton, + gpui2::MouseButton::Navigate(_) => AlacMouseButton::Other, } } fn from_scroll(e: &ScrollWheelEvent) -> Self { - if e.delta.raw().y() > 0. { - MouseButton::ScrollUp + let is_positive = match e.delta { + gpui2::ScrollDelta::Pixels(pixels) => pixels.y > px(0.), + gpui2::ScrollDelta::Lines(lines) => lines.y > 0., + }; + + if is_positive { + AlacMouseButton::ScrollUp } else { - MouseButton::ScrollDown + AlacMouseButton::ScrollDown } } fn is_other(&self) -> bool { match self { - MouseButton::Other => true, + AlacMouseButton::Other => true, _ => false, } } } pub fn scroll_report( - point: Point, + point: AlacPoint, scroll_lines: i32, - e: &MouseScrollWheel, + e: &ScrollWheelEvent, mode: TermMode, ) -> Option>> { if mode.intersects(TermMode::MOUSE_MODE) { mouse_report( point, - MouseButton::from_scroll(e), + AlacMouseButton::from_scroll(e), true, - Modifiers::from_scroll(e), + e.modifiers, MouseFormat::from_mode(mode), ) .map(|report| repeat(report).take(max(scroll_lines, 1) as usize)) @@ -149,18 +117,19 @@ pub fn alt_scroll(scroll_lines: i32) -> Vec { } pub fn mouse_button_report( - point: Point, - e: &MouseButtonEvent, + point: AlacPoint, + button: gpui2::MouseButton, + modifiers: Modifiers, pressed: bool, mode: TermMode, ) -> Option> { - let button = MouseButton::from_button(e); + let button = AlacMouseButton::from_button(button); if !button.is_other() && mode.intersects(TermMode::MOUSE_MODE) { mouse_report( point, button, pressed, - Modifiers::from_button(e), + modifiers, MouseFormat::from_mode(mode), ) } else { @@ -168,19 +137,19 @@ pub fn mouse_button_report( } } -pub fn mouse_moved_report(point: Point, e: &MouseMovedEvent, mode: TermMode) -> Option> { - let button = MouseButton::from_move(e); +pub fn mouse_moved_report(point: AlacPoint, e: &MouseMoveEvent, mode: TermMode) -> Option> { + let button = AlacMouseButton::from_move(e); if !button.is_other() && mode.intersects(TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG) { //Only drags are reported in drag mode, so block NoneMove. - if mode.contains(TermMode::MOUSE_DRAG) && matches!(button, MouseButton::NoneMove) { + if mode.contains(TermMode::MOUSE_DRAG) && matches!(button, AlacMouseButton::NoneMove) { None } else { mouse_report( point, button, true, - Modifiers::from_moved(e), + e.modifiers, MouseFormat::from_mode(mode), ) } @@ -189,19 +158,26 @@ pub fn mouse_moved_report(point: Point, e: &MouseMovedEvent, mode: TermMode) -> } } -pub fn mouse_side(pos: Vector2F, cur_size: TerminalSize) -> alacritty_terminal::index::Direction { - if cur_size.cell_width as usize == 0 { +pub fn mouse_side( + pos: Point, + cur_size: TerminalSize, +) -> alacritty_terminal::index::Direction { + let cell_width = cur_size.cell_width.floor(); + if cell_width == px(0.) { return Side::Right; } - let x = pos.0.x() as usize; - let cell_x = x.saturating_sub(cur_size.cell_width as usize) % cur_size.cell_width as usize; - let half_cell_width = (cur_size.cell_width / 2.0) as usize; + + let x = pos.x.floor(); + + let cell_x = cmp::max(px(0.), x - cell_width) % cell_width; + let half_cell_width = (cur_size.cell_width / 2.0).floor(); let additional_padding = (cur_size.width() - cur_size.cell_width * 2.) % cur_size.cell_width; let end_of_grid = cur_size.width() - cur_size.cell_width - additional_padding; + //Width: Pixels or columns? if cell_x > half_cell_width // Edge case when mouse leaves the window. - || x as f32 >= end_of_grid + || x >= end_of_grid { Side::Right } else { @@ -209,18 +185,18 @@ pub fn mouse_side(pos: Vector2F, cur_size: TerminalSize) -> alacritty_terminal:: } } -pub fn grid_point(pos: Vector2F, cur_size: TerminalSize, display_offset: usize) -> Point { - let col = pos.x() / cur_size.cell_width; - let col = min(GridCol(col as usize), cur_size.last_column()); - let line = pos.y() / cur_size.line_height; - let line = min(line as i32, cur_size.bottommost_line().0); - Point::new(GridLine(line - display_offset as i32), col) +pub fn grid_point(pos: Point, cur_size: TerminalSize, display_offset: usize) -> AlacPoint { + let col = GridCol((pos.x / cur_size.cell_width).as_usize()); + let col = min(col, cur_size.last_column()); + let line = (pos.y / cur_size.line_height).as_isize() as i32; + let line = min(line, cur_size.bottommost_line().0); + AlacPoint::new(GridLine(line - display_offset as i32), col) } ///Generate the bytes to send to the terminal, from the cell location, a mouse event, and the terminal mode fn mouse_report( - point: Point, - button: MouseButton, + point: AlacPoint, + button: AlacMouseButton, pressed: bool, modifiers: Modifiers, format: MouseFormat, @@ -236,7 +212,7 @@ fn mouse_report( if modifiers.alt { mods += 8; } - if modifiers.ctrl { + if modifiers.control { mods += 16; } @@ -254,8 +230,8 @@ fn mouse_report( } } -fn normal_mouse_report(point: Point, button: u8, utf8: bool) -> Option> { - let Point { line, column } = point; +fn normal_mouse_report(point: AlacPoint, button: u8, utf8: bool) -> Option> { + let AlacPoint { line, column } = point; let max_point = if utf8 { 2015 } else { 223 }; if line >= max_point || column >= max_point { @@ -286,7 +262,7 @@ fn normal_mouse_report(point: Point, button: u8, utf8: bool) -> Option> Some(msg) } -fn sgr_mouse_report(point: Point, button: u8, pressed: bool) -> String { +fn sgr_mouse_report(point: AlacPoint, button: u8, pressed: bool) -> String { let c = if pressed { 'M' } else { 'm' }; let msg = format!( @@ -299,38 +275,3 @@ fn sgr_mouse_report(point: Point, button: u8, pressed: bool) -> String { msg } - -#[cfg(test)] -mod test { - use crate::mappings::mouse::grid_point; - - #[test] - fn test_mouse_to_selection() { - let term_width = 100.; - let term_height = 200.; - let cell_width = 10.; - let line_height = 20.; - let mouse_pos_x = 100.; //Window relative - let mouse_pos_y = 100.; //Window relative - let origin_x = 10.; - let origin_y = 20.; - - let cur_size = crate::TerminalSize::new( - line_height, - cell_width, - gpui::geometry::vector::vec2f(term_width, term_height), - ); - - let mouse_pos = gpui::geometry::vector::vec2f(mouse_pos_x, mouse_pos_y); - let origin = gpui::geometry::vector::vec2f(origin_x, origin_y); //Position of terminal window, 1 'cell' in - let mouse_pos = mouse_pos - origin; - let point = grid_point(mouse_pos, cur_size, 0); - assert_eq!( - point, - alacritty_terminal::index::Point::new( - alacritty_terminal::index::Line(((mouse_pos_y - origin_y) / line_height) as i32), - alacritty_terminal::index::Column(((mouse_pos_x - origin_x) / cell_width) as usize), - ) - ); - } -} diff --git a/crates/terminal2/src/terminal2.rs b/crates/terminal2/src/terminal2.rs index 4d194cfde8..b48db2e32d 100644 --- a/crates/terminal2/src/terminal2.rs +++ b/crates/terminal2/src/terminal2.rs @@ -37,7 +37,7 @@ use terminal_settings::{AlternateScroll, Shell, TerminalBlink, TerminalSettings} use util::truncate_and_trailoff; use std::{ - cmp::min, + cmp::{self, min}, collections::{HashMap, VecDeque}, fmt::Display, ops::{Deref, Index, RangeInclusive}, @@ -49,15 +49,12 @@ use std::{ use thiserror::Error; use gpui2::{ - px, AnyWindowHandle, AppContext, ClipboardItem, EventEmitter, Keystroke, MainThread, - ModelContext, Modifiers, MouseButton, MouseDragEvent, MouseScrollWheel, MouseUp, Pixels, Point, - Task, TouchPhase, + px, AnyWindowHandle, AppContext, Bounds, ClipboardItem, EventEmitter, Hsla, Keystroke, + MainThread, ModelContext, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, + Pixels, Point, ScrollWheelEvent, Size, Task, TouchPhase, }; -use crate::mappings::{ - colors::{get_color_at_index, to_alac_rgb}, - keys::to_esc_str, -}; +use crate::mappings::{colors::to_alac_rgb, keys::to_esc_str}; use lazy_static::lazy_static; ///Scrolling is unbearably sluggish by default. Alacritty supports a configurable @@ -136,34 +133,32 @@ pub fn init(cx: &mut AppContext) { pub struct TerminalSize { pub cell_width: Pixels, pub line_height: Pixels, - pub height: Pixels, - pub width: Pixels, + pub size: Size, } impl TerminalSize { - pub fn new(line_height: Pixels, cell_width: Pixels, size: Point) -> Self { + pub fn new(line_height: Pixels, cell_width: Pixels, size: Size) -> Self { TerminalSize { cell_width, line_height, - width: size.x(), - height: size.y(), + size, } } pub fn num_lines(&self) -> usize { - (self.height / self.line_height).floor() as usize + f32::from((self.size.height / self.line_height).floor()) as usize } pub fn num_columns(&self) -> usize { - (self.width / self.cell_width).floor() as usize + f32::from((self.size.width / self.cell_width).floor()) as usize } pub fn height(&self) -> Pixels { - self.height + self.size.height } pub fn width(&self) -> Pixels { - self.width + self.size.width } pub fn cell_width(&self) -> Pixels { @@ -179,7 +174,10 @@ impl Default for TerminalSize { TerminalSize::new( DEBUG_LINE_HEIGHT, DEBUG_CELL_WIDTH, - Point::new(DEBUG_TERMINAL_WIDTH, DEBUG_TERMINAL_HEIGHT), + Size { + width: DEBUG_TERMINAL_WIDTH, + height: DEBUG_TERMINAL_HEIGHT, + }, ) } } @@ -287,6 +285,7 @@ impl TerminalBuilder { blink_settings: Option, alternate_scroll: AlternateScroll, window: AnyWindowHandle, + color_for_index: impl Fn(usize, &mut AppContext) -> Hsla + Send + Sync + 'static, ) -> Result { let pty_config = { let alac_shell = match shell.clone() { @@ -392,6 +391,7 @@ impl TerminalBuilder { selection_phase: SelectionPhase::Ended, cmd_pressed: false, hovered_word: false, + color_for_index: Box::new(color_for_index), }; Ok(TerminalBuilder { @@ -402,7 +402,7 @@ impl TerminalBuilder { pub fn subscribe(mut self, cx: &mut ModelContext) -> Terminal { //Event loop - cx.spawn(|this, mut cx| async move { + cx.spawn_on_main(|this, mut cx| async move { use futures::StreamExt; while let Some(event) = self.events_rx.next().await { @@ -545,6 +545,8 @@ pub struct Terminal { selection_phase: SelectionPhase, cmd_pressed: bool, hovered_word: bool, + // An implementation of the 8 bit ANSI color palette + color_for_index: Box Hsla + Send + Sync + 'static>, } impl Terminal { @@ -627,19 +629,17 @@ impl Terminal { ) { match event { InternalEvent::ColorRequest(index, format) => { - let color = term.colors()[*index].unwrap_or_else(|| { - let term_style = &theme::current(cx).terminal; - to_alac_rgb(get_color_at_index(index, &term_style)) - }); + let color = term.colors()[*index] + .unwrap_or_else(|| to_alac_rgb((self.color_for_index)(*index, cx))); self.write_to_pty(format(color)) } InternalEvent::Resize(mut new_size) => { - new_size.height = f32::max(new_size.line_height, new_size.height); - new_size.width = f32::max(new_size.cell_width, new_size.width); + new_size.size.height = cmp::max(new_size.line_height, new_size.height()); + new_size.size.width = cmp::max(new_size.cell_width, new_size.width()); self.last_content.size = new_size.clone(); - self.pty_tx.0.send(Msg::Resize((new_size).into())).ok(); + self.pty_tx.0.send(Msg::Resize(new_size.into())).ok(); term.resize(new_size); } @@ -707,7 +707,8 @@ impl Terminal { InternalEvent::Copy => { if let Some(txt) = term.selection_to_string() { - cx.write_to_clipboard(ClipboardItem::new(txt)) + cx.run_on_main(|cx| cx.write_to_clipboard(ClipboardItem::new(txt))) + .detach(); } } InternalEvent::ScrollToAlacPoint(point) => { @@ -952,11 +953,11 @@ impl Terminal { } pub fn try_modifiers_change(&mut self, modifiers: &Modifiers) -> bool { - let changed = self.cmd_pressed != modifiers.cmd; - if !self.cmd_pressed && modifiers.cmd { + let changed = self.cmd_pressed != modifiers.command; + if !self.cmd_pressed && modifiers.command { self.refresh_hovered_word(); } - self.cmd_pressed = modifiers.cmd; + self.cmd_pressed = modifiers.command; changed } @@ -983,14 +984,14 @@ impl Terminal { let delay = cx.executor().timer(Duration::from_millis(16)); self.sync_task = Some(cx.spawn(|weak_handle, mut cx| async move { delay.await; - cx.update(|cx| { - if let Some(handle) = weak_handle.upgrade(cx) { - handle.update(cx, |terminal, cx| { + if let Some(handle) = weak_handle.upgrade() { + handle + .update(&mut cx, |terminal, cx| { terminal.sync_task.take(); cx.notify(); - }); - } - }); + }) + .ok(); + } })); return; } else { @@ -1069,10 +1070,10 @@ impl Terminal { self.last_content.mode.intersects(TermMode::MOUSE_MODE) && !shift } - pub fn mouse_move(&mut self, e: &MouseMovedEvent, origin: Point) { - let position = e.position.sub(origin); + pub fn mouse_move(&mut self, e: &MouseMoveEvent, origin: Point) { + let position = e.position - origin; self.last_mouse_position = Some(position); - if self.mouse_mode(e.shift) { + if self.mouse_mode(e.modifiers.shift) { let point = grid_point( position, self.last_content.size, @@ -1099,11 +1100,11 @@ impl Terminal { } } - pub fn mouse_drag(&mut self, e: MouseDrag, origin: Point) { - let position = e.position.sub(origin); + pub fn mouse_drag(&mut self, e: MouseMoveEvent, origin: Point) { + let position = e.position - origin; self.last_mouse_position = Some(position); - if !self.mouse_mode(e.shift) { + if !self.mouse_mode(e.modifiers.shift) { self.selection_phase = SelectionPhase::Selecting; // Alacritty has the same ordering, of first updating the selection // then scrolling 15ms later @@ -1125,21 +1126,21 @@ impl Terminal { } } - fn drag_line_delta(&mut self, e: MouseDrag) -> Option { + fn drag_line_delta(&mut self, e: MouseMoveEvent, region: Bounds) -> Option { //TODO: Why do these need to be doubled? Probably the same problem that the IME has - let top = e.region.origin_y() + (self.last_content.size.line_height * 2.); - let bottom = e.region.lower_left().y() - (self.last_content.size.line_height * 2.); - let scroll_delta = if e.position.y() < top { - (top - e.position.y()).powf(1.1) - } else if e.position.y() > bottom { - -((e.position.y() - bottom).powf(1.1)) + let top = region.origin.y + (self.last_content.size.line_height * 2.); + let bottom = region.lower_left().y - (self.last_content.size.line_height * 2.); + let scroll_delta = if e.position.y < top { + (top - e.position.y).powf(1.1) + } else if e.position.y > bottom { + -((e.position.y - bottom).powf(1.1)) } else { return None; //Nothing to do }; Some(scroll_delta) } - pub fn mouse_down(&mut self, e: &MouseDown, origin: Point) { + pub fn mouse_down(&mut self, e: &MouseDownEvent, origin: Point) { let position = e.position.sub(origin); let point = grid_point( position, @@ -1148,7 +1149,9 @@ impl Terminal { ); if self.mouse_mode(e.shift) { - if let Some(bytes) = mouse_button_report(point, e, true, self.last_content.mode) { + if let Some(bytes) = + mouse_button_report(point, e.button, e.modifiers, true, self.last_content.mode) + { self.pty_tx.notify(bytes); } } else if e.button == MouseButton::Left { @@ -1180,7 +1183,12 @@ impl Terminal { } } - pub fn mouse_up(&mut self, e: &MouseUp, origin: Point, cx: &mut ModelContext) { + pub fn mouse_up( + &mut self, + e: &MouseUpEvent, + origin: Point, + cx: &mut ModelContext, + ) { let setting = settings2::get::(cx); let position = e.position.sub(origin); @@ -1191,7 +1199,9 @@ impl Terminal { self.last_content.display_offset, ); - if let Some(bytes) = mouse_button_report(point, e, false, self.last_content.mode) { + if let Some(bytes) = + mouse_button_report(point, e.button, e.modifiers, false, self.last_content.mode) + { self.pty_tx.notify(bytes); } } else { @@ -1274,7 +1284,7 @@ impl Terminal { // Whenever we hit the edges, reset our stored scroll to 0 // so we can respond to changes in direction quickly - self.scroll_px %= self.last_content.size.height; + self.scroll_px %= self.last_content.size.height(); Some(new_offset - old_offset) } @@ -1385,25 +1395,21 @@ fn all_search_matches<'a, T>( RegexIter::new(start, end, AlacDirection::Right, term, regex) } -fn content_index_for_mouse(pos: AlacPoint, size: &TerminalSize) -> usize { - let col = (pos.x() / size.cell_width()).round() as usize; - +fn content_index_for_mouse(pos: Point, size: &TerminalSize) -> usize { + let col = (pos.x / size.cell_width()).round().as_usize(); let clamped_col = min(col, size.columns() - 1); - - let row = (pos.y() / size.line_height()).round() as usize; - + let row = (pos.y / size.line_height()).round().as_usize(); let clamped_row = min(row, size.screen_lines() - 1); - clamped_row * size.columns() + clamped_col } #[cfg(test)] mod tests { use alacritty_terminal::{ - index::{AlacColumn, Line}, + index::{AlacColumn, Line, Point as AlacPoint}, term::cell::Cell, }; - use gpui2::geometry::vecto::vec2f; + use gpui2::{geometry::vecto::vec2f, size, Pixels}; use rand::{distributions::Alphanumeric, rngs::ThreadRng, thread_rng, Rng}; use crate::{content_index_for_mouse, IndexedCell, TerminalContent, TerminalSize}; @@ -1419,10 +1425,12 @@ mod tests { let cell_size = rng.gen_range(5 * PRECISION..20 * PRECISION) as f32 / PRECISION as f32; let size = crate::TerminalSize { - cell_width: cell_size, - line_height: cell_size, - height: cell_size * (viewport_cells as f32), - width: cell_size * (viewport_cells as f32), + cell_width: Pixels::from(cell_size), + line_height: Pixels::from(cell_size), + size: size( + Pixels::from(cell_size * (viewport_cells as f32)), + Pixels::from(cell_size * (viewport_cells as f32)), + ), }; let cells = get_cells(size, &mut rng); @@ -1456,10 +1464,9 @@ mod tests { let mut rng = thread_rng(); let size = crate::TerminalSize { - cell_width: 10., - line_height: 10., - height: 100., - width: 100., + cell_width: Pixels::from(10.), + line_height: Pixels::from(10.), + size: size(Pixels::from(100.), Pixels::from(100.)), }; let cells = get_cells(size, &mut rng); @@ -1478,9 +1485,9 @@ mod tests { fn get_cells(size: TerminalSize, rng: &mut ThreadRng) -> Vec> { let mut cells = Vec::new(); - for _ in 0..((size.height() / size.line_height()) as usize) { + for _ in 0..(f32::from(size.height() / size.line_height()) as usize) { let mut row_vec = Vec::new(); - for _ in 0..((size.width() / size.cell_width()) as usize) { + for _ in 0..(f32::from(size.width() / size.cell_width()) as usize) { let cell_char = rng.sample(Alphanumeric) as char; row_vec.push(cell_char) } @@ -1497,7 +1504,7 @@ mod tests { for col in 0..cells[row].len() { let cell_char = cells[row][col]; ic.push(IndexedCell { - point: Point::new(Line(row as i32), Column(col)), + point: AlacPoint::new(Line(row as i32), Column(col)), cell: Cell { c: cell_char, ..Default::default() diff --git a/crates/terminal2/src/terminal_settings.rs b/crates/terminal2/src/terminal_settings.rs index 9d04b38988..867c3070ba 100644 --- a/crates/terminal2/src/terminal_settings.rs +++ b/crates/terminal2/src/terminal_settings.rs @@ -1,8 +1,7 @@ -use std::{collections::HashMap, path::PathBuf}; - -use gpui2::{fonts, AppContext}; +use gpui2::{AppContext, FontFeatures}; use schemars::JsonSchema; use serde_derive::{Deserialize, Serialize}; +use std::{collections::HashMap, path::PathBuf}; #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "snake_case")] @@ -19,7 +18,7 @@ pub struct TerminalSettings { font_size: Option, pub font_family: Option, pub line_height: TerminalLineHeight, - pub font_features: Option, + pub font_features: Option, pub env: HashMap, pub blinking: TerminalBlink, pub alternate_scroll: AlternateScroll, @@ -79,7 +78,7 @@ pub struct TerminalSettingsContent { pub font_size: Option, pub font_family: Option, pub line_height: Option, - pub font_features: Option, + pub font_features: Option, pub env: Option>, pub blinking: Option, pub alternate_scroll: Option, @@ -92,10 +91,11 @@ pub struct TerminalSettingsContent { } impl TerminalSettings { - pub fn font_size(&self, cx: &AppContext) -> Option { - self.font_size - .map(|size| theme2::adjusted_font_size(size, cx)) - } + // todo!("move to terminal element") + // pub fn font_size(&self, cx: &AppContext) -> Option { + // self.font_size + // .map(|size| theme2::adjusted_font_size(size, cx)) + // } } impl settings2::Setting for TerminalSettings {