@@ -18,7 +18,6 @@ use alacritty_terminal::{
Term,
};
use anyhow::{bail, Result};
-
use futures::{
channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
FutureExt,
@@ -29,11 +28,21 @@ use mappings::mouse::{
};
use modal::deploy_modal;
use settings::{AlternateScroll, Settings, Shell, TerminalBlink};
-use std::{collections::HashMap, fmt::Display, ops::Sub, path::PathBuf, sync::Arc, time::Duration};
+use std::{
+ collections::{HashMap, VecDeque},
+ fmt::Display,
+ ops::Sub,
+ path::PathBuf,
+ sync::Arc,
+ time::Duration,
+};
use thiserror::Error;
use gpui::{
- geometry::vector::{vec2f, Vector2F},
+ geometry::{
+ rect::RectF,
+ vector::{vec2f, Vector2F},
+ },
keymap::Keystroke,
ClipboardItem, Entity, ModelContext, MouseButton, MouseButtonEvent, MouseMovedEvent,
MutableAppContext, ScrollWheelEvent,
@@ -82,7 +91,7 @@ enum InternalEvent {
Clear,
Scroll(Scroll),
SetSelection(Option<Selection>),
- UpdateSelection((Point, Direction)),
+ UpdateSelection(Vector2F),
Copy,
}
@@ -310,11 +319,8 @@ impl TerminalBuilder {
term.set_mode(alacritty_terminal::ansi::Mode::BlinkingCursor)
}
- //Start alternate_scroll if we need to
- if let AlternateScroll::On = alternate_scroll {
- term.set_mode(alacritty_terminal::ansi::Mode::AlternateScroll)
- } else {
- //Alacritty turns it on by default, so we need to turn it off.
+ //Alacritty defaults to alternate scrolling being on, so we just need to turn it off.
+ if let AlternateScroll::Off = alternate_scroll {
term.unset_mode(alacritty_terminal::ansi::Mode::AlternateScroll)
}
@@ -362,13 +368,14 @@ impl TerminalBuilder {
let terminal = Terminal {
pty_tx: Notifier(pty_tx),
term,
- events: vec![],
+ events: VecDeque::with_capacity(10), //Should never get this high.
title: shell_txt.clone(),
default_title: shell_txt,
last_mode: TermMode::NONE,
cur_size: initial_size,
last_mouse: None,
last_offset: 0,
+ current_selection: false,
};
Ok(TerminalBuilder {
@@ -433,13 +440,14 @@ impl TerminalBuilder {
pub struct Terminal {
pty_tx: Notifier,
term: Arc<FairMutex<Term<ZedListener>>>,
- events: Vec<InternalEvent>,
+ events: VecDeque<InternalEvent>,
default_title: String,
title: String,
cur_size: TerminalSize,
last_mode: TermMode,
last_offset: usize,
last_mouse: Option<(Point, Direction)>,
+ current_selection: bool,
}
impl Terminal {
@@ -479,9 +487,9 @@ impl Terminal {
cx.emit(Event::Wakeup);
cx.notify();
}
- AlacTermEvent::ColorRequest(_, _) => {
- self.events.push(InternalEvent::TermEvent(event.clone()))
- }
+ AlacTermEvent::ColorRequest(_, _) => self
+ .events
+ .push_back(InternalEvent::TermEvent(event.clone())),
}
}
@@ -513,11 +521,16 @@ impl Terminal {
self.write_to_pty("\x0c".to_string());
term.clear_screen(ClearMode::Saved);
}
- InternalEvent::Scroll(scroll) => term.scroll_display(*scroll),
+ InternalEvent::Scroll(scroll) => {
+ term.scroll_display(*scroll);
+ }
InternalEvent::SetSelection(sel) => term.selection = sel.clone(),
- InternalEvent::UpdateSelection((point, side)) => {
+ InternalEvent::UpdateSelection(position) => {
if let Some(mut selection) = term.selection.take() {
- selection.update(*point, *side);
+ let point = mouse_point(*position, self.cur_size, term.grid().display_offset());
+ let side = mouse_side(*position, self.cur_size);
+
+ selection.update(point, side);
term.selection = Some(selection);
}
}
@@ -530,24 +543,48 @@ impl Terminal {
}
}
- pub fn input(&mut self, input: String) {
- self.events.push(InternalEvent::Scroll(Scroll::Bottom));
- self.events.push(InternalEvent::SetSelection(None));
- self.write_to_pty(input);
+ fn begin_select(&mut self, sel: Selection) {
+ self.current_selection = true;
+ self.events
+ .push_back(InternalEvent::SetSelection(Some(sel)));
}
- ///Write the Input payload to the tty.
- fn write_to_pty(&self, input: String) {
- self.pty_tx.notify(input.into_bytes());
+ fn continue_selection(&mut self, location: Vector2F) {
+ self.events
+ .push_back(InternalEvent::UpdateSelection(location))
+ }
+
+ fn end_select(&mut self) {
+ self.current_selection = false;
+ self.events.push_back(InternalEvent::SetSelection(None));
+ }
+
+ fn scroll(&mut self, scroll: Scroll) {
+ self.events.push_back(InternalEvent::Scroll(scroll));
+ }
+
+ pub fn copy(&mut self) {
+ self.events.push_back(InternalEvent::Copy);
+ }
+
+ pub fn clear(&mut self) {
+ self.events.push_back(InternalEvent::Clear)
}
///Resize the terminal and the PTY.
pub fn set_size(&mut self, new_size: TerminalSize) {
- self.events.push(InternalEvent::Resize(new_size))
+ self.events.push_back(InternalEvent::Resize(new_size))
}
- pub fn clear(&mut self) {
- self.events.push(InternalEvent::Clear)
+ ///Write the Input payload to the tty.
+ fn write_to_pty(&self, input: String) {
+ self.pty_tx.notify(input.into_bytes());
+ }
+
+ pub fn input(&mut self, input: String) {
+ self.scroll(Scroll::Bottom);
+ self.end_select();
+ self.write_to_pty(input);
}
pub fn try_keystroke(&mut self, keystroke: &Keystroke) -> bool {
@@ -570,10 +607,6 @@ impl Terminal {
self.input(paste_text)
}
- pub fn copy(&mut self) {
- self.events.push(InternalEvent::Copy);
- }
-
pub fn render_lock<F, T>(&mut self, cx: &mut ModelContext<Self>, f: F) -> T
where
F: FnOnce(RenderableContent, char) -> T,
@@ -581,7 +614,8 @@ impl Terminal {
let m = self.term.clone(); //Arc clone
let mut term = m.lock();
- while let Some(e) = self.events.pop() {
+ //Note that this ordering matters for
+ while let Some(e) = self.events.pop_front() {
self.process_terminal_event(&e, &mut term, cx)
}
@@ -642,15 +676,32 @@ impl Terminal {
}
}
- pub fn mouse_drag(&mut self, e: MouseMovedEvent, origin: Vector2F) {
+ pub fn mouse_drag(&mut self, e: MouseMovedEvent, origin: Vector2F, bounds: RectF) {
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);
+ // Alacritty has the same ordering, of first updating the selection
+ // then scrolling 15ms later
+ self.continue_selection(position);
+
+ // Doesn't make sense to scroll the alt screen
+ if !self.last_mode.contains(TermMode::ALT_SCREEN) {
+ //TODO: Why do these need to be doubled?
+ let top = bounds.origin_y() + (self.cur_size.line_height * 2.);
+ let bottom = bounds.lower_left().y() - (self.cur_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; //Nothing to do
+ };
- self.events
- .push(InternalEvent::UpdateSelection((point, side)));
+ let scroll_lines = (scroll_delta / self.cur_size.line_height) as i32;
+ self.scroll(Scroll::Delta(scroll_lines));
+ self.continue_selection(position)
+ }
}
}
@@ -664,12 +715,7 @@ impl Terminal {
self.pty_tx.notify(bytes);
}
} else if e.button == MouseButton::Left {
- self.events
- .push(InternalEvent::SetSelection(Some(Selection::new(
- SelectionType::Simple,
- point,
- side,
- ))));
+ self.begin_select(Selection::new(SelectionType::Simple, point, side));
}
}
@@ -691,7 +737,9 @@ impl Terminal {
let selection =
selection_type.map(|selection_type| Selection::new(selection_type, point, side));
- self.events.push(InternalEvent::SetSelection(selection));
+ if let Some(sel) = selection {
+ self.begin_select(sel);
+ }
}
}
@@ -711,17 +759,16 @@ impl Terminal {
}
///Scroll the terminal
- pub fn scroll(&mut self, scroll: &ScrollWheelEvent, origin: Vector2F) {
- if self.mouse_mode(scroll.shift) {
+ pub fn scroll_wheel(&mut self, e: &ScrollWheelEvent, origin: Vector2F) {
+ if self.mouse_mode(e.shift) {
//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);
+ let scroll_lines = (e.delta.y() / self.cur_size.line_height) as i32;
+ let point = mouse_point(e.position.sub(origin), self.cur_size, self.last_offset);
- if let Some(scrolls) = scroll_report(point, scroll_lines as i32, scroll, self.last_mode)
- {
+ if let Some(scrolls) = scroll_report(point, scroll_lines as i32, e, self.last_mode) {
for scroll in scrolls {
self.pty_tx.notify(scroll);
}
@@ -729,19 +776,19 @@ impl Terminal {
} else if self
.last_mode
.contains(TermMode::ALT_SCREEN | TermMode::ALTERNATE_SCROLL)
- && !scroll.shift
+ && !e.shift
{
//TODO: See above TODO, also applies here.
- let scroll_lines = ((scroll.delta.y() * ALACRITTY_SCROLL_MULTIPLIER)
- / self.cur_size.line_height) as i32;
+ let scroll_lines =
+ ((e.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;
+ let scroll_lines =
+ ((e.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));
+ self.scroll(scroll);
}
}
}