Allow languages to be registered at any time
Co-Authored-By: Nathan Sobo <nathan@zed.dev> Co-Authored-By: Antonio Scandurra <me@as-cii.com>
This commit is contained in:
parent
d7db3791d5
commit
64098247cb
9 changed files with 225 additions and 195 deletions
|
@ -864,7 +864,7 @@ mod tests {
|
||||||
let language = Arc::new(
|
let language = Arc::new(
|
||||||
Language::new(
|
Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Test".to_string(),
|
name: "Test".into(),
|
||||||
path_suffixes: vec![".test".to_string()],
|
path_suffixes: vec![".test".to_string()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -951,7 +951,7 @@ mod tests {
|
||||||
let language = Arc::new(
|
let language = Arc::new(
|
||||||
Language::new(
|
Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Test".to_string(),
|
name: "Test".into(),
|
||||||
path_suffixes: vec![".test".to_string()],
|
path_suffixes: vec![".test".to_string()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,7 +16,7 @@ use futures::{
|
||||||
use gpui::{AppContext, Task};
|
use gpui::{AppContext, Task};
|
||||||
use highlight_map::HighlightMap;
|
use highlight_map::HighlightMap;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::{Mutex, RwLock};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
|
@ -45,7 +45,7 @@ thread_local! {
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref PLAIN_TEXT: Arc<Language> = Arc::new(Language::new(
|
pub static ref PLAIN_TEXT: Arc<Language> = Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Plain Text".to_string(),
|
name: "Plain Text".into(),
|
||||||
path_suffixes: Default::default(),
|
path_suffixes: Default::default(),
|
||||||
brackets: Default::default(),
|
brackets: Default::default(),
|
||||||
line_comment: None,
|
line_comment: None,
|
||||||
|
@ -92,15 +92,27 @@ pub struct CodeLabel {
|
||||||
pub filter_range: Range<usize>,
|
pub filter_range: Range<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct LanguageConfig {
|
pub struct LanguageConfig {
|
||||||
pub name: String,
|
pub name: Arc<str>,
|
||||||
pub path_suffixes: Vec<String>,
|
pub path_suffixes: Vec<String>,
|
||||||
pub brackets: Vec<BracketPair>,
|
pub brackets: Vec<BracketPair>,
|
||||||
pub line_comment: Option<String>,
|
pub line_comment: Option<String>,
|
||||||
pub language_server: Option<LanguageServerConfig>,
|
pub language_server: Option<LanguageServerConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for LanguageConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
name: "".into(),
|
||||||
|
path_suffixes: Default::default(),
|
||||||
|
brackets: Default::default(),
|
||||||
|
line_comment: Default::default(),
|
||||||
|
language_server: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize)]
|
#[derive(Default, Deserialize)]
|
||||||
pub struct LanguageServerConfig {
|
pub struct LanguageServerConfig {
|
||||||
pub disk_based_diagnostic_sources: HashSet<String>,
|
pub disk_based_diagnostic_sources: HashSet<String>,
|
||||||
|
@ -151,7 +163,7 @@ pub enum LanguageServerBinaryStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LanguageRegistry {
|
pub struct LanguageRegistry {
|
||||||
languages: Vec<Arc<Language>>,
|
languages: RwLock<Vec<Arc<Language>>>,
|
||||||
language_server_download_dir: Option<Arc<Path>>,
|
language_server_download_dir: Option<Arc<Path>>,
|
||||||
lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
|
lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
|
||||||
lsp_binary_statuses_rx: async_broadcast::Receiver<(Arc<Language>, LanguageServerBinaryStatus)>,
|
lsp_binary_statuses_rx: async_broadcast::Receiver<(Arc<Language>, LanguageServerBinaryStatus)>,
|
||||||
|
@ -168,12 +180,12 @@ impl LanguageRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, language: Arc<Language>) {
|
pub fn add(&self, language: Arc<Language>) {
|
||||||
self.languages.push(language.clone());
|
self.languages.write().push(language.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_theme(&self, theme: &SyntaxTheme) {
|
pub fn set_theme(&self, theme: &SyntaxTheme) {
|
||||||
for language in &self.languages {
|
for language in self.languages.read().iter() {
|
||||||
language.set_theme(theme);
|
language.set_theme(theme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,24 +194,30 @@ impl LanguageRegistry {
|
||||||
self.language_server_download_dir = Some(path.into());
|
self.language_server_download_dir = Some(path.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_language(&self, name: &str) -> Option<&Arc<Language>> {
|
pub fn get_language(&self, name: &str) -> Option<Arc<Language>> {
|
||||||
self.languages
|
self.languages
|
||||||
|
.read()
|
||||||
.iter()
|
.iter()
|
||||||
.find(|language| language.name() == name)
|
.find(|language| language.name().as_ref() == name)
|
||||||
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select_language(&self, path: impl AsRef<Path>) -> Option<&Arc<Language>> {
|
pub fn select_language(&self, path: impl AsRef<Path>) -> Option<Arc<Language>> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let filename = path.file_name().and_then(|name| name.to_str());
|
let filename = path.file_name().and_then(|name| name.to_str());
|
||||||
let extension = path.extension().and_then(|name| name.to_str());
|
let extension = path.extension().and_then(|name| name.to_str());
|
||||||
let path_suffixes = [extension, filename];
|
let path_suffixes = [extension, filename];
|
||||||
self.languages.iter().find(|language| {
|
self.languages
|
||||||
|
.read()
|
||||||
|
.iter()
|
||||||
|
.find(|language| {
|
||||||
language
|
language
|
||||||
.config
|
.config
|
||||||
.path_suffixes
|
.path_suffixes
|
||||||
.iter()
|
.iter()
|
||||||
.any(|suffix| path_suffixes.contains(&Some(suffix.as_str())))
|
.any(|suffix| path_suffixes.contains(&Some(suffix.as_str())))
|
||||||
})
|
})
|
||||||
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_language_server(
|
pub fn start_language_server(
|
||||||
|
@ -401,8 +419,8 @@ impl Language {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> Arc<str> {
|
||||||
self.config.name.as_str()
|
self.config.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line_comment_prefix(&self) -> Option<&str> {
|
pub fn line_comment_prefix(&self) -> Option<&str> {
|
||||||
|
|
|
@ -24,10 +24,10 @@ fn init_logger() {
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
fn test_select_language() {
|
fn test_select_language() {
|
||||||
let mut registry = LanguageRegistry::new();
|
let registry = LanguageRegistry::new();
|
||||||
registry.add(Arc::new(Language::new(
|
registry.add(Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Rust".to_string(),
|
name: "Rust".into(),
|
||||||
path_suffixes: vec!["rs".to_string()],
|
path_suffixes: vec!["rs".to_string()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -35,7 +35,7 @@ fn test_select_language() {
|
||||||
)));
|
)));
|
||||||
registry.add(Arc::new(Language::new(
|
registry.add(Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Make".to_string(),
|
name: "Make".into(),
|
||||||
path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
|
path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -45,17 +45,17 @@ fn test_select_language() {
|
||||||
// matching file extension
|
// matching file extension
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
registry.select_language("zed/lib.rs").map(|l| l.name()),
|
registry.select_language("zed/lib.rs").map(|l| l.name()),
|
||||||
Some("Rust")
|
Some("Rust".into())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
registry.select_language("zed/lib.mk").map(|l| l.name()),
|
registry.select_language("zed/lib.mk").map(|l| l.name()),
|
||||||
Some("Make")
|
Some("Make".into())
|
||||||
);
|
);
|
||||||
|
|
||||||
// matching filename
|
// matching filename
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
registry.select_language("zed/Makefile").map(|l| l.name()),
|
registry.select_language("zed/Makefile").map(|l| l.name()),
|
||||||
Some("Make")
|
Some("Make".into())
|
||||||
);
|
);
|
||||||
|
|
||||||
// matching suffix that is not the full file extension or filename
|
// matching suffix that is not the full file extension or filename
|
||||||
|
@ -1354,7 +1354,7 @@ impl Buffer {
|
||||||
fn rust_lang() -> Language {
|
fn rust_lang() -> Language {
|
||||||
Language::new(
|
Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Rust".to_string(),
|
name: "Rust".into(),
|
||||||
path_suffixes: vec!["rs".to_string()],
|
path_suffixes: vec!["rs".to_string()],
|
||||||
language_server: None,
|
language_server: None,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
|
@ -387,6 +387,11 @@ impl Project {
|
||||||
.any(|buffer| matches!(buffer, OpenBuffer::Loading(_)))
|
.any(|buffer| matches!(buffer, OpenBuffer::Loading(_)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
pub fn languages(&self) -> &Arc<LanguageRegistry> {
|
||||||
|
&self.languages
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fs(&self) -> &Arc<dyn Fs> {
|
pub fn fs(&self) -> &Arc<dyn Fs> {
|
||||||
&self.fs
|
&self.fs
|
||||||
}
|
}
|
||||||
|
@ -817,7 +822,7 @@ impl Project {
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the buffer has a language, set it and start/assign the language server
|
// If the buffer has a language, set it and start/assign the language server
|
||||||
if let Some(language) = self.languages.select_language(&full_path).cloned() {
|
if let Some(language) = self.languages.select_language(&full_path) {
|
||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.set_language(Some(language.clone()), cx);
|
buffer.set_language(Some(language.clone()), cx);
|
||||||
});
|
});
|
||||||
|
@ -3386,7 +3391,7 @@ mod tests {
|
||||||
|
|
||||||
let language = Arc::new(Language::new(
|
let language = Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Rust".to_string(),
|
name: "Rust".into(),
|
||||||
path_suffixes: vec!["rs".to_string()],
|
path_suffixes: vec!["rs".to_string()],
|
||||||
language_server: Some(language_server_config),
|
language_server: Some(language_server_config),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -3532,7 +3537,7 @@ mod tests {
|
||||||
let (language_server_config, mut fake_servers) = LanguageServerConfig::fake();
|
let (language_server_config, mut fake_servers) = LanguageServerConfig::fake();
|
||||||
let language = Arc::new(Language::new(
|
let language = Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Rust".to_string(),
|
name: "Rust".into(),
|
||||||
path_suffixes: vec!["rs".to_string()],
|
path_suffixes: vec!["rs".to_string()],
|
||||||
language_server: Some(language_server_config),
|
language_server: Some(language_server_config),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -4425,7 +4430,7 @@ mod tests {
|
||||||
let (language_server_config, mut fake_servers) = LanguageServerConfig::fake();
|
let (language_server_config, mut fake_servers) = LanguageServerConfig::fake();
|
||||||
let language = Arc::new(Language::new(
|
let language = Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Rust".to_string(),
|
name: "Rust".into(),
|
||||||
path_suffixes: vec!["rs".to_string()],
|
path_suffixes: vec!["rs".to_string()],
|
||||||
language_server: Some(language_server_config),
|
language_server: Some(language_server_config),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
|
@ -2035,7 +2035,7 @@ mod tests {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add(Arc::new(Language::new(
|
.add(Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Rust".to_string(),
|
name: "Rust".into(),
|
||||||
path_suffixes: vec!["rs".to_string()],
|
path_suffixes: vec!["rs".to_string()],
|
||||||
language_server: Some(language_server_config),
|
language_server: Some(language_server_config),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -2266,7 +2266,7 @@ mod tests {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add(Arc::new(Language::new(
|
.add(Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Rust".to_string(),
|
name: "Rust".into(),
|
||||||
path_suffixes: vec!["rs".to_string()],
|
path_suffixes: vec!["rs".to_string()],
|
||||||
language_server: Some(language_server_config),
|
language_server: Some(language_server_config),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -2468,7 +2468,7 @@ mod tests {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add(Arc::new(Language::new(
|
.add(Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Rust".to_string(),
|
name: "Rust".into(),
|
||||||
path_suffixes: vec!["rs".to_string()],
|
path_suffixes: vec!["rs".to_string()],
|
||||||
language_server: Some(language_server_config),
|
language_server: Some(language_server_config),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -2585,7 +2585,7 @@ mod tests {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add(Arc::new(Language::new(
|
.add(Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Rust".to_string(),
|
name: "Rust".into(),
|
||||||
path_suffixes: vec!["rs".to_string()],
|
path_suffixes: vec!["rs".to_string()],
|
||||||
language_server: Some(language_server_config),
|
language_server: Some(language_server_config),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -2733,7 +2733,7 @@ mod tests {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add(Arc::new(Language::new(
|
.add(Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Rust".to_string(),
|
name: "Rust".into(),
|
||||||
path_suffixes: vec!["rs".to_string()],
|
path_suffixes: vec!["rs".to_string()],
|
||||||
language_server: Some(language_server_config),
|
language_server: Some(language_server_config),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -2834,7 +2834,7 @@ mod tests {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add(Arc::new(Language::new(
|
.add(Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Rust".to_string(),
|
name: "Rust".into(),
|
||||||
path_suffixes: vec!["rs".to_string()],
|
path_suffixes: vec!["rs".to_string()],
|
||||||
language_server: Some(language_server_config),
|
language_server: Some(language_server_config),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -3073,7 +3073,7 @@ mod tests {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add(Arc::new(Language::new(
|
.add(Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Rust".to_string(),
|
name: "Rust".into(),
|
||||||
path_suffixes: vec!["rs".to_string()],
|
path_suffixes: vec!["rs".to_string()],
|
||||||
language_server: Some(language_server_config),
|
language_server: Some(language_server_config),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -3842,50 +3842,8 @@ mod tests {
|
||||||
|
|
||||||
let rng = Rc::new(RefCell::new(rng));
|
let rng = Rc::new(RefCell::new(rng));
|
||||||
|
|
||||||
let mut host_lang_registry = Arc::new(LanguageRegistry::new());
|
|
||||||
let guest_lang_registry = Arc::new(LanguageRegistry::new());
|
let guest_lang_registry = Arc::new(LanguageRegistry::new());
|
||||||
|
let (language_server_config, _fake_language_servers) = LanguageServerConfig::fake();
|
||||||
// Set up a fake language server.
|
|
||||||
let (mut language_server_config, _fake_language_servers) = LanguageServerConfig::fake();
|
|
||||||
language_server_config.set_fake_initializer(|fake_server| {
|
|
||||||
fake_server.handle_request::<lsp::request::Completion, _>(|_| {
|
|
||||||
Some(lsp::CompletionResponse::Array(vec![lsp::CompletionItem {
|
|
||||||
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
|
||||||
range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 0)),
|
|
||||||
new_text: "the-new-text".to_string(),
|
|
||||||
})),
|
|
||||||
..Default::default()
|
|
||||||
}]))
|
|
||||||
});
|
|
||||||
|
|
||||||
fake_server.handle_request::<lsp::request::CodeActionRequest, _>(|_| {
|
|
||||||
Some(vec![lsp::CodeActionOrCommand::CodeAction(
|
|
||||||
lsp::CodeAction {
|
|
||||||
title: "the-code-action".to_string(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)])
|
|
||||||
});
|
|
||||||
|
|
||||||
fake_server.handle_request::<lsp::request::PrepareRenameRequest, _>(|params| {
|
|
||||||
Some(lsp::PrepareRenameResponse::Range(lsp::Range::new(
|
|
||||||
params.position,
|
|
||||||
params.position,
|
|
||||||
)))
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Arc::get_mut(&mut host_lang_registry)
|
|
||||||
.unwrap()
|
|
||||||
.add(Arc::new(Language::new(
|
|
||||||
LanguageConfig {
|
|
||||||
name: "Rust".to_string(),
|
|
||||||
path_suffixes: vec!["rs".to_string()],
|
|
||||||
language_server: Some(language_server_config),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
)));
|
|
||||||
|
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
fs.insert_tree(
|
fs.insert_tree(
|
||||||
|
@ -3914,7 +3872,7 @@ mod tests {
|
||||||
Project::local(
|
Project::local(
|
||||||
host.client.clone(),
|
host.client.clone(),
|
||||||
host.user_store.clone(),
|
host.user_store.clone(),
|
||||||
host_lang_registry.clone(),
|
Arc::new(LanguageRegistry::new()),
|
||||||
fs.clone(),
|
fs.clone(),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -3939,6 +3897,7 @@ mod tests {
|
||||||
|
|
||||||
clients.push(cx.foreground().spawn(host.simulate_host(
|
clients.push(cx.foreground().spawn(host.simulate_host(
|
||||||
host_project.clone(),
|
host_project.clone(),
|
||||||
|
language_server_config,
|
||||||
operations.clone(),
|
operations.clone(),
|
||||||
max_operations,
|
max_operations,
|
||||||
rng.clone(),
|
rng.clone(),
|
||||||
|
@ -4268,14 +4227,60 @@ mod tests {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn simulate_host(
|
fn simulate_host(
|
||||||
mut self,
|
mut self,
|
||||||
project: ModelHandle<Project>,
|
project: ModelHandle<Project>,
|
||||||
|
mut language_server_config: LanguageServerConfig,
|
||||||
operations: Rc<Cell<usize>>,
|
operations: Rc<Cell<usize>>,
|
||||||
max_operations: usize,
|
max_operations: usize,
|
||||||
rng: Rc<RefCell<StdRng>>,
|
rng: Rc<RefCell<StdRng>>,
|
||||||
mut cx: TestAppContext,
|
mut cx: TestAppContext,
|
||||||
) -> (Self, TestAppContext) {
|
) -> impl Future<Output = (Self, TestAppContext)> {
|
||||||
|
// Set up a fake language server.
|
||||||
|
language_server_config.set_fake_initializer(|fake_server| {
|
||||||
|
fake_server.handle_request::<lsp::request::Completion, _>(|_| {
|
||||||
|
Some(lsp::CompletionResponse::Array(vec![lsp::CompletionItem {
|
||||||
|
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||||
|
range: lsp::Range::new(
|
||||||
|
lsp::Position::new(0, 0),
|
||||||
|
lsp::Position::new(0, 0),
|
||||||
|
),
|
||||||
|
new_text: "the-new-text".to_string(),
|
||||||
|
})),
|
||||||
|
..Default::default()
|
||||||
|
}]))
|
||||||
|
});
|
||||||
|
|
||||||
|
fake_server.handle_request::<lsp::request::CodeActionRequest, _>(|_| {
|
||||||
|
Some(vec![lsp::CodeActionOrCommand::CodeAction(
|
||||||
|
lsp::CodeAction {
|
||||||
|
title: "the-code-action".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)])
|
||||||
|
});
|
||||||
|
|
||||||
|
fake_server.handle_request::<lsp::request::PrepareRenameRequest, _>(|params| {
|
||||||
|
Some(lsp::PrepareRenameResponse::Range(lsp::Range::new(
|
||||||
|
params.position,
|
||||||
|
params.position,
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
project.update(&mut cx, |project, _| {
|
||||||
|
project.languages().add(Arc::new(Language::new(
|
||||||
|
LanguageConfig {
|
||||||
|
name: "Rust".into(),
|
||||||
|
path_suffixes: vec!["rs".to_string()],
|
||||||
|
language_server: Some(language_server_config),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)));
|
||||||
|
});
|
||||||
|
|
||||||
|
async move {
|
||||||
let fs = project.read_with(&cx, |project, _| project.fs().clone());
|
let fs = project.read_with(&cx, |project, _| project.fs().clone());
|
||||||
let mut files: Vec<PathBuf> = Default::default();
|
let mut files: Vec<PathBuf> = Default::default();
|
||||||
while operations.get() < max_operations {
|
while operations.get() < max_operations {
|
||||||
|
@ -4376,6 +4381,7 @@ mod tests {
|
||||||
self.project = Some(project);
|
self.project = Some(project);
|
||||||
(self, cx)
|
(self, cx)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn simulate_guest(
|
pub async fn simulate_guest(
|
||||||
mut self,
|
mut self,
|
||||||
|
|
|
@ -37,7 +37,7 @@ impl LspStatus {
|
||||||
&mut this.downloading,
|
&mut this.downloading,
|
||||||
&mut this.failed,
|
&mut this.failed,
|
||||||
] {
|
] {
|
||||||
vector.retain(|name| name != language.name());
|
vector.retain(|name| name != language.name().as_ref());
|
||||||
}
|
}
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub struct Settings {
|
||||||
pub tab_size: usize,
|
pub tab_size: usize,
|
||||||
soft_wrap: SoftWrap,
|
soft_wrap: SoftWrap,
|
||||||
preferred_line_length: u32,
|
preferred_line_length: u32,
|
||||||
overrides: HashMap<String, Override>,
|
overrides: HashMap<Arc<str>, Override>,
|
||||||
pub theme: Arc<Theme>,
|
pub theme: Arc<Theme>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,21 +50,25 @@ impl Settings {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_overrides(mut self, language_name: impl Into<String>, overrides: Override) -> Self {
|
pub fn with_overrides(
|
||||||
|
mut self,
|
||||||
|
language_name: impl Into<Arc<str>>,
|
||||||
|
overrides: Override,
|
||||||
|
) -> Self {
|
||||||
self.overrides.insert(language_name.into(), overrides);
|
self.overrides.insert(language_name.into(), overrides);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn soft_wrap(&self, language: Option<&Arc<Language>>) -> SoftWrap {
|
pub fn soft_wrap(&self, language: Option<&Arc<Language>>) -> SoftWrap {
|
||||||
language
|
language
|
||||||
.and_then(|language| self.overrides.get(language.name()))
|
.and_then(|language| self.overrides.get(language.name().as_ref()))
|
||||||
.and_then(|settings| settings.soft_wrap)
|
.and_then(|settings| settings.soft_wrap)
|
||||||
.unwrap_or(self.soft_wrap)
|
.unwrap_or(self.soft_wrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn preferred_line_length(&self, language: Option<&Arc<Language>>) -> u32 {
|
pub fn preferred_line_length(&self, language: Option<&Arc<Language>>) -> u32 {
|
||||||
language
|
language
|
||||||
.and_then(|language| self.overrides.get(language.name()))
|
.and_then(|language| self.overrides.get(language.name().as_ref()))
|
||||||
.and_then(|settings| settings.preferred_line_length)
|
.and_then(|settings| settings.preferred_line_length)
|
||||||
.unwrap_or(self.preferred_line_length)
|
.unwrap_or(self.preferred_line_length)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,18 +25,15 @@ pub fn test_app_state(cx: &mut MutableAppContext) -> Arc<AppState> {
|
||||||
let http = FakeHttpClient::with_404_response();
|
let http = FakeHttpClient::with_404_response();
|
||||||
let client = Client::new(http.clone());
|
let client = Client::new(http.clone());
|
||||||
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx));
|
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx));
|
||||||
let mut languages = LanguageRegistry::new();
|
let languages = LanguageRegistry::new();
|
||||||
languages.add(
|
languages.add(Arc::new(language::Language::new(
|
||||||
Arc::new(language::Language::new(
|
|
||||||
language::LanguageConfig {
|
language::LanguageConfig {
|
||||||
name: "Rust".to_string(),
|
name: "Rust".into(),
|
||||||
path_suffixes: vec!["rs".to_string()],
|
path_suffixes: vec!["rs".to_string()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Some(tree_sitter_rust::language()),
|
Some(tree_sitter_rust::language()),
|
||||||
)),
|
)));
|
||||||
|
|
||||||
);
|
|
||||||
Arc::new(AppState {
|
Arc::new(AppState {
|
||||||
settings_tx: Arc::new(Mutex::new(settings_tx)),
|
settings_tx: Arc::new(Mutex::new(settings_tx)),
|
||||||
settings,
|
settings,
|
||||||
|
|
|
@ -534,7 +534,7 @@ mod tests {
|
||||||
editor.read_with(&cx, |editor, cx| {
|
editor.read_with(&cx, |editor, cx| {
|
||||||
assert!(!editor.is_dirty(cx));
|
assert!(!editor.is_dirty(cx));
|
||||||
assert_eq!(editor.title(cx), "the-new-name.rs");
|
assert_eq!(editor.title(cx), "the-new-name.rs");
|
||||||
assert_eq!(editor.language(cx).unwrap().name(), "Rust");
|
assert_eq!(editor.language(cx).unwrap().name().as_ref(), "Rust");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Edit the file and save it again. This time, there is no filename prompt.
|
// Edit the file and save it again. This time, there is no filename prompt.
|
||||||
|
@ -614,7 +614,7 @@ mod tests {
|
||||||
// The buffer is not dirty anymore and the language is assigned based on the path.
|
// The buffer is not dirty anymore and the language is assigned based on the path.
|
||||||
editor.read_with(&cx, |editor, cx| {
|
editor.read_with(&cx, |editor, cx| {
|
||||||
assert!(!editor.is_dirty(cx));
|
assert!(!editor.is_dirty(cx));
|
||||||
assert_eq!(editor.language(cx).unwrap().name(), "Rust")
|
assert_eq!(editor.language(cx).unwrap().name().as_ref(), "Rust")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue