Add a setting for custom associations between languages and files (#9290)
Closes #5178 Release Notes: - Added a `file_types` setting that can be used to associate languages with file names and file extensions. For example, to interpret all `.c` files as C++, and files called `MyLockFile` as TOML, add the following to `settings.json`: ```json { "file_types": { "C++": ["c"], "TOML": ["MyLockFile"] } } ``` As with most zed settings, this can be configured on a per-directory basis by including a local `.zed/settings.json` file in that directory. --------- Co-authored-by: Marshall <marshall@zed.dev>
This commit is contained in:
co-authored by
Marshall
parent
77de5689a3
commit
724c19a223
@@ -9302,8 +9302,7 @@ impl Editor {
|
||||
.redacted_ranges(search_range, |file| {
|
||||
if let Some(file) = file {
|
||||
file.is_private()
|
||||
&& EditorSettings::get(Some((file.worktree_id(), file.path())), cx)
|
||||
.redact_private_values
|
||||
&& EditorSettings::get(Some(file.as_ref().into()), cx).redact_private_values
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@@ -9645,22 +9644,16 @@ impl Editor {
|
||||
telemetry.report_copilot_event(suggestion_id, suggestion_accepted, file_extension)
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
fn report_editor_event(
|
||||
&self,
|
||||
_operation: &'static str,
|
||||
_file_extension: Option<String>,
|
||||
_cx: &AppContext,
|
||||
) {
|
||||
}
|
||||
|
||||
#[cfg(not(any(test, feature = "test-support")))]
|
||||
fn report_editor_event(
|
||||
&self,
|
||||
operation: &'static str,
|
||||
file_extension: Option<String>,
|
||||
cx: &AppContext,
|
||||
) {
|
||||
if cfg!(any(test, feature = "test-support")) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(project) = &self.project else { return };
|
||||
|
||||
// If None, we are in a file without an extension
|
||||
|
||||
@@ -15,8 +15,7 @@ use language::{
|
||||
language_settings::{AllLanguageSettings, AllLanguageSettingsContent, LanguageSettingsContent},
|
||||
BracketPairConfig,
|
||||
Capability::ReadWrite,
|
||||
FakeLspAdapter, LanguageConfig, LanguageConfigOverride, LanguageMatcher, LanguageRegistry,
|
||||
Override, Point,
|
||||
FakeLspAdapter, LanguageConfig, LanguageConfigOverride, LanguageMatcher, Override, Point,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use project::project_settings::{LspSettings, ProjectSettings};
|
||||
@@ -4447,10 +4446,8 @@ async fn test_autoclose_pairs(cx: &mut gpui::TestAppContext) {
|
||||
Some(tree_sitter_rust::language()),
|
||||
));
|
||||
|
||||
let registry = Arc::new(LanguageRegistry::test());
|
||||
registry.add(language.clone());
|
||||
cx.language_registry().add(language.clone());
|
||||
cx.update_buffer(|buffer, cx| {
|
||||
buffer.set_language_registry(registry);
|
||||
buffer.set_language(Some(language), cx);
|
||||
});
|
||||
|
||||
@@ -4649,12 +4646,10 @@ async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) {
|
||||
Some(tree_sitter_typescript::language_tsx()),
|
||||
));
|
||||
|
||||
let registry = Arc::new(LanguageRegistry::test());
|
||||
registry.add(html_language.clone());
|
||||
registry.add(javascript_language.clone());
|
||||
cx.language_registry().add(html_language.clone());
|
||||
cx.language_registry().add(javascript_language.clone());
|
||||
|
||||
cx.update_buffer(|buffer, cx| {
|
||||
buffer.set_language_registry(registry);
|
||||
buffer.set_language(Some(html_language), cx);
|
||||
});
|
||||
|
||||
@@ -4829,11 +4824,8 @@ async fn test_autoclose_with_overrides(cx: &mut gpui::TestAppContext) {
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let registry = Arc::new(LanguageRegistry::test());
|
||||
registry.add(rust_language.clone());
|
||||
|
||||
cx.language_registry().add(rust_language.clone());
|
||||
cx.update_buffer(|buffer, cx| {
|
||||
buffer.set_language_registry(registry);
|
||||
buffer.set_language(Some(rust_language), cx);
|
||||
});
|
||||
|
||||
@@ -6139,12 +6131,10 @@ async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext)
|
||||
Some(tree_sitter_rust::language()),
|
||||
));
|
||||
|
||||
let registry = Arc::new(LanguageRegistry::test());
|
||||
registry.add(language.clone());
|
||||
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
|
||||
cx.language_registry().add(language.clone());
|
||||
cx.update_buffer(|buffer, cx| {
|
||||
buffer.set_language_registry(registry);
|
||||
buffer.set_language(Some(language), cx);
|
||||
});
|
||||
|
||||
@@ -6294,12 +6284,9 @@ async fn test_toggle_block_comment(cx: &mut gpui::TestAppContext) {
|
||||
Some(tree_sitter_typescript::language_tsx()),
|
||||
));
|
||||
|
||||
let registry = Arc::new(LanguageRegistry::test());
|
||||
registry.add(html_language.clone());
|
||||
registry.add(javascript_language.clone());
|
||||
|
||||
cx.language_registry().add(html_language.clone());
|
||||
cx.language_registry().add(javascript_language.clone());
|
||||
cx.update_buffer(|buffer, cx| {
|
||||
buffer.set_language_registry(registry);
|
||||
buffer.set_language(Some(html_language), cx);
|
||||
});
|
||||
|
||||
|
||||
@@ -824,6 +824,8 @@ mod tests {
|
||||
.next()
|
||||
.await;
|
||||
|
||||
let languages = cx.language_registry().clone();
|
||||
|
||||
cx.condition(|editor, _| editor.hover_state.visible()).await;
|
||||
cx.editor(|editor, _| {
|
||||
let blocks = editor.hover_state.info_popover.clone().unwrap().blocks;
|
||||
@@ -835,7 +837,7 @@ mod tests {
|
||||
}],
|
||||
);
|
||||
|
||||
let rendered = smol::block_on(parse_blocks(&blocks, &Default::default(), None));
|
||||
let rendered = smol::block_on(parse_blocks(&blocks, &languages, None));
|
||||
assert_eq!(
|
||||
rendered.text,
|
||||
code_str.trim(),
|
||||
@@ -916,6 +918,7 @@ mod tests {
|
||||
fn test_render_blocks(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let languages = Arc::new(LanguageRegistry::test(cx.executor()));
|
||||
let editor = cx.add_window(|cx| Editor::single_line(cx));
|
||||
editor
|
||||
.update(cx, |editor, _cx| {
|
||||
@@ -1028,7 +1031,7 @@ mod tests {
|
||||
expected_styles,
|
||||
} in &rows[0..]
|
||||
{
|
||||
let rendered = smol::block_on(parse_blocks(&blocks, &Default::default(), None));
|
||||
let rendered = smol::block_on(parse_blocks(&blocks, &languages, None));
|
||||
|
||||
let (expected_text, ranges) = marked_text_ranges(expected_marked_text, false);
|
||||
let expected_highlights = ranges
|
||||
|
||||
@@ -3387,17 +3387,7 @@ pub mod tests {
|
||||
let project = Project::test(fs, ["/a".as_ref()], cx).await;
|
||||
|
||||
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
|
||||
language_registry.add(Arc::new(Language::new(
|
||||
LanguageConfig {
|
||||
name: "Rust".into(),
|
||||
matcher: LanguageMatcher {
|
||||
path_suffixes: vec!["rs".to_string()],
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
Some(tree_sitter_rust::language()),
|
||||
)));
|
||||
language_registry.add(crate::editor_tests::rust_lang());
|
||||
let mut fake_servers = language_registry.register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
|
||||
@@ -1247,65 +1247,15 @@ fn path_for_file<'a>(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use gpui::AppContext;
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
time::SystemTime,
|
||||
};
|
||||
use language::TestFile;
|
||||
use std::path::Path;
|
||||
|
||||
#[gpui::test]
|
||||
fn test_path_for_file(cx: &mut AppContext) {
|
||||
let file = TestFile {
|
||||
path: Path::new("").into(),
|
||||
full_path: PathBuf::from(""),
|
||||
root_name: String::new(),
|
||||
};
|
||||
assert_eq!(path_for_file(&file, 0, false, cx), None);
|
||||
}
|
||||
|
||||
struct TestFile {
|
||||
path: Arc<Path>,
|
||||
full_path: PathBuf,
|
||||
}
|
||||
|
||||
impl language::File for TestFile {
|
||||
fn path(&self) -> &Arc<Path> {
|
||||
&self.path
|
||||
}
|
||||
|
||||
fn full_path(&self, _: &gpui::AppContext) -> PathBuf {
|
||||
self.full_path.clone()
|
||||
}
|
||||
|
||||
fn as_local(&self) -> Option<&dyn language::LocalFile> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn mtime(&self) -> Option<SystemTime> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn file_name<'a>(&'a self, _: &'a gpui::AppContext) -> &'a std::ffi::OsStr {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn worktree_id(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn is_deleted(&self) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn to_proto(&self) -> rpc::proto::File {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn is_private(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use gpui::{
|
||||
};
|
||||
use indoc::indoc;
|
||||
use itertools::Itertools;
|
||||
use language::{Buffer, BufferSnapshot};
|
||||
use language::{Buffer, BufferSnapshot, LanguageRegistry};
|
||||
use parking_lot::RwLock;
|
||||
use project::{FakeFs, Project};
|
||||
use std::{
|
||||
@@ -120,6 +120,18 @@ impl EditorTestContext {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn language_registry(&mut self) -> Arc<LanguageRegistry> {
|
||||
self.editor(|editor, cx| {
|
||||
editor
|
||||
.project
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.read(cx)
|
||||
.languages()
|
||||
.clone()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn update_buffer<F, T>(&mut self, update: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Buffer, &mut ModelContext<Buffer>) -> T,
|
||||
|
||||
Reference in New Issue
Block a user