debugger: Improve performance with large # of output (#33874)
Closes #33820 Release Notes: - Improved performance of debug console when there are lots of output events. --------- Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
parent
0ebf7f54bb
commit
91bfe6f968
3 changed files with 230 additions and 218 deletions
|
@ -16,12 +16,14 @@ use language::{Buffer, CodeLabel, ToOffset};
|
||||||
use menu::Confirm;
|
use menu::Confirm;
|
||||||
use project::{
|
use project::{
|
||||||
Completion, CompletionResponse,
|
Completion, CompletionResponse,
|
||||||
debugger::session::{CompletionsQuery, OutputToken, Session, SessionEvent},
|
debugger::session::{CompletionsQuery, OutputToken, Session},
|
||||||
};
|
};
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
|
use std::fmt::Write;
|
||||||
use std::{cell::RefCell, ops::Range, rc::Rc, usize};
|
use std::{cell::RefCell, ops::Range, rc::Rc, usize};
|
||||||
use theme::{Theme, ThemeSettings};
|
use theme::{Theme, ThemeSettings};
|
||||||
use ui::{ContextMenu, Divider, PopoverMenu, SplitButton, Tooltip, prelude::*};
|
use ui::{ContextMenu, Divider, PopoverMenu, SplitButton, Tooltip, prelude::*};
|
||||||
|
use util::ResultExt;
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
console,
|
console,
|
||||||
|
@ -39,7 +41,7 @@ pub struct Console {
|
||||||
variable_list: Entity<VariableList>,
|
variable_list: Entity<VariableList>,
|
||||||
stack_frame_list: Entity<StackFrameList>,
|
stack_frame_list: Entity<StackFrameList>,
|
||||||
last_token: OutputToken,
|
last_token: OutputToken,
|
||||||
update_output_task: Task<()>,
|
update_output_task: Option<Task<()>>,
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,11 +91,6 @@ impl Console {
|
||||||
|
|
||||||
let _subscriptions = vec![
|
let _subscriptions = vec![
|
||||||
cx.subscribe(&stack_frame_list, Self::handle_stack_frame_list_events),
|
cx.subscribe(&stack_frame_list, Self::handle_stack_frame_list_events),
|
||||||
cx.subscribe_in(&session, window, |this, _, event, window, cx| {
|
|
||||||
if let SessionEvent::ConsoleOutput = event {
|
|
||||||
this.update_output(window, cx)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
cx.on_focus(&focus_handle, window, |console, window, cx| {
|
cx.on_focus(&focus_handle, window, |console, window, cx| {
|
||||||
if console.is_running(cx) {
|
if console.is_running(cx) {
|
||||||
console.query_bar.focus_handle(cx).focus(window);
|
console.query_bar.focus_handle(cx).focus(window);
|
||||||
|
@ -108,7 +105,7 @@ impl Console {
|
||||||
variable_list,
|
variable_list,
|
||||||
_subscriptions,
|
_subscriptions,
|
||||||
stack_frame_list,
|
stack_frame_list,
|
||||||
update_output_task: Task::ready(()),
|
update_output_task: None,
|
||||||
last_token: OutputToken(0),
|
last_token: OutputToken(0),
|
||||||
focus_handle,
|
focus_handle,
|
||||||
}
|
}
|
||||||
|
@ -139,202 +136,116 @@ impl Console {
|
||||||
self.session.read(cx).has_new_output(self.last_token)
|
self.session.read(cx).has_new_output(self.last_token)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_messages<'a>(
|
fn add_messages(
|
||||||
&mut self,
|
&mut self,
|
||||||
events: impl Iterator<Item = &'a OutputEvent>,
|
events: Vec<OutputEvent>,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) {
|
) -> Task<Result<()>> {
|
||||||
self.console.update(cx, |console, cx| {
|
self.console.update(cx, |_, cx| {
|
||||||
console.set_read_only(false);
|
cx.spawn_in(window, async move |console, cx| {
|
||||||
|
let mut len = console.update(cx, |this, cx| this.buffer().read(cx).len(cx))?;
|
||||||
|
let (output, spans, background_spans) = cx
|
||||||
|
.background_spawn(async move {
|
||||||
|
let mut all_spans = Vec::new();
|
||||||
|
let mut all_background_spans = Vec::new();
|
||||||
|
let mut to_insert = String::new();
|
||||||
|
let mut scratch = String::new();
|
||||||
|
|
||||||
for event in events {
|
for event in &events {
|
||||||
let to_insert = format!("{}\n", event.output.trim_end());
|
scratch.clear();
|
||||||
|
let mut ansi_handler = ConsoleHandler::default();
|
||||||
|
let mut ansi_processor =
|
||||||
|
ansi::Processor::<ansi::StdSyncHandler>::default();
|
||||||
|
|
||||||
let mut ansi_handler = ConsoleHandler::default();
|
let trimmed_output = event.output.trim_end();
|
||||||
let mut ansi_processor = ansi::Processor::<ansi::StdSyncHandler>::default();
|
let _ = writeln!(&mut scratch, "{trimmed_output}");
|
||||||
|
ansi_processor.advance(&mut ansi_handler, scratch.as_bytes());
|
||||||
|
let output = std::mem::take(&mut ansi_handler.output);
|
||||||
|
to_insert.extend(output.chars());
|
||||||
|
let mut spans = std::mem::take(&mut ansi_handler.spans);
|
||||||
|
let mut background_spans =
|
||||||
|
std::mem::take(&mut ansi_handler.background_spans);
|
||||||
|
if ansi_handler.current_range_start < output.len() {
|
||||||
|
spans.push((
|
||||||
|
ansi_handler.current_range_start..output.len(),
|
||||||
|
ansi_handler.current_color,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if ansi_handler.current_background_range_start < output.len() {
|
||||||
|
background_spans.push((
|
||||||
|
ansi_handler.current_background_range_start..output.len(),
|
||||||
|
ansi_handler.current_background_color,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let len = console.buffer().read(cx).len(cx);
|
for (range, _) in spans.iter_mut() {
|
||||||
ansi_processor.advance(&mut ansi_handler, to_insert.as_bytes());
|
let start_offset = len + range.start;
|
||||||
let output = std::mem::take(&mut ansi_handler.output);
|
*range = start_offset..len + range.end;
|
||||||
let mut spans = std::mem::take(&mut ansi_handler.spans);
|
}
|
||||||
let mut background_spans = std::mem::take(&mut ansi_handler.background_spans);
|
|
||||||
if ansi_handler.current_range_start < output.len() {
|
|
||||||
spans.push((
|
|
||||||
ansi_handler.current_range_start..output.len(),
|
|
||||||
ansi_handler.current_color,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if ansi_handler.current_background_range_start < output.len() {
|
|
||||||
background_spans.push((
|
|
||||||
ansi_handler.current_background_range_start..output.len(),
|
|
||||||
ansi_handler.current_background_color,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
console.move_to_end(&editor::actions::MoveToEnd, window, cx);
|
|
||||||
console.insert(&output, window, cx);
|
|
||||||
let buffer = console.buffer().read(cx).snapshot(cx);
|
|
||||||
|
|
||||||
struct ConsoleAnsiHighlight;
|
for (range, _) in background_spans.iter_mut() {
|
||||||
|
let start_offset = len + range.start;
|
||||||
|
*range = start_offset..len + range.end;
|
||||||
|
}
|
||||||
|
|
||||||
for (range, color) in spans {
|
len += output.len();
|
||||||
let Some(color) = color else { continue };
|
|
||||||
let start_offset = len + range.start;
|
|
||||||
let range = start_offset..len + range.end;
|
|
||||||
let range = buffer.anchor_after(range.start)..buffer.anchor_before(range.end);
|
|
||||||
let style = HighlightStyle {
|
|
||||||
color: Some(terminal_view::terminal_element::convert_color(
|
|
||||||
&color,
|
|
||||||
cx.theme(),
|
|
||||||
)),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
console.highlight_text_key::<ConsoleAnsiHighlight>(
|
|
||||||
start_offset,
|
|
||||||
vec![range],
|
|
||||||
style,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (range, color) in background_spans {
|
all_spans.extend(spans);
|
||||||
let Some(color) = color else { continue };
|
all_background_spans.extend(background_spans);
|
||||||
let start_offset = len + range.start;
|
|
||||||
let range = start_offset..len + range.end;
|
|
||||||
let range = buffer.anchor_after(range.start)..buffer.anchor_before(range.end);
|
|
||||||
|
|
||||||
let color_fetcher: fn(&Theme) -> Hsla = match color {
|
|
||||||
// Named and theme defined colors
|
|
||||||
ansi::Color::Named(n) => match n {
|
|
||||||
ansi::NamedColor::Black => |theme| theme.colors().terminal_ansi_black,
|
|
||||||
ansi::NamedColor::Red => |theme| theme.colors().terminal_ansi_red,
|
|
||||||
ansi::NamedColor::Green => |theme| theme.colors().terminal_ansi_green,
|
|
||||||
ansi::NamedColor::Yellow => |theme| theme.colors().terminal_ansi_yellow,
|
|
||||||
ansi::NamedColor::Blue => |theme| theme.colors().terminal_ansi_blue,
|
|
||||||
ansi::NamedColor::Magenta => {
|
|
||||||
|theme| theme.colors().terminal_ansi_magenta
|
|
||||||
}
|
|
||||||
ansi::NamedColor::Cyan => |theme| theme.colors().terminal_ansi_cyan,
|
|
||||||
ansi::NamedColor::White => |theme| theme.colors().terminal_ansi_white,
|
|
||||||
ansi::NamedColor::BrightBlack => {
|
|
||||||
|theme| theme.colors().terminal_ansi_bright_black
|
|
||||||
}
|
|
||||||
ansi::NamedColor::BrightRed => {
|
|
||||||
|theme| theme.colors().terminal_ansi_bright_red
|
|
||||||
}
|
|
||||||
ansi::NamedColor::BrightGreen => {
|
|
||||||
|theme| theme.colors().terminal_ansi_bright_green
|
|
||||||
}
|
|
||||||
ansi::NamedColor::BrightYellow => {
|
|
||||||
|theme| theme.colors().terminal_ansi_bright_yellow
|
|
||||||
}
|
|
||||||
ansi::NamedColor::BrightBlue => {
|
|
||||||
|theme| theme.colors().terminal_ansi_bright_blue
|
|
||||||
}
|
|
||||||
ansi::NamedColor::BrightMagenta => {
|
|
||||||
|theme| theme.colors().terminal_ansi_bright_magenta
|
|
||||||
}
|
|
||||||
ansi::NamedColor::BrightCyan => {
|
|
||||||
|theme| theme.colors().terminal_ansi_bright_cyan
|
|
||||||
}
|
|
||||||
ansi::NamedColor::BrightWhite => {
|
|
||||||
|theme| theme.colors().terminal_ansi_bright_white
|
|
||||||
}
|
|
||||||
ansi::NamedColor::Foreground => {
|
|
||||||
|theme| theme.colors().terminal_foreground
|
|
||||||
}
|
|
||||||
ansi::NamedColor::Background => {
|
|
||||||
|theme| theme.colors().terminal_background
|
|
||||||
}
|
|
||||||
ansi::NamedColor::Cursor => |theme| theme.players().local().cursor,
|
|
||||||
ansi::NamedColor::DimBlack => {
|
|
||||||
|theme| theme.colors().terminal_ansi_dim_black
|
|
||||||
}
|
|
||||||
ansi::NamedColor::DimRed => {
|
|
||||||
|theme| theme.colors().terminal_ansi_dim_red
|
|
||||||
}
|
|
||||||
ansi::NamedColor::DimGreen => {
|
|
||||||
|theme| theme.colors().terminal_ansi_dim_green
|
|
||||||
}
|
|
||||||
ansi::NamedColor::DimYellow => {
|
|
||||||
|theme| theme.colors().terminal_ansi_dim_yellow
|
|
||||||
}
|
|
||||||
ansi::NamedColor::DimBlue => {
|
|
||||||
|theme| theme.colors().terminal_ansi_dim_blue
|
|
||||||
}
|
|
||||||
ansi::NamedColor::DimMagenta => {
|
|
||||||
|theme| theme.colors().terminal_ansi_dim_magenta
|
|
||||||
}
|
|
||||||
ansi::NamedColor::DimCyan => {
|
|
||||||
|theme| theme.colors().terminal_ansi_dim_cyan
|
|
||||||
}
|
|
||||||
ansi::NamedColor::DimWhite => {
|
|
||||||
|theme| theme.colors().terminal_ansi_dim_white
|
|
||||||
}
|
|
||||||
ansi::NamedColor::BrightForeground => {
|
|
||||||
|theme| theme.colors().terminal_bright_foreground
|
|
||||||
}
|
|
||||||
ansi::NamedColor::DimForeground => {
|
|
||||||
|theme| theme.colors().terminal_dim_foreground
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 'True' colors
|
|
||||||
ansi::Color::Spec(_) => |theme| theme.colors().editor_background,
|
|
||||||
// 8 bit, indexed colors
|
|
||||||
ansi::Color::Indexed(i) => {
|
|
||||||
match i {
|
|
||||||
// 0-15 are the same as the named colors above
|
|
||||||
0 => |theme| theme.colors().terminal_ansi_black,
|
|
||||||
1 => |theme| theme.colors().terminal_ansi_red,
|
|
||||||
2 => |theme| theme.colors().terminal_ansi_green,
|
|
||||||
3 => |theme| theme.colors().terminal_ansi_yellow,
|
|
||||||
4 => |theme| theme.colors().terminal_ansi_blue,
|
|
||||||
5 => |theme| theme.colors().terminal_ansi_magenta,
|
|
||||||
6 => |theme| theme.colors().terminal_ansi_cyan,
|
|
||||||
7 => |theme| theme.colors().terminal_ansi_white,
|
|
||||||
8 => |theme| theme.colors().terminal_ansi_bright_black,
|
|
||||||
9 => |theme| theme.colors().terminal_ansi_bright_red,
|
|
||||||
10 => |theme| theme.colors().terminal_ansi_bright_green,
|
|
||||||
11 => |theme| theme.colors().terminal_ansi_bright_yellow,
|
|
||||||
12 => |theme| theme.colors().terminal_ansi_bright_blue,
|
|
||||||
13 => |theme| theme.colors().terminal_ansi_bright_magenta,
|
|
||||||
14 => |theme| theme.colors().terminal_ansi_bright_cyan,
|
|
||||||
15 => |theme| theme.colors().terminal_ansi_bright_white,
|
|
||||||
// 16-231 are a 6x6x6 RGB color cube, mapped to 0-255 using steps defined by XTerm.
|
|
||||||
// See: https://github.com/xterm-x11/xterm-snapshots/blob/master/256colres.pl
|
|
||||||
// 16..=231 => {
|
|
||||||
// let (r, g, b) = rgb_for_index(index as u8);
|
|
||||||
// rgba_color(
|
|
||||||
// if r == 0 { 0 } else { r * 40 + 55 },
|
|
||||||
// if g == 0 { 0 } else { g * 40 + 55 },
|
|
||||||
// if b == 0 { 0 } else { b * 40 + 55 },
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// 232-255 are a 24-step grayscale ramp from (8, 8, 8) to (238, 238, 238).
|
|
||||||
// 232..=255 => {
|
|
||||||
// let i = index as u8 - 232; // Align index to 0..24
|
|
||||||
// let value = i * 10 + 8;
|
|
||||||
// rgba_color(value, value, value)
|
|
||||||
// }
|
|
||||||
// For compatibility with the alacritty::Colors interface
|
|
||||||
// See: https://github.com/alacritty/alacritty/blob/master/alacritty_terminal/src/term/color.rs
|
|
||||||
_ => |_| gpui::black(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
(to_insert, all_spans, all_background_spans)
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
console.update_in(cx, |console, window, cx| {
|
||||||
|
console.set_read_only(false);
|
||||||
|
console.move_to_end(&editor::actions::MoveToEnd, window, cx);
|
||||||
|
console.insert(&output, window, cx);
|
||||||
|
console.set_read_only(true);
|
||||||
|
|
||||||
console.highlight_background_key::<ConsoleAnsiHighlight>(
|
struct ConsoleAnsiHighlight;
|
||||||
start_offset,
|
|
||||||
&[range],
|
|
||||||
color_fetcher,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.set_read_only(true);
|
let buffer = console.buffer().read(cx).snapshot(cx);
|
||||||
cx.notify();
|
|
||||||
});
|
for (range, color) in spans {
|
||||||
|
let Some(color) = color else { continue };
|
||||||
|
let start_offset = range.start;
|
||||||
|
let range =
|
||||||
|
buffer.anchor_after(range.start)..buffer.anchor_before(range.end);
|
||||||
|
let style = HighlightStyle {
|
||||||
|
color: Some(terminal_view::terminal_element::convert_color(
|
||||||
|
&color,
|
||||||
|
cx.theme(),
|
||||||
|
)),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
console.highlight_text_key::<ConsoleAnsiHighlight>(
|
||||||
|
start_offset,
|
||||||
|
vec![range],
|
||||||
|
style,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (range, color) in background_spans {
|
||||||
|
let Some(color) = color else { continue };
|
||||||
|
let start_offset = range.start;
|
||||||
|
let range =
|
||||||
|
buffer.anchor_after(range.start)..buffer.anchor_before(range.end);
|
||||||
|
console.highlight_background_key::<ConsoleAnsiHighlight>(
|
||||||
|
start_offset,
|
||||||
|
&[range],
|
||||||
|
color_fetcher(color),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.notify();
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn watch_expression(
|
pub fn watch_expression(
|
||||||
|
@ -464,31 +375,50 @@ impl Console {
|
||||||
EditorElement::new(&self.query_bar, Self::editor_style(&self.query_bar, cx))
|
EditorElement::new(&self.query_bar, Self::editor_style(&self.query_bar, cx))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_output(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
pub(crate) fn update_output(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
if self.update_output_task.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let session = self.session.clone();
|
let session = self.session.clone();
|
||||||
let token = self.last_token;
|
let token = self.last_token;
|
||||||
|
self.update_output_task = Some(cx.spawn_in(window, async move |this, cx| {
|
||||||
|
let Some((last_processed_token, task)) = session
|
||||||
|
.update_in(cx, |session, window, cx| {
|
||||||
|
let (output, last_processed_token) = session.output(token);
|
||||||
|
|
||||||
self.update_output_task = cx.spawn_in(window, async move |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
_ = session.update_in(cx, move |session, window, cx| {
|
if last_processed_token == this.last_token {
|
||||||
let (output, last_processed_token) = session.output(token);
|
return None;
|
||||||
|
}
|
||||||
_ = this.update(cx, |this, cx| {
|
Some((
|
||||||
if last_processed_token == this.last_token {
|
last_processed_token,
|
||||||
return;
|
this.add_messages(output.cloned().collect(), window, cx),
|
||||||
}
|
))
|
||||||
this.add_messages(output, window, cx);
|
})
|
||||||
|
.ok()
|
||||||
this.last_token = last_processed_token;
|
.flatten()
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
else {
|
||||||
|
_ = this.update(cx, |this, _| {
|
||||||
|
this.update_output_task.take();
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
_ = task.await.log_err();
|
||||||
|
_ = this.update(cx, |this, _| {
|
||||||
|
this.last_token = last_processed_token;
|
||||||
|
this.update_output_task.take();
|
||||||
});
|
});
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for Console {
|
impl Render for Console {
|
||||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
let query_focus_handle = self.query_bar.focus_handle(cx);
|
let query_focus_handle = self.query_bar.focus_handle(cx);
|
||||||
|
self.update_output(window, cx);
|
||||||
v_flex()
|
v_flex()
|
||||||
.track_focus(&self.focus_handle)
|
.track_focus(&self.focus_handle)
|
||||||
.key_context("DebugConsole")
|
.key_context("DebugConsole")
|
||||||
|
@ -851,3 +781,84 @@ impl ansi::Handler for ConsoleHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn color_fetcher(color: ansi::Color) -> fn(&Theme) -> Hsla {
|
||||||
|
let color_fetcher: fn(&Theme) -> Hsla = match color {
|
||||||
|
// Named and theme defined colors
|
||||||
|
ansi::Color::Named(n) => match n {
|
||||||
|
ansi::NamedColor::Black => |theme| theme.colors().terminal_ansi_black,
|
||||||
|
ansi::NamedColor::Red => |theme| theme.colors().terminal_ansi_red,
|
||||||
|
ansi::NamedColor::Green => |theme| theme.colors().terminal_ansi_green,
|
||||||
|
ansi::NamedColor::Yellow => |theme| theme.colors().terminal_ansi_yellow,
|
||||||
|
ansi::NamedColor::Blue => |theme| theme.colors().terminal_ansi_blue,
|
||||||
|
ansi::NamedColor::Magenta => |theme| theme.colors().terminal_ansi_magenta,
|
||||||
|
ansi::NamedColor::Cyan => |theme| theme.colors().terminal_ansi_cyan,
|
||||||
|
ansi::NamedColor::White => |theme| theme.colors().terminal_ansi_white,
|
||||||
|
ansi::NamedColor::BrightBlack => |theme| theme.colors().terminal_ansi_bright_black,
|
||||||
|
ansi::NamedColor::BrightRed => |theme| theme.colors().terminal_ansi_bright_red,
|
||||||
|
ansi::NamedColor::BrightGreen => |theme| theme.colors().terminal_ansi_bright_green,
|
||||||
|
ansi::NamedColor::BrightYellow => |theme| theme.colors().terminal_ansi_bright_yellow,
|
||||||
|
ansi::NamedColor::BrightBlue => |theme| theme.colors().terminal_ansi_bright_blue,
|
||||||
|
ansi::NamedColor::BrightMagenta => |theme| theme.colors().terminal_ansi_bright_magenta,
|
||||||
|
ansi::NamedColor::BrightCyan => |theme| theme.colors().terminal_ansi_bright_cyan,
|
||||||
|
ansi::NamedColor::BrightWhite => |theme| theme.colors().terminal_ansi_bright_white,
|
||||||
|
ansi::NamedColor::Foreground => |theme| theme.colors().terminal_foreground,
|
||||||
|
ansi::NamedColor::Background => |theme| theme.colors().terminal_background,
|
||||||
|
ansi::NamedColor::Cursor => |theme| theme.players().local().cursor,
|
||||||
|
ansi::NamedColor::DimBlack => |theme| theme.colors().terminal_ansi_dim_black,
|
||||||
|
ansi::NamedColor::DimRed => |theme| theme.colors().terminal_ansi_dim_red,
|
||||||
|
ansi::NamedColor::DimGreen => |theme| theme.colors().terminal_ansi_dim_green,
|
||||||
|
ansi::NamedColor::DimYellow => |theme| theme.colors().terminal_ansi_dim_yellow,
|
||||||
|
ansi::NamedColor::DimBlue => |theme| theme.colors().terminal_ansi_dim_blue,
|
||||||
|
ansi::NamedColor::DimMagenta => |theme| theme.colors().terminal_ansi_dim_magenta,
|
||||||
|
ansi::NamedColor::DimCyan => |theme| theme.colors().terminal_ansi_dim_cyan,
|
||||||
|
ansi::NamedColor::DimWhite => |theme| theme.colors().terminal_ansi_dim_white,
|
||||||
|
ansi::NamedColor::BrightForeground => |theme| theme.colors().terminal_bright_foreground,
|
||||||
|
ansi::NamedColor::DimForeground => |theme| theme.colors().terminal_dim_foreground,
|
||||||
|
},
|
||||||
|
// 'True' colors
|
||||||
|
ansi::Color::Spec(_) => |theme| theme.colors().editor_background,
|
||||||
|
// 8 bit, indexed colors
|
||||||
|
ansi::Color::Indexed(i) => {
|
||||||
|
match i {
|
||||||
|
// 0-15 are the same as the named colors above
|
||||||
|
0 => |theme| theme.colors().terminal_ansi_black,
|
||||||
|
1 => |theme| theme.colors().terminal_ansi_red,
|
||||||
|
2 => |theme| theme.colors().terminal_ansi_green,
|
||||||
|
3 => |theme| theme.colors().terminal_ansi_yellow,
|
||||||
|
4 => |theme| theme.colors().terminal_ansi_blue,
|
||||||
|
5 => |theme| theme.colors().terminal_ansi_magenta,
|
||||||
|
6 => |theme| theme.colors().terminal_ansi_cyan,
|
||||||
|
7 => |theme| theme.colors().terminal_ansi_white,
|
||||||
|
8 => |theme| theme.colors().terminal_ansi_bright_black,
|
||||||
|
9 => |theme| theme.colors().terminal_ansi_bright_red,
|
||||||
|
10 => |theme| theme.colors().terminal_ansi_bright_green,
|
||||||
|
11 => |theme| theme.colors().terminal_ansi_bright_yellow,
|
||||||
|
12 => |theme| theme.colors().terminal_ansi_bright_blue,
|
||||||
|
13 => |theme| theme.colors().terminal_ansi_bright_magenta,
|
||||||
|
14 => |theme| theme.colors().terminal_ansi_bright_cyan,
|
||||||
|
15 => |theme| theme.colors().terminal_ansi_bright_white,
|
||||||
|
// 16-231 are a 6x6x6 RGB color cube, mapped to 0-255 using steps defined by XTerm.
|
||||||
|
// See: https://github.com/xterm-x11/xterm-snapshots/blob/master/256colres.pl
|
||||||
|
// 16..=231 => {
|
||||||
|
// let (r, g, b) = rgb_for_index(index as u8);
|
||||||
|
// rgba_color(
|
||||||
|
// if r == 0 { 0 } else { r * 40 + 55 },
|
||||||
|
// if g == 0 { 0 } else { g * 40 + 55 },
|
||||||
|
// if b == 0 { 0 } else { b * 40 + 55 },
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// 232-255 are a 24-step grayscale ramp from (8, 8, 8) to (238, 238, 238).
|
||||||
|
// 232..=255 => {
|
||||||
|
// let i = index as u8 - 232; // Align index to 0..24
|
||||||
|
// let value = i * 10 + 8;
|
||||||
|
// rgba_color(value, value, value)
|
||||||
|
// }
|
||||||
|
// For compatibility with the alacritty::Colors interface
|
||||||
|
// See: https://github.com/alacritty/alacritty/blob/master/alacritty_terminal/src/term/color.rs
|
||||||
|
_ => |_| gpui::black(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
color_fetcher
|
||||||
|
}
|
||||||
|
|
|
@ -232,7 +232,6 @@ async fn test_escape_code_processing(executor: BackgroundExecutor, cx: &mut Test
|
||||||
location_reference: None,
|
location_reference: None,
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
// [crates/debugger_ui/src/session/running/console.rs:147:9] &to_insert = "Could not read source map for file:///Users/cole/roles-at/node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/typescript.js: ENOENT: no such file or directory, open '/Users/cole/roles-at/node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/typescript.js.map'\n"
|
|
||||||
client
|
client
|
||||||
.fake_event(dap::messages::Events::Output(dap::OutputEvent {
|
.fake_event(dap::messages::Events::Output(dap::OutputEvent {
|
||||||
category: None,
|
category: None,
|
||||||
|
@ -260,7 +259,6 @@ async fn test_escape_code_processing(executor: BackgroundExecutor, cx: &mut Test
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// introduce some background highlight
|
|
||||||
client
|
client
|
||||||
.fake_event(dap::messages::Events::Output(dap::OutputEvent {
|
.fake_event(dap::messages::Events::Output(dap::OutputEvent {
|
||||||
category: None,
|
category: None,
|
||||||
|
@ -274,7 +272,6 @@ async fn test_escape_code_processing(executor: BackgroundExecutor, cx: &mut Test
|
||||||
location_reference: None,
|
location_reference: None,
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
// another random line
|
|
||||||
client
|
client
|
||||||
.fake_event(dap::messages::Events::Output(dap::OutputEvent {
|
.fake_event(dap::messages::Events::Output(dap::OutputEvent {
|
||||||
category: None,
|
category: None,
|
||||||
|
@ -294,6 +291,11 @@ async fn test_escape_code_processing(executor: BackgroundExecutor, cx: &mut Test
|
||||||
let _running_state =
|
let _running_state =
|
||||||
active_debug_session_panel(workspace, cx).update_in(cx, |item, window, cx| {
|
active_debug_session_panel(workspace, cx).update_in(cx, |item, window, cx| {
|
||||||
cx.focus_self(window);
|
cx.focus_self(window);
|
||||||
|
item.running_state().update(cx, |this, cx| {
|
||||||
|
this.console()
|
||||||
|
.update(cx, |this, cx| this.update_output(window, cx));
|
||||||
|
});
|
||||||
|
|
||||||
item.running_state().clone()
|
item.running_state().clone()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1016,7 +1016,7 @@ impl Session {
|
||||||
|
|
||||||
cx.spawn(async move |this, cx| {
|
cx.spawn(async move |this, cx| {
|
||||||
while let Some(output) = rx.next().await {
|
while let Some(output) = rx.next().await {
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, _| {
|
||||||
let event = dap::OutputEvent {
|
let event = dap::OutputEvent {
|
||||||
category: None,
|
category: None,
|
||||||
output,
|
output,
|
||||||
|
@ -1028,7 +1028,7 @@ impl Session {
|
||||||
data: None,
|
data: None,
|
||||||
location_reference: None,
|
location_reference: None,
|
||||||
};
|
};
|
||||||
this.push_output(event, cx);
|
this.push_output(event);
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
anyhow::Ok(())
|
anyhow::Ok(())
|
||||||
|
@ -1458,7 +1458,7 @@ impl Session {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.push_output(event, cx);
|
self.push_output(event);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
Events::Breakpoint(event) => self.breakpoint_store.update(cx, |store, _| {
|
Events::Breakpoint(event) => self.breakpoint_store.update(cx, |store, _| {
|
||||||
|
@ -1645,10 +1645,9 @@ impl Session {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_output(&mut self, event: OutputEvent, cx: &mut Context<Self>) {
|
fn push_output(&mut self, event: OutputEvent) {
|
||||||
self.output.push_back(event);
|
self.output.push_back(event);
|
||||||
self.output_token.0 += 1;
|
self.output_token.0 += 1;
|
||||||
cx.emit(SessionEvent::ConsoleOutput);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn any_stopped_thread(&self) -> bool {
|
pub fn any_stopped_thread(&self) -> bool {
|
||||||
|
@ -2352,7 +2351,7 @@ impl Session {
|
||||||
data: None,
|
data: None,
|
||||||
location_reference: None,
|
location_reference: None,
|
||||||
};
|
};
|
||||||
self.push_output(event, cx);
|
self.push_output(event);
|
||||||
let request = self.mode.request_dap(EvaluateCommand {
|
let request = self.mode.request_dap(EvaluateCommand {
|
||||||
expression,
|
expression,
|
||||||
context,
|
context,
|
||||||
|
@ -2375,7 +2374,7 @@ impl Session {
|
||||||
data: None,
|
data: None,
|
||||||
location_reference: None,
|
location_reference: None,
|
||||||
};
|
};
|
||||||
this.push_output(event, cx);
|
this.push_output(event);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let event = dap::OutputEvent {
|
let event = dap::OutputEvent {
|
||||||
|
@ -2389,7 +2388,7 @@ impl Session {
|
||||||
data: None,
|
data: None,
|
||||||
location_reference: None,
|
location_reference: None,
|
||||||
};
|
};
|
||||||
this.push_output(event, cx);
|
this.push_output(event);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue