Define language settings in the language crate

This commit is contained in:
Max Brunsfeld 2023-05-11 14:40:35 -07:00
parent 9ae10a5dd9
commit 39618ae32d
54 changed files with 1348 additions and 1161 deletions

View file

@ -23,6 +23,7 @@ use gpui::{
ModelHandle, Task, WeakModelHandle,
};
use language::{
language_settings::{all_language_settings, language_settings, FormatOnSave, Formatter},
point_to_lsp,
proto::{
deserialize_anchor, deserialize_fingerprint, deserialize_line_ending, deserialize_version,
@ -44,7 +45,7 @@ use postage::watch;
use rand::prelude::*;
use search::SearchQuery;
use serde::Serialize;
use settings::{FormatOnSave, Formatter, Settings};
use settings::{Settings, SettingsStore};
use sha2::{Digest, Sha256};
use similar::{ChangeTag, TextDiff};
use std::{
@ -64,9 +65,7 @@ use std::{
},
time::{Duration, Instant, SystemTime},
};
use terminals::Terminals;
use util::{debug_panic, defer, merge_json_value_into, post_inc, ResultExt, TryFutureExt as _};
pub use fs::*;
@ -454,7 +453,9 @@ impl Project {
client_state: None,
opened_buffer: watch::channel(),
client_subscriptions: Vec::new(),
_subscriptions: vec![cx.observe_global::<Settings, _>(Self::on_settings_changed)],
_subscriptions: vec![
cx.observe_global::<SettingsStore, _>(Self::on_settings_changed)
],
_maintain_buffer_languages: Self::maintain_buffer_languages(&languages, cx),
_maintain_workspace_config: Self::maintain_workspace_config(languages.clone(), cx),
active_entry: None,
@ -622,7 +623,7 @@ impl Project {
}
fn on_settings_changed(&mut self, cx: &mut ModelContext<Self>) {
let settings = cx.global::<Settings>();
let settings = all_language_settings(None, cx);
let mut language_servers_to_start = Vec::new();
for buffer in self.opened_buffers.values() {
@ -630,7 +631,10 @@ impl Project {
let buffer = buffer.read(cx);
if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language())
{
if settings.enable_language_server(Some(&language.name())) {
if settings
.language(Some(&language.name()))
.enable_language_server
{
let worktree = file.worktree.read(cx);
language_servers_to_start.push((
worktree.id(),
@ -645,7 +649,10 @@ impl Project {
let mut language_servers_to_stop = Vec::new();
for language in self.languages.to_vec() {
for lsp_adapter in language.lsp_adapters() {
if !settings.enable_language_server(Some(&language.name())) {
if !settings
.language(Some(&language.name()))
.enable_language_server
{
let lsp_name = &lsp_adapter.name;
for (worktree_id, started_lsp_name) in self.language_server_ids.keys() {
if lsp_name == started_lsp_name {
@ -2178,10 +2185,7 @@ impl Project {
language: Arc<Language>,
cx: &mut ModelContext<Self>,
) {
if !cx
.global::<Settings>()
.enable_language_server(Some(&language.name()))
{
if !language_settings(None, Some(&language.name()), cx).enable_language_server {
return;
}
@ -3228,24 +3232,18 @@ impl Project {
let mut project_transaction = ProjectTransaction::default();
for (buffer, buffer_abs_path, language_server) in &buffers_with_paths_and_servers {
let (
format_on_save,
remove_trailing_whitespace,
ensure_final_newline,
formatter,
tab_size,
) = buffer.read_with(&cx, |buffer, cx| {
let settings = cx.global::<Settings>();
let settings = buffer.read_with(&cx, |buffer, cx| {
let language_name = buffer.language().map(|language| language.name());
(
settings.format_on_save(language_name.as_deref()),
settings.remove_trailing_whitespace_on_save(language_name.as_deref()),
settings.ensure_final_newline_on_save(language_name.as_deref()),
settings.formatter(language_name.as_deref()),
settings.tab_size(language_name.as_deref()),
)
language_settings(buffer_abs_path.as_deref(), language_name.as_deref(), cx)
.clone()
});
let remove_trailing_whitespace = settings.remove_trailing_whitespace_on_save;
let ensure_final_newline = settings.ensure_final_newline_on_save;
let format_on_save = settings.format_on_save.clone();
let formatter = settings.formatter.clone();
let tab_size = settings.tab_size;
// First, format buffer's whitespace according to the settings.
let trailing_whitespace_diff = if remove_trailing_whitespace {
Some(

View file

@ -1,10 +1,9 @@
use crate::{worktree::WorktreeHandle, Event, *};
use fs::LineEnding;
use fs::{FakeFs, RealFs};
use fs::{FakeFs, LineEnding, RealFs};
use futures::{future, StreamExt};
use gpui::AppContext;
use gpui::{executor::Deterministic, test::subscribe};
use gpui::{executor::Deterministic, test::subscribe, AppContext};
use language::{
language_settings::{AllLanguageSettings, LanguageSettingsContent},
tree_sitter_rust, tree_sitter_typescript, Diagnostic, FakeLspAdapter, LanguageConfig,
OffsetRangeExt, Point, ToPoint,
};
@ -26,6 +25,9 @@ fn init_logger() {
#[gpui::test]
async fn test_symlinks(cx: &mut gpui::TestAppContext) {
init_test(cx);
cx.foreground().allow_parking();
let dir = temp_tree(json!({
"root": {
"apple": "",
@ -65,7 +67,7 @@ async fn test_managing_language_servers(
deterministic: Arc<Deterministic>,
cx: &mut gpui::TestAppContext,
) {
cx.foreground().forbid_parking();
init_test(cx);
let mut rust_language = Language::new(
LanguageConfig {
@ -451,7 +453,7 @@ async fn test_managing_language_servers(
#[gpui::test]
async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
init_test(cx);
let mut language = Language::new(
LanguageConfig {
@ -556,7 +558,7 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
#[gpui::test]
async fn test_single_file_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
init_test(cx);
let fs = FakeFs::new(cx.background());
fs.insert_tree(
@ -648,7 +650,7 @@ async fn test_single_file_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
init_test(cx);
let fs = FakeFs::new(cx.background());
fs.insert_tree(
@ -719,7 +721,7 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
init_test(cx);
let progress_token = "the-progress-token";
let mut language = Language::new(
@ -847,7 +849,7 @@ async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
init_test(cx);
let progress_token = "the-progress-token";
let mut language = Language::new(
@ -925,7 +927,7 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC
#[gpui::test]
async fn test_restarted_server_reporting_invalid_buffer_version(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
init_test(cx);
let mut language = Language::new(
LanguageConfig {
@ -973,11 +975,8 @@ async fn test_restarted_server_reporting_invalid_buffer_version(cx: &mut gpui::T
}
#[gpui::test]
async fn test_toggling_enable_language_server(
deterministic: Arc<Deterministic>,
cx: &mut gpui::TestAppContext,
) {
deterministic.forbid_parking();
async fn test_toggling_enable_language_server(cx: &mut gpui::TestAppContext) {
init_test(cx);
let mut rust = Language::new(
LanguageConfig {
@ -1051,14 +1050,16 @@ async fn test_toggling_enable_language_server(
// Disable Rust language server, ensuring only that server gets stopped.
cx.update(|cx| {
cx.update_global(|settings: &mut Settings, _| {
settings.language_overrides.insert(
Arc::from("Rust"),
settings::EditorSettings {
enable_language_server: Some(false),
..Default::default()
},
);
cx.update_global(|settings: &mut SettingsStore, cx| {
settings.update_user_settings::<AllLanguageSettings>(cx, |settings| {
settings.languages.insert(
Arc::from("Rust"),
LanguageSettingsContent {
enable_language_server: Some(false),
..Default::default()
},
);
});
})
});
fake_rust_server_1
@ -1068,21 +1069,23 @@ async fn test_toggling_enable_language_server(
// Enable Rust and disable JavaScript language servers, ensuring that the
// former gets started again and that the latter stops.
cx.update(|cx| {
cx.update_global(|settings: &mut Settings, _| {
settings.language_overrides.insert(
Arc::from("Rust"),
settings::EditorSettings {
enable_language_server: Some(true),
..Default::default()
},
);
settings.language_overrides.insert(
Arc::from("JavaScript"),
settings::EditorSettings {
enable_language_server: Some(false),
..Default::default()
},
);
cx.update_global(|settings: &mut SettingsStore, cx| {
settings.update_user_settings::<AllLanguageSettings>(cx, |settings| {
settings.languages.insert(
Arc::from("Rust"),
LanguageSettingsContent {
enable_language_server: Some(true),
..Default::default()
},
);
settings.languages.insert(
Arc::from("JavaScript"),
LanguageSettingsContent {
enable_language_server: Some(false),
..Default::default()
},
);
});
})
});
let mut fake_rust_server_2 = fake_rust_servers.next().await.unwrap();
@ -1102,7 +1105,7 @@ async fn test_toggling_enable_language_server(
#[gpui::test]
async fn test_transforming_diagnostics(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
init_test(cx);
let mut language = Language::new(
LanguageConfig {
@ -1388,7 +1391,7 @@ async fn test_transforming_diagnostics(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_empty_diagnostic_ranges(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
init_test(cx);
let text = concat!(
"let one = ;\n", //
@ -1457,9 +1460,7 @@ async fn test_empty_diagnostic_ranges(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_diagnostics_from_multiple_language_servers(cx: &mut gpui::TestAppContext) {
println!("hello from stdout");
eprintln!("hello from stderr");
cx.foreground().forbid_parking();
init_test(cx);
let fs = FakeFs::new(cx.background());
fs.insert_tree("/dir", json!({ "a.rs": "one two three" }))
@ -1515,7 +1516,7 @@ async fn test_diagnostics_from_multiple_language_servers(cx: &mut gpui::TestAppC
#[gpui::test]
async fn test_edits_from_lsp_with_past_version(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
init_test(cx);
let mut language = Language::new(
LanguageConfig {
@ -1673,7 +1674,7 @@ async fn test_edits_from_lsp_with_past_version(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_edits_from_lsp_with_edits_on_adjacent_lines(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
init_test(cx);
let text = "
use a::b;
@ -1781,7 +1782,7 @@ async fn test_edits_from_lsp_with_edits_on_adjacent_lines(cx: &mut gpui::TestApp
#[gpui::test]
async fn test_invalid_edits_from_lsp(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
init_test(cx);
let text = "
use a::b;
@ -1902,6 +1903,8 @@ fn chunks_with_diagnostics<T: ToOffset + ToPoint>(
#[gpui::test(iterations = 10)]
async fn test_definition(cx: &mut gpui::TestAppContext) {
init_test(cx);
let mut language = Language::new(
LanguageConfig {
name: "Rust".into(),
@ -2001,6 +2004,8 @@ async fn test_definition(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_completions_without_edit_ranges(cx: &mut gpui::TestAppContext) {
init_test(cx);
let mut language = Language::new(
LanguageConfig {
name: "TypeScript".into(),
@ -2085,6 +2090,8 @@ async fn test_completions_without_edit_ranges(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_completions_with_carriage_returns(cx: &mut gpui::TestAppContext) {
init_test(cx);
let mut language = Language::new(
LanguageConfig {
name: "TypeScript".into(),
@ -2138,6 +2145,8 @@ async fn test_completions_with_carriage_returns(cx: &mut gpui::TestAppContext) {
#[gpui::test(iterations = 10)]
async fn test_apply_code_actions_with_commands(cx: &mut gpui::TestAppContext) {
init_test(cx);
let mut language = Language::new(
LanguageConfig {
name: "TypeScript".into(),
@ -2254,6 +2263,8 @@ async fn test_apply_code_actions_with_commands(cx: &mut gpui::TestAppContext) {
#[gpui::test(iterations = 10)]
async fn test_save_file(cx: &mut gpui::TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.background());
fs.insert_tree(
"/dir",
@ -2284,6 +2295,8 @@ async fn test_save_file(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_save_in_single_file_worktree(cx: &mut gpui::TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.background());
fs.insert_tree(
"/dir",
@ -2313,6 +2326,8 @@ async fn test_save_in_single_file_worktree(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_save_as(cx: &mut gpui::TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.background());
fs.insert_tree("/dir", json!({})).await;
@ -2373,6 +2388,9 @@ async fn test_rescan_and_remote_updates(
deterministic: Arc<Deterministic>,
cx: &mut gpui::TestAppContext,
) {
init_test(cx);
cx.foreground().allow_parking();
let dir = temp_tree(json!({
"a": {
"file1": "",
@ -2529,6 +2547,8 @@ async fn test_buffer_identity_across_renames(
deterministic: Arc<Deterministic>,
cx: &mut gpui::TestAppContext,
) {
init_test(cx);
let fs = FakeFs::new(cx.background());
fs.insert_tree(
"/dir",
@ -2577,6 +2597,8 @@ async fn test_buffer_identity_across_renames(
#[gpui::test]
async fn test_buffer_deduping(cx: &mut gpui::TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.background());
fs.insert_tree(
"/dir",
@ -2621,6 +2643,8 @@ async fn test_buffer_deduping(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_buffer_is_dirty(cx: &mut gpui::TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.background());
fs.insert_tree(
"/dir",
@ -2765,6 +2789,8 @@ async fn test_buffer_is_dirty(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_buffer_file_changes_on_disk(cx: &mut gpui::TestAppContext) {
init_test(cx);
let initial_contents = "aaa\nbbbbb\nc\n";
let fs = FakeFs::new(cx.background());
fs.insert_tree(
@ -2844,6 +2870,8 @@ async fn test_buffer_file_changes_on_disk(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_buffer_line_endings(cx: &mut gpui::TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.background());
fs.insert_tree(
"/dir",
@ -2904,7 +2932,7 @@ async fn test_buffer_line_endings(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_grouped_diagnostics(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
init_test(cx);
let fs = FakeFs::new(cx.background());
fs.insert_tree(
@ -3146,7 +3174,7 @@ async fn test_grouped_diagnostics(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_rename(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
init_test(cx);
let mut language = Language::new(
LanguageConfig {
@ -3284,6 +3312,8 @@ async fn test_rename(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_search(cx: &mut gpui::TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.background());
fs.insert_tree(
"/dir",
@ -3339,6 +3369,8 @@ async fn test_search(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
init_test(cx);
let search_query = "file";
let fs = FakeFs::new(cx.background());
@ -3447,6 +3479,8 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
init_test(cx);
let search_query = "file";
let fs = FakeFs::new(cx.background());
@ -3554,6 +3588,8 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContext) {
init_test(cx);
let search_query = "file";
let fs = FakeFs::new(cx.background());
@ -3680,3 +3716,12 @@ async fn search(
})
.collect())
}
fn init_test(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
cx.update(|cx| {
cx.set_global(SettingsStore::test(cx));
language::init(cx);
});
}