Handlers attached, things are looking good 2 go
This commit is contained in:
parent
04600d73fc
commit
a806634b82
3 changed files with 270 additions and 250 deletions
|
@ -1,26 +1,22 @@
|
|||
use alacritty_terminal::{
|
||||
ansi::{Color as AnsiColor, Color::Named, CursorShape as AlacCursorShape, NamedColor},
|
||||
grid::{Dimensions, Scroll},
|
||||
index::{Column as GridCol, Direction, Line as GridLine, Point, Side},
|
||||
grid::Dimensions,
|
||||
index::Point,
|
||||
selection::SelectionRange,
|
||||
term::{
|
||||
cell::{Cell, Flags},
|
||||
TermMode,
|
||||
},
|
||||
term::cell::{Cell, Flags},
|
||||
};
|
||||
use editor::{Cursor, CursorShape, HighlightedRange, HighlightedRangeLine};
|
||||
use gpui::{
|
||||
color::Color,
|
||||
elements::*,
|
||||
fonts::{Properties, Style::Italic, TextStyle, Underline, Weight},
|
||||
geometry::{
|
||||
rect::RectF,
|
||||
vector::{vec2f, Vector2F},
|
||||
},
|
||||
json::json,
|
||||
serde_json::json,
|
||||
text_layout::{Line, RunStyle},
|
||||
Event, EventContext, FontCache, KeyDownEvent, ModelContext, MouseButton, MouseButtonEvent,
|
||||
MouseRegion, PaintContext, Quad, ScrollWheelEvent, TextLayoutCache, WeakModelHandle,
|
||||
Element, Event, EventContext, FontCache, KeyDownEvent, ModelContext, MouseButton,
|
||||
MouseButtonEvent, MouseRegion, PaintContext, Quad, TextLayoutCache, WeakModelHandle,
|
||||
WeakViewHandle,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
|
@ -29,12 +25,11 @@ use settings::Settings;
|
|||
use theme::TerminalStyle;
|
||||
use util::ResultExt;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::{
|
||||
cmp::min,
|
||||
mem,
|
||||
ops::{Deref, Range},
|
||||
};
|
||||
use std::{fmt::Debug, ops::Sub};
|
||||
|
||||
use crate::{
|
||||
connected_view::{ConnectedView, DeployContextMenu},
|
||||
|
@ -42,11 +37,6 @@ use crate::{
|
|||
Terminal, TerminalSize,
|
||||
};
|
||||
|
||||
///Scrolling is unbearably sluggish by default. Alacritty supports a configurable
|
||||
///Scroll multiplier that is set to 3 by default. This will be removed when I
|
||||
///Implement scroll bars.
|
||||
pub const ALACRITTY_SCROLL_MULTIPLIER: f32 = 3.;
|
||||
|
||||
///The information generated during layout that is nescessary for painting
|
||||
pub struct LayoutState {
|
||||
cells: Vec<LayoutCell>,
|
||||
|
@ -56,7 +46,6 @@ pub struct LayoutState {
|
|||
background_color: Color,
|
||||
selection_color: Color,
|
||||
size: TerminalSize,
|
||||
display_offset: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -420,22 +409,13 @@ impl TerminalEl {
|
|||
fn generic_button_handler(
|
||||
connection: WeakModelHandle<Terminal>,
|
||||
origin: Vector2F,
|
||||
cur_size: TerminalSize,
|
||||
display_offset: usize,
|
||||
f: impl Fn(&mut Terminal, Point, Direction, MouseButtonEvent, &mut ModelContext<Terminal>),
|
||||
f: impl Fn(&mut Terminal, Vector2F, MouseButtonEvent, &mut ModelContext<Terminal>),
|
||||
) -> impl Fn(MouseButtonEvent, &mut EventContext) {
|
||||
move |event, cx| {
|
||||
cx.focus_parent_view();
|
||||
if let Some(conn_handle) = connection.upgrade(cx.app) {
|
||||
conn_handle.update(cx.app, |terminal, cx| {
|
||||
let (point, side) = TerminalEl::mouse_to_cell_data(
|
||||
event.position,
|
||||
origin,
|
||||
cur_size,
|
||||
display_offset,
|
||||
);
|
||||
|
||||
f(terminal, point, side, event, cx);
|
||||
f(terminal, origin, event, cx);
|
||||
|
||||
cx.notify();
|
||||
})
|
||||
|
@ -448,8 +428,6 @@ impl TerminalEl {
|
|||
origin: Vector2F,
|
||||
view_id: usize,
|
||||
visible_bounds: RectF,
|
||||
cur_size: TerminalSize,
|
||||
display_offset: usize,
|
||||
cx: &mut PaintContext,
|
||||
) {
|
||||
let connection = self.terminal;
|
||||
|
@ -459,45 +437,29 @@ impl TerminalEl {
|
|||
if cx.is_parent_view_focused() {
|
||||
if let Some(conn_handle) = connection.upgrade(cx.app) {
|
||||
conn_handle.update(cx.app, |terminal, cx| {
|
||||
let (point, side) = TerminalEl::mouse_to_cell_data(
|
||||
event.position,
|
||||
origin,
|
||||
cur_size,
|
||||
display_offset,
|
||||
);
|
||||
|
||||
terminal.mouse_move(point, side, &event);
|
||||
|
||||
terminal.mouse_move(&event, origin);
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
.on_drag(MouseButton::Left, move |_prev, event, cx| {
|
||||
if cx.is_parent_view_focused() {
|
||||
if let Some(conn_handle) = connection.upgrade(cx.app) {
|
||||
conn_handle.update(cx.app, |terminal, cx| {
|
||||
let (point, side) = TerminalEl::mouse_to_cell_data(
|
||||
event.position,
|
||||
origin,
|
||||
cur_size,
|
||||
display_offset,
|
||||
);
|
||||
|
||||
terminal.mouse_drag(point, side);
|
||||
|
||||
terminal.mouse_drag(event, origin);
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
.on_down(
|
||||
MouseButton::Left,
|
||||
TerminalEl::generic_button_handler(
|
||||
connection,
|
||||
origin,
|
||||
cur_size,
|
||||
display_offset,
|
||||
move |terminal, point, side, _e, _cx| {
|
||||
terminal.mouse_down(point, side);
|
||||
move |terminal, origin, e, _cx| {
|
||||
terminal.mouse_down(&e, origin);
|
||||
},
|
||||
),
|
||||
)
|
||||
|
@ -506,10 +468,8 @@ impl TerminalEl {
|
|||
TerminalEl::generic_button_handler(
|
||||
connection,
|
||||
origin,
|
||||
cur_size,
|
||||
display_offset,
|
||||
move |terminal, point, side, _e, _cx| {
|
||||
terminal.mouse_down(point, side);
|
||||
move |terminal, origin, e, _cx| {
|
||||
terminal.mouse_down(&e, origin);
|
||||
},
|
||||
),
|
||||
)
|
||||
|
@ -518,65 +478,61 @@ impl TerminalEl {
|
|||
TerminalEl::generic_button_handler(
|
||||
connection,
|
||||
origin,
|
||||
cur_size,
|
||||
display_offset,
|
||||
move |terminal, point, side, _e, _cx| {
|
||||
terminal.mouse_down(point, side);
|
||||
move |terminal, origin, e, _cx| {
|
||||
terminal.mouse_down(&e, origin);
|
||||
},
|
||||
),
|
||||
)
|
||||
.on_up(
|
||||
MouseButton::Left,
|
||||
TerminalEl::generic_button_handler(
|
||||
connection,
|
||||
origin,
|
||||
move |terminal, origin, e, _cx| {
|
||||
terminal.mouse_up(&e, origin);
|
||||
},
|
||||
),
|
||||
)
|
||||
.on_up(
|
||||
MouseButton::Right,
|
||||
TerminalEl::generic_button_handler(
|
||||
connection,
|
||||
origin,
|
||||
move |terminal, origin, e, _cx| {
|
||||
terminal.mouse_up(&e, origin);
|
||||
},
|
||||
),
|
||||
)
|
||||
.on_up(
|
||||
MouseButton::Middle,
|
||||
TerminalEl::generic_button_handler(
|
||||
connection,
|
||||
origin,
|
||||
move |terminal, origin, e, _cx| {
|
||||
terminal.mouse_up(&e, origin);
|
||||
},
|
||||
),
|
||||
)
|
||||
//TODO
|
||||
.on_click(
|
||||
MouseButton::Left,
|
||||
TerminalEl::generic_button_handler(
|
||||
connection,
|
||||
origin,
|
||||
cur_size,
|
||||
display_offset,
|
||||
move |terminal, point, side, e, _cx| {
|
||||
terminal.click(point, side, e.click_count);
|
||||
},
|
||||
),
|
||||
)
|
||||
.on_click(
|
||||
MouseButton::Middle,
|
||||
TerminalEl::generic_button_handler(
|
||||
connection,
|
||||
origin,
|
||||
cur_size,
|
||||
display_offset,
|
||||
move |terminal, point, side, e, _cx| {
|
||||
terminal.click(point, side, e.click_count);
|
||||
move |terminal, origin, e, _cx| {
|
||||
terminal.left_click(&e, origin);
|
||||
},
|
||||
),
|
||||
)
|
||||
.on_click(
|
||||
MouseButton::Right,
|
||||
move |e @ MouseButtonEvent { position, .. }, cx| {
|
||||
//Attempt to check the mode
|
||||
if let Some(conn_handle) = connection.upgrade(cx.app) {
|
||||
let handled = conn_handle.update(cx.app, |terminal, _cx| {
|
||||
//Finally, we can check the mode!
|
||||
if terminal.last_mode.intersects(TermMode::MOUSE_MODE) {
|
||||
let (point, side) = TerminalEl::mouse_to_cell_data(
|
||||
position,
|
||||
origin,
|
||||
cur_size,
|
||||
display_offset,
|
||||
);
|
||||
|
||||
terminal.click(point, side, e.click_count);
|
||||
let mouse_mode = if let Some(conn_handle) = connection.upgrade(cx.app) {
|
||||
conn_handle.update(cx.app, |terminal, _cx| terminal.mouse_mode(e.shift))
|
||||
} else {
|
||||
//If we can't get the model handle, probably can't deploy the context menu
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
//If I put this up by the true, then we're in the wrong 'cx'
|
||||
if !handled {
|
||||
cx.dispatch_action(DeployContextMenu { position });
|
||||
}
|
||||
} else {
|
||||
};
|
||||
if !mouse_mode {
|
||||
cx.dispatch_action(DeployContextMenu { position });
|
||||
}
|
||||
},
|
||||
|
@ -615,47 +571,6 @@ impl TerminalEl {
|
|||
underline: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mouse_to_cell_data(
|
||||
pos: Vector2F,
|
||||
origin: Vector2F,
|
||||
cur_size: TerminalSize,
|
||||
display_offset: usize,
|
||||
) -> (Point, alacritty_terminal::index::Direction) {
|
||||
let pos = pos.sub(origin);
|
||||
let point = {
|
||||
let col = pos.x() / cur_size.cell_width; //TODO: underflow...
|
||||
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)
|
||||
};
|
||||
|
||||
//Copied (with modifications) from alacritty/src/input.rs > Processor::cell_side()
|
||||
let side = {
|
||||
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 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
|
||||
{
|
||||
Side::Right
|
||||
} else {
|
||||
Side::Left
|
||||
}
|
||||
};
|
||||
|
||||
(point, side)
|
||||
}
|
||||
}
|
||||
|
||||
impl Element for TerminalEl {
|
||||
|
@ -712,7 +627,7 @@ impl Element for TerminalEl {
|
|||
|
||||
(
|
||||
cells,
|
||||
dbg!(content.selection),
|
||||
content.selection,
|
||||
content.cursor,
|
||||
content.display_offset,
|
||||
cursor_text,
|
||||
|
@ -794,7 +709,6 @@ impl Element for TerminalEl {
|
|||
size: dimensions,
|
||||
rects,
|
||||
highlights,
|
||||
display_offset,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -813,14 +727,7 @@ impl Element for TerminalEl {
|
|||
let origin = bounds.origin() + vec2f(layout.size.cell_width, 0.);
|
||||
|
||||
//Elements are ephemeral, only at paint time do we know what could be clicked by a mouse
|
||||
self.attach_mouse_handlers(
|
||||
origin,
|
||||
self.view.id(),
|
||||
visible_bounds,
|
||||
layout.size,
|
||||
layout.display_offset,
|
||||
cx,
|
||||
);
|
||||
self.attach_mouse_handlers(origin, self.view.id(), visible_bounds, cx);
|
||||
|
||||
cx.paint_layer(clip_bounds, |cx| {
|
||||
//Start with a background color
|
||||
|
@ -884,28 +791,22 @@ impl Element for TerminalEl {
|
|||
fn dispatch_event(
|
||||
&mut self,
|
||||
event: &gpui::Event,
|
||||
_bounds: gpui::geometry::rect::RectF,
|
||||
bounds: gpui::geometry::rect::RectF,
|
||||
visible_bounds: gpui::geometry::rect::RectF,
|
||||
layout: &mut Self::LayoutState,
|
||||
_paint: &mut Self::PaintState,
|
||||
cx: &mut gpui::EventContext,
|
||||
) -> bool {
|
||||
match event {
|
||||
Event::ScrollWheel(ScrollWheelEvent {
|
||||
delta, position, ..
|
||||
}) => visible_bounds
|
||||
.contains_point(*position)
|
||||
Event::ScrollWheel(e) => visible_bounds
|
||||
.contains_point(e.position)
|
||||
.then(|| {
|
||||
let scroll_lines =
|
||||
(delta.y() / layout.size.line_height) * ALACRITTY_SCROLL_MULTIPLIER;
|
||||
let origin = bounds.origin() + vec2f(layout.size.cell_width, 0.);
|
||||
|
||||
if let Some(terminal) = self.terminal.upgrade(cx.app) {
|
||||
terminal.update(cx.app, |term, _| {
|
||||
term.scroll(Scroll::Delta(scroll_lines.round() as i32))
|
||||
});
|
||||
}
|
||||
|
||||
terminal.update(cx.app, |term, _| term.scroll(e, origin));
|
||||
cx.notify();
|
||||
}
|
||||
})
|
||||
.is_some(),
|
||||
Event::KeyDown(KeyDownEvent { keystroke, .. }) => {
|
||||
|
@ -913,7 +814,6 @@ impl Element for TerminalEl {
|
|||
return false;
|
||||
}
|
||||
|
||||
//TODO Talk to keith about how to catch events emitted from an element.
|
||||
if let Some(view) = self.view.upgrade(cx.app) {
|
||||
view.update(cx.app, |view, cx| {
|
||||
view.clear_bel(cx);
|
||||
|
@ -969,36 +869,3 @@ impl Element for TerminalEl {
|
|||
Some(layout.cursor.as_ref()?.bounding_rect(origin))
|
||||
}
|
||||
}
|
||||
|
||||
mod test {
|
||||
|
||||
#[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::connected_el::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 (point, _) =
|
||||
crate::connected_el::TerminalEl::mouse_to_cell_data(mouse_pos, origin, 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),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,23 @@
|
|||
use std::cmp::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::Point, term::TermMode};
|
||||
use gpui::{MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent};
|
||||
use alacritty_terminal::index::{Column as GridCol, Line as GridLine, Point, Side};
|
||||
use alacritty_terminal::term::TermMode;
|
||||
use gpui::{geometry::vector::Vector2F, MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent};
|
||||
|
||||
pub struct Modifiers {
|
||||
use crate::TerminalSize;
|
||||
|
||||
struct Modifiers {
|
||||
ctrl: bool,
|
||||
shift: bool,
|
||||
alt: bool,
|
||||
}
|
||||
|
||||
impl Modifiers {
|
||||
pub fn from_moved(e: &MouseMovedEvent) -> Self {
|
||||
fn from_moved(e: &MouseMovedEvent) -> Self {
|
||||
Modifiers {
|
||||
ctrl: e.ctrl,
|
||||
shift: e.shift,
|
||||
|
@ -18,7 +25,7 @@ impl Modifiers {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_button(e: &MouseButtonEvent) -> Self {
|
||||
fn from_button(e: &MouseButtonEvent) -> Self {
|
||||
Modifiers {
|
||||
ctrl: e.ctrl,
|
||||
shift: e.shift,
|
||||
|
@ -27,7 +34,7 @@ impl Modifiers {
|
|||
}
|
||||
|
||||
//TODO: Determine if I should add modifiers into the ScrollWheelEvent type
|
||||
pub fn from_scroll() -> Self {
|
||||
fn from_scroll() -> Self {
|
||||
Modifiers {
|
||||
ctrl: false,
|
||||
shift: false,
|
||||
|
@ -36,13 +43,13 @@ impl Modifiers {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum MouseFormat {
|
||||
enum MouseFormat {
|
||||
SGR,
|
||||
Normal(bool),
|
||||
}
|
||||
|
||||
impl MouseFormat {
|
||||
pub fn from_mode(mode: TermMode) -> Self {
|
||||
fn from_mode(mode: TermMode) -> Self {
|
||||
if mode.contains(TermMode::SGR_MOUSE) {
|
||||
MouseFormat::SGR
|
||||
} else if mode.contains(TermMode::UTF8_MOUSE) {
|
||||
|
@ -53,7 +60,7 @@ impl MouseFormat {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum MouseButton {
|
||||
enum MouseButton {
|
||||
LeftButton = 0,
|
||||
MiddleButton = 1,
|
||||
RightButton = 2,
|
||||
|
@ -67,7 +74,7 @@ pub enum MouseButton {
|
|||
}
|
||||
|
||||
impl MouseButton {
|
||||
pub fn from_move(e: &MouseMovedEvent) -> Self {
|
||||
fn from_move(e: &MouseMovedEvent) -> Self {
|
||||
match e.pressed_button {
|
||||
Some(b) => match b {
|
||||
gpui::MouseButton::Left => MouseButton::LeftMove,
|
||||
|
@ -79,7 +86,7 @@ impl MouseButton {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_button(e: &MouseButtonEvent) -> Self {
|
||||
fn from_button(e: &MouseButtonEvent) -> Self {
|
||||
match e.button {
|
||||
gpui::MouseButton::Left => MouseButton::LeftButton,
|
||||
gpui::MouseButton::Right => MouseButton::MiddleButton,
|
||||
|
@ -88,7 +95,7 @@ impl MouseButton {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_scroll(e: &ScrollWheelEvent) -> Self {
|
||||
fn from_scroll(e: &ScrollWheelEvent) -> Self {
|
||||
if e.delta.y() > 0. {
|
||||
MouseButton::ScrollUp
|
||||
} else {
|
||||
|
@ -96,7 +103,7 @@ impl MouseButton {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_other(&self) -> bool {
|
||||
fn is_other(&self) -> bool {
|
||||
match self {
|
||||
MouseButton::Other => true,
|
||||
_ => false,
|
||||
|
@ -109,24 +116,31 @@ pub fn scroll_report(
|
|||
scroll_lines: i32,
|
||||
e: &ScrollWheelEvent,
|
||||
mode: TermMode,
|
||||
) -> Option<Vec<Vec<u8>>> {
|
||||
) -> Option<impl Iterator<Item = Vec<u8>>> {
|
||||
if mode.intersects(TermMode::MOUSE_MODE) && scroll_lines >= 1 {
|
||||
if let Some(report) = mouse_report(
|
||||
mouse_report(
|
||||
point,
|
||||
MouseButton::from_scroll(e),
|
||||
true,
|
||||
Modifiers::from_scroll(),
|
||||
MouseFormat::from_mode(mode),
|
||||
) {
|
||||
let mut res = vec![];
|
||||
for _ in 0..scroll_lines.abs() {
|
||||
res.push(report.clone());
|
||||
}
|
||||
return Some(res);
|
||||
)
|
||||
.map(|report| repeat(report).take(scroll_lines as usize))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
pub fn alt_scroll(scroll_lines: i32) -> Vec<u8> {
|
||||
let cmd = if scroll_lines > 0 { b'A' } else { b'B' };
|
||||
|
||||
let mut content = Vec::with_capacity(scroll_lines as usize * 3);
|
||||
for _ in 0..scroll_lines {
|
||||
content.push(0x1b);
|
||||
content.push(b'O');
|
||||
content.push(cmd);
|
||||
}
|
||||
content
|
||||
}
|
||||
|
||||
pub fn mouse_button_report(
|
||||
|
@ -164,6 +178,31 @@ pub fn mouse_moved_report(point: Point, e: &MouseMovedEvent, mode: TermMode) ->
|
|||
}
|
||||
}
|
||||
|
||||
pub fn mouse_side(pos: Vector2F, cur_size: TerminalSize) -> alacritty_terminal::index::Direction {
|
||||
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 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
|
||||
{
|
||||
Side::Right
|
||||
} else {
|
||||
Side::Left
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mouse_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)
|
||||
}
|
||||
|
||||
///Generate the bytes to send to the terminal, from the cell location, a mouse event, and the terminal mode
|
||||
fn mouse_report(
|
||||
point: Point,
|
||||
|
@ -246,3 +285,38 @@ fn sgr_mouse_report(point: Point, button: u8, pressed: bool) -> String {
|
|||
|
||||
msg
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::mappings::mouse::mouse_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 = mouse_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),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,16 +24,19 @@ use futures::{
|
|||
FutureExt,
|
||||
};
|
||||
|
||||
use mappings::mouse::mouse_moved_report;
|
||||
use mappings::mouse::{
|
||||
alt_scroll, mouse_button_report, mouse_moved_report, mouse_point, mouse_side, scroll_report,
|
||||
};
|
||||
use modal::deploy_modal;
|
||||
use settings::{Settings, Shell, TerminalBlink};
|
||||
use std::{collections::HashMap, fmt::Display, path::PathBuf, sync::Arc, time::Duration};
|
||||
use std::{collections::HashMap, fmt::Display, ops::Sub, path::PathBuf, sync::Arc, time::Duration};
|
||||
use thiserror::Error;
|
||||
|
||||
use gpui::{
|
||||
geometry::vector::{vec2f, Vector2F},
|
||||
keymap::Keystroke,
|
||||
ClipboardItem, Entity, ModelContext, MouseMovedEvent, MutableAppContext,
|
||||
ClipboardItem, Entity, ModelContext, MouseButtonEvent, MouseMovedEvent, MutableAppContext,
|
||||
ScrollWheelEvent,
|
||||
};
|
||||
|
||||
use crate::mappings::{
|
||||
|
@ -49,6 +52,11 @@ pub fn init(cx: &mut MutableAppContext) {
|
|||
connected_view::init(cx);
|
||||
}
|
||||
|
||||
///Scrolling is unbearably sluggish by default. Alacritty supports a configurable
|
||||
///Scroll multiplier that is set to 3 by default. This will be removed when I
|
||||
///Implement scroll bars.
|
||||
pub const ALACRITTY_SCROLL_MULTIPLIER: f32 = 3.;
|
||||
|
||||
const DEBUG_TERMINAL_WIDTH: f32 = 500.;
|
||||
const DEBUG_TERMINAL_HEIGHT: f32 = 30.;
|
||||
const DEBUG_CELL_WIDTH: f32 = 5.;
|
||||
|
@ -348,6 +356,7 @@ impl TerminalBuilder {
|
|||
last_mode: TermMode::NONE,
|
||||
cur_size: initial_size,
|
||||
last_mouse: None,
|
||||
last_offset: 0,
|
||||
};
|
||||
|
||||
Ok(TerminalBuilder {
|
||||
|
@ -417,6 +426,7 @@ pub struct Terminal {
|
|||
title: String,
|
||||
cur_size: TerminalSize,
|
||||
last_mode: TermMode,
|
||||
last_offset: usize,
|
||||
last_mouse: Option<(Point, Direction)>,
|
||||
}
|
||||
|
||||
|
@ -509,7 +519,7 @@ impl Terminal {
|
|||
}
|
||||
|
||||
pub fn input(&mut self, input: String) {
|
||||
self.scroll(Scroll::Bottom);
|
||||
self.events.push(InternalEvent::Scroll(Scroll::Bottom));
|
||||
self.events.push(InternalEvent::SetSelection(None));
|
||||
self.write_to_pty(input);
|
||||
}
|
||||
|
@ -563,11 +573,12 @@ impl Terminal {
|
|||
self.process_terminal_event(&e, &mut term, cx)
|
||||
}
|
||||
|
||||
// self.utilization = Self::estimate_utilization(term.take_last_processed_bytes());
|
||||
self.last_mode = *term.mode();
|
||||
|
||||
let content = term.renderable_content();
|
||||
|
||||
self.last_offset = content.display_offset;
|
||||
|
||||
let cursor_text = term.grid()[content.cursor.point].c;
|
||||
|
||||
f(content, cursor_text)
|
||||
|
@ -602,23 +613,45 @@ impl Terminal {
|
|||
}
|
||||
}
|
||||
|
||||
/// Handle a mouse move
|
||||
pub fn mouse_move(&mut self, point: Point, side: Direction, e: &MouseMovedEvent) {
|
||||
if self.mouse_changed(point, side) {
|
||||
pub fn mouse_mode(&self, shift: bool) -> bool {
|
||||
self.last_mode.intersects(TermMode::MOUSE_MODE) && !shift
|
||||
}
|
||||
|
||||
pub fn mouse_move(&mut self, e: &MouseMovedEvent, origin: Vector2F) {
|
||||
let position = e.position.sub(origin);
|
||||
|
||||
let point = mouse_point(position, self.cur_size, self.last_offset);
|
||||
let side = mouse_side(position, self.cur_size);
|
||||
|
||||
if self.mouse_changed(point, side) && self.mouse_mode(e.shift) {
|
||||
if let Some(bytes) = mouse_moved_report(point, e, self.last_mode) {
|
||||
self.pty_tx.notify(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mouse_drag(&mut self, point: Point, side: Direction) {
|
||||
pub fn mouse_drag(&mut self, e: MouseMovedEvent, origin: Vector2F) {
|
||||
let position = e.position.sub(origin);
|
||||
|
||||
if !self.mouse_mode(e.shift) {
|
||||
let point = mouse_point(position, self.cur_size, self.last_offset);
|
||||
let side = mouse_side(position, self.cur_size);
|
||||
|
||||
self.events
|
||||
.push(InternalEvent::UpdateSelection((point, side)));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mouse_down(&mut self, point: Point, side: Direction) {
|
||||
if self.last_mode.intersects(TermMode::MOUSE_REPORT_CLICK) {
|
||||
//TODE: MOUSE MODE
|
||||
pub fn mouse_down(&mut self, e: &MouseButtonEvent, origin: Vector2F) {
|
||||
let position = e.position.sub(origin);
|
||||
|
||||
let point = mouse_point(position, self.cur_size, self.last_offset);
|
||||
let side = mouse_side(position, self.cur_size);
|
||||
|
||||
if self.mouse_mode(e.shift) {
|
||||
if let Some(bytes) = mouse_button_report(point, e, true, self.last_mode) {
|
||||
self.pty_tx.notify(bytes);
|
||||
}
|
||||
} else {
|
||||
self.events
|
||||
.push(InternalEvent::SetSelection(Some(Selection::new(
|
||||
|
@ -629,11 +662,15 @@ impl Terminal {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn click(&mut self, point: Point, side: Direction, clicks: usize) {
|
||||
if self.last_mode.intersects(TermMode::MOUSE_MODE) {
|
||||
//TODE: MOUSE MODE
|
||||
} else {
|
||||
let selection_type = match clicks {
|
||||
pub fn left_click(&mut self, e: &MouseButtonEvent, origin: Vector2F) {
|
||||
let position = e.position.sub(origin);
|
||||
//TODO: Alt-click cursor position
|
||||
|
||||
if !self.mouse_mode(e.shift) {
|
||||
let point = mouse_point(position, self.cur_size, self.last_offset);
|
||||
let side = mouse_side(position, self.cur_size);
|
||||
|
||||
let selection_type = match e.click_count {
|
||||
0 => return, //This is a release
|
||||
1 => Some(SelectionType::Simple),
|
||||
2 => Some(SelectionType::Semantic),
|
||||
|
@ -648,15 +685,57 @@ impl Terminal {
|
|||
}
|
||||
}
|
||||
|
||||
///Scroll the terminal
|
||||
pub fn scroll(&mut self, scroll: Scroll) {
|
||||
if self.last_mode.intersects(TermMode::MOUSE_MODE) {
|
||||
//TODE: MOUSE MODE
|
||||
pub fn mouse_up(&mut self, e: &MouseButtonEvent, origin: Vector2F) {
|
||||
let position = e.position.sub(origin);
|
||||
|
||||
if self.mouse_mode(e.shift) {
|
||||
let point = mouse_point(position, self.cur_size, self.last_offset);
|
||||
|
||||
if let Some(bytes) = mouse_button_report(point, e, false, self.last_mode) {
|
||||
self.pty_tx.notify(bytes);
|
||||
}
|
||||
} else {
|
||||
// Seems pretty standard to automatically copy on mouse_up for terminals,
|
||||
// so let's do that here
|
||||
self.copy();
|
||||
}
|
||||
}
|
||||
|
||||
///Scroll the terminal
|
||||
pub fn scroll(&mut self, scroll: &ScrollWheelEvent, origin: Vector2F) {
|
||||
if self.mouse_mode(false) {
|
||||
//TODO: Currently this only sends the current scroll reports as they come in. Alacritty
|
||||
//Sends the *entire* scroll delta on *every* scroll event, only resetting it when
|
||||
//The scroll enters 'TouchPhase::Started'. Do I need to replicate this?
|
||||
//This would be consistent with a scroll model based on 'distance from origin'...
|
||||
let scroll_lines = (scroll.delta.y() / self.cur_size.line_height) as i32;
|
||||
let point = mouse_point(scroll.position.sub(origin), self.cur_size, self.last_offset);
|
||||
|
||||
if let Some(scrolls) = scroll_report(point, scroll_lines as i32, scroll, self.last_mode)
|
||||
{
|
||||
for scroll in scrolls {
|
||||
self.pty_tx.notify(scroll);
|
||||
}
|
||||
};
|
||||
} else if self
|
||||
.last_mode
|
||||
.contains(TermMode::ALT_SCREEN | TermMode::ALTERNATE_SCROLL)
|
||||
{
|
||||
//TODO: See above TODO, also applies here.
|
||||
let scroll_lines = ((scroll.delta.y() * ALACRITTY_SCROLL_MULTIPLIER)
|
||||
/ self.cur_size.line_height) as i32;
|
||||
|
||||
self.pty_tx.notify(alt_scroll(scroll_lines))
|
||||
} else {
|
||||
let scroll_lines = ((scroll.delta.y() * ALACRITTY_SCROLL_MULTIPLIER)
|
||||
/ self.cur_size.line_height) as i32;
|
||||
if scroll_lines != 0 {
|
||||
let scroll = Scroll::Delta(scroll_lines);
|
||||
self.events.push(InternalEvent::Scroll(scroll));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Terminal {
|
||||
fn drop(&mut self) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue