diff --git a/Cargo.lock b/Cargo.lock index 3d74213062..79eae80258 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1719,6 +1719,8 @@ dependencies = [ "text", "theme", "tree-sitter", + "tree-sitter-html", + "tree-sitter-javascript", "tree-sitter-rust", "unindent", "util", @@ -6062,6 +6064,16 @@ dependencies = [ "tree-sitter", ] +[[package]] +name = "tree-sitter-javascript" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2490fab08630b2c8943c320f7b63473cbf65511c8d83aec551beb9b4375906ed" +dependencies = [ + "cc", + "tree-sitter", +] + [[package]] name = "tree-sitter-json" version = "0.19.0" diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index dfd4938742..cfe244d4fa 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -51,6 +51,8 @@ serde = { version = "1.0", features = ["derive", "rc"] } smallvec = { version = "1.6", features = ["union"] } smol = "1.2" tree-sitter-rust = { version = "*", optional = true } +tree-sitter-html = { version = "*", optional = true } +tree-sitter-javascript = { version = "*", optional = true } [dev-dependencies] text = { path = "../text", features = ["test-support"] } @@ -67,3 +69,5 @@ rand = "0.8" unindent = "0.1.7" tree-sitter = "0.20" tree-sitter-rust = "0.20" +tree-sitter-html = "0.19" +tree-sitter-javascript = "0.20" diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index c6cfd887db..b313d2de55 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1116,7 +1116,7 @@ impl Editor { &self, point: T, cx: &'a AppContext, - ) -> Option<&'a Arc> { + ) -> Option> { self.buffer.read(cx).language_at(point, cx) } @@ -4501,9 +4501,9 @@ impl Editor { // as that portion won't be used for detecting if a line is a comment. let full_comment_prefix: Arc = if let Some(prefix) = buffer .language_at(selection.start, cx) - .and_then(|l| l.line_comment_prefix()) + .and_then(|l| l.line_comment_prefix().map(|p| p.into())) { - prefix.into() + prefix } else { return; }; @@ -6713,7 +6713,7 @@ mod tests { platform::{WindowBounds, WindowOptions}, }; use indoc::indoc; - use language::{FakeLspAdapter, LanguageConfig}; + use language::{FakeLspAdapter, LanguageConfig, LanguageRegistry}; use project::FakeFs; use settings::EditorSettings; use std::{cell::RefCell, rc::Rc, time::Instant}; @@ -9792,6 +9792,92 @@ mod tests { }); } + #[gpui::test] + async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) { + let mut cx = EditorTestContext::new(cx).await; + + let html_language = Arc::new( + Language::new( + LanguageConfig { + name: "HTML".into(), + brackets: vec![BracketPair { + start: "<".to_string(), + end: ">".to_string(), + close: true, + newline: true, + }], + autoclose_before: "})]".to_string(), + ..Default::default() + }, + Some(tree_sitter_html::language()), + ) + .with_injection_query( + r#" + (script_element + (raw_text) @content + (#set! "language" "javascript")) + "#, + ) + .unwrap(), + ); + + let javascript_language = Arc::new(Language::new( + LanguageConfig { + name: "JavaScript".into(), + brackets: vec![BracketPair { + start: "/*".to_string(), + end: "*/".to_string(), + close: true, + newline: true, + }], + autoclose_before: "})]".to_string(), + ..Default::default() + }, + Some(tree_sitter_javascript::language()), + )); + + let registry = Arc::new(LanguageRegistry::test()); + registry.add(html_language.clone()); + registry.add(javascript_language.clone()); + + cx.update_buffer(|buffer, cx| { + buffer.set_language_registry(registry); + buffer.set_language(Some(html_language), cx); + }); + + cx.set_state( + &r#" + ˇ + + + "# + .unindent(), + ); + + let cursors = cx.update_editor(|editor, cx| editor.selections.ranges::(cx)); + cx.update_buffer(|buffer, _| { + let snapshot = buffer.snapshot(); + assert_eq!( + snapshot + .language_at(cursors[0].start) + .unwrap() + .name() + .as_ref(), + "HTML" + ); + assert_eq!( + snapshot + .language_at(cursors[1].start) + .unwrap() + .name() + .as_ref(), + "JavaScript" + ); + }); + } + #[gpui::test] async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { cx.update(|cx| cx.set_global(Settings::test(cx))); diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index 4ee9526a67..3b43f99ca0 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -1212,9 +1212,9 @@ impl MultiBuffer { &self, point: T, cx: &'a AppContext, - ) -> Option<&'a Arc> { + ) -> Option> { self.point_to_buffer_offset(point, cx) - .and_then(|(buffer, _)| buffer.read(cx).language()) + .and_then(|(buffer, offset)| buffer.read(cx).language_at(offset)) } pub fn files<'a>(&'a self, cx: &'a AppContext) -> SmallVec<[&'a dyn File; 2]> { @@ -1940,6 +1940,24 @@ impl MultiBufferSnapshot { } } + pub fn point_to_buffer_offset( + &self, + point: T, + ) -> Option<(&BufferSnapshot, usize)> { + let offset = point.to_offset(&self); + let mut cursor = self.excerpts.cursor::(); + cursor.seek(&offset, Bias::Right, &()); + if cursor.item().is_none() { + cursor.prev(&()); + } + + cursor.item().map(|excerpt| { + let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer); + let buffer_point = excerpt_start + offset - *cursor.start(); + (&excerpt.buffer, buffer_point) + }) + } + pub fn suggested_indents( &self, rows: impl IntoIterator, @@ -2490,6 +2508,11 @@ impl MultiBufferSnapshot { .and_then(|excerpt| excerpt.buffer.language()) } + pub fn language_at<'a, T: ToOffset>(&'a self, point: T) -> Option<&'a Arc> { + self.point_to_buffer_offset(point) + .and_then(|(buffer, offset)| buffer.language_at(offset)) + } + pub fn is_dirty(&self) -> bool { self.is_dirty } diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index c8730be452..372f77cf20 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -641,6 +641,15 @@ impl Buffer { self.language.as_ref() } + pub fn language_at(&self, position: D) -> Option> { + let offset = position.to_offset(self); + self.syntax_map + .lock() + .layers_for_range(offset..offset, &self.text) + .last() + .map(|info| info.language.clone()) + } + pub fn parse_count(&self) -> usize { self.parse_count } @@ -1826,6 +1835,14 @@ impl BufferSnapshot { self.language.as_ref() } + pub fn language_at(&self, position: D) -> Option<&Arc> { + let offset = position.to_offset(self); + self.syntax + .layers_for_range(offset..offset, &self.text) + .last() + .map(|info| info.language) + } + pub fn surrounding_word(&self, start: T) -> (Range, Option) { let mut start = start.to_offset(self); let mut end = start; @@ -1858,8 +1875,8 @@ impl BufferSnapshot { pub fn range_for_syntax_ancestor(&self, range: Range) -> Option> { let range = range.start.to_offset(self)..range.end.to_offset(self); let mut result: Option> = None; - 'outer: for (_, _, node) in self.syntax.layers_for_range(range.clone(), &self.text) { - let mut cursor = node.walk(); + 'outer: for layer in self.syntax.layers_for_range(range.clone(), &self.text) { + let mut cursor = layer.node.walk(); // Descend to the first leaf that touches the start of the range, // and if the range is non-empty, extends beyond the start. diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 0366bdf669..341f70bff9 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -135,7 +135,7 @@ impl CachedLspAdapter { pub async fn label_for_completion( &self, completion_item: &lsp::CompletionItem, - language: &Language, + language: &Arc, ) -> Option { self.adapter .label_for_completion(completion_item, language) @@ -146,7 +146,7 @@ impl CachedLspAdapter { &self, name: &str, kind: lsp::SymbolKind, - language: &Language, + language: &Arc, ) -> Option { self.adapter.label_for_symbol(name, kind, language).await } @@ -175,7 +175,7 @@ pub trait LspAdapter: 'static + Send + Sync { async fn label_for_completion( &self, _: &lsp::CompletionItem, - _: &Language, + _: &Arc, ) -> Option { None } @@ -184,7 +184,7 @@ pub trait LspAdapter: 'static + Send + Sync { &self, _: &str, _: lsp::SymbolKind, - _: &Language, + _: &Arc, ) -> Option { None } @@ -793,7 +793,7 @@ impl Language { } pub async fn label_for_completion( - &self, + self: &Arc, completion: &lsp::CompletionItem, ) -> Option { self.adapter @@ -802,7 +802,11 @@ impl Language { .await } - pub async fn label_for_symbol(&self, name: &str, kind: lsp::SymbolKind) -> Option { + pub async fn label_for_symbol( + self: &Arc, + name: &str, + kind: lsp::SymbolKind, + ) -> Option { self.adapter .as_ref()? .label_for_symbol(name, kind, self) @@ -810,20 +814,17 @@ impl Language { } pub fn highlight_text<'a>( - &'a self, + self: &'a Arc, text: &'a Rope, range: Range, ) -> Vec<(Range, HighlightId)> { let mut result = Vec::new(); if let Some(grammar) = &self.grammar { let tree = grammar.parse_text(text, None); - let captures = SyntaxSnapshot::single_tree_captures( - range.clone(), - text, - &tree, - grammar, - |grammar| grammar.highlights_query.as_ref(), - ); + let captures = + SyntaxSnapshot::single_tree_captures(range.clone(), text, &tree, self, |grammar| { + grammar.highlights_query.as_ref() + }); let highlight_maps = vec![grammar.highlight_map()]; let mut offset = 0; for chunk in BufferChunks::new(text, range, Some((captures, highlight_maps)), vec![]) { diff --git a/crates/language/src/syntax_map.rs b/crates/language/src/syntax_map.rs index a8cac76ac7..a7d9101d7b 100644 --- a/crates/language/src/syntax_map.rs +++ b/crates/language/src/syntax_map.rs @@ -92,6 +92,12 @@ struct SyntaxLayer { language: Arc, } +pub struct SyntaxLayerInfo<'a> { + pub depth: usize, + pub node: Node<'a>, + pub language: &'a Arc, +} + #[derive(Debug, Clone)] struct SyntaxLayerSummary { min_depth: usize, @@ -473,13 +479,18 @@ impl SyntaxSnapshot { range: Range, text: &'a Rope, tree: &'a Tree, - grammar: &'a Grammar, + language: &'a Arc, query: fn(&Grammar) -> Option<&Query>, ) -> SyntaxMapCaptures<'a> { SyntaxMapCaptures::new( range.clone(), text, - [(grammar, 0, tree.root_node())].into_iter(), + [SyntaxLayerInfo { + language, + depth: 0, + node: tree.root_node(), + }] + .into_iter(), query, ) } @@ -513,7 +524,7 @@ impl SyntaxSnapshot { } #[cfg(test)] - pub fn layers(&self, buffer: &BufferSnapshot) -> Vec<(&Grammar, usize, Node)> { + pub fn layers(&self, buffer: &BufferSnapshot) -> Vec { self.layers_for_range(0..buffer.len(), buffer) } @@ -521,7 +532,7 @@ impl SyntaxSnapshot { &self, range: Range, buffer: &BufferSnapshot, - ) -> Vec<(&Grammar, usize, Node)> { + ) -> Vec { let start = buffer.anchor_before(range.start.to_offset(buffer)); let end = buffer.anchor_after(range.end.to_offset(buffer)); @@ -538,16 +549,14 @@ impl SyntaxSnapshot { let mut result = Vec::new(); cursor.next(buffer); while let Some(layer) = cursor.item() { - if let Some(grammar) = &layer.language.grammar { - result.push(( - grammar.as_ref(), - layer.depth, - layer.tree.root_node_with_offset( - layer.range.start.to_offset(buffer), - layer.range.start.to_point(buffer).to_ts_point(), - ), - )); - } + result.push(SyntaxLayerInfo { + language: &layer.language, + depth: layer.depth, + node: layer.tree.root_node_with_offset( + layer.range.start.to_offset(buffer), + layer.range.start.to_point(buffer).to_ts_point(), + ), + }); cursor.next(buffer) } @@ -559,7 +568,7 @@ impl<'a> SyntaxMapCaptures<'a> { fn new( range: Range, text: &'a Rope, - layers: impl Iterator)>, + layers: impl Iterator>, query: fn(&Grammar) -> Option<&Query>, ) -> Self { let mut result = Self { @@ -567,11 +576,19 @@ impl<'a> SyntaxMapCaptures<'a> { grammars: Vec::new(), active_layer_count: 0, }; - for (grammar, depth, node) in layers { - let query = if let Some(query) = query(grammar) { - query - } else { - continue; + for SyntaxLayerInfo { + language, + depth, + node, + } in layers + { + let grammar = match &language.grammar { + Some(grammer) => grammer, + None => continue, + }; + let query = match query(&grammar) { + Some(query) => query, + None => continue, }; let mut query_cursor = QueryCursorHandle::new(); @@ -678,15 +695,23 @@ impl<'a> SyntaxMapMatches<'a> { fn new( range: Range, text: &'a Rope, - layers: impl Iterator)>, + layers: impl Iterator>, query: fn(&Grammar) -> Option<&Query>, ) -> Self { let mut result = Self::default(); - for (grammar, depth, node) in layers { - let query = if let Some(query) = query(grammar) { - query - } else { - continue; + for SyntaxLayerInfo { + language, + depth, + node, + } in layers + { + let grammar = match &language.grammar { + Some(grammer) => grammer, + None => continue, + }; + let query = match query(&grammar) { + Some(query) => query, + None => continue, }; let mut query_cursor = QueryCursorHandle::new(); @@ -1624,8 +1649,8 @@ mod tests { let reference_layers = reference_syntax_map.layers(&buffer); for (edited_layer, reference_layer) in layers.into_iter().zip(reference_layers.into_iter()) { - assert_eq!(edited_layer.2.to_sexp(), reference_layer.2.to_sexp()); - assert_eq!(edited_layer.2.range(), reference_layer.2.range()); + assert_eq!(edited_layer.node.to_sexp(), reference_layer.node.to_sexp()); + assert_eq!(edited_layer.node.range(), reference_layer.node.range()); } } @@ -1770,13 +1795,13 @@ mod tests { mutated_layers.into_iter().zip(reference_layers.into_iter()) { assert_eq!( - edited_layer.2.to_sexp(), - reference_layer.2.to_sexp(), + edited_layer.node.to_sexp(), + reference_layer.node.to_sexp(), "different layer at step {i}" ); assert_eq!( - edited_layer.2.range(), - reference_layer.2.range(), + edited_layer.node.range(), + reference_layer.node.range(), "different layer at step {i}" ); } @@ -1828,7 +1853,7 @@ mod tests { expected_layers.len(), "wrong number of layers" ); - for (i, ((_, _, node), expected_s_exp)) in + for (i, (SyntaxLayerInfo { node, .. }, expected_s_exp)) in layers.iter().zip(expected_layers.iter()).enumerate() { let actual_s_exp = node.to_sexp(); diff --git a/crates/language/src/tests.rs b/crates/language/src/tests.rs index 821bbc9968..8f56f3287e 100644 --- a/crates/language/src/tests.rs +++ b/crates/language/src/tests.rs @@ -1449,7 +1449,7 @@ fn get_tree_sexp(buffer: &ModelHandle, cx: &gpui::TestAppContext) -> Str buffer.read_with(cx, |buffer, _| { let snapshot = buffer.snapshot(); let layers = snapshot.syntax.layers(buffer.as_text_snapshot()); - layers[0].2.to_sexp() + layers[0].node.to_sexp() }) } diff --git a/crates/zed/src/languages.rs b/crates/zed/src/languages.rs index 71a85af0c8..2745fa824a 100644 --- a/crates/zed/src/languages.rs +++ b/crates/zed/src/languages.rs @@ -108,7 +108,7 @@ pub async fn init(languages: Arc, _executor: Arc) Some(CachedLspAdapter::new(html::HtmlLspAdapter).await), ), ] { - languages.add(Arc::new(language(name, grammar, lsp_adapter))); + languages.add(language(name, grammar, lsp_adapter)); } } @@ -116,7 +116,7 @@ pub(crate) fn language( name: &str, grammar: tree_sitter::Language, lsp_adapter: Option>, -) -> Language { +) -> Arc { let config = toml::from_slice( &LanguageDir::get(&format!("{}/config.toml", name)) .unwrap() @@ -153,7 +153,7 @@ pub(crate) fn language( if let Some(lsp_adapter) = lsp_adapter { language = language.with_lsp_adapter(lsp_adapter) } - language + Arc::new(language) } fn load_query(name: &str, filename_prefix: &str) -> Option> { diff --git a/crates/zed/src/languages/c.rs b/crates/zed/src/languages/c.rs index 6aa750f6a0..712e87101b 100644 --- a/crates/zed/src/languages/c.rs +++ b/crates/zed/src/languages/c.rs @@ -112,7 +112,7 @@ impl super::LspAdapter for CLspAdapter { async fn label_for_completion( &self, completion: &lsp::CompletionItem, - language: &Language, + language: &Arc, ) -> Option { let label = completion .label @@ -190,7 +190,7 @@ impl super::LspAdapter for CLspAdapter { &self, name: &str, kind: lsp::SymbolKind, - language: &Language, + language: &Arc, ) -> Option { let (text, filter_range, display_range) = match kind { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { @@ -251,7 +251,6 @@ mod tests { use gpui::MutableAppContext; use language::{AutoindentMode, Buffer}; use settings::Settings; - use std::sync::Arc; #[gpui::test] fn test_c_autoindent(cx: &mut MutableAppContext) { @@ -262,7 +261,7 @@ mod tests { let language = crate::languages::language("c", tree_sitter_c::language(), None); cx.add_model(|cx| { - let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(language), cx); + let mut buffer = Buffer::new(0, "", cx).with_language(language, cx); // empty function buffer.edit([(0..0, "int main() {}")], None, cx); diff --git a/crates/zed/src/languages/elixir.rs b/crates/zed/src/languages/elixir.rs index 4959338522..75b35bb630 100644 --- a/crates/zed/src/languages/elixir.rs +++ b/crates/zed/src/languages/elixir.rs @@ -113,7 +113,7 @@ impl LspAdapter for ElixirLspAdapter { async fn label_for_completion( &self, completion: &lsp::CompletionItem, - language: &Language, + language: &Arc, ) -> Option { match completion.kind.zip(completion.detail.as_ref()) { Some((_, detail)) if detail.starts_with("(function)") => { @@ -168,7 +168,7 @@ impl LspAdapter for ElixirLspAdapter { &self, name: &str, kind: SymbolKind, - language: &Language, + language: &Arc, ) -> Option { let (text, filter_range, display_range) = match kind { SymbolKind::METHOD | SymbolKind::FUNCTION => { diff --git a/crates/zed/src/languages/go.rs b/crates/zed/src/languages/go.rs index 729d39b513..19692fdf44 100644 --- a/crates/zed/src/languages/go.rs +++ b/crates/zed/src/languages/go.rs @@ -134,7 +134,7 @@ impl super::LspAdapter for GoLspAdapter { async fn label_for_completion( &self, completion: &lsp::CompletionItem, - language: &Language, + language: &Arc, ) -> Option { let label = &completion.label; @@ -235,7 +235,7 @@ impl super::LspAdapter for GoLspAdapter { &self, name: &str, kind: lsp::SymbolKind, - language: &Language, + language: &Arc, ) -> Option { let (text, filter_range, display_range) = match kind { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { diff --git a/crates/zed/src/languages/python.rs b/crates/zed/src/languages/python.rs index 274fc3216c..e6e55eeac4 100644 --- a/crates/zed/src/languages/python.rs +++ b/crates/zed/src/languages/python.rs @@ -90,7 +90,7 @@ impl LspAdapter for PythonLspAdapter { async fn label_for_completion( &self, item: &lsp::CompletionItem, - language: &language::Language, + language: &Arc, ) -> Option { let label = &item.label; let grammar = language.grammar()?; @@ -112,7 +112,7 @@ impl LspAdapter for PythonLspAdapter { &self, name: &str, kind: lsp::SymbolKind, - language: &language::Language, + language: &Arc, ) -> Option { let (text, filter_range, display_range) = match kind { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { @@ -149,7 +149,6 @@ mod tests { use gpui::{ModelContext, MutableAppContext}; use language::{AutoindentMode, Buffer}; use settings::Settings; - use std::sync::Arc; #[gpui::test] fn test_python_autoindent(cx: &mut MutableAppContext) { @@ -160,7 +159,7 @@ mod tests { cx.set_global(settings); cx.add_model(|cx| { - let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(language), cx); + let mut buffer = Buffer::new(0, "", cx).with_language(language, cx); let append = |buffer: &mut Buffer, text: &str, cx: &mut ModelContext| { let ix = buffer.len(); buffer.edit([(ix..ix, text)], Some(AutoindentMode::EachLine), cx); diff --git a/crates/zed/src/languages/rust.rs b/crates/zed/src/languages/rust.rs index adbe431279..f5776f3420 100644 --- a/crates/zed/src/languages/rust.rs +++ b/crates/zed/src/languages/rust.rs @@ -119,7 +119,7 @@ impl LspAdapter for RustLspAdapter { async fn label_for_completion( &self, completion: &lsp::CompletionItem, - language: &Language, + language: &Arc, ) -> Option { match completion.kind { Some(lsp::CompletionItemKind::FIELD) if completion.detail.is_some() => { @@ -196,7 +196,7 @@ impl LspAdapter for RustLspAdapter { &self, name: &str, kind: lsp::SymbolKind, - language: &Language, + language: &Arc, ) -> Option { let (text, filter_range, display_range) = match kind { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { @@ -439,7 +439,7 @@ mod tests { cx.set_global(settings); cx.add_model(|cx| { - let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(language), cx); + let mut buffer = Buffer::new(0, "", cx).with_language(language, cx); // indent between braces buffer.set_text("fn a() {}", cx); diff --git a/crates/zed/src/languages/typescript.rs b/crates/zed/src/languages/typescript.rs index 85a1bd6400..95f56bce5b 100644 --- a/crates/zed/src/languages/typescript.rs +++ b/crates/zed/src/languages/typescript.rs @@ -115,7 +115,7 @@ impl LspAdapter for TypeScriptLspAdapter { async fn label_for_completion( &self, item: &lsp::CompletionItem, - language: &language::Language, + language: &Arc, ) -> Option { use lsp::CompletionItemKind as Kind; let len = item.label.len(); @@ -144,7 +144,6 @@ impl LspAdapter for TypeScriptLspAdapter { #[cfg(test)] mod tests { - use std::sync::Arc; use gpui::MutableAppContext; use unindent::Unindent; @@ -172,9 +171,8 @@ mod tests { "# .unindent(); - let buffer = cx.add_model(|cx| { - language::Buffer::new(0, text, cx).with_language(Arc::new(language), cx) - }); + let buffer = + cx.add_model(|cx| language::Buffer::new(0, text, cx).with_language(language, cx)); let outline = buffer.read(cx).snapshot().outline(None).unwrap(); assert_eq!( outline diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 76bc62e4cb..f86022e39c 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -1133,7 +1133,7 @@ mod tests { assert!(!editor.is_dirty(cx)); assert_eq!(editor.title(cx), "untitled"); assert!(Arc::ptr_eq( - editor.language_at(0, cx).unwrap(), + &editor.language_at(0, cx).unwrap(), &languages::PLAIN_TEXT )); editor.handle_input("hi", cx); @@ -1220,7 +1220,7 @@ mod tests { editor.update(cx, |editor, cx| { assert!(Arc::ptr_eq( - editor.language_at(0, cx).unwrap(), + &editor.language_at(0, cx).unwrap(), &languages::PLAIN_TEXT )); editor.handle_input("hi", cx);