Finished refactor for mutable terminal and long-single-lock style. Currently terminal is deadlocking instantly, need to just do the full refactor

This commit is contained in:
Mikayla Maki 2022-07-25 17:04:51 -07:00
parent be4873b92b
commit bc2c8e0e05
4 changed files with 124 additions and 101 deletions

View file

@ -512,10 +512,10 @@ impl Element for TerminalEl {
cx: &mut gpui::LayoutContext, cx: &mut gpui::LayoutContext,
) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) {
let settings = cx.global::<Settings>(); let settings = cx.global::<Settings>();
let font_cache = &cx.font_cache(); let font_cache = cx.font_cache();
//Setup layout information //Setup layout information
let terminal_theme = &settings.theme.terminal; let terminal_theme = settings.theme.terminal.clone(); //-_-
let text_style = TerminalEl::make_text_style(font_cache, &settings); let text_style = TerminalEl::make_text_style(font_cache, &settings);
let selection_color = settings.theme.editor.selection.selection; let selection_color = settings.theme.editor.selection.selection;
let dimensions = { let dimensions = {
@ -524,62 +524,64 @@ impl Element for TerminalEl {
TermDimensions::new(line_height, cell_width, constraint.max) TermDimensions::new(line_height, cell_width, constraint.max)
}; };
let terminal = self.terminal.upgrade(cx).unwrap().read(cx); let background_color = if self.modal {
terminal_theme.colors.modal_background.clone()
} else {
terminal_theme.colors.background.clone()
};
let (cursor, cells, rects, highlights) = let (cursor, cells, rects, highlights) =
terminal.render_lock(Some(dimensions.clone()), |content, cursor_text| { self.terminal
let (cells, rects, highlights) = TerminalEl::layout_grid( .upgrade(cx)
content.display_iter, .unwrap()
&text_style, .update(cx.app, |terminal, mcx| {
terminal_theme, terminal.render_lock(mcx, |content, cursor_text| {
cx.text_layout_cache, let (cells, rects, highlights) = TerminalEl::layout_grid(
self.modal, content.display_iter,
content.selection, &text_style,
); &terminal_theme,
cx.text_layout_cache,
self.modal,
content.selection,
);
//Layout cursor //Layout cursor
let cursor = { let cursor = {
let cursor_point = let cursor_point =
DisplayCursor::from(content.cursor.point, content.display_offset); DisplayCursor::from(content.cursor.point, content.display_offset);
let cursor_text = { let cursor_text = {
let str_trxt = cursor_text.to_string(); let str_trxt = cursor_text.to_string();
cx.text_layout_cache.layout_str( cx.text_layout_cache.layout_str(
&str_trxt, &str_trxt,
text_style.font_size, text_style.font_size,
&[( &[(
str_trxt.len(), str_trxt.len(),
RunStyle { RunStyle {
font_id: text_style.font_id, font_id: text_style.font_id,
color: terminal_theme.colors.background, color: terminal_theme.colors.background,
underline: Default::default(), underline: Default::default(),
},
)],
)
};
TerminalEl::shape_cursor(cursor_point, dimensions, &cursor_text).map(
move |(cursor_position, block_width)| {
Cursor::new(
cursor_position,
block_width,
dimensions.line_height,
terminal_theme.colors.cursor,
CursorShape::Block,
Some(cursor_text.clone()),
)
}, },
)],
)
};
TerminalEl::shape_cursor(cursor_point, dimensions, &cursor_text).map(
move |(cursor_position, block_width)| {
Cursor::new(
cursor_position,
block_width,
dimensions.line_height,
terminal_theme.colors.cursor,
CursorShape::Block,
Some(cursor_text.clone()),
) )
}, };
)
};
(cursor, cells, rects, highlights) (cursor, cells, rects, highlights)
}); })
});
//Select background color
let background_color = if self.modal {
terminal_theme.colors.modal_background
} else {
terminal_theme.colors.background
};
//Done! //Done!
( (
@ -706,8 +708,9 @@ impl Element for TerminalEl {
self.terminal self.terminal
.upgrade(cx.app) .upgrade(cx.app)
.map(|model_handle| model_handle.read(cx.app)) .map(|model_handle| {
.map(|term| term.try_keystroke(keystroke)) model_handle.update(cx.app, |term, _| term.try_keystroke(keystroke))
})
.unwrap_or(false) .unwrap_or(false)
} }
_ => false, _ => false,

View file

@ -87,7 +87,7 @@ impl ConnectedView {
} }
fn clear(&mut self, _: &Clear, cx: &mut ViewContext<Self>) { fn clear(&mut self, _: &Clear, cx: &mut ViewContext<Self>) {
self.terminal.read(cx).clear(); self.terminal.update(cx, |term, _| term.clear());
} }
///Attempt to paste the clipboard into the terminal ///Attempt to paste the clipboard into the terminal
@ -101,43 +101,43 @@ impl ConnectedView {
///Attempt to paste the clipboard into the terminal ///Attempt to paste the clipboard into the terminal
fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) { fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
cx.read_from_clipboard().map(|item| { cx.read_from_clipboard().map(|item| {
self.terminal.read(cx).paste(item.text()); self.terminal.update(cx, |term, _| term.paste(item.text()));
}); });
} }
///Synthesize the keyboard event corresponding to 'up' ///Synthesize the keyboard event corresponding to 'up'
fn up(&mut self, _: &Up, cx: &mut ViewContext<Self>) { fn up(&mut self, _: &Up, cx: &mut ViewContext<Self>) {
self.terminal self.terminal.update(cx, |term, _| {
.read(cx) term.try_keystroke(&Keystroke::parse("up").unwrap());
.try_keystroke(&Keystroke::parse("up").unwrap()); });
} }
///Synthesize the keyboard event corresponding to 'down' ///Synthesize the keyboard event corresponding to 'down'
fn down(&mut self, _: &Down, cx: &mut ViewContext<Self>) { fn down(&mut self, _: &Down, cx: &mut ViewContext<Self>) {
self.terminal self.terminal.update(cx, |term, _| {
.read(cx) term.try_keystroke(&Keystroke::parse("down").unwrap());
.try_keystroke(&Keystroke::parse("down").unwrap()); });
} }
///Synthesize the keyboard event corresponding to 'ctrl-c' ///Synthesize the keyboard event corresponding to 'ctrl-c'
fn ctrl_c(&mut self, _: &CtrlC, cx: &mut ViewContext<Self>) { fn ctrl_c(&mut self, _: &CtrlC, cx: &mut ViewContext<Self>) {
self.terminal self.terminal.update(cx, |term, _| {
.read(cx) term.try_keystroke(&Keystroke::parse("ctrl-c").unwrap());
.try_keystroke(&Keystroke::parse("ctrl-c").unwrap()); });
} }
///Synthesize the keyboard event corresponding to 'escape' ///Synthesize the keyboard event corresponding to 'escape'
fn escape(&mut self, _: &Escape, cx: &mut ViewContext<Self>) { fn escape(&mut self, _: &Escape, cx: &mut ViewContext<Self>) {
self.terminal self.terminal.update(cx, |term, _| {
.read(cx) term.try_keystroke(&Keystroke::parse("escape").unwrap());
.try_keystroke(&Keystroke::parse("escape").unwrap()); });
} }
///Synthesize the keyboard event corresponding to 'enter' ///Synthesize the keyboard event corresponding to 'enter'
fn enter(&mut self, _: &Enter, cx: &mut ViewContext<Self>) { fn enter(&mut self, _: &Enter, cx: &mut ViewContext<Self>) {
self.terminal self.terminal.update(cx, |term, _| {
.read(cx) term.try_keystroke(&Keystroke::parse("enter").unwrap());
.try_keystroke(&Keystroke::parse("enter").unwrap()); });
} }
} }

View file

@ -4,6 +4,11 @@ pub mod mappings;
pub mod modal; pub mod modal;
pub mod terminal_view; pub mod terminal_view;
#[cfg(test)]
use alacritty_terminal::term::cell::Cell;
#[cfg(test)]
use alacritty_terminal::Grid;
use alacritty_terminal::{ use alacritty_terminal::{
ansi::{ClearMode, Handler}, ansi::{ClearMode, Handler},
config::{Config, Program, PtyConfig}, config::{Config, Program, PtyConfig},
@ -383,13 +388,11 @@ impl Terminal {
&mut self, &mut self,
event: alacritty_terminal::event::Event, event: alacritty_terminal::event::Event,
term: &mut Term<ZedListener>, term: &mut Term<ZedListener>,
cx: &mut ModelContext<Terminal>, cx: &mut ModelContext<Self>,
) { ) {
match event { match event {
// TODO: Handle is_self_focused in subscription on terminal view // TODO: Handle is_self_focused in subscription on terminal view
AlacTermEvent::Wakeup => { AlacTermEvent::Wakeup => { /* Irrelevant, as we always notify on any event */ }
cx.emit(Event::Wakeup);
}
AlacTermEvent::PtyWrite(out) => { AlacTermEvent::PtyWrite(out) => {
term.scroll_display(Scroll::Bottom); term.scroll_display(Scroll::Bottom);
self.pty_tx.notify(out.into_bytes()) self.pty_tx.notify(out.into_bytes())
@ -411,17 +414,20 @@ impl Terminal {
AlacTermEvent::ClipboardStore(_, data) => { AlacTermEvent::ClipboardStore(_, data) => {
cx.write_to_clipboard(ClipboardItem::new(data)) cx.write_to_clipboard(ClipboardItem::new(data))
} }
AlacTermEvent::ClipboardLoad(_, format) => self.write_to_pty(format( AlacTermEvent::ClipboardLoad(_, format) => self.pty_tx.notify(
&cx.read_from_clipboard() format(
.map(|ci| ci.text().to_string()) &cx.read_from_clipboard()
.unwrap_or("".to_string()), .map(|ci| ci.text().to_string())
)), .unwrap_or("".to_string()),
)
.into_bytes(),
),
AlacTermEvent::ColorRequest(index, format) => { AlacTermEvent::ColorRequest(index, format) => {
let color = term.colors()[index].unwrap_or_else(|| { let color = term.colors()[index].unwrap_or_else(|| {
let term_style = &cx.global::<Settings>().theme.terminal; let term_style = &cx.global::<Settings>().theme.terminal;
to_alac_rgb(get_color_at_index(&index, &term_style.colors)) to_alac_rgb(get_color_at_index(&index, &term_style.colors))
}); });
self.write_to_pty(format(color)) self.pty_tx.notify(format(color).into_bytes())
} }
AlacTermEvent::CursorBlinkingChange => { AlacTermEvent::CursorBlinkingChange => {
//TODO: Set a timer to blink the cursor on and off //TODO: Set a timer to blink the cursor on and off
@ -435,7 +441,7 @@ impl Terminal {
} }
///Write the Input payload to the tty. This locks the terminal so we can scroll it. ///Write the Input payload to the tty. This locks the terminal so we can scroll it.
pub fn write_to_pty(&self, input: String) { pub fn write_to_pty(&mut self, input: String) {
self.event_stack.push(AlacTermEvent::PtyWrite(input)) self.event_stack.push(AlacTermEvent::PtyWrite(input))
} }
@ -447,12 +453,12 @@ impl Terminal {
self.term.lock().resize(term_size); self.term.lock().resize(term_size);
} }
pub fn clear(&self) { pub fn clear(&mut self) {
self.write_to_pty("\x0c".into()); self.write_to_pty("\x0c".into());
self.term.lock().clear_screen(ClearMode::Saved); self.term.lock().clear_screen(ClearMode::Saved);
} }
pub fn try_keystroke(&self, keystroke: &Keystroke) -> bool { pub fn try_keystroke(&mut self, keystroke: &Keystroke) -> bool {
let guard = self.term.lock(); let guard = self.term.lock();
let mode = guard.mode(); let mode = guard.mode();
let esc = to_esc_str(keystroke, mode); let esc = to_esc_str(keystroke, mode);
@ -466,7 +472,7 @@ impl Terminal {
} }
///Paste text into the terminal ///Paste text into the terminal
pub fn paste(&self, text: &str) { pub fn paste(&mut self, text: &str) {
if self.term.lock().mode().contains(TermMode::BRACKETED_PASTE) { if self.term.lock().mode().contains(TermMode::BRACKETED_PASTE) {
self.write_to_pty("\x1b[200~".to_string()); self.write_to_pty("\x1b[200~".to_string());
self.write_to_pty(text.replace('\x1b', "").to_string()); self.write_to_pty(text.replace('\x1b', "").to_string());
@ -490,11 +496,12 @@ impl Terminal {
self.term.lock().selection = sel; self.term.lock().selection = sel;
} }
pub fn render_lock<F, T>(&self, cx: &mut ModelContext<Self>, f: F) -> T pub fn render_lock<F, T>(&mut self, cx: &mut ModelContext<Self>, f: F) -> T
where where
F: FnOnce(RenderableContent, char) -> T, F: FnOnce(RenderableContent, char) -> T,
{ {
let mut term = self.term.lock(); //Lock let m = self.term.clone(); //TODO avoid clone?
let mut term = m.lock(); //Lock
//TODO, handle resizes //TODO, handle resizes
// if let Some(new_size) = new_size { // if let Some(new_size) = new_size {
@ -505,7 +512,13 @@ impl Terminal {
// term.resize(new_size); //Reflow // term.resize(new_size); //Reflow
// } // }
for event in self.event_stack.drain(..) { for event in self
.event_stack
.iter()
.map(|event| event.clone())
.collect::<Vec<AlacTermEvent>>() //TODO avoid copy
.drain(..)
{
self.process_terminal_event(event, &mut term, cx) self.process_terminal_event(event, &mut term, cx)
} }
@ -516,12 +529,13 @@ impl Terminal {
} }
pub fn get_display_offset(&self) -> usize { pub fn get_display_offset(&self) -> usize {
self.term.lock().renderable_content().display_offset 10
// self.term.lock().renderable_content().display_offset
} }
///Scroll the terminal ///Scroll the terminal
pub fn scroll(&self, scroll: Scroll) { pub fn scroll(&self, _scroll: Scroll) {
self.term.lock().scroll_display(scroll) // self.term.lock().scroll_display(scroll)
} }
pub fn click(&self, point: Point, side: Direction, clicks: usize) { pub fn click(&self, point: Point, side: Direction, clicks: usize) {
@ -549,6 +563,11 @@ impl Terminal {
pub fn mouse_down(&self, point: Point, side: Direction) { pub fn mouse_down(&self, point: Point, side: Direction) {
self.set_selection(Some(Selection::new(SelectionType::Simple, point, side))); self.set_selection(Some(Selection::new(SelectionType::Simple, point, side)));
} }
#[cfg(test)]
fn grid(&self) -> Grid<Cell> {
self.term.lock().grid().clone()
}
} }
impl Drop for Terminal { impl Drop for Terminal {

View file

@ -43,8 +43,9 @@ impl<'a> TerminalTestContext<'a> {
}); });
connection connection
.condition(self.cx, |conn, cx| { .condition(self.cx, |term, cx| {
let content = Self::grid_as_str(conn); let content = Self::grid_as_str(term);
f(content, cx) f(content, cx)
}) })
.await; .await;
@ -132,14 +133,14 @@ impl<'a> TerminalTestContext<'a> {
} }
fn grid_as_str(connection: &Terminal) -> String { fn grid_as_str(connection: &Terminal) -> String {
connection.render_lock(None, |content, _| { let content = connection.grid();
let lines = content.display_iter.group_by(|i| i.point.line.0);
lines let lines = content.display_iter().group_by(|i| i.point.line.0);
.into_iter() lines
.map(|(_, line)| line.map(|i| i.c).collect::<String>()) .into_iter()
.collect::<Vec<String>>() .map(|(_, line)| line.map(|i| i.c).collect::<String>())
.join("\n") .collect::<Vec<String>>()
}) .join("\n")
} }
} }