WIP

Antonio Scandurra created

Change summary

crates/gpui2/src/app.rs                   |  11 
crates/gpui2/src/app/model_context.rs     |  35 ++
crates/gpui2/src/color.rs                 |  10 
crates/gpui2/src/geometry.rs              |  47 +++
crates/terminal2/src/mappings/colors.rs   |  40 ++-
crates/terminal2/src/mappings/keys.rs     | 287 ++++++++++++------------
crates/terminal2/src/mappings/mouse.rs    | 187 +++++----------
crates/terminal2/src/terminal2.rs         | 155 +++++++------
crates/terminal2/src/terminal_settings.rs |  18 
9 files changed, 413 insertions(+), 377 deletions(-)

Detailed changes

crates/gpui2/src/app.rs 🔗

@@ -476,19 +476,14 @@ impl AppContext {
 
     pub fn spawn_on_main<F, R>(
         &self,
-        f: impl FnOnce(&mut MainThread<AppContext>) -> F + Send + 'static,
+        f: impl FnOnce(MainThread<AsyncAppContext>) -> F + Send + 'static,
     ) -> Task<R>
     where
         F: Future<Output = R> + '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<AppContext>>(cx) })
-            })
-        })
+        let cx = self.to_async();
+        self.executor.spawn_on_main(move || f(MainThread(cx)))
     }
 
     pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>

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<Fut, R>(
+        &self,
+        f: impl FnOnce(WeakHandle<T>, MainThread<AsyncAppContext>) -> Fut + Send + 'static,
+    ) -> Task<R>
+    where
+        Fut: Future<Output = R> + '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<T> Borrow<AppContext> for ModelContext<'_, T> {
+    fn borrow(&self) -> &AppContext {
+        &self.app
+    }
+}
+
+impl<T> BorrowMut<AppContext> for ModelContext<'_, T> {
+    fn borrow_mut(&mut self) -> &mut AppContext {
+        &mut self.app
+    }
+}

crates/gpui2/src/color.rs 🔗

@@ -203,6 +203,16 @@ impl Hsla {
     }
 }
 
+// impl From<Hsla> 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<Rgba> for Hsla {
     fn from(color: Rgba) -> Self {
         let r = color.r;

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<T: Clone + Default + Debug> Clone for Point<T> {
     }
 }
 
-#[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<T: Clone + Default + Debug> {
@@ -660,8 +660,9 @@ impl<T> Copy for Corners<T> where T: Copy + Clone + Default + Debug {}
     AddAssign,
     Sub,
     SubAssign,
-    Div,
     Neg,
+    Div,
+    DivAssign,
     PartialEq,
     PartialOrd,
     Serialize,
@@ -670,6 +671,34 @@ impl<T> Copy for Corners<T> 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<f32> for Pixels {
     type Output = Pixels;
 
@@ -703,6 +732,14 @@ impl MulAssign<f32> 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<Pixels> for Pixels {

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<Rgba>) -> 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 {

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<String> {
-    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,
         };

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<impl Iterator<Item = Vec<u8>>> {
     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<u8> {
 }
 
 pub fn mouse_button_report(
-    point: Point,
-    e: &MouseButtonEvent,
+    point: AlacPoint,
+    button: gpui2::MouseButton,
+    modifiers: Modifiers,
     pressed: bool,
     mode: TermMode,
 ) -> Option<Vec<u8>> {
-    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<Vec<u8>> {
-    let button = MouseButton::from_move(e);
+pub fn mouse_moved_report(point: AlacPoint, e: &MouseMoveEvent, mode: TermMode) -> Option<Vec<u8>> {
+    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<Pixels>,
+    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<Pixels>, 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<Vec<u8>> {
-    let Point { line, column } = point;
+fn normal_mouse_report(point: AlacPoint, button: u8, utf8: bool) -> Option<Vec<u8>> {
+    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<Vec<u8>>
     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),
-            )
-        );
-    }
-}

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<Pixels>,
 }
 
 impl TerminalSize {
-    pub fn new(line_height: Pixels, cell_width: Pixels, size: Point<Pixels>) -> Self {
+    pub fn new(line_height: Pixels, cell_width: Pixels, size: Size<Pixels>) -> 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<TerminalBlink>,
         alternate_scroll: AlternateScroll,
         window: AnyWindowHandle,
+        color_for_index: impl Fn(usize, &mut AppContext) -> Hsla + Send + Sync + 'static,
     ) -> Result<TerminalBuilder> {
         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>) -> 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<dyn Fn(usize, &mut AppContext) -> 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<Pixels>) {
-        let position = e.position.sub(origin);
+    pub fn mouse_move(&mut self, e: &MouseMoveEvent, origin: Point<Pixels>) {
+        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<Pixels>) {
-        let position = e.position.sub(origin);
+    pub fn mouse_drag(&mut self, e: MouseMoveEvent, origin: Point<Pixels>) {
+        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<f32> {
+    fn drag_line_delta(&mut self, e: MouseMoveEvent, region: Bounds<Pixels>) -> Option<f32> {
         //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<Pixels>) {
+    pub fn mouse_down(&mut self, e: &MouseDownEvent, origin: Point<Pixels>) {
         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<Pixels>, cx: &mut ModelContext<Self>) {
+    pub fn mouse_up(
+        &mut self,
+        e: &MouseUpEvent,
+        origin: Point<Pixels>,
+        cx: &mut ModelContext<Self>,
+    ) {
         let setting = settings2::get::<TerminalSettings>(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<Pixels>, size: &TerminalSize) -> usize {
-    let col = (pos.x() / size.cell_width()).round() as usize;
-
+fn content_index_for_mouse(pos: Point<Pixels>, 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<Vec<char>> {
         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()

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<f32>,
     pub font_family: Option<String>,
     pub line_height: TerminalLineHeight,
-    pub font_features: Option<fonts::Features>,
+    pub font_features: Option<FontFeatures>,
     pub env: HashMap<String, String>,
     pub blinking: TerminalBlink,
     pub alternate_scroll: AlternateScroll,
@@ -79,7 +78,7 @@ pub struct TerminalSettingsContent {
     pub font_size: Option<f32>,
     pub font_family: Option<String>,
     pub line_height: Option<TerminalLineHeight>,
-    pub font_features: Option<fonts::Features>,
+    pub font_features: Option<FontFeatures>,
     pub env: Option<HashMap<String, String>>,
     pub blinking: Option<TerminalBlink>,
     pub alternate_scroll: Option<AlternateScroll>,
@@ -92,10 +91,11 @@ pub struct TerminalSettingsContent {
 }
 
 impl TerminalSettings {
-    pub fn font_size(&self, cx: &AppContext) -> Option<f32> {
-        self.font_size
-            .map(|size| theme2::adjusted_font_size(size, cx))
-    }
+    // todo!("move to terminal element")
+    // pub fn font_size(&self, cx: &AppContext) -> Option<f32> {
+    //     self.font_size
+    //         .map(|size| theme2::adjusted_font_size(size, cx))
+    // }
 }
 
 impl settings2::Setting for TerminalSettings {