Abandoning this attempt, nto good enough at async
This commit is contained in:
parent
8471af5a7d
commit
05cc78d929
7 changed files with 263 additions and 158 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -62,7 +62,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "alacritty_config_derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/alacritty?rev=ba56f545e3e3606af0112c6bdfe998baf7faab50#ba56f545e3e3606af0112c6bdfe998baf7faab50"
|
||||
source = "git+https://github.com/zed-industries/alacritty?rev=a274ff43c38c76f9766a908ff86a4e10a8998a6f#a274ff43c38c76f9766a908ff86a4e10a8998a6f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -72,7 +72,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "alacritty_terminal"
|
||||
version = "0.17.0-dev"
|
||||
source = "git+https://github.com/zed-industries/alacritty?rev=ba56f545e3e3606af0112c6bdfe998baf7faab50#ba56f545e3e3606af0112c6bdfe998baf7faab50"
|
||||
source = "git+https://github.com/zed-industries/alacritty?rev=a274ff43c38c76f9766a908ff86a4e10a8998a6f#a274ff43c38c76f9766a908ff86a4e10a8998a6f"
|
||||
dependencies = [
|
||||
"alacritty_config_derive",
|
||||
"base64 0.13.0",
|
||||
|
|
|
@ -8,7 +8,7 @@ path = "src/terminal.rs"
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "ba56f545e3e3606af0112c6bdfe998baf7faab50"}
|
||||
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "a274ff43c38c76f9766a908ff86a4e10a8998a6f"}
|
||||
editor = { path = "../editor" }
|
||||
util = { path = "../util" }
|
||||
gpui = { path = "../gpui" }
|
||||
|
|
|
@ -32,7 +32,7 @@ use std::{
|
|||
use std::{fmt::Debug, ops::Sub};
|
||||
|
||||
use crate::{
|
||||
connected_view::ConnectedView, mappings::colors::convert_color, TermDimensions, Terminal,
|
||||
connected_view::ConnectedView, mappings::colors::convert_color, Terminal, TerminalSize,
|
||||
};
|
||||
|
||||
///Scrolling is unbearably sluggish by default. Alacritty supports a configurable
|
||||
|
@ -48,7 +48,7 @@ pub struct LayoutState {
|
|||
cursor: Option<Cursor>,
|
||||
background_color: Color,
|
||||
selection_color: Color,
|
||||
size: TermDimensions,
|
||||
size: TerminalSize,
|
||||
display_offset: usize,
|
||||
}
|
||||
|
||||
|
@ -319,7 +319,7 @@ impl TerminalEl {
|
|||
// the same position for sequential indexes. Use em_width instead
|
||||
fn shape_cursor(
|
||||
cursor_point: DisplayCursor,
|
||||
size: TermDimensions,
|
||||
size: TerminalSize,
|
||||
text_fragment: &Line,
|
||||
) -> Option<(Vector2F, f32)> {
|
||||
if cursor_point.line() < size.total_lines() as i32 {
|
||||
|
@ -372,7 +372,7 @@ impl TerminalEl {
|
|||
origin: Vector2F,
|
||||
view_id: usize,
|
||||
visible_bounds: RectF,
|
||||
cur_size: TermDimensions,
|
||||
cur_size: TerminalSize,
|
||||
display_offset: usize,
|
||||
cx: &mut PaintContext,
|
||||
) {
|
||||
|
@ -482,7 +482,7 @@ impl TerminalEl {
|
|||
pub fn mouse_to_cell_data(
|
||||
pos: Vector2F,
|
||||
origin: Vector2F,
|
||||
cur_size: TermDimensions,
|
||||
cur_size: TerminalSize,
|
||||
display_offset: usize,
|
||||
) -> (Point, alacritty_terminal::index::Direction) {
|
||||
let pos = pos.sub(origin);
|
||||
|
@ -540,7 +540,7 @@ impl Element for TerminalEl {
|
|||
let dimensions = {
|
||||
let line_height = font_cache.line_height(text_style.font_size);
|
||||
let cell_width = font_cache.em_advance(text_style.font_id, text_style.font_size);
|
||||
TermDimensions::new(line_height, cell_width, constraint.max)
|
||||
TerminalSize::new(line_height, cell_width, constraint.max)
|
||||
};
|
||||
|
||||
let background_color = if self.modal {
|
||||
|
@ -807,7 +807,7 @@ mod test {
|
|||
let origin_x = 10.;
|
||||
let origin_y = 20.;
|
||||
|
||||
let cur_size = crate::connected_el::TermDimensions::new(
|
||||
let cur_size = crate::connected_el::TerminalSize::new(
|
||||
line_height,
|
||||
cell_width,
|
||||
gpui::geometry::vector::vec2f(term_width, term_height),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use alacritty_terminal::term::TermMode;
|
||||
use gpui::{
|
||||
actions, keymap::Keystroke, AppContext, Element, ElementBox, ModelHandle, MutableAppContext,
|
||||
View, ViewContext,
|
||||
|
@ -98,43 +99,43 @@ impl ConnectedView {
|
|||
///Attempt to paste the clipboard into the terminal
|
||||
fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
|
||||
cx.read_from_clipboard().map(|item| {
|
||||
self.terminal.update(cx, |term, _| term.paste(item.text()));
|
||||
self.terminal.read(cx).paste(item.text());
|
||||
});
|
||||
}
|
||||
|
||||
///Synthesize the keyboard event corresponding to 'up'
|
||||
fn up(&mut self, _: &Up, cx: &mut ViewContext<Self>) {
|
||||
self.terminal.update(cx, |term, _| {
|
||||
term.try_keystroke(&Keystroke::parse("up").unwrap());
|
||||
});
|
||||
self.terminal
|
||||
.read(cx)
|
||||
.try_keystroke(&Keystroke::parse("up").unwrap());
|
||||
}
|
||||
|
||||
///Synthesize the keyboard event corresponding to 'down'
|
||||
fn down(&mut self, _: &Down, cx: &mut ViewContext<Self>) {
|
||||
self.terminal.update(cx, |term, _| {
|
||||
term.try_keystroke(&Keystroke::parse("down").unwrap());
|
||||
});
|
||||
self.terminal
|
||||
.read(cx)
|
||||
.try_keystroke(&Keystroke::parse("down").unwrap());
|
||||
}
|
||||
|
||||
///Synthesize the keyboard event corresponding to 'ctrl-c'
|
||||
fn ctrl_c(&mut self, _: &CtrlC, cx: &mut ViewContext<Self>) {
|
||||
self.terminal.update(cx, |term, _| {
|
||||
term.try_keystroke(&Keystroke::parse("ctrl-c").unwrap());
|
||||
});
|
||||
self.terminal
|
||||
.read(cx)
|
||||
.try_keystroke(&Keystroke::parse("ctrl-c").unwrap());
|
||||
}
|
||||
|
||||
///Synthesize the keyboard event corresponding to 'escape'
|
||||
fn escape(&mut self, _: &Escape, cx: &mut ViewContext<Self>) {
|
||||
self.terminal.update(cx, |term, _| {
|
||||
term.try_keystroke(&Keystroke::parse("escape").unwrap());
|
||||
});
|
||||
self.terminal
|
||||
.read(cx)
|
||||
.try_keystroke(&Keystroke::parse("escape").unwrap());
|
||||
}
|
||||
|
||||
///Synthesize the keyboard event corresponding to 'enter'
|
||||
fn enter(&mut self, _: &Enter, cx: &mut ViewContext<Self>) {
|
||||
self.terminal.update(cx, |term, _| {
|
||||
term.try_keystroke(&Keystroke::parse("enter").unwrap());
|
||||
});
|
||||
self.terminal
|
||||
.read(cx)
|
||||
.try_keystroke(&Keystroke::parse("enter").unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,8 +155,17 @@ impl View for ConnectedView {
|
|||
self.has_new_content = false;
|
||||
}
|
||||
|
||||
fn selected_text_range(&self, _: &AppContext) -> Option<std::ops::Range<usize>> {
|
||||
Some(0..0)
|
||||
fn selected_text_range(&self, cx: &AppContext) -> Option<std::ops::Range<usize>> {
|
||||
if self
|
||||
.terminal
|
||||
.read(cx)
|
||||
.last_mode
|
||||
.contains(TermMode::ALT_SCREEN)
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(0..0)
|
||||
}
|
||||
}
|
||||
|
||||
fn replace_text_in_range(
|
||||
|
|
|
@ -24,18 +24,27 @@ use alacritty_terminal::{
|
|||
};
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
use futures::channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
|
||||
use mappings::keys::might_convert;
|
||||
use futures::{
|
||||
channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
|
||||
future,
|
||||
};
|
||||
|
||||
use modal::deploy_modal;
|
||||
use settings::{Settings, Shell};
|
||||
use std::{collections::HashMap, fmt::Display, path::PathBuf, sync::Arc, time::Duration};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::Display,
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use terminal_view::TerminalView;
|
||||
use thiserror::Error;
|
||||
|
||||
use gpui::{
|
||||
geometry::vector::{vec2f, Vector2F},
|
||||
keymap::Keystroke,
|
||||
ClipboardItem, CursorStyle, Entity, ModelContext, MutableAppContext,
|
||||
AsyncAppContext, ClipboardItem, Entity, ModelContext, MutableAppContext, WeakModelHandle,
|
||||
};
|
||||
|
||||
use crate::mappings::{
|
||||
|
@ -71,10 +80,8 @@ pub enum Event {
|
|||
#[derive(Clone, Debug)]
|
||||
enum InternalEvent {
|
||||
TermEvent(AlacTermEvent),
|
||||
Resize(TermDimensions),
|
||||
Resize(TerminalSize),
|
||||
Clear,
|
||||
Keystroke(Keystroke),
|
||||
Paste(String),
|
||||
Scroll(Scroll),
|
||||
SetSelection(Option<Selection>),
|
||||
UpdateSelection((Point, Direction)),
|
||||
|
@ -92,16 +99,16 @@ impl EventListener for ZedListener {
|
|||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct TermDimensions {
|
||||
pub struct TerminalSize {
|
||||
cell_width: f32,
|
||||
line_height: f32,
|
||||
height: f32,
|
||||
width: f32,
|
||||
}
|
||||
|
||||
impl TermDimensions {
|
||||
impl TerminalSize {
|
||||
pub fn new(line_height: f32, cell_width: f32, size: Vector2F) -> Self {
|
||||
TermDimensions {
|
||||
TerminalSize {
|
||||
cell_width,
|
||||
line_height,
|
||||
width: size.x(),
|
||||
|
@ -133,9 +140,9 @@ impl TermDimensions {
|
|||
self.line_height
|
||||
}
|
||||
}
|
||||
impl Default for TermDimensions {
|
||||
impl Default for TerminalSize {
|
||||
fn default() -> Self {
|
||||
TermDimensions::new(
|
||||
TerminalSize::new(
|
||||
DEBUG_LINE_HEIGHT,
|
||||
DEBUG_CELL_WIDTH,
|
||||
vec2f(DEBUG_TERMINAL_WIDTH, DEBUG_TERMINAL_HEIGHT),
|
||||
|
@ -143,7 +150,7 @@ impl Default for TermDimensions {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<WindowSize> for TermDimensions {
|
||||
impl Into<WindowSize> for TerminalSize {
|
||||
fn into(self) -> WindowSize {
|
||||
WindowSize {
|
||||
num_lines: self.num_lines() as u16,
|
||||
|
@ -154,7 +161,7 @@ impl Into<WindowSize> for TermDimensions {
|
|||
}
|
||||
}
|
||||
|
||||
impl Dimensions for TermDimensions {
|
||||
impl Dimensions for TerminalSize {
|
||||
fn total_lines(&self) -> usize {
|
||||
self.screen_lines() //TODO: Check that this is fine. This is supposed to be for the back buffer...
|
||||
}
|
||||
|
@ -249,6 +256,46 @@ impl Display for TerminalError {
|
|||
}
|
||||
}
|
||||
|
||||
///This is a helper struct that represents a block on a
|
||||
struct ThrottleGuard {
|
||||
should_complete: bool,
|
||||
length: Duration,
|
||||
start: Instant,
|
||||
}
|
||||
|
||||
impl ThrottleGuard {
|
||||
fn new<T, F>(duration: Duration, cx: &mut ModelContext<T>, on_completion: F) -> Arc<Self>
|
||||
where
|
||||
T: Entity,
|
||||
F: FnOnce(WeakModelHandle<T>, AsyncAppContext) -> () + 'static,
|
||||
{
|
||||
let selff = Arc::new(Self {
|
||||
should_complete: false,
|
||||
start: Instant::now(),
|
||||
length: duration,
|
||||
});
|
||||
|
||||
let moved_self = selff.clone();
|
||||
cx.spawn_weak(|w, cx| async move {
|
||||
cx.background().timer(duration).await;
|
||||
|
||||
if moved_self.should_complete {
|
||||
on_completion(w, cx);
|
||||
}
|
||||
});
|
||||
|
||||
selff
|
||||
}
|
||||
|
||||
fn activate(&mut self) {
|
||||
self.should_complete = true;
|
||||
}
|
||||
|
||||
fn is_done(&self) -> bool {
|
||||
self.start.elapsed() > self.length
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TerminalBuilder {
|
||||
terminal: Terminal,
|
||||
events_rx: UnboundedReceiver<AlacTermEvent>,
|
||||
|
@ -259,7 +306,7 @@ impl TerminalBuilder {
|
|||
working_directory: Option<PathBuf>,
|
||||
shell: Option<Shell>,
|
||||
env: Option<HashMap<String, String>>,
|
||||
initial_size: TermDimensions,
|
||||
initial_size: TerminalSize,
|
||||
) -> Result<TerminalBuilder> {
|
||||
let pty_config = {
|
||||
let alac_shell = shell.clone().and_then(|shell| match shell {
|
||||
|
@ -299,7 +346,7 @@ impl TerminalBuilder {
|
|||
let term = Arc::new(FairMutex::new(term));
|
||||
|
||||
//Setup the pty...
|
||||
let pty = match tty::new(&pty_config, initial_size.into(), None) {
|
||||
let pty = match tty::new(&pty_config, initial_size.clone().into(), None) {
|
||||
Ok(pty) => pty,
|
||||
Err(error) => {
|
||||
bail!(TerminalError {
|
||||
|
@ -340,11 +387,12 @@ impl TerminalBuilder {
|
|||
let terminal = Terminal {
|
||||
pty_tx: Notifier(pty_tx),
|
||||
term,
|
||||
|
||||
events: vec![],
|
||||
title: shell_txt.clone(),
|
||||
default_title: shell_txt,
|
||||
frames_to_skip: 0,
|
||||
last_mode: TermMode::NONE,
|
||||
cur_size: initial_size,
|
||||
utilization: 0.,
|
||||
};
|
||||
|
||||
Ok(TerminalBuilder {
|
||||
|
@ -353,45 +401,93 @@ impl TerminalBuilder {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn subscribe(mut self, cx: &mut ModelContext<Terminal>) -> Terminal {
|
||||
let mut frames_to_skip = 0;
|
||||
pub fn subscribe(self, cx: &mut ModelContext<Terminal>) -> Terminal {
|
||||
//Event loop
|
||||
cx.spawn_weak(|this, mut cx| async move {
|
||||
'outer: loop {
|
||||
let delay = cx
|
||||
.background()
|
||||
.timer(Duration::from_secs_f32(1.0 / Terminal::default_fps()));
|
||||
if frames_to_skip == 0 {
|
||||
let mut events = vec![];
|
||||
use futures::StreamExt;
|
||||
|
||||
loop {
|
||||
match self.events_rx.try_next() {
|
||||
//Have a buffered event
|
||||
Ok(Some(e)) => events.push(e),
|
||||
//Channel closed, exit
|
||||
Ok(None) => break 'outer,
|
||||
//Ran out of buffered events
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
//Throttle guard
|
||||
let mut guard: Option<Arc<ThrottleGuard>> = None;
|
||||
|
||||
self.events_rx
|
||||
.for_each(|event| {
|
||||
match this.upgrade(&cx) {
|
||||
Some(this) => {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.push_events(events);
|
||||
frames_to_skip = this.frames_to_skip();
|
||||
cx.notify();
|
||||
//Process the event
|
||||
this.process_event(&event, cx);
|
||||
|
||||
//Clean up the guard if it's expired
|
||||
guard = match guard.take() {
|
||||
Some(guard) => {
|
||||
if guard.is_done() {
|
||||
None
|
||||
} else {
|
||||
Some(guard)
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
//Figure out whether to render or not.
|
||||
if matches!(event, AlacTermEvent::Wakeup) {
|
||||
if guard.is_none() {
|
||||
cx.emit(Event::Wakeup);
|
||||
cx.notify();
|
||||
|
||||
let dur = Duration::from_secs_f32(
|
||||
1.0 / (Terminal::default_fps()
|
||||
* (1. - this.utilization()).clamp(0.1, 1.)),
|
||||
);
|
||||
|
||||
guard = Some(ThrottleGuard::new(dur, cx, |this, mut cx| {
|
||||
match this.upgrade(&cx) {
|
||||
Some(handle) => handle.update(&mut cx, |_, cx| {
|
||||
cx.emit(Event::Wakeup);
|
||||
cx.notify();
|
||||
}),
|
||||
None => {}
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
let taken = guard.take().unwrap();
|
||||
taken.activate();
|
||||
guard = Some(taken);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
None => break 'outer,
|
||||
None => {}
|
||||
}
|
||||
} else {
|
||||
frames_to_skip = frames_to_skip - 1;
|
||||
}
|
||||
|
||||
delay.await;
|
||||
}
|
||||
future::ready(())
|
||||
})
|
||||
.await;
|
||||
})
|
||||
.detach();
|
||||
|
||||
// //Render loop
|
||||
// cx.spawn_weak(|this, mut cx| async move {
|
||||
// loop {
|
||||
// let utilization = match this.upgrade(&cx) {
|
||||
// Some(this) => this.update(&mut cx, |this, cx| {
|
||||
// cx.emit(Event::Wakeup);
|
||||
// cx.notify();
|
||||
// this.utilization()
|
||||
// }),
|
||||
// None => break,
|
||||
// };
|
||||
|
||||
// let utilization = (1. - this.utilization()).clamp(0.1, 1.);
|
||||
|
||||
// let delay = cx.background().timer(Duration::from_secs_f32(
|
||||
// 1.0 / (Terminal::default_fps() * utilization),
|
||||
// ));
|
||||
|
||||
// delay.await;
|
||||
// }
|
||||
// })
|
||||
// .detach();
|
||||
|
||||
self.terminal
|
||||
}
|
||||
}
|
||||
|
@ -402,7 +498,10 @@ pub struct Terminal {
|
|||
events: Vec<InternalEvent>,
|
||||
default_title: String,
|
||||
title: String,
|
||||
frames_to_skip: usize,
|
||||
cur_size: TerminalSize,
|
||||
last_mode: TermMode,
|
||||
//Percentage, between 0 and 1
|
||||
utilization: f32,
|
||||
}
|
||||
|
||||
impl Terminal {
|
||||
|
@ -410,16 +509,57 @@ impl Terminal {
|
|||
MAX_FRAME_RATE
|
||||
}
|
||||
|
||||
///Tells the render loop how many frames to skip before reading from the terminal.
|
||||
fn frames_to_skip(&self) -> usize {
|
||||
0 //self.frames_to_skip
|
||||
fn utilization(&self) -> f32 {
|
||||
self.utilization
|
||||
}
|
||||
|
||||
fn push_events(&mut self, events: Vec<AlacTermEvent>) {
|
||||
self.events
|
||||
.extend(events.into_iter().map(|e| InternalEvent::TermEvent(e)))
|
||||
fn process_event(&mut self, event: &AlacTermEvent, cx: &mut ModelContext<Self>) {
|
||||
match event {
|
||||
AlacTermEvent::Title(title) => {
|
||||
self.title = title.to_string();
|
||||
cx.emit(Event::TitleChanged);
|
||||
}
|
||||
AlacTermEvent::ResetTitle => {
|
||||
self.title = self.default_title.clone();
|
||||
cx.emit(Event::TitleChanged);
|
||||
}
|
||||
AlacTermEvent::ClipboardStore(_, data) => {
|
||||
cx.write_to_clipboard(ClipboardItem::new(data.to_string()))
|
||||
}
|
||||
AlacTermEvent::ClipboardLoad(_, format) => self.notify_pty(format(
|
||||
&cx.read_from_clipboard()
|
||||
.map(|ci| ci.text().to_string())
|
||||
.unwrap_or("".to_string()),
|
||||
)),
|
||||
AlacTermEvent::PtyWrite(out) => self.notify_pty(out.clone()),
|
||||
AlacTermEvent::TextAreaSizeRequest(format) => {
|
||||
self.notify_pty(format(self.cur_size.clone().into()))
|
||||
}
|
||||
AlacTermEvent::CursorBlinkingChange => {
|
||||
//TODO whatever state we need to set to get the cursor blinking
|
||||
}
|
||||
AlacTermEvent::Bell => {
|
||||
cx.emit(Event::Bell);
|
||||
}
|
||||
AlacTermEvent::Exit => cx.emit(Event::CloseTerminal),
|
||||
AlacTermEvent::MouseCursorDirty => {
|
||||
//NOOP, Handled in render
|
||||
}
|
||||
AlacTermEvent::Wakeup => {
|
||||
//NOOP, Handled elsewhere
|
||||
}
|
||||
AlacTermEvent::ColorRequest(_, _) => {
|
||||
self.events.push(InternalEvent::TermEvent(event.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fn process_events(&mut self, events: Vec<AlacTermEvent>, cx: &mut ModelContext<Self>) {
|
||||
// for event in events.into_iter() {
|
||||
// self.process_event(&event, cx);
|
||||
// }
|
||||
// }
|
||||
|
||||
///Takes events from Alacritty and translates them to behavior on this view
|
||||
fn process_terminal_event(
|
||||
&mut self,
|
||||
|
@ -430,35 +570,7 @@ impl Terminal {
|
|||
// TODO: Handle is_self_focused in subscription on terminal view
|
||||
match event {
|
||||
InternalEvent::TermEvent(term_event) => match term_event {
|
||||
AlacTermEvent::Wakeup => {
|
||||
cx.emit(Event::Wakeup);
|
||||
}
|
||||
//TODO: Does not need to be in lock context
|
||||
AlacTermEvent::PtyWrite(out) => self.notify_pty(out.clone()),
|
||||
AlacTermEvent::MouseCursorDirty => {
|
||||
//Calculate new cursor style.
|
||||
//TODO: alacritty/src/input.rs:L922-L939
|
||||
//Check on correctly handling mouse events for terminals
|
||||
cx.platform().set_cursor_style(CursorStyle::Arrow); //???
|
||||
}
|
||||
AlacTermEvent::Title(title) => {
|
||||
self.title = title.to_string();
|
||||
cx.emit(Event::TitleChanged);
|
||||
}
|
||||
AlacTermEvent::ResetTitle => {
|
||||
self.title = self.default_title.clone();
|
||||
cx.emit(Event::TitleChanged);
|
||||
}
|
||||
//TODO: Does not need to be in lock context
|
||||
AlacTermEvent::ClipboardStore(_, data) => {
|
||||
cx.write_to_clipboard(ClipboardItem::new(data.to_string()))
|
||||
}
|
||||
//TODO: Does not need to be in lock context
|
||||
AlacTermEvent::ClipboardLoad(_, format) => self.notify_pty(format(
|
||||
&cx.read_from_clipboard()
|
||||
.map(|ci| ci.text().to_string())
|
||||
.unwrap_or("".to_string()),
|
||||
)),
|
||||
//Needs to lock
|
||||
AlacTermEvent::ColorRequest(index, format) => {
|
||||
let color = term.colors()[*index].unwrap_or_else(|| {
|
||||
let term_style = &cx.global::<Settings>().theme.terminal;
|
||||
|
@ -466,18 +578,11 @@ impl Terminal {
|
|||
});
|
||||
self.notify_pty(format(color))
|
||||
}
|
||||
AlacTermEvent::CursorBlinkingChange => {
|
||||
//TODO: Set a timer to blink the cursor on and off
|
||||
}
|
||||
AlacTermEvent::Bell => {
|
||||
cx.emit(Event::Bell);
|
||||
}
|
||||
AlacTermEvent::Exit => cx.emit(Event::CloseTerminal),
|
||||
AlacTermEvent::TextAreaSizeRequest(_) => {
|
||||
println!("Received text area resize request")
|
||||
}
|
||||
_ => {} //Other events are handled in the event loop
|
||||
},
|
||||
InternalEvent::Resize(new_size) => {
|
||||
self.cur_size = new_size.clone();
|
||||
|
||||
self.pty_tx
|
||||
.0
|
||||
.send(Msg::Resize(new_size.clone().into()))
|
||||
|
@ -489,21 +594,6 @@ impl Terminal {
|
|||
self.notify_pty("\x0c".to_string());
|
||||
term.clear_screen(ClearMode::Saved);
|
||||
}
|
||||
InternalEvent::Keystroke(keystroke) => {
|
||||
let esc = to_esc_str(keystroke, term.mode());
|
||||
if let Some(esc) = esc {
|
||||
self.notify_pty(esc);
|
||||
}
|
||||
}
|
||||
InternalEvent::Paste(text) => {
|
||||
if term.mode().contains(TermMode::BRACKETED_PASTE) {
|
||||
self.notify_pty("\x1b[200~".to_string());
|
||||
self.notify_pty(text.replace('\x1b', "").to_string());
|
||||
self.notify_pty("\x1b[201~".to_string());
|
||||
} else {
|
||||
self.notify_pty(text.replace("\r\n", "\r").replace('\n', "\r"));
|
||||
}
|
||||
}
|
||||
InternalEvent::Scroll(scroll) => term.scroll_display(*scroll),
|
||||
InternalEvent::SetSelection(sel) => term.selection = sel.clone(),
|
||||
InternalEvent::UpdateSelection((point, side)) => {
|
||||
|
@ -521,18 +611,17 @@ impl Terminal {
|
|||
}
|
||||
}
|
||||
|
||||
fn notify_pty(&self, txt: String) {
|
||||
pub fn notify_pty(&self, txt: String) {
|
||||
self.pty_tx.notify(txt.into_bytes());
|
||||
}
|
||||
|
||||
///Write the Input payload to the tty.
|
||||
pub fn write_to_pty(&mut self, input: String) {
|
||||
self.events
|
||||
.push(InternalEvent::TermEvent(AlacTermEvent::PtyWrite(input)))
|
||||
self.pty_tx.notify(input.into_bytes());
|
||||
}
|
||||
|
||||
///Resize the terminal and the PTY.
|
||||
pub fn set_size(&mut self, new_size: TermDimensions) {
|
||||
pub fn set_size(&mut self, new_size: TerminalSize) {
|
||||
self.events.push(InternalEvent::Resize(new_size.into()))
|
||||
}
|
||||
|
||||
|
@ -540,10 +629,10 @@ impl Terminal {
|
|||
self.events.push(InternalEvent::Clear)
|
||||
}
|
||||
|
||||
pub fn try_keystroke(&mut self, keystroke: &Keystroke) -> bool {
|
||||
if might_convert(keystroke) {
|
||||
self.events
|
||||
.push(InternalEvent::Keystroke(keystroke.clone()));
|
||||
pub fn try_keystroke(&self, keystroke: &Keystroke) -> bool {
|
||||
let esc = to_esc_str(keystroke, &self.last_mode);
|
||||
if let Some(esc) = esc {
|
||||
self.notify_pty(esc);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
@ -551,8 +640,14 @@ impl Terminal {
|
|||
}
|
||||
|
||||
///Paste text into the terminal
|
||||
pub fn paste(&mut self, text: &str) {
|
||||
self.events.push(InternalEvent::Paste(text.to_string()));
|
||||
pub fn paste(&self, text: &str) {
|
||||
if self.last_mode.contains(TermMode::BRACKETED_PASTE) {
|
||||
self.notify_pty("\x1b[200~".to_string());
|
||||
self.notify_pty(text.replace('\x1b', "").to_string());
|
||||
self.notify_pty("\x1b[201~".to_string());
|
||||
} else {
|
||||
self.notify_pty(text.replace("\r\n", "\r").replace('\n', "\r"));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy(&mut self) {
|
||||
|
@ -570,16 +665,9 @@ impl Terminal {
|
|||
self.process_terminal_event(&e, &mut term, cx)
|
||||
}
|
||||
|
||||
//TODO: determine a better metric for this
|
||||
let buffer_velocity =
|
||||
(term.last_processed_bytes() as f32 / (READ_BUFFER_SIZE as f32 / 4.)).clamp(0., 1.);
|
||||
self.utilization = Self::estimate_utilization(term.take_last_processed_bytes());
|
||||
|
||||
//2nd power
|
||||
let scaled_velocity = buffer_velocity * buffer_velocity;
|
||||
|
||||
self.frames_to_skip = (scaled_velocity * (Self::default_fps() / 10.)).round() as usize;
|
||||
|
||||
term.set_last_processed_bytes(0); //Clear it in case no reads between this lock and the next.
|
||||
self.last_mode = term.mode().clone();
|
||||
|
||||
let content = term.renderable_content();
|
||||
|
||||
|
@ -588,6 +676,13 @@ impl Terminal {
|
|||
f(content, cursor_text)
|
||||
}
|
||||
|
||||
fn estimate_utilization(last_processed: usize) -> f32 {
|
||||
let buffer_utilization = (last_processed as f32 / (READ_BUFFER_SIZE as f32)).clamp(0., 1.);
|
||||
|
||||
//Scale result to bias low, then high
|
||||
buffer_utilization * buffer_utilization
|
||||
}
|
||||
|
||||
///Scroll the terminal
|
||||
pub fn scroll(&mut self, scroll: Scroll) {
|
||||
self.events.push(InternalEvent::Scroll(scroll));
|
||||
|
|
|
@ -6,7 +6,7 @@ use gpui::{
|
|||
ViewHandle,
|
||||
};
|
||||
|
||||
use crate::TermDimensions;
|
||||
use crate::TerminalSize;
|
||||
use project::{LocalWorktree, Project, ProjectPath};
|
||||
use settings::{Settings, WorkingDirectory};
|
||||
use smallvec::SmallVec;
|
||||
|
@ -72,7 +72,7 @@ impl TerminalView {
|
|||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
//The exact size here doesn't matter, the terminal will be resized on the first layout
|
||||
let size_info = TermDimensions::default();
|
||||
let size_info = TerminalSize::default();
|
||||
|
||||
let settings = cx.global::<Settings>();
|
||||
let shell = settings.terminal_overrides.shell.clone();
|
||||
|
|
|
@ -6,7 +6,7 @@ use itertools::Itertools;
|
|||
use project::{Entry, Project, ProjectPath, Worktree};
|
||||
use workspace::{AppState, Workspace};
|
||||
|
||||
use crate::{TermDimensions, Terminal, TerminalBuilder};
|
||||
use crate::{Terminal, TerminalBuilder, TerminalSize};
|
||||
|
||||
pub struct TerminalTestContext<'a> {
|
||||
pub cx: &'a mut TestAppContext,
|
||||
|
@ -17,7 +17,7 @@ impl<'a> TerminalTestContext<'a> {
|
|||
pub fn new(cx: &'a mut TestAppContext, term: bool) -> Self {
|
||||
cx.set_condition_duration(Some(Duration::from_secs(5)));
|
||||
|
||||
let size_info = TermDimensions::default();
|
||||
let size_info = TerminalSize::default();
|
||||
|
||||
let connection = term.then(|| {
|
||||
cx.add_model(|cx| {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue