Skip to content

Commit 838eb5a

Browse files
committed
Merge pull request #87099 from bitwise-aiden/ba-add-trim-newlines
Implement `trim_final_newlines` setting and functionality
2 parents ffad49f + b4c1634 commit 838eb5a

13 files changed

+99
-4
lines changed

doc/classes/EditorSettings.xml

+3
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,9 @@
10281028
<member name="text_editor/behavior/files/restore_scripts_on_load" type="bool" setter="" getter="">
10291029
If [code]true[/code], reopens scripts that were opened in the last session when the editor is reopened on a given project.
10301030
</member>
1031+
<member name="text_editor/behavior/files/trim_final_newlines_on_save" type="bool" setter="" getter="">
1032+
If [code]true[/code], trims all empty newlines after the final newline when saving a script. Final newlines refer to the empty newlines found at the end of files. Since these serve no practical purpose, they can and should be removed to make version control diffs less noisy.
1033+
</member>
10311034
<member name="text_editor/behavior/files/trim_trailing_whitespace_on_save" type="bool" setter="" getter="">
10321035
If [code]true[/code], trims trailing whitespace when saving a script. Trailing whitespace refers to tab and space characters placed at the end of lines. Since these serve no practical purpose, they can and should be removed to make version control diffs less noisy.
10331036
</member>

editor/code_editor.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,31 @@ void CodeTextEditor::trim_trailing_whitespace() {
11241124
}
11251125
}
11261126

1127+
void CodeTextEditor::trim_final_newlines() {
1128+
int final_line = text_editor->get_line_count() - 1;
1129+
int check_line = final_line;
1130+
1131+
String line = text_editor->get_line(check_line);
1132+
1133+
while (line.is_empty() && check_line > -1) {
1134+
--check_line;
1135+
1136+
line = text_editor->get_line(check_line);
1137+
}
1138+
1139+
++check_line;
1140+
1141+
if (check_line < final_line) {
1142+
text_editor->begin_complex_operation();
1143+
1144+
text_editor->remove_text(check_line, 0, final_line, 0);
1145+
1146+
text_editor->merge_overlapping_carets();
1147+
text_editor->end_complex_operation();
1148+
text_editor->queue_redraw();
1149+
}
1150+
}
1151+
11271152
void CodeTextEditor::insert_final_newline() {
11281153
int final_line = text_editor->get_line_count() - 1;
11291154
String line = text_editor->get_line(final_line);

editor/code_editor.h

+1
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ class CodeTextEditor : public VBoxContainer {
224224

225225
public:
226226
void trim_trailing_whitespace();
227+
void trim_final_newlines();
227228
void insert_final_newline();
228229

229230
enum CaseStyle {

editor/editor_settings.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
651651

652652
// Behavior: Files
653653
_initial_set("text_editor/behavior/files/trim_trailing_whitespace_on_save", false);
654+
_initial_set("text_editor/behavior/files/trim_final_newlines_on_save", true);
654655
_initial_set("text_editor/behavior/files/autosave_interval_secs", 0);
655656
_initial_set("text_editor/behavior/files/restore_scripts_on_load", true);
656657
_initial_set("text_editor/behavior/files/convert_indent_on_save", true);

editor/plugins/script_editor_plugin.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,10 @@ void ScriptEditor::_resave_scripts(const String &p_str) {
10081008
se->trim_trailing_whitespace();
10091009
}
10101010

1011+
if (trim_final_newlines_on_save) {
1012+
se->trim_final_newlines();
1013+
}
1014+
10111015
se->insert_final_newline();
10121016

10131017
if (convert_indent_on_save) {
@@ -1402,6 +1406,10 @@ void ScriptEditor::_menu_option(int p_option) {
14021406
current->trim_trailing_whitespace();
14031407
}
14041408

1409+
if (trim_final_newlines_on_save) {
1410+
current->trim_final_newlines();
1411+
}
1412+
14051413
current->insert_final_newline();
14061414

14071415
if (convert_indent_on_save) {
@@ -2602,6 +2610,10 @@ void ScriptEditor::save_current_script() {
26022610
current->trim_trailing_whitespace();
26032611
}
26042612

2613+
if (trim_final_newlines_on_save) {
2614+
current->trim_final_newlines();
2615+
}
2616+
26052617
current->insert_final_newline();
26062618

26072619
if (convert_indent_on_save) {
@@ -2646,6 +2658,10 @@ void ScriptEditor::save_all_scripts() {
26462658
se->trim_trailing_whitespace();
26472659
}
26482660

2661+
if (trim_final_newlines_on_save) {
2662+
se->trim_final_newlines();
2663+
}
2664+
26492665
se->insert_final_newline();
26502666

26512667
if (!se->is_unsaved()) {
@@ -2883,6 +2899,7 @@ void ScriptEditor::_apply_editor_settings() {
28832899
}
28842900

28852901
trim_trailing_whitespace_on_save = EDITOR_GET("text_editor/behavior/files/trim_trailing_whitespace_on_save");
2902+
trim_final_newlines_on_save = EDITOR_GET("text_editor/behavior/files/trim_final_newlines_on_save");
28862903
convert_indent_on_save = EDITOR_GET("text_editor/behavior/files/convert_indent_on_save");
28872904

28882905
members_overview_enabled = EDITOR_GET("text_editor/script_list/show_members_overview");
@@ -4307,6 +4324,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
43074324

43084325
edit_pass = 0;
43094326
trim_trailing_whitespace_on_save = EDITOR_GET("text_editor/behavior/files/trim_trailing_whitespace_on_save");
4327+
trim_final_newlines_on_save = EDITOR_GET("text_editor/behavior/files/trim_final_newlines_on_save");
43104328
convert_indent_on_save = EDITOR_GET("text_editor/behavior/files/convert_indent_on_save");
43114329

43124330
ScriptServer::edit_request_func = _open_script_request;

editor/plugins/script_editor_plugin.h

+2
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ class ScriptEditorBase : public VBoxContainer {
174174
virtual void set_executing_line(int p_line) = 0;
175175
virtual void clear_executing_line() = 0;
176176
virtual void trim_trailing_whitespace() = 0;
177+
virtual void trim_final_newlines() = 0;
177178
virtual void insert_final_newline() = 0;
178179
virtual void convert_indent() = 0;
179180
virtual void ensure_focus() = 0;
@@ -408,6 +409,7 @@ class ScriptEditor : public PanelContainer {
408409

409410
bool open_textfile_after_create = true;
410411
bool trim_trailing_whitespace_on_save;
412+
bool trim_final_newlines_on_save;
411413
bool convert_indent_on_save;
412414
bool external_editor_active;
413415

editor/plugins/script_text_editor.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,10 @@ void ScriptTextEditor::trim_trailing_whitespace() {
431431
code_editor->trim_trailing_whitespace();
432432
}
433433

434+
void ScriptTextEditor::trim_final_newlines() {
435+
code_editor->trim_final_newlines();
436+
}
437+
434438
void ScriptTextEditor::insert_final_newline() {
435439
code_editor->insert_final_newline();
436440
}
@@ -1427,6 +1431,9 @@ void ScriptTextEditor::_edit_option(int p_op) {
14271431
case EDIT_TRIM_TRAILING_WHITESAPCE: {
14281432
trim_trailing_whitespace();
14291433
} break;
1434+
case EDIT_TRIM_FINAL_NEWLINES: {
1435+
trim_final_newlines();
1436+
} break;
14301437
case EDIT_CONVERT_INDENT_TO_SPACES: {
14311438
code_editor->set_indent_using_spaces(true);
14321439
convert_indent();
@@ -2300,6 +2307,7 @@ void ScriptTextEditor::_enable_code_editor() {
23002307
edit_menu->get_popup()->add_separator();
23012308
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_completion_query"), EDIT_COMPLETE);
23022309
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE);
2310+
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_final_newlines"), EDIT_TRIM_FINAL_NEWLINES);
23032311
{
23042312
PopupMenu *sub_menu = memnew(PopupMenu);
23052313
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);
@@ -2485,6 +2493,7 @@ void ScriptTextEditor::register_editor() {
24852493
ED_SHORTCUT("script_text_editor/evaluate_selection", TTR("Evaluate Selection"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::E);
24862494
ED_SHORTCUT("script_text_editor/toggle_word_wrap", TTR("Toggle Word Wrap"), KeyModifierMask::ALT | Key::Z);
24872495
ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::T);
2496+
ED_SHORTCUT("script_text_editor/trim_final_newlines", TTR("Trim Final Newlines"), Key::NONE);
24882497
ED_SHORTCUT("script_text_editor/convert_indent_to_spaces", TTR("Convert Indent to Spaces"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::Y);
24892498
ED_SHORTCUT("script_text_editor/convert_indent_to_tabs", TTR("Convert Indent to Tabs"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::I);
24902499
ED_SHORTCUT("script_text_editor/auto_indent", TTR("Auto Indent"), KeyModifierMask::CMD_OR_CTRL | Key::I);

editor/plugins/script_text_editor.h

+2
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ class ScriptTextEditor : public ScriptEditorBase {
118118
EDIT_COMPLETE,
119119
EDIT_AUTO_INDENT,
120120
EDIT_TRIM_TRAILING_WHITESAPCE,
121+
EDIT_TRIM_FINAL_NEWLINES,
121122
EDIT_CONVERT_INDENT_TO_SPACES,
122123
EDIT_CONVERT_INDENT_TO_TABS,
123124
EDIT_TOGGLE_COMMENT,
@@ -228,6 +229,7 @@ class ScriptTextEditor : public ScriptEditorBase {
228229
virtual Variant get_navigation_state() override;
229230
virtual void ensure_focus() override;
230231
virtual void trim_trailing_whitespace() override;
232+
virtual void trim_final_newlines() override;
231233
virtual void insert_final_newline() override;
232234
virtual void convert_indent() override;
233235
virtual void tag_saved_version() override;

editor/plugins/shader_editor_plugin.cpp

+16-4
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,14 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) {
436436
int index = shader_tabs->get_current_tab();
437437
ERR_FAIL_INDEX(index, shader_tabs->get_tab_count());
438438
TextShaderEditor *editor = edited_shaders[index].shader_editor;
439-
if (editor && editor->get_trim_trailing_whitespace_on_save()) {
440-
editor->trim_trailing_whitespace();
439+
if (editor) {
440+
if (editor->get_trim_trailing_whitespace_on_save()) {
441+
editor->trim_trailing_whitespace();
442+
}
443+
444+
if (editor->get_trim_final_newlines_on_save()) {
445+
editor->trim_final_newlines();
446+
}
441447
}
442448
if (edited_shaders[index].shader.is_valid()) {
443449
EditorNode::get_singleton()->save_resource(edited_shaders[index].shader);
@@ -452,8 +458,14 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) {
452458
int index = shader_tabs->get_current_tab();
453459
ERR_FAIL_INDEX(index, shader_tabs->get_tab_count());
454460
TextShaderEditor *editor = edited_shaders[index].shader_editor;
455-
if (editor && editor->get_trim_trailing_whitespace_on_save()) {
456-
editor->trim_trailing_whitespace();
461+
if (editor) {
462+
if (editor->get_trim_trailing_whitespace_on_save()) {
463+
editor->trim_trailing_whitespace();
464+
}
465+
466+
if (editor->get_trim_final_newlines_on_save()) {
467+
editor->trim_final_newlines();
468+
}
457469
}
458470
String path;
459471
if (edited_shaders[index].shader.is_valid()) {

editor/plugins/text_editor.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ void TextEditor::trim_trailing_whitespace() {
288288
code_editor->trim_trailing_whitespace();
289289
}
290290

291+
void TextEditor::trim_final_newlines() {
292+
code_editor->trim_final_newlines();
293+
}
294+
291295
void TextEditor::insert_final_newline() {
292296
code_editor->insert_final_newline();
293297
}
@@ -414,6 +418,9 @@ void TextEditor::_edit_option(int p_op) {
414418
case EDIT_TRIM_TRAILING_WHITESAPCE: {
415419
trim_trailing_whitespace();
416420
} break;
421+
case EDIT_TRIM_FINAL_NEWLINES: {
422+
trim_final_newlines();
423+
} break;
417424
case EDIT_CONVERT_INDENT_TO_SPACES: {
418425
code_editor->set_indent_using_spaces(true);
419426
convert_indent();
@@ -641,6 +648,7 @@ TextEditor::TextEditor() {
641648
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_lines"), EDIT_DUPLICATE_LINES);
642649
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_word_wrap"), EDIT_TOGGLE_WORD_WRAP);
643650
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE);
651+
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_final_newlines"), EDIT_TRIM_FINAL_NEWLINES);
644652
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);
645653
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS);
646654

editor/plugins/text_editor.h

+2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class TextEditor : public ScriptEditorBase {
6363
EDIT_PASTE,
6464
EDIT_SELECT_ALL,
6565
EDIT_TRIM_TRAILING_WHITESAPCE,
66+
EDIT_TRIM_FINAL_NEWLINES,
6667
EDIT_CONVERT_INDENT_TO_SPACES,
6768
EDIT_CONVERT_INDENT_TO_TABS,
6869
EDIT_MOVE_LINE_UP,
@@ -133,6 +134,7 @@ class TextEditor : public ScriptEditorBase {
133134
virtual void set_executing_line(int p_line) override;
134135
virtual void clear_executing_line() override;
135136
virtual void trim_trailing_whitespace() override;
137+
virtual void trim_final_newlines() override;
136138
virtual void insert_final_newline() override;
137139
virtual void convert_indent() override;
138140
virtual void ensure_focus() override;

editor/plugins/text_shader_editor.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,7 @@ void TextShaderEditor::_apply_editor_settings() {
770770
code_editor->update_editor_settings();
771771

772772
trim_trailing_whitespace_on_save = EDITOR_GET("text_editor/behavior/files/trim_trailing_whitespace_on_save");
773+
trim_final_newlines_on_save = EDITOR_GET("text_editor/behavior/files/trim_final_newlines_on_save");
773774
}
774775

775776
void TextShaderEditor::_show_warnings_panel(bool p_show) {
@@ -934,6 +935,10 @@ void TextShaderEditor::save_external_data(const String &p_str) {
934935
trim_trailing_whitespace();
935936
}
936937

938+
if (trim_final_newlines_on_save) {
939+
trim_final_newlines();
940+
}
941+
937942
apply_shaders();
938943

939944
Ref<Shader> edited_shader = code_editor->get_edited_shader();
@@ -960,6 +965,10 @@ void TextShaderEditor::trim_trailing_whitespace() {
960965
code_editor->trim_trailing_whitespace();
961966
}
962967

968+
void TextShaderEditor::trim_final_newlines() {
969+
code_editor->trim_final_newlines();
970+
}
971+
963972
void TextShaderEditor::validate_script() {
964973
code_editor->_validate_script();
965974
}

editor/plugins/text_shader_editor.h

+3
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ class TextShaderEditor : public MarginContainer {
176176
uint32_t dependencies_version = 0xFFFFFFFF;
177177

178178
bool trim_trailing_whitespace_on_save;
179+
bool trim_final_newlines_on_save;
179180

180181
protected:
181182
void _notification(int p_what);
@@ -189,13 +190,15 @@ class TextShaderEditor : public MarginContainer {
189190
public:
190191
bool was_compilation_successful() const { return compilation_success; }
191192
bool get_trim_trailing_whitespace_on_save() const { return trim_trailing_whitespace_on_save; }
193+
bool get_trim_final_newlines_on_save() const { return trim_final_newlines_on_save; }
192194
void apply_shaders();
193195
void ensure_select_current();
194196
void edit(const Ref<Shader> &p_shader);
195197
void edit(const Ref<ShaderInclude> &p_shader_inc);
196198
void goto_line_selection(int p_line, int p_begin, int p_end);
197199
void save_external_data(const String &p_str = "");
198200
void trim_trailing_whitespace();
201+
void trim_final_newlines();
199202
void validate_script();
200203
bool is_unsaved() const;
201204
void tag_saved_version();

0 commit comments

Comments
 (0)