Compare commits
3 Commits
fix-linux-
...
fix-code-a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6418b05a4f | ||
|
|
cdaacd4803 | ||
|
|
53fab9730b |
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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());
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user