Detailed changes
@@ -1104,22 +1104,28 @@
// Whether or not to perform a buffer format before saving: [on, off]
// Keep in mind, if the autosave with delay is enabled, format_on_save will be ignored
"format_on_save": "on",
- // How to perform a buffer format. This setting can take 4 values:
+ // How to perform a buffer format. This setting can take multiple values:
//
- // 1. Format code using the current language server:
+ // 1. Default. Format files using Zed's Prettier integration (if applicable),
+ // or falling back to formatting via language server:
+ // "formatter": "auto"
+ // 2. Format code using the current language server:
// "formatter": "language_server"
- // 2. Format code using an external command:
+ // 3. Format code using a specific language server:
+ // "formatter": {"language_server": {"name": "ruff"}}
+ // 4. Format code using an external command:
// "formatter": {
// "external": {
// "command": "prettier",
// "arguments": ["--stdin-filepath", "{buffer_path}"]
// }
// }
- // 3. Format code using Zed's Prettier integration:
+ // 5. Format code using Zed's Prettier integration:
// "formatter": "prettier"
- // 4. Default. Format files using Zed's Prettier integration (if applicable),
- // or falling back to formatting via language server:
- // "formatter": "auto"
+ // 6. Format code using a code action
+ // "formatter": {"code_action": "source.fixAll.eslint"}
+ // 7. An array of any format step specified above to apply in order
+ // "formatter": [{"code_action": "source.fixAll.eslint"}, "prettier"]
"formatter": "auto",
// How to soft-wrap long lines of text.
// Possible values:
@@ -1684,7 +1690,7 @@
"preferred_line_length": 72
},
"Go": {
- "formatter": [{ "code_action": "source.organizeImports" }, { "language_server": {} }],
+ "formatter": [{ "code_action": "source.organizeImports" }, "language_server"],
"debuggers": ["Delve"]
},
"GraphQL": {
@@ -790,7 +790,7 @@ mod tests {
store.update_user_settings(cx, |settings| {
settings.project.all_languages.defaults.format_on_save = Some(FormatOnSave::On);
settings.project.all_languages.defaults.formatter =
- Some(language::language_settings::SelectedFormatter::Auto);
+ Some(language::language_settings::FormatterList::default());
});
});
});
@@ -1538,7 +1538,7 @@ mod tests {
store.update_user_settings(cx, |settings| {
settings.project.all_languages.defaults.format_on_save = Some(FormatOnSave::On);
settings.project.all_languages.defaults.formatter =
- Some(language::language_settings::SelectedFormatter::Auto);
+ Some(language::language_settings::FormatterList::default());
});
});
});
@@ -25,7 +25,7 @@ use gpui::{
use language::{
Diagnostic, DiagnosticEntry, DiagnosticSourceKind, FakeLspAdapter, Language, LanguageConfig,
LanguageMatcher, LineEnding, OffsetRangeExt, Point, Rope,
- language_settings::{Formatter, FormatterList, SelectedFormatter},
+ language_settings::{Formatter, FormatterList},
tree_sitter_rust, tree_sitter_typescript,
};
use lsp::{LanguageServerId, OneOf};
@@ -39,7 +39,7 @@ use project::{
use prompt_store::PromptBuilder;
use rand::prelude::*;
use serde_json::json;
-use settings::{PrettierSettingsContent, SettingsStore};
+use settings::{LanguageServerFormatterSpecifier, PrettierSettingsContent, SettingsStore};
use std::{
cell::{Cell, RefCell},
env, future, mem,
@@ -4610,14 +4610,13 @@ async fn test_formatting_buffer(
cx_a.update(|cx| {
SettingsStore::update_global(cx, |store, cx| {
store.update_user_settings(cx, |file| {
- file.project.all_languages.defaults.formatter = Some(SelectedFormatter::List(
- FormatterList::Single(Formatter::External {
+ file.project.all_languages.defaults.formatter =
+ Some(FormatterList::Single(Formatter::External {
command: "awk".into(),
arguments: Some(
vec!["{sub(/two/,\"{buffer_path}\")}1".to_string()].into(),
),
- }),
- ));
+ }));
});
});
});
@@ -4708,7 +4707,7 @@ async fn test_prettier_formatting_buffer(
cx_a.update(|cx| {
SettingsStore::update_global(cx, |store, cx| {
store.update_user_settings(cx, |file| {
- file.project.all_languages.defaults.formatter = Some(SelectedFormatter::Auto);
+ file.project.all_languages.defaults.formatter = Some(FormatterList::default());
file.project.all_languages.defaults.prettier = Some(PrettierSettingsContent {
allowed: Some(true),
..Default::default()
@@ -4719,8 +4718,8 @@ async fn test_prettier_formatting_buffer(
cx_b.update(|cx| {
SettingsStore::update_global(cx, |store, cx| {
store.update_user_settings(cx, |file| {
- file.project.all_languages.defaults.formatter = Some(SelectedFormatter::List(
- FormatterList::Single(Formatter::LanguageServer { name: None }),
+ file.project.all_languages.defaults.formatter = Some(FormatterList::Single(
+ Formatter::LanguageServer(LanguageServerFormatterSpecifier::Current),
));
file.project.all_languages.defaults.prettier = Some(PrettierSettingsContent {
allowed: Some(true),
@@ -14,7 +14,7 @@ use gpui::{
use http_client::BlockedHttpClient;
use language::{
FakeLspAdapter, Language, LanguageConfig, LanguageMatcher, LanguageRegistry,
- language_settings::{Formatter, FormatterList, SelectedFormatter, language_settings},
+ language_settings::{Formatter, FormatterList, language_settings},
tree_sitter_typescript,
};
use node_runtime::NodeRuntime;
@@ -27,7 +27,7 @@ use remote::RemoteClient;
use remote_server::{HeadlessAppState, HeadlessProject};
use rpc::proto;
use serde_json::json;
-use settings::{PrettierSettingsContent, SettingsStore};
+use settings::{LanguageServerFormatterSpecifier, PrettierSettingsContent, SettingsStore};
use std::{
path::Path,
sync::{Arc, atomic::AtomicUsize},
@@ -491,7 +491,7 @@ async fn test_ssh_collaboration_formatting_with_prettier(
cx_a.update(|cx| {
SettingsStore::update_global(cx, |store, cx| {
store.update_user_settings(cx, |file| {
- file.project.all_languages.defaults.formatter = Some(SelectedFormatter::Auto);
+ file.project.all_languages.defaults.formatter = Some(FormatterList::default());
file.project.all_languages.defaults.prettier = Some(PrettierSettingsContent {
allowed: Some(true),
..Default::default()
@@ -502,8 +502,8 @@ async fn test_ssh_collaboration_formatting_with_prettier(
cx_b.update(|cx| {
SettingsStore::update_global(cx, |store, cx| {
store.update_user_settings(cx, |file| {
- file.project.all_languages.defaults.formatter = Some(SelectedFormatter::List(
- FormatterList::Single(Formatter::LanguageServer { name: None }),
+ file.project.all_languages.defaults.formatter = Some(FormatterList::Single(
+ Formatter::LanguageServer(LanguageServerFormatterSpecifier::Current),
));
file.project.all_languages.defaults.prettier = Some(PrettierSettingsContent {
allowed: Some(true),
@@ -550,7 +550,7 @@ async fn test_ssh_collaboration_formatting_with_prettier(
cx_a.update(|cx| {
SettingsStore::update_global(cx, |store, cx| {
store.update_user_settings(cx, |file| {
- file.project.all_languages.defaults.formatter = Some(SelectedFormatter::Auto);
+ file.project.all_languages.defaults.formatter = Some(FormatterList::default());
file.project.all_languages.defaults.prettier = Some(PrettierSettingsContent {
allowed: Some(true),
..Default::default()
@@ -27,7 +27,6 @@ use language::{
LanguageConfigOverride, LanguageMatcher, LanguageName, Override, Point,
language_settings::{
CompletionSettingsContent, FormatterList, LanguageSettingsContent, LspInsertMode,
- SelectedFormatter,
},
tree_sitter_python,
};
@@ -11821,8 +11820,8 @@ async fn test_range_format_respects_language_tab_size_override(cx: &mut TestAppC
#[gpui::test]
async fn test_document_format_manual_trigger(cx: &mut TestAppContext) {
init_test(cx, |settings| {
- settings.defaults.formatter = Some(SelectedFormatter::List(FormatterList::Single(
- Formatter::LanguageServer { name: None },
+ settings.defaults.formatter = Some(FormatterList::Single(Formatter::LanguageServer(
+ settings::LanguageServerFormatterSpecifier::Current,
)))
});
@@ -11947,11 +11946,11 @@ async fn test_document_format_manual_trigger(cx: &mut TestAppContext) {
async fn test_multiple_formatters(cx: &mut TestAppContext) {
init_test(cx, |settings| {
settings.defaults.remove_trailing_whitespace_on_save = Some(true);
- settings.defaults.formatter = Some(SelectedFormatter::List(FormatterList::Vec(vec![
- Formatter::LanguageServer { name: None },
+ settings.defaults.formatter = Some(FormatterList::Vec(vec![
+ Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current),
Formatter::CodeAction("code-action-1".into()),
Formatter::CodeAction("code-action-2".into()),
- ])))
+ ]))
});
let fs = FakeFs::new(cx.executor());
@@ -12206,9 +12205,9 @@ async fn test_multiple_formatters(cx: &mut TestAppContext) {
#[gpui::test]
async fn test_organize_imports_manual_trigger(cx: &mut TestAppContext) {
init_test(cx, |settings| {
- settings.defaults.formatter = Some(SelectedFormatter::List(FormatterList::Vec(vec![
- Formatter::LanguageServer { name: None },
- ])))
+ settings.defaults.formatter = Some(FormatterList::Vec(vec![Formatter::LanguageServer(
+ settings::LanguageServerFormatterSpecifier::Current,
+ )]))
});
let fs = FakeFs::new(cx.executor());
@@ -12411,7 +12410,7 @@ async fn test_concurrent_format_requests(cx: &mut TestAppContext) {
#[gpui::test]
async fn test_strip_whitespace_and_format_via_lsp(cx: &mut TestAppContext) {
init_test(cx, |settings| {
- settings.defaults.formatter = Some(SelectedFormatter::Auto)
+ settings.defaults.formatter = Some(FormatterList::default())
});
let mut cx = EditorLspTestContext::new_rust(
@@ -18097,9 +18096,7 @@ fn completion_menu_entries(menu: &CompletionsMenu) -> Vec<String> {
#[gpui::test]
async fn test_document_format_with_prettier(cx: &mut TestAppContext) {
init_test(cx, |settings| {
- settings.defaults.formatter = Some(SelectedFormatter::List(FormatterList::Single(
- Formatter::Prettier,
- )))
+ settings.defaults.formatter = Some(FormatterList::Single(Formatter::Prettier))
});
let fs = FakeFs::new(cx.executor());
@@ -18166,7 +18163,7 @@ async fn test_document_format_with_prettier(cx: &mut TestAppContext) {
);
update_test_language_settings(cx, |settings| {
- settings.defaults.formatter = Some(SelectedFormatter::Auto)
+ settings.defaults.formatter = Some(FormatterList::default())
});
let format = editor.update_in(cx, |editor, window, cx| {
editor.perform_format(
@@ -13,7 +13,7 @@ use itertools::{Either, Itertools};
pub use settings::{
CompletionSettingsContent, EditPredictionProvider, EditPredictionsMode, FormatOnSave,
Formatter, FormatterList, InlayHintKind, LanguageSettingsContent, LspInsertMode,
- RewrapBehavior, SelectedFormatter, ShowWhitespaceSetting, SoftWrap, WordsCompletionMode,
+ RewrapBehavior, ShowWhitespaceSetting, SoftWrap, WordsCompletionMode,
};
use settings::{ExtendingVec, Settings, SettingsContent, SettingsLocation, SettingsStore};
use shellexpand;
@@ -96,7 +96,7 @@ pub struct LanguageSettings {
/// when saving it.
pub ensure_final_newline_on_save: bool,
/// How to perform a buffer format.
- pub formatter: settings::SelectedFormatter,
+ pub formatter: settings::FormatterList,
/// Zed's Prettier integration settings.
pub prettier: PrettierSettings,
/// Whether to automatically close JSX tags.
@@ -61,9 +61,7 @@ use language::{
LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
Transaction, Unclipped,
- language_settings::{
- FormatOnSave, Formatter, LanguageSettings, SelectedFormatter, language_settings,
- },
+ language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
point_to_lsp,
proto::{
deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
@@ -1341,23 +1339,24 @@ impl LocalLspStore {
let formatters = match (trigger, &settings.format_on_save) {
(FormatTrigger::Save, FormatOnSave::Off) => &[],
(FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
- match &settings.formatter {
- SelectedFormatter::Auto => {
- if settings.prettier.allowed {
- zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
- std::slice::from_ref(&Formatter::Prettier)
- } else {
- zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
- std::slice::from_ref(&Formatter::LanguageServer { name: None })
- }
- }
- SelectedFormatter::List(formatter_list) => formatter_list.as_ref(),
- }
+ settings.formatter.as_ref()
}
};
for formatter in formatters {
+ let formatter = if formatter == &Formatter::Auto {
+ if settings.prettier.allowed {
+ zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
+ &Formatter::Prettier
+ } else {
+ zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
+ &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
+ }
+ } else {
+ formatter
+ };
match formatter {
+ Formatter::Auto => unreachable!("Auto resolved above"),
Formatter::Prettier => {
let logger = zlog::scoped!(logger => "prettier");
zlog::trace!(logger => "formatting");
@@ -1412,7 +1411,7 @@ impl LocalLspStore {
},
)?;
}
- Formatter::LanguageServer { name } => {
+ Formatter::LanguageServer(specifier) => {
let logger = zlog::scoped!(logger => "language-server");
zlog::trace!(logger => "formatting");
let _timer = zlog::time!(logger => "Formatting buffer using language server");
@@ -1422,16 +1421,19 @@ impl LocalLspStore {
continue;
};
- let language_server = if let Some(name) = name.as_deref() {
- adapters_and_servers.iter().find_map(|(adapter, server)| {
- if adapter.name.0.as_ref() == name {
- Some(server.clone())
- } else {
- None
- }
- })
- } else {
- adapters_and_servers.first().map(|e| e.1.clone())
+ let language_server = match specifier {
+ settings::LanguageServerFormatterSpecifier::Specific { name } => {
+ adapters_and_servers.iter().find_map(|(adapter, server)| {
+ if adapter.name.0.as_ref() == name {
+ Some(server.clone())
+ } else {
+ None
+ }
+ })
+ }
+ settings::LanguageServerFormatterSpecifier::Current => {
+ adapters_and_servers.first().map(|e| e.1.clone())
+ }
};
let Some(language_server) = language_server else {
@@ -16,7 +16,7 @@ use futures::{
use gpui::{AppContext as _, AsyncApp, Context, Entity, EventEmitter, Task, WeakEntity};
use language::{
Buffer, LanguageRegistry, LocalFile,
- language_settings::{Formatter, LanguageSettings, SelectedFormatter},
+ language_settings::{Formatter, LanguageSettings},
};
use lsp::{LanguageServer, LanguageServerId, LanguageServerName};
use node_runtime::NodeRuntime;
@@ -700,14 +700,11 @@ impl PrettierStore {
pub fn prettier_plugins_for_language(
language_settings: &LanguageSettings,
) -> Option<&HashSet<String>> {
- match &language_settings.formatter {
- SelectedFormatter::Auto => Some(&language_settings.prettier.plugins),
-
- SelectedFormatter::List(list) => list
- .as_ref()
- .contains(&Formatter::Prettier)
- .then_some(&language_settings.prettier.plugins),
+ let formatters = language_settings.formatter.as_ref();
+ if formatters.contains(&Formatter::Prettier) || formatters.contains(&Formatter::Auto) {
+ return Some(&language_settings.prettier.plugins);
}
+ None
}
pub(super) async fn format_with_prettier(
@@ -1,12 +1,9 @@
-use std::{borrow::Cow, num::NonZeroU32};
+use std::num::NonZeroU32;
use collections::{HashMap, HashSet};
use gpui::{Modifiers, SharedString};
-use schemars::{JsonSchema, json_schema};
-use serde::{
- Deserialize, Deserializer, Serialize,
- de::{self, IntoDeserializer, MapAccess, SeqAccess, Visitor},
-};
+use schemars::JsonSchema;
+use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use settings_macros::MergeFrom;
use std::sync::Arc;
@@ -228,7 +225,7 @@ pub struct LanguageSettingsContent {
/// How to perform a buffer format.
///
/// Default: auto
- pub formatter: Option<SelectedFormatter>,
+ pub formatter: Option<FormatterList>,
/// Zed's Prettier integration settings.
/// Allows to enable/disable formatting with Prettier
/// and configure default Prettier, used when no project-level Prettier installation is found.
@@ -621,102 +618,6 @@ pub enum FormatOnSave {
Off,
}
-/// Controls which formatter should be used when formatting code.
-#[derive(Clone, Debug, Default, PartialEq, Eq, MergeFrom)]
-pub enum SelectedFormatter {
- /// Format files using Zed's Prettier integration (if applicable),
- /// or falling back to formatting via language server.
- #[default]
- Auto,
- List(FormatterList),
-}
-
-impl JsonSchema for SelectedFormatter {
- fn schema_name() -> Cow<'static, str> {
- "Formatter".into()
- }
-
- fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
- let formatter_schema = Formatter::json_schema(generator);
-
- json_schema!({
- "oneOf": [
- {
- "type": "array",
- "items": formatter_schema
- },
- {
- "type": "string",
- "enum": ["auto", "language_server"]
- },
- formatter_schema
- ]
- })
- }
-}
-
-impl Serialize for SelectedFormatter {
- fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
- where
- S: serde::Serializer,
- {
- match self {
- SelectedFormatter::Auto => serializer.serialize_str("auto"),
- SelectedFormatter::List(list) => list.serialize(serializer),
- }
- }
-}
-
-impl<'de> Deserialize<'de> for SelectedFormatter {
- fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
- where
- D: Deserializer<'de>,
- {
- struct FormatDeserializer;
-
- impl<'d> Visitor<'d> for FormatDeserializer {
- type Value = SelectedFormatter;
-
- fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
- formatter.write_str("a valid formatter kind")
- }
- fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
- where
- E: serde::de::Error,
- {
- if v == "auto" {
- Ok(Self::Value::Auto)
- } else if v == "language_server" {
- Ok(Self::Value::List(FormatterList::Single(
- Formatter::LanguageServer { name: None },
- )))
- } else {
- let ret: Result<FormatterList, _> =
- Deserialize::deserialize(v.into_deserializer());
- ret.map(SelectedFormatter::List)
- }
- }
- fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
- where
- A: MapAccess<'d>,
- {
- let ret: Result<FormatterList, _> =
- Deserialize::deserialize(de::value::MapAccessDeserializer::new(map));
- ret.map(SelectedFormatter::List)
- }
- fn visit_seq<A>(self, map: A) -> Result<Self::Value, A::Error>
- where
- A: SeqAccess<'d>,
- {
- let ret: Result<FormatterList, _> =
- Deserialize::deserialize(de::value::SeqAccessDeserializer::new(map));
- ret.map(SelectedFormatter::List)
- }
- }
- deserializer.deserialize_any(FormatDeserializer)
- }
-}
-
/// Controls which formatters should be used when formatting code.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom)]
#[serde(untagged)]
@@ -744,10 +645,11 @@ impl AsRef<[Formatter]> for FormatterList {
#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom)]
#[serde(rename_all = "snake_case")]
pub enum Formatter {
- /// Format code using the current language server.
- LanguageServer { name: Option<String> },
- /// Format code using Zed's Prettier integration.
+ /// Format files using Zed's Prettier integration (if applicable),
+ /// or falling back to formatting via language server.
#[default]
+ Auto,
+ /// Format code using Zed's Prettier integration.
Prettier,
/// Format code using an external command.
External {
@@ -758,6 +660,73 @@ pub enum Formatter {
},
/// Files should be formatted using a code action executed by language servers.
CodeAction(String),
+ /// Format code using a language server.
+ #[serde(untagged)]
+ LanguageServer(LanguageServerFormatterSpecifier),
+}
+
+#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom)]
+#[serde(
+ rename_all = "snake_case",
+ // allow specifying language servers as "language_server" or {"language_server": {"name": ...}}
+ from = "LanguageServerVariantContent",
+ into = "LanguageServerVariantContent"
+)]
+pub enum LanguageServerFormatterSpecifier {
+ Specific {
+ name: String,
+ },
+ #[default]
+ Current,
+}
+
+impl From<LanguageServerVariantContent> for LanguageServerFormatterSpecifier {
+ fn from(value: LanguageServerVariantContent) -> Self {
+ match value {
+ LanguageServerVariantContent::Specific {
+ language_server: LanguageServerSpecifierContent { name: Some(name) },
+ } => Self::Specific { name },
+ _ => Self::Current,
+ }
+ }
+}
+
+impl From<LanguageServerFormatterSpecifier> for LanguageServerVariantContent {
+ fn from(value: LanguageServerFormatterSpecifier) -> Self {
+ match value {
+ LanguageServerFormatterSpecifier::Specific { name } => Self::Specific {
+ language_server: LanguageServerSpecifierContent { name: Some(name) },
+ },
+ LanguageServerFormatterSpecifier::Current => {
+ Self::Current(CurrentLanguageServerContent::LanguageServer)
+ }
+ }
+ }
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom)]
+#[serde(rename_all = "snake_case", untagged)]
+enum LanguageServerVariantContent {
+ /// Format code using a specific language server.
+ Specific {
+ language_server: LanguageServerSpecifierContent,
+ },
+ /// Format code using the current language server.
+ Current(CurrentLanguageServerContent),
+}
+
+#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom)]
+#[serde(rename_all = "snake_case")]
+enum CurrentLanguageServerContent {
+ #[default]
+ LanguageServer,
+}
+
+#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom)]
+#[serde(rename_all = "snake_case")]
+struct LanguageServerSpecifierContent {
+ /// The name of the language server to format with
+ name: Option<String>,
}
/// The settings for indent guides.
@@ -866,31 +835,53 @@ mod test {
fn test_formatter_deserialization() {
let raw_auto = "{\"formatter\": \"auto\"}";
let settings: LanguageSettingsContent = serde_json::from_str(raw_auto).unwrap();
- assert_eq!(settings.formatter, Some(SelectedFormatter::Auto));
+ assert_eq!(
+ settings.formatter,
+ Some(FormatterList::Single(Formatter::Auto))
+ );
let raw = "{\"formatter\": \"language_server\"}";
let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
assert_eq!(
settings.formatter,
- Some(SelectedFormatter::List(FormatterList::Single(
- Formatter::LanguageServer { name: None }
+ Some(FormatterList::Single(Formatter::LanguageServer(
+ LanguageServerFormatterSpecifier::Current
)))
);
+
let raw = "{\"formatter\": [{\"language_server\": {\"name\": null}}]}";
let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
assert_eq!(
settings.formatter,
- Some(SelectedFormatter::List(FormatterList::Vec(vec![
- Formatter::LanguageServer { name: None }
- ])))
+ Some(FormatterList::Vec(vec![Formatter::LanguageServer(
+ LanguageServerFormatterSpecifier::Current
+ )]))
);
- let raw = "{\"formatter\": [{\"language_server\": {\"name\": null}}, \"prettier\"]}";
+ let raw = "{\"formatter\": [{\"language_server\": {\"name\": null}}, \"language_server\", \"prettier\"]}";
let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
assert_eq!(
settings.formatter,
- Some(SelectedFormatter::List(FormatterList::Vec(vec![
- Formatter::LanguageServer { name: None },
+ Some(FormatterList::Vec(vec![
+ Formatter::LanguageServer(LanguageServerFormatterSpecifier::Current),
+ Formatter::LanguageServer(LanguageServerFormatterSpecifier::Current),
Formatter::Prettier
- ])))
+ ]))
+ );
+
+ let raw = "{\"formatter\": [{\"language_server\": {\"name\": \"ruff\"}}, \"prettier\"]}";
+ let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
+ assert_eq!(
+ settings.formatter,
+ Some(FormatterList::Vec(vec![
+ Formatter::LanguageServer(LanguageServerFormatterSpecifier::Specific {
+ name: "ruff".to_string()
+ }),
+ Formatter::Prettier
+ ]))
+ );
+
+ assert_eq!(
+ serde_json::to_string(&LanguageServerFormatterSpecifier::Current).unwrap(),
+ "\"language_server\"",
);
}