Respect disabled trailing whitespace removal (#58776)

Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
 - [x] Tests cover the new/changed behavior
 - [x] Performance impact has been considered and is acceptable

  Closes #58686

Release Notes:

- Fixed `.editorconfig` re-enabling trailing whitespace removal when Zed
settings disable it.

---------

Co-authored-by: Martin Ye <martin@zed.dev>
This commit is contained in:
Mohit GoyalandMartin Ye authored and GitHub committed 2026-07-22 21:10:32 +00:00
1 parent aa2a4211a3
commit cb68afbd2b
3 files changed
+102 -4

No files matched your search

+70
View File
@@ -16,6 +16,7 @@ use crate::{
};
use buffer_diff::{BufferDiff, DiffHunkSecondaryStatus, DiffHunkStatus, DiffHunkStatusKind};
use collections::HashMap;
use fs::Fs as _;
use futures::{StreamExt, channel::oneshot};
use gpui::{
BackgroundExecutor, DismissEvent, Task, TaskExt, TestAppContext, UpdateGlobal,
@@ -17603,6 +17604,75 @@ async fn test_multiple_formatters(cx: &mut TestAppContext) {
});
}
#[gpui::test]
async fn test_markdown_save_respects_disabled_trailing_whitespace_removal(cx: &mut TestAppContext) {
init_test(cx, |settings| {
settings.defaults.ensure_final_newline_on_save = Some(false);
settings.languages.0.insert(
"Markdown".into(),
LanguageSettingsContent {
remove_trailing_whitespace_on_save: Some(false),
..Default::default()
},
);
});
let fs = FakeFs::new(cx.executor());
fs.insert_file(
path!("/.editorconfig"),
"root = true\n[*]\ntrim_trailing_whitespace = true\n".into(),
)
.await;
fs.insert_file(path!("/README.md"), "".into()).await;
let project = Project::test(fs.clone(), [path!("/").as_ref()], cx).await;
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(markdown_lang());
let buffer = project
.update(cx, |project, cx| {
project.open_local_buffer(path!("/README.md"), cx)
})
.await
.unwrap();
let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
let (editor, cx) = cx.add_window_view(|window, cx| {
build_editor_with_project(project.clone(), buffer, window, cx)
});
editor.update_in(cx, |editor, window, cx| {
editor.set_text("line with spaces \n", window, cx)
});
let save = editor
.update_in(cx, |editor, window, cx| {
editor.save(
SaveOptions {
format: true,
force_format: false,
autosave: false,
},
project.clone(),
window,
cx,
)
})
.unwrap();
save.await;
assert_eq!(
editor.update(cx, |editor, cx| editor.text(cx)),
"line with spaces \n"
);
assert_eq!(
fs.load(path!("/README.md").as_ref())
.await
.unwrap()
.replace("\r\n", "\n"),
"line with spaces \n"
);
}
#[gpui::test]
async fn test_organize_imports_manual_trigger(cx: &mut TestAppContext) {
init_test(cx, |settings| {
+9 -3
View File
@@ -695,9 +695,15 @@ fn merge_with_editorconfig(settings: &mut LanguageSettings, cfg: &EditorconfigPr
.merge_from_option(preferred_line_length.as_ref());
settings.tab_size.merge_from_option(tab_size.as_ref());
settings.hard_tabs.merge_from_option(hard_tabs.as_ref());
settings
.remove_trailing_whitespace_on_save
.merge_from_option(remove_trailing_whitespace_on_save.as_ref());
// Avoid re-enabling destructive whitespace trimming when Zed settings have
// disabled it, e.g. for Markdown hard breaks.
if !matches!(remove_trailing_whitespace_on_save, Some(true))
|| settings.remove_trailing_whitespace_on_save
{
settings
.remove_trailing_whitespace_on_save
.merge_from_option(remove_trailing_whitespace_on_save.as_ref());
}
settings
.ensure_final_newline_on_save
.merge_from_option(ensure_final_newline_on_save.as_ref());
@@ -254,7 +254,10 @@ async fn test_editorconfig_support(cx: &mut gpui::TestAppContext) {
max_line_length = 120
[*.js]
tab_width = 10
trim_trailing_whitespace = false
max_line_length = off
[*.json]
trim_trailing_whitespace = true
"#,
".zed": {
"settings.json": r#"{
@@ -264,6 +267,17 @@ async fn test_editorconfig_support(cx: &mut gpui::TestAppContext) {
"remove_trailing_whitespace_on_save": false,
"preferred_line_length": 64,
"soft_wrap": "editor_width",
"languages": {
"JavaScript": {
"remove_trailing_whitespace_on_save": true,
},
"JSON": {
"remove_trailing_whitespace_on_save": true,
},
"Markdown": {
"remove_trailing_whitespace_on_save": true,
},
},
}"#,
},
"a.rs": "fn a() {\n A\n}",
@@ -293,6 +307,7 @@ async fn test_editorconfig_support(cx: &mut gpui::TestAppContext) {
"e.rs": "fn e() {\n E\n}",
},
"README.json": "tabs are better\n",
"README.md": "spaces are meaningful \n",
}));
let path = dir.path();
@@ -303,6 +318,7 @@ async fn test_editorconfig_support(cx: &mut gpui::TestAppContext) {
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(js_lang());
language_registry.add(json_lang());
language_registry.add(markdown_lang());
language_registry.add(rust_lang());
let worktree = project.update(cx, |project, cx| project.worktrees(cx).next().unwrap());
@@ -325,11 +341,14 @@ async fn test_editorconfig_support(cx: &mut gpui::TestAppContext) {
let settings_d = settings_for("d/d.rs", cx).await;
let settings_e = settings_for("e/e.rs", cx).await;
let settings_readme = settings_for("README.json", cx).await;
let settings_markdown = settings_for("README.md", cx).await;
// .editorconfig overrides .zed/settings
assert_eq!(Some(settings_a.tab_size), NonZeroU32::new(3));
assert_eq!(settings_a.hard_tabs, true);
assert_eq!(settings_a.ensure_final_newline_on_save, true);
assert_eq!(settings_a.remove_trailing_whitespace_on_save, true);
// .editorconfig can disable trailing whitespace removal, but should not
// re-enable it when Zed settings have disabled it.
assert_eq!(settings_a.remove_trailing_whitespace_on_save, false);
assert_eq!(settings_a.line_ending, LineEndingSetting::EnforceLf);
assert_eq!(settings_a.preferred_line_length, 120);
@@ -348,6 +367,9 @@ async fn test_editorconfig_support(cx: &mut gpui::TestAppContext) {
// "indent_size" is not set, so "tab_width" is used
assert_eq!(Some(settings_c.tab_size), NonZeroU32::new(10));
assert_eq!(settings_c.remove_trailing_whitespace_on_save, false);
assert_eq!(settings_readme.remove_trailing_whitespace_on_save, true);
assert_eq!(settings_markdown.remove_trailing_whitespace_on_save, true);
// When max_line_length is "off", default to .zed/settings.json
assert_eq!(settings_b.preferred_line_length, 64);