mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 10:29:35 +03:00
Improved performance of terminal rendering further
This commit is contained in:
parent
a8b8003980
commit
faad24542f
@ -4,7 +4,7 @@ use workspace::Workspace;
|
||||
|
||||
use crate::{
|
||||
terminal_container_view::{
|
||||
get_working_directory, DeployModal, TerminalContainer, TerminalContent,
|
||||
get_working_directory, DeployModal, TerminalContainer, TerminalContainerContent,
|
||||
},
|
||||
Event, Terminal,
|
||||
};
|
||||
@ -42,7 +42,7 @@ pub fn deploy_modal(workspace: &mut Workspace, _: &DeployModal, cx: &mut ViewCon
|
||||
|
||||
let this = cx.add_view(|cx| TerminalContainer::new(working_directory, true, cx));
|
||||
|
||||
if let TerminalContent::Connected(connected) = &this.read(cx).content {
|
||||
if let TerminalContainerContent::Connected(connected) = &this.read(cx).content {
|
||||
let terminal_handle = connected.read(cx).handle();
|
||||
cx.subscribe(&terminal_handle, on_event).detach();
|
||||
// Set the global immediately if terminal construction was successful,
|
||||
@ -55,7 +55,8 @@ pub fn deploy_modal(workspace: &mut Workspace, _: &DeployModal, cx: &mut ViewCon
|
||||
this
|
||||
}) {
|
||||
// Terminal modal was dismissed. Store terminal if the terminal view is connected
|
||||
if let TerminalContent::Connected(connected) = &closed_terminal_handle.read(cx).content
|
||||
if let TerminalContainerContent::Connected(connected) =
|
||||
&closed_terminal_handle.read(cx).content
|
||||
{
|
||||
let terminal_handle = connected.read(cx).handle();
|
||||
// Set the global immediately if terminal construction was successful,
|
||||
|
@ -11,17 +11,19 @@ use alacritty_terminal::{
|
||||
event_loop::{EventLoop, Msg, Notifier},
|
||||
grid::{Dimensions, Scroll as AlacScroll},
|
||||
index::{Column, Direction, Line, Point},
|
||||
selection::{Selection, SelectionType},
|
||||
selection::{Selection, SelectionRange, SelectionType},
|
||||
sync::FairMutex,
|
||||
term::{
|
||||
cell::Cell,
|
||||
color::Rgb,
|
||||
search::{Match, RegexIter, RegexSearch},
|
||||
RenderableContent, TermMode,
|
||||
RenderableCursor, TermMode,
|
||||
},
|
||||
tty::{self, setup_env},
|
||||
Term,
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
use futures::{
|
||||
channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
|
||||
FutureExt,
|
||||
@ -36,10 +38,10 @@ use settings::{AlternateScroll, Settings, Shell, TerminalBlink};
|
||||
use std::{
|
||||
collections::{HashMap, VecDeque},
|
||||
fmt::Display,
|
||||
ops::{RangeInclusive, Sub},
|
||||
ops::{Deref, RangeInclusive, Sub},
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
@ -376,12 +378,12 @@ impl TerminalBuilder {
|
||||
events: VecDeque::with_capacity(10), //Should never get this high.
|
||||
title: shell_txt.clone(),
|
||||
default_title: shell_txt,
|
||||
last_mode: TermMode::NONE,
|
||||
last_content: Default::default(),
|
||||
cur_size: initial_size,
|
||||
last_mouse: None,
|
||||
last_offset: 0,
|
||||
matches: Vec::new(),
|
||||
selection_text: None,
|
||||
last_synced: Instant::now(),
|
||||
sync_task: None,
|
||||
};
|
||||
|
||||
Ok(TerminalBuilder {
|
||||
@ -443,18 +445,61 @@ impl TerminalBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct IndexedCell {
|
||||
point: Point,
|
||||
cell: Cell,
|
||||
}
|
||||
|
||||
impl Deref for IndexedCell {
|
||||
type Target = Cell;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Cell {
|
||||
&self.cell
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TerminalContent {
|
||||
cells: Vec<IndexedCell>,
|
||||
mode: TermMode,
|
||||
display_offset: usize,
|
||||
selection_text: Option<String>,
|
||||
selection: Option<SelectionRange>,
|
||||
cursor: RenderableCursor,
|
||||
cursor_char: char,
|
||||
}
|
||||
|
||||
impl Default for TerminalContent {
|
||||
fn default() -> Self {
|
||||
TerminalContent {
|
||||
cells: Default::default(),
|
||||
mode: Default::default(),
|
||||
display_offset: Default::default(),
|
||||
selection_text: Default::default(),
|
||||
selection: Default::default(),
|
||||
cursor: RenderableCursor {
|
||||
shape: alacritty_terminal::ansi::CursorShape::Block,
|
||||
point: Point::new(Line(0), Column(0)),
|
||||
},
|
||||
cursor_char: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Terminal {
|
||||
pty_tx: Notifier,
|
||||
term: Arc<FairMutex<Term<ZedListener>>>,
|
||||
events: VecDeque<InternalEvent>,
|
||||
default_title: String,
|
||||
title: String,
|
||||
cur_size: TerminalSize,
|
||||
last_mode: TermMode,
|
||||
last_offset: usize,
|
||||
last_mouse: Option<(Point, Direction)>,
|
||||
pub matches: Vec<RangeInclusive<Point>>,
|
||||
pub selection_text: Option<String>,
|
||||
cur_size: TerminalSize,
|
||||
last_content: TerminalContent,
|
||||
last_synced: Instant,
|
||||
sync_task: Option<Task<()>>,
|
||||
}
|
||||
|
||||
impl Terminal {
|
||||
@ -576,6 +621,10 @@ impl Terminal {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn last_content(&self) -> &TerminalContent {
|
||||
&self.last_content
|
||||
}
|
||||
|
||||
fn begin_select(&mut self, sel: Selection) {
|
||||
self.events
|
||||
.push_back(InternalEvent::SetSelection(Some(sel)));
|
||||
@ -648,7 +697,7 @@ impl Terminal {
|
||||
}
|
||||
|
||||
pub fn try_keystroke(&mut self, keystroke: &Keystroke) -> bool {
|
||||
let esc = to_esc_str(keystroke, &self.last_mode);
|
||||
let esc = to_esc_str(keystroke, &self.last_content.mode);
|
||||
if let Some(esc) = esc {
|
||||
self.input(esc);
|
||||
true
|
||||
@ -659,7 +708,7 @@ impl Terminal {
|
||||
|
||||
///Paste text into the terminal
|
||||
pub fn paste(&mut self, text: &str) {
|
||||
let paste_text = if self.last_mode.contains(TermMode::BRACKETED_PASTE) {
|
||||
let paste_text = if self.last_content.mode.contains(TermMode::BRACKETED_PASTE) {
|
||||
format!("{}{}{}", "\x1b[200~", text.replace('\x1b', ""), "\x1b[201~")
|
||||
} else {
|
||||
text.replace("\r\n", "\r").replace('\n', "\r")
|
||||
@ -667,38 +716,76 @@ impl Terminal {
|
||||
self.input(paste_text)
|
||||
}
|
||||
|
||||
pub fn render_lock<F, T>(&mut self, cx: &mut ModelContext<Self>, f: F) -> T
|
||||
where
|
||||
F: FnOnce(RenderableContent, char) -> T,
|
||||
{
|
||||
pub fn try_sync(&mut self, cx: &mut ModelContext<Self>) {
|
||||
let term = self.term.clone();
|
||||
let mut term = term.lock();
|
||||
|
||||
let mut terminal = if let Some(term) = term.try_lock_unfair() {
|
||||
term
|
||||
} else if self.last_synced.elapsed().as_secs_f32() > 0.25 {
|
||||
term.lock_unfair()
|
||||
} else if let None = self.sync_task {
|
||||
//Skip this frame
|
||||
let delay = cx.background().timer(Duration::from_millis(16));
|
||||
self.sync_task = Some(cx.spawn_weak(|weak_handle, mut cx| async move {
|
||||
delay.await;
|
||||
cx.update(|cx| {
|
||||
if let Some(handle) = weak_handle.upgrade(cx) {
|
||||
handle.update(cx, |terminal, cx| {
|
||||
terminal.sync_task.take();
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
return;
|
||||
} else {
|
||||
//No lock and delayed rendering already scheduled, nothing to do
|
||||
return;
|
||||
};
|
||||
|
||||
//Note that this ordering matters for event processing
|
||||
while let Some(e) = self.events.pop_front() {
|
||||
self.process_terminal_event(&e, &mut term, cx)
|
||||
self.process_terminal_event(&e, &mut terminal, cx)
|
||||
}
|
||||
|
||||
self.last_mode = *term.mode();
|
||||
self.last_content = Self::make_content(&terminal);
|
||||
self.last_synced = Instant::now();
|
||||
}
|
||||
|
||||
fn make_content(term: &Term<ZedListener>) -> TerminalContent {
|
||||
let content = term.renderable_content();
|
||||
|
||||
self.selection_text = term.selection_to_string();
|
||||
self.last_offset = content.display_offset;
|
||||
|
||||
let cursor_text = term.grid()[content.cursor.point].c;
|
||||
|
||||
f(content, cursor_text)
|
||||
TerminalContent {
|
||||
cells: content
|
||||
.display_iter
|
||||
//TODO: Add this once there's a way to retain empty lines
|
||||
// .filter(|ic| {
|
||||
// !ic.flags.contains(Flags::HIDDEN)
|
||||
// && !(ic.bg == Named(NamedColor::Background)
|
||||
// && ic.c == ' '
|
||||
// && !ic.flags.contains(Flags::INVERSE))
|
||||
// })
|
||||
.map(|ic| IndexedCell {
|
||||
point: ic.point,
|
||||
cell: ic.cell.clone(),
|
||||
})
|
||||
.collect::<Vec<IndexedCell>>(),
|
||||
mode: content.mode,
|
||||
display_offset: content.display_offset,
|
||||
selection_text: term.selection_to_string(),
|
||||
selection: content.selection,
|
||||
cursor: content.cursor,
|
||||
cursor_char: term.grid()[content.cursor.point].c,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn focus_in(&self) {
|
||||
if self.last_mode.contains(TermMode::FOCUS_IN_OUT) {
|
||||
if self.last_content.mode.contains(TermMode::FOCUS_IN_OUT) {
|
||||
self.write_to_pty("\x1b[I".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn focus_out(&self) {
|
||||
if self.last_mode.contains(TermMode::FOCUS_IN_OUT) {
|
||||
if self.last_content.mode.contains(TermMode::FOCUS_IN_OUT) {
|
||||
self.write_to_pty("\x1b[O".to_string());
|
||||
}
|
||||
}
|
||||
@ -721,17 +808,17 @@ impl Terminal {
|
||||
}
|
||||
|
||||
pub fn mouse_mode(&self, shift: bool) -> bool {
|
||||
self.last_mode.intersects(TermMode::MOUSE_MODE) && !shift
|
||||
self.last_content.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 point = mouse_point(position, self.cur_size, self.last_content.display_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) {
|
||||
if let Some(bytes) = mouse_moved_report(point, e, self.last_content.mode) {
|
||||
self.pty_tx.notify(bytes);
|
||||
}
|
||||
}
|
||||
@ -746,7 +833,7 @@ impl Terminal {
|
||||
self.continue_selection(position);
|
||||
|
||||
// Doesn't make sense to scroll the alt screen
|
||||
if !self.last_mode.contains(TermMode::ALT_SCREEN) {
|
||||
if !self.last_content.mode.contains(TermMode::ALT_SCREEN) {
|
||||
let scroll_delta = match self.drag_line_delta(e) {
|
||||
Some(value) => value,
|
||||
None => return,
|
||||
@ -775,11 +862,11 @@ impl Terminal {
|
||||
|
||||
pub fn mouse_down(&mut self, e: &DownRegionEvent, origin: Vector2F) {
|
||||
let position = e.position.sub(origin);
|
||||
let point = mouse_point(position, self.cur_size, self.last_offset);
|
||||
let point = mouse_point(position, self.cur_size, self.last_content.display_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) {
|
||||
if let Some(bytes) = mouse_button_report(point, e, true, self.last_content.mode) {
|
||||
self.pty_tx.notify(bytes);
|
||||
}
|
||||
} else if e.button == MouseButton::Left {
|
||||
@ -791,7 +878,7 @@ impl Terminal {
|
||||
let position = e.position.sub(origin);
|
||||
|
||||
if !self.mouse_mode(e.shift) {
|
||||
let point = mouse_point(position, self.cur_size, self.last_offset);
|
||||
let point = mouse_point(position, self.cur_size, self.last_content.display_offset);
|
||||
let side = mouse_side(position, self.cur_size);
|
||||
|
||||
let selection_type = match e.click_count {
|
||||
@ -814,9 +901,9 @@ impl Terminal {
|
||||
pub fn mouse_up(&mut self, e: &UpRegionEvent, 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 point = mouse_point(position, self.cur_size, self.last_content.display_offset);
|
||||
|
||||
if let Some(bytes) = mouse_button_report(point, e, false, self.last_mode) {
|
||||
if let Some(bytes) = mouse_button_report(point, e, false, self.last_content.mode) {
|
||||
self.pty_tx.notify(bytes);
|
||||
}
|
||||
} else if e.button == MouseButton::Left {
|
||||
@ -835,15 +922,22 @@ impl Terminal {
|
||||
//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 = (e.delta.y() / self.cur_size.line_height) as i32;
|
||||
let point = mouse_point(e.position.sub(origin), self.cur_size, self.last_offset);
|
||||
let point = mouse_point(
|
||||
e.position.sub(origin),
|
||||
self.cur_size,
|
||||
self.last_content.display_offset,
|
||||
);
|
||||
|
||||
if let Some(scrolls) = scroll_report(point, scroll_lines as i32, e, self.last_mode) {
|
||||
if let Some(scrolls) =
|
||||
scroll_report(point, scroll_lines as i32, e, self.last_content.mode)
|
||||
{
|
||||
for scroll in scrolls {
|
||||
self.pty_tx.notify(scroll);
|
||||
}
|
||||
};
|
||||
} else if self
|
||||
.last_mode
|
||||
.last_content
|
||||
.mode
|
||||
.contains(TermMode::ALT_SCREEN | TermMode::ALTERNATE_SCROLL)
|
||||
&& !e.shift
|
||||
{
|
||||
@ -868,7 +962,6 @@ impl Terminal {
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Vec<RangeInclusive<Point>>> {
|
||||
let term = self.term.clone();
|
||||
dbg!("Spawning find_matches");
|
||||
cx.background().spawn(async move {
|
||||
let searcher = match query {
|
||||
project::search::SearchQuery::Text { query, .. } => {
|
||||
@ -885,7 +978,8 @@ impl Terminal {
|
||||
let searcher = searcher.unwrap();
|
||||
|
||||
let term = term.lock();
|
||||
dbg!(make_search_matches(&term, &searcher).collect())
|
||||
|
||||
make_search_matches(&term, &searcher).collect()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -29,12 +29,12 @@ pub fn init(cx: &mut MutableAppContext) {
|
||||
//Take away all the result unwrapping in the current TerminalView by making it 'infallible'
|
||||
//Bubble up to deploy(_modal)() calls
|
||||
|
||||
pub enum TerminalContent {
|
||||
pub enum TerminalContainerContent {
|
||||
Connected(ViewHandle<TerminalView>),
|
||||
Error(ViewHandle<ErrorView>),
|
||||
}
|
||||
|
||||
impl TerminalContent {
|
||||
impl TerminalContainerContent {
|
||||
fn handle(&self) -> AnyViewHandle {
|
||||
match self {
|
||||
Self::Connected(handle) => handle.into(),
|
||||
@ -45,7 +45,7 @@ impl TerminalContent {
|
||||
|
||||
pub struct TerminalContainer {
|
||||
modal: bool,
|
||||
pub content: TerminalContent,
|
||||
pub content: TerminalContainerContent,
|
||||
associated_directory: Option<PathBuf>,
|
||||
}
|
||||
|
||||
@ -119,13 +119,13 @@ impl TerminalContainer {
|
||||
let view = cx.add_view(|cx| TerminalView::from_terminal(terminal, modal, cx));
|
||||
cx.subscribe(&view, |_this, _content, event, cx| cx.emit(*event))
|
||||
.detach();
|
||||
TerminalContent::Connected(view)
|
||||
TerminalContainerContent::Connected(view)
|
||||
}
|
||||
Err(error) => {
|
||||
let view = cx.add_view(|_| ErrorView {
|
||||
error: error.downcast::<TerminalError>().unwrap(),
|
||||
});
|
||||
TerminalContent::Error(view)
|
||||
TerminalContainerContent::Error(view)
|
||||
}
|
||||
};
|
||||
cx.focus(content.handle());
|
||||
@ -145,7 +145,7 @@ impl TerminalContainer {
|
||||
let connected_view = cx.add_view(|cx| TerminalView::from_terminal(terminal, modal, cx));
|
||||
TerminalContainer {
|
||||
modal,
|
||||
content: TerminalContent::Connected(connected_view),
|
||||
content: TerminalContainerContent::Connected(connected_view),
|
||||
associated_directory: None,
|
||||
}
|
||||
}
|
||||
@ -158,8 +158,8 @@ impl View for TerminalContainer {
|
||||
|
||||
fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox {
|
||||
let child_view = match &self.content {
|
||||
TerminalContent::Connected(connected) => ChildView::new(connected),
|
||||
TerminalContent::Error(error) => ChildView::new(error),
|
||||
TerminalContainerContent::Connected(connected) => ChildView::new(connected),
|
||||
TerminalContainerContent::Error(error) => ChildView::new(error),
|
||||
};
|
||||
if self.modal {
|
||||
let settings = cx.global::<Settings>();
|
||||
@ -238,10 +238,10 @@ impl Item for TerminalContainer {
|
||||
cx: &gpui::AppContext,
|
||||
) -> ElementBox {
|
||||
let title = match &self.content {
|
||||
TerminalContent::Connected(connected) => {
|
||||
TerminalContainerContent::Connected(connected) => {
|
||||
connected.read(cx).handle().read(cx).title.to_string()
|
||||
}
|
||||
TerminalContent::Error(_) => "Terminal".to_string(),
|
||||
TerminalContainerContent::Error(_) => "Terminal".to_string(),
|
||||
};
|
||||
|
||||
Flex::row()
|
||||
@ -309,7 +309,7 @@ impl Item for TerminalContainer {
|
||||
}
|
||||
|
||||
fn is_dirty(&self, cx: &gpui::AppContext) -> bool {
|
||||
if let TerminalContent::Connected(connected) = &self.content {
|
||||
if let TerminalContainerContent::Connected(connected) = &self.content {
|
||||
connected.read(cx).has_new_content()
|
||||
} else {
|
||||
false
|
||||
@ -317,7 +317,7 @@ impl Item for TerminalContainer {
|
||||
}
|
||||
|
||||
fn has_conflict(&self, cx: &AppContext) -> bool {
|
||||
if let TerminalContent::Connected(connected) = &self.content {
|
||||
if let TerminalContainerContent::Connected(connected) = &self.content {
|
||||
connected.read(cx).has_bell()
|
||||
} else {
|
||||
false
|
||||
@ -351,7 +351,7 @@ impl SearchableItem for TerminalContainer {
|
||||
|
||||
/// Clear stored matches
|
||||
fn clear_matches(&mut self, cx: &mut ViewContext<Self>) {
|
||||
if let TerminalContent::Connected(connected) = &self.content {
|
||||
if let TerminalContainerContent::Connected(connected) = &self.content {
|
||||
let terminal = connected.read(cx).terminal().clone();
|
||||
terminal.update(cx, |term, _| term.matches.clear())
|
||||
}
|
||||
@ -359,18 +359,22 @@ impl SearchableItem for TerminalContainer {
|
||||
|
||||
/// Store matches returned from find_matches somewhere for rendering
|
||||
fn update_matches(&mut self, matches: Vec<Self::Match>, cx: &mut ViewContext<Self>) {
|
||||
if let TerminalContent::Connected(connected) = &self.content {
|
||||
if let TerminalContainerContent::Connected(connected) = &self.content {
|
||||
let terminal = connected.read(cx).terminal().clone();
|
||||
dbg!(&matches);
|
||||
terminal.update(cx, |term, _| term.matches = matches)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the selection content to pre-load into this search
|
||||
fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String {
|
||||
if let TerminalContent::Connected(connected) = &self.content {
|
||||
if let TerminalContainerContent::Connected(connected) = &self.content {
|
||||
let terminal = connected.read(cx).terminal().clone();
|
||||
terminal.read(cx).selection_text.clone().unwrap_or_default()
|
||||
terminal
|
||||
.read(cx)
|
||||
.last_content
|
||||
.selection_text
|
||||
.clone()
|
||||
.unwrap_or_default()
|
||||
} else {
|
||||
Default::default()
|
||||
}
|
||||
@ -403,7 +407,7 @@ impl SearchableItem for TerminalContainer {
|
||||
query: project::search::SearchQuery,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<Vec<Self::Match>> {
|
||||
if let TerminalContent::Connected(connected) = &self.content {
|
||||
if let TerminalContainerContent::Connected(connected) = &self.content {
|
||||
let terminal = connected.read(cx).terminal().clone();
|
||||
terminal.update(cx, |term, cx| term.find_matches(query, cx))
|
||||
} else {
|
||||
|
@ -2,10 +2,7 @@ use alacritty_terminal::{
|
||||
ansi::{Color as AnsiColor, Color::Named, CursorShape as AlacCursorShape, NamedColor},
|
||||
grid::Dimensions,
|
||||
index::Point,
|
||||
term::{
|
||||
cell::{Cell, Flags},
|
||||
TermMode,
|
||||
},
|
||||
term::{cell::Flags, TermMode},
|
||||
};
|
||||
use editor::{Cursor, CursorShape, HighlightedRange, HighlightedRangeLine};
|
||||
use gpui::{
|
||||
@ -27,15 +24,12 @@ use theme::TerminalStyle;
|
||||
use util::ResultExt;
|
||||
|
||||
use std::{fmt::Debug, ops::RangeInclusive};
|
||||
use std::{
|
||||
mem,
|
||||
ops::{Deref, Range},
|
||||
};
|
||||
use std::{mem, ops::Range};
|
||||
|
||||
use crate::{
|
||||
mappings::colors::convert_color,
|
||||
terminal_view::{DeployContextMenu, TerminalView},
|
||||
Terminal, TerminalSize,
|
||||
IndexedCell, Terminal, TerminalContent, TerminalSize,
|
||||
};
|
||||
|
||||
///The information generated during layout that is nescessary for painting
|
||||
@ -50,21 +44,6 @@ pub struct LayoutState {
|
||||
display_offset: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct IndexedCell {
|
||||
point: Point,
|
||||
cell: Cell,
|
||||
}
|
||||
|
||||
impl Deref for IndexedCell {
|
||||
type Target = Cell;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Cell {
|
||||
&self.cell
|
||||
}
|
||||
}
|
||||
|
||||
///Helper struct for converting data between alacritty's cursor points, and displayed cursor points
|
||||
struct DisplayCursor {
|
||||
line: i32,
|
||||
@ -195,7 +174,7 @@ impl TerminalElement {
|
||||
//Vec<Range<Point>> -> Clip out the parts of the ranges
|
||||
|
||||
fn layout_grid(
|
||||
grid: Vec<IndexedCell>,
|
||||
grid: &Vec<IndexedCell>,
|
||||
text_style: &TextStyle,
|
||||
terminal_theme: &TerminalStyle,
|
||||
text_layout_cache: &TextLayoutCache,
|
||||
@ -581,40 +560,22 @@ impl Element for TerminalElement {
|
||||
} else {
|
||||
terminal_theme.colors.background
|
||||
};
|
||||
let terminal_handle = self.terminal.upgrade(cx).unwrap();
|
||||
|
||||
let (cells, selection, cursor, display_offset, cursor_text, mode) = self
|
||||
.terminal
|
||||
.upgrade(cx)
|
||||
.unwrap()
|
||||
.update(cx.app, |terminal, cx| {
|
||||
terminal.set_size(dimensions);
|
||||
terminal.render_lock(cx, |content, cursor_text| {
|
||||
let mut cells = vec![];
|
||||
cells.extend(
|
||||
content
|
||||
.display_iter
|
||||
//TODO: Add this once there's a way to retain empty lines
|
||||
// .filter(|ic| {
|
||||
// !ic.flags.contains(Flags::HIDDEN)
|
||||
// && !(ic.bg == Named(NamedColor::Background)
|
||||
// && ic.c == ' '
|
||||
// && !ic.flags.contains(Flags::INVERSE))
|
||||
// })
|
||||
.map(|ic| IndexedCell {
|
||||
point: ic.point,
|
||||
cell: ic.cell.clone(),
|
||||
}),
|
||||
);
|
||||
(
|
||||
cells,
|
||||
content.selection,
|
||||
content.cursor,
|
||||
content.display_offset,
|
||||
cursor_text,
|
||||
content.mode,
|
||||
)
|
||||
})
|
||||
});
|
||||
terminal_handle.update(cx.app, |terminal, cx| {
|
||||
terminal.set_size(dimensions);
|
||||
terminal.try_sync(cx)
|
||||
});
|
||||
|
||||
let TerminalContent {
|
||||
cells,
|
||||
mode,
|
||||
display_offset,
|
||||
cursor_char,
|
||||
selection,
|
||||
cursor,
|
||||
..
|
||||
} = &terminal_handle.read(cx).last_content;
|
||||
|
||||
// searches, highlights to a single range representations
|
||||
let mut relative_highlighted_ranges = Vec::new();
|
||||
@ -641,9 +602,9 @@ impl Element for TerminalElement {
|
||||
let cursor = if let AlacCursorShape::Hidden = cursor.shape {
|
||||
None
|
||||
} else {
|
||||
let cursor_point = DisplayCursor::from(cursor.point, display_offset);
|
||||
let cursor_point = DisplayCursor::from(cursor.point, *display_offset);
|
||||
let cursor_text = {
|
||||
let str_trxt = cursor_text.to_string();
|
||||
let str_trxt = cursor_char.to_string();
|
||||
|
||||
let color = if self.focused {
|
||||
terminal_theme.colors.background
|
||||
@ -699,8 +660,8 @@ impl Element for TerminalElement {
|
||||
size: dimensions,
|
||||
rects,
|
||||
relative_highlighted_ranges,
|
||||
mode,
|
||||
display_offset,
|
||||
mode: *mode,
|
||||
display_offset: *display_offset,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -149,7 +149,8 @@ impl TerminalView {
|
||||
if !self
|
||||
.terminal
|
||||
.read(cx)
|
||||
.last_mode
|
||||
.last_content
|
||||
.mode
|
||||
.contains(TermMode::ALT_SCREEN)
|
||||
{
|
||||
cx.show_character_palette();
|
||||
@ -177,7 +178,8 @@ impl TerminalView {
|
||||
|| self
|
||||
.terminal
|
||||
.read(cx)
|
||||
.last_mode
|
||||
.last_content
|
||||
.mode
|
||||
.contains(TermMode::ALT_SCREEN)
|
||||
{
|
||||
return true;
|
||||
@ -362,7 +364,8 @@ impl View for TerminalView {
|
||||
if self
|
||||
.terminal
|
||||
.read(cx)
|
||||
.last_mode
|
||||
.last_content
|
||||
.mode
|
||||
.contains(TermMode::ALT_SCREEN)
|
||||
{
|
||||
None
|
||||
@ -387,7 +390,7 @@ impl View for TerminalView {
|
||||
if self.modal {
|
||||
context.set.insert("ModalTerminal".into());
|
||||
}
|
||||
let mode = self.terminal.read(cx).last_mode;
|
||||
let mode = self.terminal.read(cx).last_content.mode;
|
||||
context.map.insert(
|
||||
"screen".to_string(),
|
||||
(if mode.contains(TermMode::ALT_SCREEN) {
|
||||
|
1
styles/package-lock.json
generated
1
styles/package-lock.json
generated
@ -5,7 +5,6 @@
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "styles",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
|
Loading…
Reference in New Issue
Block a user