Add Buffer::language_at, update MultiBuffer to use it

Co-authored-by: Julia Risley <floc@unpromptedtirade.com>
This commit is contained in:
Max Brunsfeld 2022-08-31 16:50:44 -07:00
parent a2e57e8d71
commit 67e188a015
16 changed files with 245 additions and 81 deletions

12
Cargo.lock generated
View file

@ -1719,6 +1719,8 @@ dependencies = [
"text", "text",
"theme", "theme",
"tree-sitter", "tree-sitter",
"tree-sitter-html",
"tree-sitter-javascript",
"tree-sitter-rust", "tree-sitter-rust",
"unindent", "unindent",
"util", "util",
@ -6062,6 +6064,16 @@ dependencies = [
"tree-sitter", "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]] [[package]]
name = "tree-sitter-json" name = "tree-sitter-json"
version = "0.19.0" version = "0.19.0"

View file

@ -51,6 +51,8 @@ serde = { version = "1.0", features = ["derive", "rc"] }
smallvec = { version = "1.6", features = ["union"] } smallvec = { version = "1.6", features = ["union"] }
smol = "1.2" smol = "1.2"
tree-sitter-rust = { version = "*", optional = true } tree-sitter-rust = { version = "*", optional = true }
tree-sitter-html = { version = "*", optional = true }
tree-sitter-javascript = { version = "*", optional = true }
[dev-dependencies] [dev-dependencies]
text = { path = "../text", features = ["test-support"] } text = { path = "../text", features = ["test-support"] }
@ -67,3 +69,5 @@ rand = "0.8"
unindent = "0.1.7" unindent = "0.1.7"
tree-sitter = "0.20" tree-sitter = "0.20"
tree-sitter-rust = "0.20" tree-sitter-rust = "0.20"
tree-sitter-html = "0.19"
tree-sitter-javascript = "0.20"

View file

@ -1116,7 +1116,7 @@ impl Editor {
&self, &self,
point: T, point: T,
cx: &'a AppContext, cx: &'a AppContext,
) -> Option<&'a Arc<Language>> { ) -> Option<Arc<Language>> {
self.buffer.read(cx).language_at(point, cx) 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. // as that portion won't be used for detecting if a line is a comment.
let full_comment_prefix: Arc<str> = if let Some(prefix) = buffer let full_comment_prefix: Arc<str> = if let Some(prefix) = buffer
.language_at(selection.start, cx) .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 { } else {
return; return;
}; };
@ -6713,7 +6713,7 @@ mod tests {
platform::{WindowBounds, WindowOptions}, platform::{WindowBounds, WindowOptions},
}; };
use indoc::indoc; use indoc::indoc;
use language::{FakeLspAdapter, LanguageConfig}; use language::{FakeLspAdapter, LanguageConfig, LanguageRegistry};
use project::FakeFs; use project::FakeFs;
use settings::EditorSettings; use settings::EditorSettings;
use std::{cell::RefCell, rc::Rc, time::Instant}; 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#"
<body>ˇ
<script>
var x = 1;ˇ
</script>
</body>
"#
.unindent(),
);
let cursors = cx.update_editor(|editor, cx| editor.selections.ranges::<usize>(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] #[gpui::test]
async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) { async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) {
cx.update(|cx| cx.set_global(Settings::test(cx))); cx.update(|cx| cx.set_global(Settings::test(cx)));

View file

@ -1212,9 +1212,9 @@ impl MultiBuffer {
&self, &self,
point: T, point: T,
cx: &'a AppContext, cx: &'a AppContext,
) -> Option<&'a Arc<Language>> { ) -> Option<Arc<Language>> {
self.point_to_buffer_offset(point, cx) 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]> { 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<T: ToOffset>(
&self,
point: T,
) -> Option<(&BufferSnapshot, usize)> {
let offset = point.to_offset(&self);
let mut cursor = self.excerpts.cursor::<usize>();
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( pub fn suggested_indents(
&self, &self,
rows: impl IntoIterator<Item = u32>, rows: impl IntoIterator<Item = u32>,
@ -2490,6 +2508,11 @@ impl MultiBufferSnapshot {
.and_then(|excerpt| excerpt.buffer.language()) .and_then(|excerpt| excerpt.buffer.language())
} }
pub fn language_at<'a, T: ToOffset>(&'a self, point: T) -> Option<&'a Arc<Language>> {
self.point_to_buffer_offset(point)
.and_then(|(buffer, offset)| buffer.language_at(offset))
}
pub fn is_dirty(&self) -> bool { pub fn is_dirty(&self) -> bool {
self.is_dirty self.is_dirty
} }

View file

@ -641,6 +641,15 @@ impl Buffer {
self.language.as_ref() self.language.as_ref()
} }
pub fn language_at<D: ToOffset>(&self, position: D) -> Option<Arc<Language>> {
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 { pub fn parse_count(&self) -> usize {
self.parse_count self.parse_count
} }
@ -1826,6 +1835,14 @@ impl BufferSnapshot {
self.language.as_ref() self.language.as_ref()
} }
pub fn language_at<D: ToOffset>(&self, position: D) -> Option<&Arc<Language>> {
let offset = position.to_offset(self);
self.syntax
.layers_for_range(offset..offset, &self.text)
.last()
.map(|info| info.language)
}
pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) { pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) {
let mut start = start.to_offset(self); let mut start = start.to_offset(self);
let mut end = start; let mut end = start;
@ -1858,8 +1875,8 @@ impl BufferSnapshot {
pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> { pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
let range = range.start.to_offset(self)..range.end.to_offset(self); let range = range.start.to_offset(self)..range.end.to_offset(self);
let mut result: Option<Range<usize>> = None; let mut result: Option<Range<usize>> = None;
'outer: for (_, _, node) in self.syntax.layers_for_range(range.clone(), &self.text) { 'outer: for layer in self.syntax.layers_for_range(range.clone(), &self.text) {
let mut cursor = node.walk(); let mut cursor = layer.node.walk();
// Descend to the first leaf that touches the start of the range, // Descend to the first leaf that touches the start of the range,
// and if the range is non-empty, extends beyond the start. // and if the range is non-empty, extends beyond the start.

View file

@ -135,7 +135,7 @@ impl CachedLspAdapter {
pub async fn label_for_completion( pub async fn label_for_completion(
&self, &self,
completion_item: &lsp::CompletionItem, completion_item: &lsp::CompletionItem,
language: &Language, language: &Arc<Language>,
) -> Option<CodeLabel> { ) -> Option<CodeLabel> {
self.adapter self.adapter
.label_for_completion(completion_item, language) .label_for_completion(completion_item, language)
@ -146,7 +146,7 @@ impl CachedLspAdapter {
&self, &self,
name: &str, name: &str,
kind: lsp::SymbolKind, kind: lsp::SymbolKind,
language: &Language, language: &Arc<Language>,
) -> Option<CodeLabel> { ) -> Option<CodeLabel> {
self.adapter.label_for_symbol(name, kind, language).await self.adapter.label_for_symbol(name, kind, language).await
} }
@ -175,7 +175,7 @@ pub trait LspAdapter: 'static + Send + Sync {
async fn label_for_completion( async fn label_for_completion(
&self, &self,
_: &lsp::CompletionItem, _: &lsp::CompletionItem,
_: &Language, _: &Arc<Language>,
) -> Option<CodeLabel> { ) -> Option<CodeLabel> {
None None
} }
@ -184,7 +184,7 @@ pub trait LspAdapter: 'static + Send + Sync {
&self, &self,
_: &str, _: &str,
_: lsp::SymbolKind, _: lsp::SymbolKind,
_: &Language, _: &Arc<Language>,
) -> Option<CodeLabel> { ) -> Option<CodeLabel> {
None None
} }
@ -793,7 +793,7 @@ impl Language {
} }
pub async fn label_for_completion( pub async fn label_for_completion(
&self, self: &Arc<Self>,
completion: &lsp::CompletionItem, completion: &lsp::CompletionItem,
) -> Option<CodeLabel> { ) -> Option<CodeLabel> {
self.adapter self.adapter
@ -802,7 +802,11 @@ impl Language {
.await .await
} }
pub async fn label_for_symbol(&self, name: &str, kind: lsp::SymbolKind) -> Option<CodeLabel> { pub async fn label_for_symbol(
self: &Arc<Self>,
name: &str,
kind: lsp::SymbolKind,
) -> Option<CodeLabel> {
self.adapter self.adapter
.as_ref()? .as_ref()?
.label_for_symbol(name, kind, self) .label_for_symbol(name, kind, self)
@ -810,20 +814,17 @@ impl Language {
} }
pub fn highlight_text<'a>( pub fn highlight_text<'a>(
&'a self, self: &'a Arc<Self>,
text: &'a Rope, text: &'a Rope,
range: Range<usize>, range: Range<usize>,
) -> Vec<(Range<usize>, HighlightId)> { ) -> Vec<(Range<usize>, HighlightId)> {
let mut result = Vec::new(); let mut result = Vec::new();
if let Some(grammar) = &self.grammar { if let Some(grammar) = &self.grammar {
let tree = grammar.parse_text(text, None); let tree = grammar.parse_text(text, None);
let captures = SyntaxSnapshot::single_tree_captures( let captures =
range.clone(), SyntaxSnapshot::single_tree_captures(range.clone(), text, &tree, self, |grammar| {
text, grammar.highlights_query.as_ref()
&tree, });
grammar,
|grammar| grammar.highlights_query.as_ref(),
);
let highlight_maps = vec![grammar.highlight_map()]; let highlight_maps = vec![grammar.highlight_map()];
let mut offset = 0; let mut offset = 0;
for chunk in BufferChunks::new(text, range, Some((captures, highlight_maps)), vec![]) { for chunk in BufferChunks::new(text, range, Some((captures, highlight_maps)), vec![]) {

View file

@ -92,6 +92,12 @@ struct SyntaxLayer {
language: Arc<Language>, language: Arc<Language>,
} }
pub struct SyntaxLayerInfo<'a> {
pub depth: usize,
pub node: Node<'a>,
pub language: &'a Arc<Language>,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct SyntaxLayerSummary { struct SyntaxLayerSummary {
min_depth: usize, min_depth: usize,
@ -473,13 +479,18 @@ impl SyntaxSnapshot {
range: Range<usize>, range: Range<usize>,
text: &'a Rope, text: &'a Rope,
tree: &'a Tree, tree: &'a Tree,
grammar: &'a Grammar, language: &'a Arc<Language>,
query: fn(&Grammar) -> Option<&Query>, query: fn(&Grammar) -> Option<&Query>,
) -> SyntaxMapCaptures<'a> { ) -> SyntaxMapCaptures<'a> {
SyntaxMapCaptures::new( SyntaxMapCaptures::new(
range.clone(), range.clone(),
text, text,
[(grammar, 0, tree.root_node())].into_iter(), [SyntaxLayerInfo {
language,
depth: 0,
node: tree.root_node(),
}]
.into_iter(),
query, query,
) )
} }
@ -513,7 +524,7 @@ impl SyntaxSnapshot {
} }
#[cfg(test)] #[cfg(test)]
pub fn layers(&self, buffer: &BufferSnapshot) -> Vec<(&Grammar, usize, Node)> { pub fn layers(&self, buffer: &BufferSnapshot) -> Vec<SyntaxLayerInfo> {
self.layers_for_range(0..buffer.len(), buffer) self.layers_for_range(0..buffer.len(), buffer)
} }
@ -521,7 +532,7 @@ impl SyntaxSnapshot {
&self, &self,
range: Range<T>, range: Range<T>,
buffer: &BufferSnapshot, buffer: &BufferSnapshot,
) -> Vec<(&Grammar, usize, Node)> { ) -> Vec<SyntaxLayerInfo> {
let start = buffer.anchor_before(range.start.to_offset(buffer)); let start = buffer.anchor_before(range.start.to_offset(buffer));
let end = buffer.anchor_after(range.end.to_offset(buffer)); let end = buffer.anchor_after(range.end.to_offset(buffer));
@ -538,16 +549,14 @@ impl SyntaxSnapshot {
let mut result = Vec::new(); let mut result = Vec::new();
cursor.next(buffer); cursor.next(buffer);
while let Some(layer) = cursor.item() { while let Some(layer) = cursor.item() {
if let Some(grammar) = &layer.language.grammar { result.push(SyntaxLayerInfo {
result.push(( language: &layer.language,
grammar.as_ref(), depth: layer.depth,
layer.depth, node: layer.tree.root_node_with_offset(
layer.tree.root_node_with_offset( layer.range.start.to_offset(buffer),
layer.range.start.to_offset(buffer), layer.range.start.to_point(buffer).to_ts_point(),
layer.range.start.to_point(buffer).to_ts_point(), ),
), });
));
}
cursor.next(buffer) cursor.next(buffer)
} }
@ -559,7 +568,7 @@ impl<'a> SyntaxMapCaptures<'a> {
fn new( fn new(
range: Range<usize>, range: Range<usize>,
text: &'a Rope, text: &'a Rope,
layers: impl Iterator<Item = (&'a Grammar, usize, Node<'a>)>, layers: impl Iterator<Item = SyntaxLayerInfo<'a>>,
query: fn(&Grammar) -> Option<&Query>, query: fn(&Grammar) -> Option<&Query>,
) -> Self { ) -> Self {
let mut result = Self { let mut result = Self {
@ -567,11 +576,19 @@ impl<'a> SyntaxMapCaptures<'a> {
grammars: Vec::new(), grammars: Vec::new(),
active_layer_count: 0, active_layer_count: 0,
}; };
for (grammar, depth, node) in layers { for SyntaxLayerInfo {
let query = if let Some(query) = query(grammar) { language,
query depth,
} else { node,
continue; } 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(); let mut query_cursor = QueryCursorHandle::new();
@ -678,15 +695,23 @@ impl<'a> SyntaxMapMatches<'a> {
fn new( fn new(
range: Range<usize>, range: Range<usize>,
text: &'a Rope, text: &'a Rope,
layers: impl Iterator<Item = (&'a Grammar, usize, Node<'a>)>, layers: impl Iterator<Item = SyntaxLayerInfo<'a>>,
query: fn(&Grammar) -> Option<&Query>, query: fn(&Grammar) -> Option<&Query>,
) -> Self { ) -> Self {
let mut result = Self::default(); let mut result = Self::default();
for (grammar, depth, node) in layers { for SyntaxLayerInfo {
let query = if let Some(query) = query(grammar) { language,
query depth,
} else { node,
continue; } 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(); let mut query_cursor = QueryCursorHandle::new();
@ -1624,8 +1649,8 @@ mod tests {
let reference_layers = reference_syntax_map.layers(&buffer); let reference_layers = reference_syntax_map.layers(&buffer);
for (edited_layer, reference_layer) in layers.into_iter().zip(reference_layers.into_iter()) 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.node.to_sexp(), reference_layer.node.to_sexp());
assert_eq!(edited_layer.2.range(), reference_layer.2.range()); 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()) mutated_layers.into_iter().zip(reference_layers.into_iter())
{ {
assert_eq!( assert_eq!(
edited_layer.2.to_sexp(), edited_layer.node.to_sexp(),
reference_layer.2.to_sexp(), reference_layer.node.to_sexp(),
"different layer at step {i}" "different layer at step {i}"
); );
assert_eq!( assert_eq!(
edited_layer.2.range(), edited_layer.node.range(),
reference_layer.2.range(), reference_layer.node.range(),
"different layer at step {i}" "different layer at step {i}"
); );
} }
@ -1828,7 +1853,7 @@ mod tests {
expected_layers.len(), expected_layers.len(),
"wrong number of layers" "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() layers.iter().zip(expected_layers.iter()).enumerate()
{ {
let actual_s_exp = node.to_sexp(); let actual_s_exp = node.to_sexp();

View file

@ -1449,7 +1449,7 @@ fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> Str
buffer.read_with(cx, |buffer, _| { buffer.read_with(cx, |buffer, _| {
let snapshot = buffer.snapshot(); let snapshot = buffer.snapshot();
let layers = snapshot.syntax.layers(buffer.as_text_snapshot()); let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
layers[0].2.to_sexp() layers[0].node.to_sexp()
}) })
} }

View file

@ -108,7 +108,7 @@ pub async fn init(languages: Arc<LanguageRegistry>, _executor: Arc<Background>)
Some(CachedLspAdapter::new(html::HtmlLspAdapter).await), 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, name: &str,
grammar: tree_sitter::Language, grammar: tree_sitter::Language,
lsp_adapter: Option<Arc<CachedLspAdapter>>, lsp_adapter: Option<Arc<CachedLspAdapter>>,
) -> Language { ) -> Arc<Language> {
let config = toml::from_slice( let config = toml::from_slice(
&LanguageDir::get(&format!("{}/config.toml", name)) &LanguageDir::get(&format!("{}/config.toml", name))
.unwrap() .unwrap()
@ -153,7 +153,7 @@ pub(crate) fn language(
if let Some(lsp_adapter) = lsp_adapter { if let Some(lsp_adapter) = lsp_adapter {
language = language.with_lsp_adapter(lsp_adapter) language = language.with_lsp_adapter(lsp_adapter)
} }
language Arc::new(language)
} }
fn load_query(name: &str, filename_prefix: &str) -> Option<Cow<'static, str>> { fn load_query(name: &str, filename_prefix: &str) -> Option<Cow<'static, str>> {

View file

@ -112,7 +112,7 @@ impl super::LspAdapter for CLspAdapter {
async fn label_for_completion( async fn label_for_completion(
&self, &self,
completion: &lsp::CompletionItem, completion: &lsp::CompletionItem,
language: &Language, language: &Arc<Language>,
) -> Option<CodeLabel> { ) -> Option<CodeLabel> {
let label = completion let label = completion
.label .label
@ -190,7 +190,7 @@ impl super::LspAdapter for CLspAdapter {
&self, &self,
name: &str, name: &str,
kind: lsp::SymbolKind, kind: lsp::SymbolKind,
language: &Language, language: &Arc<Language>,
) -> Option<CodeLabel> { ) -> Option<CodeLabel> {
let (text, filter_range, display_range) = match kind { let (text, filter_range, display_range) = match kind {
lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {
@ -251,7 +251,6 @@ mod tests {
use gpui::MutableAppContext; use gpui::MutableAppContext;
use language::{AutoindentMode, Buffer}; use language::{AutoindentMode, Buffer};
use settings::Settings; use settings::Settings;
use std::sync::Arc;
#[gpui::test] #[gpui::test]
fn test_c_autoindent(cx: &mut MutableAppContext) { fn test_c_autoindent(cx: &mut MutableAppContext) {
@ -262,7 +261,7 @@ mod tests {
let language = crate::languages::language("c", tree_sitter_c::language(), None); let language = crate::languages::language("c", tree_sitter_c::language(), None);
cx.add_model(|cx| { 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 // empty function
buffer.edit([(0..0, "int main() {}")], None, cx); buffer.edit([(0..0, "int main() {}")], None, cx);

View file

@ -113,7 +113,7 @@ impl LspAdapter for ElixirLspAdapter {
async fn label_for_completion( async fn label_for_completion(
&self, &self,
completion: &lsp::CompletionItem, completion: &lsp::CompletionItem,
language: &Language, language: &Arc<Language>,
) -> Option<CodeLabel> { ) -> Option<CodeLabel> {
match completion.kind.zip(completion.detail.as_ref()) { match completion.kind.zip(completion.detail.as_ref()) {
Some((_, detail)) if detail.starts_with("(function)") => { Some((_, detail)) if detail.starts_with("(function)") => {
@ -168,7 +168,7 @@ impl LspAdapter for ElixirLspAdapter {
&self, &self,
name: &str, name: &str,
kind: SymbolKind, kind: SymbolKind,
language: &Language, language: &Arc<Language>,
) -> Option<CodeLabel> { ) -> Option<CodeLabel> {
let (text, filter_range, display_range) = match kind { let (text, filter_range, display_range) = match kind {
SymbolKind::METHOD | SymbolKind::FUNCTION => { SymbolKind::METHOD | SymbolKind::FUNCTION => {

View file

@ -134,7 +134,7 @@ impl super::LspAdapter for GoLspAdapter {
async fn label_for_completion( async fn label_for_completion(
&self, &self,
completion: &lsp::CompletionItem, completion: &lsp::CompletionItem,
language: &Language, language: &Arc<Language>,
) -> Option<CodeLabel> { ) -> Option<CodeLabel> {
let label = &completion.label; let label = &completion.label;
@ -235,7 +235,7 @@ impl super::LspAdapter for GoLspAdapter {
&self, &self,
name: &str, name: &str,
kind: lsp::SymbolKind, kind: lsp::SymbolKind,
language: &Language, language: &Arc<Language>,
) -> Option<CodeLabel> { ) -> Option<CodeLabel> {
let (text, filter_range, display_range) = match kind { let (text, filter_range, display_range) = match kind {
lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {

View file

@ -90,7 +90,7 @@ impl LspAdapter for PythonLspAdapter {
async fn label_for_completion( async fn label_for_completion(
&self, &self,
item: &lsp::CompletionItem, item: &lsp::CompletionItem,
language: &language::Language, language: &Arc<language::Language>,
) -> Option<language::CodeLabel> { ) -> Option<language::CodeLabel> {
let label = &item.label; let label = &item.label;
let grammar = language.grammar()?; let grammar = language.grammar()?;
@ -112,7 +112,7 @@ impl LspAdapter for PythonLspAdapter {
&self, &self,
name: &str, name: &str,
kind: lsp::SymbolKind, kind: lsp::SymbolKind,
language: &language::Language, language: &Arc<language::Language>,
) -> Option<language::CodeLabel> { ) -> Option<language::CodeLabel> {
let (text, filter_range, display_range) = match kind { let (text, filter_range, display_range) = match kind {
lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {
@ -149,7 +149,6 @@ mod tests {
use gpui::{ModelContext, MutableAppContext}; use gpui::{ModelContext, MutableAppContext};
use language::{AutoindentMode, Buffer}; use language::{AutoindentMode, Buffer};
use settings::Settings; use settings::Settings;
use std::sync::Arc;
#[gpui::test] #[gpui::test]
fn test_python_autoindent(cx: &mut MutableAppContext) { fn test_python_autoindent(cx: &mut MutableAppContext) {
@ -160,7 +159,7 @@ mod tests {
cx.set_global(settings); cx.set_global(settings);
cx.add_model(|cx| { 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<Buffer>| { let append = |buffer: &mut Buffer, text: &str, cx: &mut ModelContext<Buffer>| {
let ix = buffer.len(); let ix = buffer.len();
buffer.edit([(ix..ix, text)], Some(AutoindentMode::EachLine), cx); buffer.edit([(ix..ix, text)], Some(AutoindentMode::EachLine), cx);

View file

@ -119,7 +119,7 @@ impl LspAdapter for RustLspAdapter {
async fn label_for_completion( async fn label_for_completion(
&self, &self,
completion: &lsp::CompletionItem, completion: &lsp::CompletionItem,
language: &Language, language: &Arc<Language>,
) -> Option<CodeLabel> { ) -> Option<CodeLabel> {
match completion.kind { match completion.kind {
Some(lsp::CompletionItemKind::FIELD) if completion.detail.is_some() => { Some(lsp::CompletionItemKind::FIELD) if completion.detail.is_some() => {
@ -196,7 +196,7 @@ impl LspAdapter for RustLspAdapter {
&self, &self,
name: &str, name: &str,
kind: lsp::SymbolKind, kind: lsp::SymbolKind,
language: &Language, language: &Arc<Language>,
) -> Option<CodeLabel> { ) -> Option<CodeLabel> {
let (text, filter_range, display_range) = match kind { let (text, filter_range, display_range) = match kind {
lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {
@ -439,7 +439,7 @@ mod tests {
cx.set_global(settings); cx.set_global(settings);
cx.add_model(|cx| { 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 // indent between braces
buffer.set_text("fn a() {}", cx); buffer.set_text("fn a() {}", cx);

View file

@ -115,7 +115,7 @@ impl LspAdapter for TypeScriptLspAdapter {
async fn label_for_completion( async fn label_for_completion(
&self, &self,
item: &lsp::CompletionItem, item: &lsp::CompletionItem,
language: &language::Language, language: &Arc<language::Language>,
) -> Option<language::CodeLabel> { ) -> Option<language::CodeLabel> {
use lsp::CompletionItemKind as Kind; use lsp::CompletionItemKind as Kind;
let len = item.label.len(); let len = item.label.len();
@ -144,7 +144,6 @@ impl LspAdapter for TypeScriptLspAdapter {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::sync::Arc;
use gpui::MutableAppContext; use gpui::MutableAppContext;
use unindent::Unindent; use unindent::Unindent;
@ -172,9 +171,8 @@ mod tests {
"# "#
.unindent(); .unindent();
let buffer = cx.add_model(|cx| { let buffer =
language::Buffer::new(0, text, cx).with_language(Arc::new(language), cx) cx.add_model(|cx| language::Buffer::new(0, text, cx).with_language(language, cx));
});
let outline = buffer.read(cx).snapshot().outline(None).unwrap(); let outline = buffer.read(cx).snapshot().outline(None).unwrap();
assert_eq!( assert_eq!(
outline outline

View file

@ -1133,7 +1133,7 @@ mod tests {
assert!(!editor.is_dirty(cx)); assert!(!editor.is_dirty(cx));
assert_eq!(editor.title(cx), "untitled"); assert_eq!(editor.title(cx), "untitled");
assert!(Arc::ptr_eq( assert!(Arc::ptr_eq(
editor.language_at(0, cx).unwrap(), &editor.language_at(0, cx).unwrap(),
&languages::PLAIN_TEXT &languages::PLAIN_TEXT
)); ));
editor.handle_input("hi", cx); editor.handle_input("hi", cx);
@ -1220,7 +1220,7 @@ mod tests {
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
assert!(Arc::ptr_eq( assert!(Arc::ptr_eq(
editor.language_at(0, cx).unwrap(), &editor.language_at(0, cx).unwrap(),
&languages::PLAIN_TEXT &languages::PLAIN_TEXT
)); ));
editor.handle_input("hi", cx); editor.handle_input("hi", cx);