diff --git a/Cargo.lock b/Cargo.lock index 4029b426c58..35ef5bc9068 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7802,7 +7802,6 @@ dependencies = [ "anyhow", "language_core", "rust-embed", - "toml 0.8.23", "tree-sitter", "tree-sitter-bash", "tree-sitter-c", @@ -14968,7 +14967,6 @@ dependencies = [ "log", "parking_lot", "paths", - "prost", "release_channel", "rpc", "schemars 1.0.4", diff --git a/crates/extension_host/src/extension_host.rs b/crates/extension_host/src/extension_host.rs index a7b377576f4..36dd2943c45 100644 --- a/crates/extension_host/src/extension_host.rs +++ b/crates/extension_host/src/extension_host.rs @@ -1797,7 +1797,7 @@ impl ExtensionStore { let config = fs.load(&language_config_path).await.with_context(|| { format!("loading language config from {language_config_path:?}") })?; - ::toml::from_str::(&config).map_err(anyhow::Error::from) + LanguageConfig::from_toml(&config).map_err(anyhow::Error::from) } }; let query_files = async { @@ -2335,7 +2335,7 @@ async fn load_plugin_language( let config_path = language_path.join(LanguageConfig::FILE_NAME); async move { let contents = fs.load(&config_path).await?; - toml::from_str::(&contents).map_err(anyhow::Error::from) + LanguageConfig::from_toml(&contents).map_err(anyhow::Error::from) } }; let context_provider = { diff --git a/crates/extension_host/src/headless_host.rs b/crates/extension_host/src/headless_host.rs index 381ffc42ae7..82fdc751016 100644 --- a/crates/extension_host/src/headless_host.rs +++ b/crates/extension_host/src/headless_host.rs @@ -272,7 +272,7 @@ impl HeadlessExtensionStore { for language_path in &manifest.languages { let config_path = load_dir.join(language_path).join(LanguageConfig::FILE_NAME); let config = fs.load(&config_path).await?; - let mut config = ::toml::from_str::(&config)?; + let mut config = LanguageConfig::from_toml(&config)?; config.grammar = None; languages.push((config.name.clone(), config)); } diff --git a/crates/fuzzy/src/strings.rs b/crates/fuzzy/src/strings.rs index e8921950c54..b48c1d7ffc9 100644 --- a/crates/fuzzy/src/strings.rs +++ b/crates/fuzzy/src/strings.rs @@ -195,6 +195,11 @@ where } let mut results = segment_results.concat(); - gpui_util::truncate_to_bottom_n_sorted_by(&mut results, max_results, &|a, b| b.cmp(a)); + rank_matches(&mut results, max_results); results } + +#[inline(never)] +fn rank_matches(results: &mut Vec, max_results: usize) { + gpui_util::truncate_to_bottom_n_sorted_by(results, max_results, &|a, b| b.cmp(a)); +} diff --git a/crates/gpui/src/element.rs b/crates/gpui/src/element.rs index c817492b949..986037094d4 100644 --- a/crates/gpui/src/element.rs +++ b/crates/gpui/src/element.rs @@ -194,7 +194,7 @@ pub trait ParentElement { where Self: Sized, { - self.extend(std::iter::once(child.into_element().into_any())); + self.extend(std::iter::once(child.into_any_element())); self } diff --git a/crates/gpui/src/view.rs b/crates/gpui/src/view.rs index f8343be29a0..7f75c7d320e 100644 --- a/crates/gpui/src/view.rs +++ b/crates/gpui/src/view.rs @@ -457,42 +457,17 @@ impl Element for ViewElement { ) { if let Some(entity_id) = self.entity_id { // Stateful path. - window.with_rendered_view(entity_id, |window| { - let caching_disabled = window.is_inspector_picking(cx); - if self.cached_style.is_some() && !caching_disabled { - window.with_element_state::( - global_id.unwrap(), - |element_state, window| { - let mut element_state = element_state.unwrap(); - - let paint_start = window.paint_index(); - - if let Some(element) = element { - let refreshing = mem::replace(&mut window.refreshing, true); - element.paint(window, cx); - window.refreshing = refreshing; - } else { - window.reuse_paint(element_state.paint_range.clone()); - } - - let paint_end = window.paint_index(); - element_state.paint_range = paint_start..paint_end; - - ((), element_state) - }, - ) - } else { - element.as_mut().unwrap().paint(window, cx); - } - }); + paint_view( + entity_id, + self.cached_style.is_some(), + global_id, + element, + window, + cx, + ); } else { // Stateless path: just paint the element. - window.with_id( - ElementId::Name(std::any::type_name::().into()), - |window| { - element.as_mut().unwrap().paint(window, cx); - }, - ); + paint_component(std::any::type_name::(), element, window, cx); } } } @@ -505,3 +480,54 @@ impl Render for EmptyView { Empty } } + +#[inline(never)] +fn paint_view( + entity_id: EntityId, + cached: bool, + global_id: Option<&GlobalElementId>, + element: &mut Option, + window: &mut Window, + cx: &mut App, +) { + window.with_rendered_view(entity_id, |window| { + let caching_disabled = window.is_inspector_picking(cx); + if cached && !caching_disabled { + window.with_element_state::( + global_id.unwrap(), + |element_state, window| { + let mut element_state = element_state.unwrap(); + + let paint_start = window.paint_index(); + + if let Some(element) = element { + let refreshing = mem::replace(&mut window.refreshing, true); + element.paint(window, cx); + window.refreshing = refreshing; + } else { + window.reuse_paint(element_state.paint_range.clone()); + } + + let paint_end = window.paint_index(); + element_state.paint_range = paint_start..paint_end; + + ((), element_state) + }, + ) + } else { + element.as_mut().unwrap().paint(window, cx); + } + }); +} + +#[inline(never)] +fn paint_component( + name: &'static str, + element: &mut Option, + window: &mut Window, + cx: &mut App, +) { + window.with_id(ElementId::Name(name.into()), |window| { + element.as_mut().unwrap().paint(window, cx); + }); +} diff --git a/crates/gpui_macros/src/derive_into_element.rs b/crates/gpui_macros/src/derive_into_element.rs index 51d2a8ab3f7..33ff658b68d 100644 --- a/crates/gpui_macros/src/derive_into_element.rs +++ b/crates/gpui_macros/src/derive_into_element.rs @@ -17,6 +17,12 @@ pub fn derive_into_element(input: TokenStream) -> TokenStream { fn into_element(self) -> Self::Element { gpui::ViewElement::new(self) } + + #[track_caller] + #[inline(never)] + fn into_any_element(self) -> gpui::AnyElement { + gpui::Element::into_any(self.into_element()) + } } }; diff --git a/crates/gpui_util/src/lib.rs b/crates/gpui_util/src/lib.rs index 109ef6f16b7..a946ea10c2f 100644 --- a/crates/gpui_util/src/lib.rs +++ b/crates/gpui_util/src/lib.rs @@ -4,6 +4,7 @@ use std::{ env, ffi::OsStr, + fmt, ops::AddAssign, panic::Location, pin::Pin, @@ -251,7 +252,7 @@ where Err(error) => { log_error_with_caller( *Location::caller(), - DebugAsDisplay(&error), + format_args!("{:#}", DebugAsDisplay(&error)), log::Level::Error, ); None @@ -277,7 +278,7 @@ where match self { Ok(value) => Some(value), Err(error) => { - log_error_with_caller(*Location::caller(), error, level); + log_error_with_caller(*Location::caller(), format_args!("{error:#}"), level); None } } @@ -291,10 +292,12 @@ where } } -fn log_error_with_caller(caller: core::panic::Location<'_>, error: E, level: log::Level) -where - E: std::fmt::Display, -{ +#[inline(never)] +fn log_error_with_caller( + caller: core::panic::Location<'_>, + arguments: fmt::Arguments<'_>, + level: log::Level, +) { #[cfg(not(windows))] let file = caller.file(); #[cfg(windows)] @@ -316,7 +319,7 @@ where &log::Record::builder() .target(module_path.as_deref().unwrap_or("")) .module_path(file.as_deref()) - .args(format_args!("{:#}", error)) + .args(arguments) .file(Some(caller.file())) .line(Some(caller.line())) .level(level) @@ -326,7 +329,11 @@ where #[track_caller] pub fn log_err(error: &E) { - log_error_with_caller(*Location::caller(), error, log::Level::Error); + log_error_with_caller( + *Location::caller(), + format_args!("{error:#}"), + log::Level::Error, + ); } // Forces `{:?}` formatting through a `Display`-bounded logging helper so `anyhow::Error` emits a @@ -452,7 +459,7 @@ where Poll::Ready(output) => Poll::Ready(match output { Ok(output) => Some(output), Err(error) => { - log_error_with_caller(location, error, level); + log_error_with_caller(location, format_args!("{error:#}"), level); None } }), @@ -479,7 +486,11 @@ where Poll::Ready(output) => Poll::Ready(match output { Ok(output) => Some(output), Err(error) => { - log_error_with_caller(location, DebugAsDisplay(&error), level); + log_error_with_caller( + location, + format_args!("{:#}", DebugAsDisplay(&error)), + level, + ); None } }), @@ -605,3 +616,68 @@ where items.truncate(limit); items.sort_by(compare); } + +#[cfg(test)] +mod logging_tests { + use super::{ResultExt, TryFutureExt, TryFutureExtBacktrace}; + use log::{Level, Log, Metadata, Record}; + use std::{ + cell::RefCell, + future::ready, + pin::pin, + task::{Context, Poll, Waker}, + }; + + #[test] + fn logging_preserves_diagnostics_and_callers() { + log::set_logger(&TestLogger).expect("failed to install test logger"); + let error = anyhow::anyhow!("root failure") + .context("inner context") + .context("outer context"); + let display = "outer context: inner context: root failure"; + let debug = format!("{error:?}"); + let line = line!() + 1; + assert_eq!(Err::<(), _>(&error).log_err(), None); + assert_logged(line, display); + let line = line!() + 1; + assert_eq!(Err::<(), _>(&error).log_err_with_backtrace(), None); + assert_logged(line, &debug); + let mut context = Context::from_waker(Waker::noop()); + let line = line!() + 1; + let mut future = pin!(ready(Err::<(), _>(&error)).log_err()); + assert_eq!(future.as_mut().poll(&mut context), Poll::Ready(None)); + assert_logged(line, display); + let line = line!() + 1; + let mut future = pin!(ready(Err::<(), _>(&error)).log_err_with_backtrace()); + assert_eq!(future.as_mut().poll(&mut context), Poll::Ready(None)); + assert_logged(line, &debug); + } + + thread_local! { + static RECORDS: RefCell, String)>> = const { RefCell::new(Vec::new()) }; + } + + struct TestLogger; + + impl Log for TestLogger { + fn enabled(&self, _: &Metadata<'_>) -> bool { + true + } + + fn log(&self, record: &Record<'_>) { + assert_eq!(record.target(), "gpui_util::lib"); + assert_eq!(record.module_path(), Some("crates/gpui_util/src/lib.rs")); + assert_eq!(record.file(), Some(file!())); + assert_eq!(record.level(), Level::Error); + RECORDS.with_borrow_mut(|records| { + records.push((record.line(), record.args().to_string())); + }); + } + + fn flush(&self) {} + } + + fn assert_logged(line: u32, message: &str) { + assert_eq!(RECORDS.take(), [(Some(line), message.to_owned())]); + } +} diff --git a/crates/grammars/Cargo.toml b/crates/grammars/Cargo.toml index 5640cd7bc58..0df1966083a 100644 --- a/crates/grammars/Cargo.toml +++ b/crates/grammars/Cargo.toml @@ -14,7 +14,6 @@ path = "src/grammars.rs" anyhow.workspace = true language_core.workspace = true rust-embed.workspace = true -toml.workspace = true util.workspace = true tree-sitter = { workspace = true, optional = true } diff --git a/crates/grammars/src/grammars.rs b/crates/grammars/src/grammars.rs index 426926d0db0..fa7b226596f 100644 --- a/crates/grammars/src/grammars.rs +++ b/crates/grammars/src/grammars.rs @@ -55,7 +55,7 @@ pub fn load_config(name: &str) -> LanguageConfig { ) .unwrap(); - let config: LanguageConfig = ::toml::from_str(&config_toml) + let config = LanguageConfig::from_toml(&config_toml) .with_context(|| format!("failed to load config.toml for language {name:?}")) .unwrap(); diff --git a/crates/html_to_markdown/src/html_to_markdown.rs b/crates/html_to_markdown/src/html_to_markdown.rs index fda2cce5f9c..f7fe9bac68c 100644 --- a/crates/html_to_markdown/src/html_to_markdown.rs +++ b/crates/html_to_markdown/src/html_to_markdown.rs @@ -18,8 +18,11 @@ pub use crate::html_element::*; pub use crate::markdown_writer::*; /// Converts the provided HTML to Markdown. -pub fn convert_html_to_markdown(html: impl Read, handlers: &mut [TagHandler]) -> Result { - let dom = parse_html(html).context("failed to parse HTML")?; +pub fn convert_html_to_markdown( + mut html: impl Read, + handlers: &mut [TagHandler], +) -> Result { + let dom = parse_html(&mut html).context("failed to parse HTML")?; let markdown_writer = MarkdownWriter::new(); let markdown = markdown_writer @@ -29,7 +32,8 @@ pub fn convert_html_to_markdown(html: impl Read, handlers: &mut [TagHandler]) -> Ok(markdown) } -fn parse_html(mut html: impl Read) -> Result { +#[inline(never)] +fn parse_html(mut html: &mut dyn Read) -> Result { let parse_options = ParseOpts { tree_builder: TreeBuilderOpts { drop_doctype: true, diff --git a/crates/language_core/src/language_config.rs b/crates/language_core/src/language_config.rs index 72ab3fcf5bd..6a0059f6846 100644 --- a/crates/language_core/src/language_config.rs +++ b/crates/language_core/src/language_config.rs @@ -150,9 +150,14 @@ pub struct LanguageConfig { impl LanguageConfig { pub const FILE_NAME: &str = "config.toml"; + #[inline(never)] + pub fn from_toml(config: &str) -> Result { + toml::from_str::(config) + } + pub fn load(config_path: impl AsRef) -> anyhow::Result { let config = std::fs::read_to_string(config_path.as_ref())?; - toml::from_str(&config).map_err(Into::into) + Self::from_toml(&config).map_err(anyhow::Error::from) } } diff --git a/crates/markdown/src/html.rs b/crates/markdown/src/html.rs index cf37f6138cd..32ffa861f72 100644 --- a/crates/markdown/src/html.rs +++ b/crates/markdown/src/html.rs @@ -1,3 +1,14 @@ mod html_minifier; pub(crate) mod html_parser; mod html_rendering; + +use html5ever::{ParseOpts, parse_document, tendril::TendrilSink}; +use markup5ever_rcdom::RcDom; +use std::io::{self, Read}; + +#[inline(never)] +fn parse_html(mut reader: &mut dyn Read) -> io::Result { + parse_document(RcDom::default(), ParseOpts::default()) + .from_utf8() + .read_from(&mut reader) +} diff --git a/crates/markdown/src/html/html_minifier.rs b/crates/markdown/src/html/html_minifier.rs index a7d5ad0be0d..47cde3c79ff 100644 --- a/crates/markdown/src/html/html_minifier.rs +++ b/crates/markdown/src/html/html_minifier.rs @@ -1,8 +1,8 @@ use html5ever::{ - Attribute, ParseOpts, QualName, parse_document, - tendril::{Tendril, TendrilSink, fmt::UTF8}, + Attribute, QualName, + tendril::{Tendril, fmt::UTF8}, }; -use markup5ever_rcdom::{Node, NodeData, RcDom}; +use markup5ever_rcdom::{Node, NodeData}; use std::{cell::RefCell, io, rc::Rc, str}; #[derive(Default)] @@ -38,10 +38,8 @@ where /// /// Will return `Err` if unable to write to the output writer. #[inline] - pub fn minify(&mut self, mut r: &mut R) -> io::Result<()> { - let dom = parse_document(RcDom::default(), ParseOpts::default()) - .from_utf8() - .read_from(&mut r)?; + pub fn minify(&mut self, reader: &mut dyn io::Read) -> io::Result<()> { + let dom = super::parse_html(reader)?; if !self.options.omit_doctype { self.w.write_all(b"")?; diff --git a/crates/markdown/src/html/html_parser.rs b/crates/markdown/src/html/html_parser.rs index 5ab9a48b720..5cd87d5d2b9 100644 --- a/crates/markdown/src/html/html_parser.rs +++ b/crates/markdown/src/html/html_parser.rs @@ -1,10 +1,8 @@ use std::{cell::RefCell, collections::HashMap, mem, ops::Range}; use gpui::{DefiniteLength, FontWeight, SharedString, TextAlign, px, relative}; -use html5ever::{ - Attribute, LocalName, ParseOpts, local_name, parse_document, tendril::TendrilSink, -}; -use markup5ever_rcdom::{Node, NodeData, RcDom}; +use html5ever::{Attribute, LocalName, local_name}; +use markup5ever_rcdom::{Node, NodeData}; use pulldown_cmark::{Alignment, HeadingLevel}; use stacksafe::stacksafe; @@ -195,10 +193,7 @@ pub(crate) fn parse_html_block( ) -> Option { let bytes = cleanup_html(source); let mut cursor = std::io::Cursor::new(bytes); - let dom = parse_document(RcDom::default(), ParseOpts::default()) - .from_utf8() - .read_from(&mut cursor) - .ok()?; + let dom = super::parse_html(&mut cursor).ok()?; let mut children = Vec::new(); parse_html_node( diff --git a/crates/open_ai/src/responses.rs b/crates/open_ai/src/responses.rs index bf34672c0cc..9c59c3bfa90 100644 --- a/crates/open_ai/src/responses.rs +++ b/crates/open_ai/src/responses.rs @@ -820,7 +820,7 @@ pub async fn stream_response( if line == "[DONE]" || line.is_empty() { None } else { - match serde_json::from_str::(line) { + match decode_stream_event(line) { Ok(event) => Some(Ok(event)), Err(error) => { log::error!( @@ -974,6 +974,11 @@ pub async fn stream_response( } } +#[inline(never)] +fn decode_stream_event(line: &str) -> serde_json::Result { + serde_json::from_str(line) +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/picker/src/persistence.rs b/crates/picker/src/persistence.rs index 59de6cf8bf2..2254e940872 100644 --- a/crates/picker/src/persistence.rs +++ b/crates/picker/src/persistence.rs @@ -69,9 +69,7 @@ pub(crate) fn try_load_shape( return Ok(None); }; - let shape = serde_json::from_str::(&shape) - .context("Could not deserialize loaded picker shape from persistence")? - .into_centered(); + let shape = parse_shape(&shape)?; Ok(Some(Shape::HorizontallyCentered(shape))) } @@ -90,6 +88,13 @@ pub(crate) fn load_last_preview_layout( parse_layout(&last_layout) } +#[inline(never)] +fn parse_shape(json: &str) -> anyhow::Result { + Ok(serde_json::from_str::(json) + .context("Could not deserialize loaded picker shape from persistence")? + .into_centered()) +} + fn shape_key(picker_delegate: &'static str, preview_layout: Option) -> String { format!("{picker_delegate}/{}", layout_as_str(preview_layout)) } diff --git a/crates/proto/src/proto.rs b/crates/proto/src/proto.rs index 103ec4f1f90..1fe9f1c6a34 100644 --- a/crates/proto/src/proto.rs +++ b/crates/proto/src/proto.rs @@ -19,6 +19,23 @@ include!(concat!(env!("OUT_DIR"), "/zed.messages.rs")); pub const REMOTE_SERVER_PEER_ID: PeerId = PeerId { owner_id: 0, id: 0 }; pub const REMOTE_SERVER_PROJECT_ID: u64 = 0; +impl Envelope { + #[inline(never)] + pub fn decode_from_slice(buffer: &[u8]) -> Result { + Self::decode(buffer) + } + + #[inline(never)] + pub fn encode_to_buffer(&self, buffer: &mut Vec) -> Result<(), prost::EncodeError> { + self.encode(buffer) + } + + #[inline(never)] + pub fn encoded_size(&self) -> usize { + self.encoded_len() + } +} + messages!( (Ack, Foreground), (AckBufferOperation, Background), diff --git a/crates/remote/Cargo.toml b/crates/remote/Cargo.toml index f420c2dca13..2c2442ea0be 100644 --- a/crates/remote/Cargo.toml +++ b/crates/remote/Cargo.toml @@ -30,7 +30,6 @@ gpui.workspace = true log.workspace = true parking_lot.workspace = true paths.workspace = true -prost.workspace = true release_channel.workspace = true rpc = { workspace = true, features = ["gpui"] } schemars.workspace = true diff --git a/crates/remote/src/protocol.rs b/crates/remote/src/protocol.rs index 867a31b1645..d9757577cb8 100644 --- a/crates/remote/src/protocol.rs +++ b/crates/remote/src/protocol.rs @@ -1,6 +1,5 @@ use anyhow::Result; use futures::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; -use prost::Message as _; use rpc::proto::Envelope; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] @@ -20,7 +19,7 @@ pub async fn read_message_with_len( ) -> Result { buffer.resize(message_len as usize, 0); stream.read_exact(buffer).await?; - Ok(Envelope::decode(buffer.as_slice())?) + Ok(Envelope::decode_from_slice(buffer.as_slice())?) } pub async fn read_message( @@ -40,13 +39,13 @@ pub async fn write_message( buffer: &mut Vec, message: Envelope, ) -> Result<()> { - let message_len = message.encoded_len() as u32; + let message_len = message.encoded_size() as u32; stream .write_all(message_len.to_le_bytes().as_slice()) .await?; buffer.clear(); buffer.reserve(message_len as usize); - message.encode(buffer)?; + message.encode_to_buffer(buffer)?; stream.write_all(buffer).await?; Ok(()) } diff --git a/crates/repl/src/outputs/plain.rs b/crates/repl/src/outputs/plain.rs index f5fa70f3e2c..f874126b9c8 100644 --- a/crates/repl/src/outputs/plain.rs +++ b/crates/repl/src/outputs/plain.rs @@ -47,13 +47,13 @@ pub struct TerminalOutput { /// Returns the default text style for the terminal output. pub fn text_style(window: &mut Window, cx: &App) -> TextStyle { - let settings = ThemeSettings::get_global(cx).clone(); + let settings = ThemeSettings::get_global(cx); let font_size = settings.buffer_font_size(cx).into(); - let font_family = settings.buffer_font.family; - let font_features = settings.buffer_font.features; + let font_family = settings.buffer_font.family.clone(); + let font_features = settings.buffer_font.features.clone(); let font_weight = settings.buffer_font.weight; - let font_fallbacks = settings.buffer_font.fallbacks; + let font_fallbacks = settings.buffer_font.fallbacks.clone(); let theme = cx.theme(); diff --git a/crates/rpc/src/message_stream.rs b/crates/rpc/src/message_stream.rs index 34888d98147..b1072216b95 100644 --- a/crates/rpc/src/message_stream.rs +++ b/crates/rpc/src/message_stream.rs @@ -4,7 +4,6 @@ pub use ::proto::*; use async_tungstenite::tungstenite::Message as WebSocketMessage; use futures::{SinkExt as _, StreamExt as _}; -use proto::Message as _; use std::time::Instant; use std::{fmt::Debug, io}; @@ -47,9 +46,9 @@ where match message { Message::Envelope(message) => { - self.encoding_buffer.reserve(message.encoded_len()); + self.encoding_buffer.reserve(message.encoded_size()); message - .encode(&mut self.encoding_buffer) + .encode_to_buffer(&mut self.encoding_buffer) .map_err(io::Error::from)?; let buffer = zstd::stream::encode_all(self.encoding_buffer.as_slice(), COMPRESSION_LEVEL) @@ -90,7 +89,7 @@ where zstd::zstd_safe::WriteBuf::as_slice(&*bytes), &mut self.encoding_buffer, )?; - let envelope = Envelope::decode(self.encoding_buffer.as_slice()) + let envelope = Envelope::decode_from_slice(self.encoding_buffer.as_slice()) .map_err(io::Error::from)?; self.encoding_buffer.clear(); diff --git a/crates/rpc/src/peer.rs b/crates/rpc/src/peer.rs index 4fac9d84caa..2ab50ae0e36 100644 --- a/crates/rpc/src/peer.rs +++ b/crates/rpc/src/peer.rs @@ -253,125 +253,8 @@ impl Peer { } }; - let response_channels = connection_state.response_channels.clone(); - let stream_response_channels = connection_state.stream_response_channels.clone(); - self.connections - .write() - .insert(connection_id, connection_state); - - let incoming_rx = incoming_rx.filter_map(move |(incoming, received_at)| { - let response_channels = response_channels.clone(); - let stream_response_channels = stream_response_channels.clone(); - async move { - let message_id = incoming.id; - tracing::trace!(?incoming, "incoming message future: start"); - let _end = util::defer(move || { - tracing::trace!(%connection_id, message_id, "incoming message future: end"); - }); - - if let Some(responding_to) = incoming.responding_to { - tracing::trace!( - %connection_id, - message_id, - responding_to, - "incoming response: received" - ); - let response_channel = - response_channels.lock().as_mut()?.remove(&responding_to); - let terminal_stream_response = matches!( - &incoming.payload, - Some(proto::envelope::Payload::Error(_)) - | Some(proto::envelope::Payload::EndStream(_)) - ); - let stream_response_channel = if terminal_stream_response { - stream_response_channels - .lock() - .as_mut()? - .remove(&responding_to) - } else { - stream_response_channels - .lock() - .as_ref()? - .get(&responding_to) - .cloned() - }; - - if let Some(tx) = response_channel { - let requester_resumed = oneshot::channel(); - if let Err(error) = tx.send((incoming, received_at, requester_resumed.0)) { - tracing::trace!( - %connection_id, - message_id, - responding_to = responding_to, - ?error, - "incoming response: request future dropped", - ); - } - - tracing::trace!( - %connection_id, - message_id, - responding_to, - "incoming response: waiting to resume requester" - ); - let _ = requester_resumed.1.await; - tracing::trace!( - %connection_id, - message_id, - responding_to, - "incoming response: requester resumed" - ); - } else if let Some(tx) = stream_response_channel { - let requester_resumed = oneshot::channel(); - if let Err(error) = tx.unbounded_send((Ok(incoming), requester_resumed.0)) { - tracing::debug!( - %connection_id, - message_id, - responding_to = responding_to, - ?error, - "incoming stream response: request future dropped", - ); - // The consumer has gone away, so drop the bookkeeping - // for this stream rather than letting it accumulate - // every subsequent message until a terminal frame. - if let Some(channels) = stream_response_channels.lock().as_mut() { - channels.remove(&responding_to); - } - } else { - let _ = requester_resumed.1.await; - } - } else { - let message_type = proto::build_typed_envelope( - connection_id.into(), - received_at, - incoming, - ) - .map(|p| p.payload_type_name()); - tracing::warn!( - %connection_id, - message_id, - responding_to, - message_type, - "incoming response: unknown request" - ); - } - - None - } else { - tracing::trace!(%connection_id, message_id, "incoming message: received"); - proto::build_typed_envelope(connection_id.into(), received_at, incoming) - .or_else(|| { - tracing::error!( - %connection_id, - message_id, - "unable to construct a typed envelope" - ); - None - }) - } - } - }); - (connection_id, handle_io, incoming_rx.boxed()) + let incoming_rx = self.register_connection(connection_id, connection_state, incoming_rx); + (connection_id, handle_io, incoming_rx) } #[cfg(any(test, feature = "test-support"))] @@ -704,6 +587,134 @@ impl Peer { Ok(()) } + #[inline(never)] + fn register_connection( + &self, + connection_id: ConnectionId, + connection_state: ConnectionState, + incoming_rx: mpsc::Receiver<(proto::Envelope, Instant)>, + ) -> BoxStream<'static, Box> { + let response_channels = connection_state.response_channels.clone(); + let stream_response_channels = connection_state.stream_response_channels.clone(); + self.connections + .write() + .insert(connection_id, connection_state); + + let incoming_rx = incoming_rx.filter_map(move |(incoming, received_at)| { + let response_channels = response_channels.clone(); + let stream_response_channels = stream_response_channels.clone(); + async move { + let message_id = incoming.id; + tracing::trace!(?incoming, "incoming message future: start"); + let _end = util::defer(move || { + tracing::trace!(%connection_id, message_id, "incoming message future: end"); + }); + + if let Some(responding_to) = incoming.responding_to { + tracing::trace!( + %connection_id, + message_id, + responding_to, + "incoming response: received" + ); + let response_channel = + response_channels.lock().as_mut()?.remove(&responding_to); + let terminal_stream_response = matches!( + &incoming.payload, + Some(proto::envelope::Payload::Error(_)) + | Some(proto::envelope::Payload::EndStream(_)) + ); + let stream_response_channel = if terminal_stream_response { + stream_response_channels + .lock() + .as_mut()? + .remove(&responding_to) + } else { + stream_response_channels + .lock() + .as_ref()? + .get(&responding_to) + .cloned() + }; + + if let Some(tx) = response_channel { + let requester_resumed = oneshot::channel(); + if let Err(error) = tx.send((incoming, received_at, requester_resumed.0)) { + tracing::trace!( + %connection_id, + message_id, + responding_to = responding_to, + ?error, + "incoming response: request future dropped", + ); + } + + tracing::trace!( + %connection_id, + message_id, + responding_to, + "incoming response: waiting to resume requester" + ); + let _ = requester_resumed.1.await; + tracing::trace!( + %connection_id, + message_id, + responding_to, + "incoming response: requester resumed" + ); + } else if let Some(tx) = stream_response_channel { + let requester_resumed = oneshot::channel(); + if let Err(error) = tx.unbounded_send((Ok(incoming), requester_resumed.0)) { + tracing::debug!( + %connection_id, + message_id, + responding_to = responding_to, + ?error, + "incoming stream response: request future dropped", + ); + // The consumer has gone away, so drop the bookkeeping + // for this stream rather than letting it accumulate + // every subsequent message until a terminal frame. + if let Some(channels) = stream_response_channels.lock().as_mut() { + channels.remove(&responding_to); + } + } else { + let _ = requester_resumed.1.await; + } + } else { + let message_type = proto::build_typed_envelope( + connection_id.into(), + received_at, + incoming, + ) + .map(|p| p.payload_type_name()); + tracing::warn!( + %connection_id, + message_id, + responding_to, + message_type, + "incoming response: unknown request" + ); + } + + None + } else { + tracing::trace!(%connection_id, message_id, "incoming message: received"); + proto::build_typed_envelope(connection_id.into(), received_at, incoming) + .or_else(|| { + tracing::error!( + %connection_id, + message_id, + "unable to construct a typed envelope" + ); + None + }) + } + } + }); + incoming_rx.boxed() + } + fn connection_state(&self, connection_id: ConnectionId) -> Result { let connections = self.connections.read(); let connection = connections diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index 893e908c57c..3067462f414 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -1106,7 +1106,7 @@ impl TerminalElement { } fn rem_size(&self, cx: &mut App) -> Option { - let settings = ThemeSettings::get_global(cx).clone(); + let settings = ThemeSettings::get_global(cx); let buffer_font_size = settings.buffer_font_size(cx); let rem_size_scale = { // Our default UI font size is 14px on a 16px base scale. @@ -1205,7 +1205,7 @@ impl Element for TerminalElement { cx, |_, _, hitbox, window, cx| { let hitbox = hitbox.unwrap(); - let settings = ThemeSettings::get_global(cx).clone(); + let settings = ThemeSettings::get_global(cx); let buffer_font_size = settings.buffer_font_size(cx); diff --git a/crates/ui/src/components/scrollbar.rs b/crates/ui/src/components/scrollbar.rs index e7177f4ecaa..8beb4a26ec4 100644 --- a/crates/ui/src/components/scrollbar.rs +++ b/crates/ui/src/components/scrollbar.rs @@ -2,12 +2,12 @@ use std::{any::Any, fmt::Debug, ops::Not, time::Duration}; use web_time::Instant; use gpui::{ - Along, Anchor, App, AppContext as _, Axis as ScrollbarAxis, BorderStyle, Bounds, ContentMask, - Context, Corners, CursorStyle, DispatchPhase, Div, Edges, Element, ElementId, Entity, EntityId, - GlobalElementId, Hitbox, HitboxBehavior, Hsla, InteractiveElement, IntoElement, IsZero, - LayoutId, ListState, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, - Pixels, Point, Position, Render, ScrollHandle, ScrollWheelEvent, Size, Stateful, - StatefulInteractiveElement, Style, Styled, Task, UniformListDecoration, + Along, Anchor, AnyElement, App, AppContext as _, Axis as ScrollbarAxis, BorderStyle, Bounds, + ContentMask, Context, Corners, CursorStyle, DispatchPhase, Div, Edges, Element, ElementId, + Entity, EntityId, GlobalElementId, Hitbox, HitboxBehavior, Hsla, InteractiveElement, + IntoElement, IsZero, LayoutId, ListState, MouseButton, MouseDownEvent, MouseMoveEvent, + MouseUpEvent, ParentElement, Pixels, Point, Position, Render, ScrollHandle, ScrollWheelEvent, + Size, Stateful, StatefulInteractiveElement, Style, Styled, Task, UniformListDecoration, UniformListScrollHandle, Window, ease_in_out, prelude::FluentBuilder as _, px, quad, relative, size, }; @@ -237,7 +237,7 @@ impl UniformListDecoration for ScrollbarStateWrapper { origin: -scroll_offset, state: self.0.clone(), } - .into_any() + .into_any_element() } } @@ -934,7 +934,7 @@ impl Render for ScrollbarState { } } -struct ScrollbarElement { +pub struct ScrollbarElement { origin: Point, state: Entity>, } @@ -954,6 +954,11 @@ impl ThumbState { } impl ScrollableHandle for UniformListScrollHandle { + #[inline(never)] + fn into_scrollbar_element(element: ScrollbarElement) -> AnyElement { + element.into_any() + } + fn max_offset(&self) -> Point { self.0.borrow().base_handle.max_offset() } @@ -972,6 +977,11 @@ impl ScrollableHandle for UniformListScrollHandle { } impl ScrollableHandle for ListState { + #[inline(never)] + fn into_scrollbar_element(element: ScrollbarElement) -> AnyElement { + element.into_any() + } + fn max_offset(&self) -> Point { self.max_offset_for_scrollbar() } @@ -998,6 +1008,11 @@ impl ScrollableHandle for ListState { } impl ScrollableHandle for ScrollHandle { + #[inline(never)] + fn into_scrollbar_element(element: ScrollbarElement) -> AnyElement { + element.into_any() + } + fn max_offset(&self) -> Point { self.max_offset() } @@ -1016,6 +1031,10 @@ impl ScrollableHandle for ScrollHandle { } pub trait ScrollableHandle: 'static + Any + Sized + Clone { + fn into_scrollbar_element(element: ScrollbarElement) -> AnyElement { + element.into_any() + } + fn max_offset(&self) -> Point; fn set_offset(&self, point: Point); fn offset(&self) -> Point; @@ -1642,6 +1661,10 @@ impl IntoElement for ScrollbarElement { fn into_element(self) -> Self::Element { self } + + fn into_any_element(self) -> AnyElement { + T::into_scrollbar_element(self) + } } #[cfg(test)]