Compare commits

...

3 Commits

Author SHA1 Message Date
Ben Kunkle
6418b05a4f clippy
Co-Authored-By: Cole <cole@zed.dev>
2025-10-16 11:15:48 -04:00
Ben Kunkle
cdaacd4803 clean
Co-Authored-By: Cole <cole@zed.dev>
2025-10-16 10:55:26 -04:00
Ben Kunkle
53fab9730b improve behavior of code_actions_on_format migration
Co-Authored-By: Cole <cole@zed.dev>
2025-10-16 10:53:30 -04:00
5 changed files with 131 additions and 28 deletions

View File

@@ -1,18 +1,62 @@
use anyhow::Result;
use serde_json::Value;
use crate::patterns::migrate_language_setting;
pub fn remove_code_actions_on_format(value: &mut Value) -> Result<()> {
migrate_language_setting(value, remove_code_actions_on_format_inner)
let defaults =
settings::parse_json_with_comments::<Value>(settings::default_settings().as_ref()).unwrap();
let default_root_formatter = defaults.get("formatter");
let root_code_actions =
remove_code_actions_on_format_inner(value, default_root_formatter, &[], &[])?;
let user_default_formatter = value.get("formatter").cloned();
let user_languages = value
.as_object_mut()
.and_then(|obj| obj.get_mut("languages"))
.and_then(|languages| languages.as_object_mut());
let default_languages = defaults
.as_object()
.and_then(|obj| obj.get("languages"))
.and_then(|languages| languages.as_object());
if let Some(languages) = user_languages {
for (language_name, language) in languages.iter_mut() {
let path = vec!["languages", language_name];
let language_default_formatter = default_languages
.and_then(|langs| langs.get(language_name))
.and_then(|lang| lang.get("formatter"));
// override order:
// 4. root from defaults
// 3. language from defaults
// 2. root from user
// 1. language from user
let default_formatter_for_language = user_default_formatter
.as_ref()
.or(language_default_formatter)
.or(default_root_formatter);
remove_code_actions_on_format_inner(
language,
default_formatter_for_language,
&root_code_actions,
&path,
)?;
}
}
Ok(())
}
fn remove_code_actions_on_format_inner(value: &mut Value, path: &[&str]) -> Result<()> {
fn remove_code_actions_on_format_inner(
value: &mut Value,
default_formatters: Option<&Value>,
parent_code_actions: &[String],
path: &[&str],
) -> Result<Vec<String>> {
let Some(obj) = value.as_object_mut() else {
return Ok(());
return Ok(vec![]);
};
let Some(code_actions_on_format) = obj.get("code_actions_on_format").cloned() else {
return Ok(());
return Ok(vec![]);
};
fn fmt_path(path: &[&str], key: &str) -> String {
@@ -35,6 +79,7 @@ fn remove_code_actions_on_format_inner(value: &mut Value, path: &[&str]) -> Resu
}
code_actions.push(code_action.clone());
}
code_actions.extend(parent_code_actions.iter().cloned());
let mut formatter_array = vec![];
if let Some(formatter) = obj.get("formatter") {
@@ -43,12 +88,18 @@ fn remove_code_actions_on_format_inner(value: &mut Value, path: &[&str]) -> Resu
} else {
formatter_array.insert(0, formatter.clone());
}
} else if let Some(formatter) = default_formatters {
if let Some(array) = formatter.as_array() {
formatter_array = array.clone();
} else {
formatter_array.push(formatter.clone());
}
};
let found_code_actions = !code_actions.is_empty();
formatter_array.splice(
0..0,
code_actions
.into_iter()
.iter()
.map(|code_action| serde_json::json!({"code_action": code_action})),
);
@@ -57,5 +108,5 @@ fn remove_code_actions_on_format_inner(value: &mut Value, path: &[&str]) -> Resu
obj.insert("formatter".to_string(), Value::Array(formatter_array));
}
Ok(())
Ok(code_actions)
}

View File

@@ -2010,7 +2010,8 @@ mod tests {
},
{
"code_action": "source.fixAll"
}
},
"auto"
]
}
"#
@@ -2041,7 +2042,8 @@ mod tests {
},
{
"code_action": "c"
}
},
"auto"
]
}
"#
@@ -2127,7 +2129,7 @@ mod tests {
"Go": {
"code_actions_on_format": {
"source.organizeImports": true
}
},
}
}
}"#
@@ -2139,14 +2141,19 @@ mod tests {
"formatter": [
{
"code_action": "source.fixAll.eslint"
}
},
"auto"
]
},
"Go": {
"formatter": [
{
"code_action": "source.organizeImports"
}
},
{
"code_action": "source.organizeImports"
},
"language_server"
]
}
}
@@ -2233,6 +2240,9 @@ mod tests {
{
"code_action": "source.organizeImports"
},
{
"code_action": "source.fixAll"
},
"rust-analyzer"
]
},
@@ -2240,7 +2250,14 @@ mod tests {
"formatter": [
{
"code_action": "source.organizeImports"
}
},
{
"code_action": "source.fixAll"
},
{
"code_action": "source.fixAll"
},
"prettier"
]
}
}
@@ -2250,6 +2267,35 @@ mod tests {
);
}
#[test]
fn test_code_actions_on_format_inserts_default_formatters() {
assert_migrate_settings_with_migrations(
&[MigrationType::Json(
migrations::m_2025_10_10::remove_code_actions_on_format,
)],
&r#"{
"code_actions_on_format": {
"source.organizeImports": false,
"source.fixAll.eslint": true
}
}"#
.unindent(),
Some(
&r#"
{
"formatter": [
{
"code_action": "source.fixAll.eslint"
},
"auto"
]
}
"#
.unindent(),
),
)
}
#[test]
fn test_code_actions_on_format_no_migration_when_not_present() {
assert_migrate_settings_with_migrations(

View File

@@ -1710,12 +1710,7 @@ impl LocalLspStore {
formatting_transaction_id,
cx,
|buffer, cx| {
zlog::info!(
"Applying edits {edits:?}. Content: {:?}",
buffer.text()
);
buffer.edit(edits, None, cx);
zlog::info!("Applied edits. New Content: {:?}", buffer.text());
},
)?;
}

View File

@@ -320,13 +320,18 @@ To run linter fixes automatically on save:
```json [settings]
"languages": {
"JavaScript": {
"formatter": {
"code_action": "source.fixAll.eslint"
}
"formatter": [
{
"code_action": "source.fixAll.eslint"
},
"auto"
]
}
}
```
This specifies that when a format is requested, Zed will first run the `source.fixAll.eslint` action, and then perform the actual format using the language-specific default formatter (for JavaScript this is Prettier, and for other languages it often corresponds to formatting using the default language server).
### Integrating Formatting and Linting
Zed allows you to run both formatting and linting on save. Here's an example that uses Prettier for formatting and ESLint for linting JavaScript files:

View File

@@ -49,9 +49,12 @@ You can configure Zed to format code using `eslint --fix` by running the ESLint
{
"languages": {
"JavaScript": {
"formatter": {
"code_action": "source.fixAll.eslint"
}
"formatter": [
{
"code_action": "source.fixAll.eslint"
},
"auto"
]
}
}
}
@@ -63,9 +66,12 @@ You can also only execute a single ESLint rule when using `fixAll`:
{
"languages": {
"JavaScript": {
"formatter": {
"code_action": "source.fixAll.eslint"
}
"formatter": [
{
"code_action": "source.fixAll.eslint"
},
"auto"
]
}
},
"lsp": {