Skip to content

Commit b4c1634

Browse files
committed
Implement trim_final_newlines functionality
1 parent d4f726f commit b4c1634

13 files changed

+99
-4
lines changed

doc/classes/EditorSettings.xml

+3
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,9 @@
10121012
<member name="text_editor/behavior/files/restore_scripts_on_load" type="bool" setter="" getter="">
10131013
If [code]true[/code], reopens scripts that were opened in the last session when the editor is reopened on a given project.
10141014
</member>
1015+
<member name="text_editor/behavior/files/trim_final_newlines_on_save" type="bool" setter="" getter="">
1016+
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.
1017+
</member>
10151018
<member name="text_editor/behavior/files/trim_trailing_whitespace_on_save" type="bool" setter="" getter="">
10161019
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.
10171020
</member>

editor/code_editor.cpp

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

1126+
void CodeTextEditor::trim_final_newlines() {
1127+
int final_line = text_editor->get_line_count() - 1;
1128+
int check_line = final_line;
1129+
1130+
String line = text_editor->get_line(check_line);
1131+
1132+
while (line.is_empty() && check_line > -1) {
1133+
--check_line;
1134+
1135+
line = text_editor->get_line(check_line);
1136+
}
1137+
1138+
++check_line;
1139+
1140+
if (check_line < final_line) {
1141+
text_editor->begin_complex_operation();
1142+
1143+
text_editor->remove_text(check_line, 0, final_line, 0);
1144+
1145+
text_editor->merge_overlapping_carets();
1146+
text_editor->end_complex_operation();
1147+
text_editor->queue_redraw();
1148+
}
1149+
}
1150+
11261151
void CodeTextEditor::insert_final_newline() {
11271152
int final_line = text_editor->get_line_count() - 1;
11281153
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
@@ -647,6 +647,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
647647

648648
// Behavior: Files
649649
_initial_set("text_editor/behavior/files/trim_trailing_whitespace_on_save", false);
650+
_initial_set("text_editor/behavior/files/trim_final_newlines_on_save", true);
650651
_initial_set("text_editor/behavior/files/autosave_interval_secs", 0);
651652
_initial_set("text_editor/behavior/files/restore_scripts_on_load", true);
652653
_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
@@ -1007,6 +1007,10 @@ void ScriptEditor::_resave_scripts(const String &p_str) {
10071007
se->trim_trailing_whitespace();
10081008
}
10091009

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

10121016
if (convert_indent_on_save) {
@@ -1387,6 +1391,10 @@ void ScriptEditor::_menu_option(int p_option) {
13871391
current->trim_trailing_whitespace();
13881392
}
13891393

1394+
if (trim_final_newlines_on_save) {
1395+
current->trim_final_newlines();
1396+
}
1397+
13901398
current->insert_final_newline();
13911399

13921400
if (convert_indent_on_save) {
@@ -2567,6 +2575,10 @@ void ScriptEditor::save_current_script() {
25672575
current->trim_trailing_whitespace();
25682576
}
25692577

2578+
if (trim_final_newlines_on_save) {
2579+
current->trim_final_newlines();
2580+
}
2581+
25702582
current->insert_final_newline();
25712583

25722584
if (convert_indent_on_save) {
@@ -2611,6 +2623,10 @@ void ScriptEditor::save_all_scripts() {
26112623
se->trim_trailing_whitespace();
26122624
}
26132625

2626+
if (trim_final_newlines_on_save) {
2627+
se->trim_final_newlines();
2628+
}
2629+
26142630
se->insert_final_newline();
26152631

26162632
if (!se->is_unsaved()) {
@@ -2848,6 +2864,7 @@ void ScriptEditor::_apply_editor_settings() {
28482864
}
28492865

28502866
trim_trailing_whitespace_on_save = EDITOR_GET("text_editor/behavior/files/trim_trailing_whitespace_on_save");
2867+
trim_final_newlines_on_save = EDITOR_GET("text_editor/behavior/files/trim_final_newlines_on_save");
28512868
convert_indent_on_save = EDITOR_GET("text_editor/behavior/files/convert_indent_on_save");
28522869

28532870
members_overview_enabled = EDITOR_GET("text_editor/script_list/show_members_overview");
@@ -4265,6 +4282,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
42654282

42664283
edit_pass = 0;
42674284
trim_trailing_whitespace_on_save = EDITOR_GET("text_editor/behavior/files/trim_trailing_whitespace_on_save");
4285+
trim_final_newlines_on_save = EDITOR_GET("text_editor/behavior/files/trim_final_newlines_on_save");
42684286
convert_indent_on_save = EDITOR_GET("text_editor/behavior/files/convert_indent_on_save");
42694287

42704288
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();
@@ -2299,6 +2306,7 @@ void ScriptTextEditor::_enable_code_editor() {
22992306
edit_menu->get_popup()->add_separator();
23002307
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_completion_query"), EDIT_COMPLETE);
23012308
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE);
2309+
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_final_newlines"), EDIT_TRIM_FINAL_NEWLINES);
23022310
{
23032311
PopupMenu *sub_menu = memnew(PopupMenu);
23042312
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);
@@ -2484,6 +2492,7 @@ void ScriptTextEditor::register_editor() {
24842492
ED_SHORTCUT("script_text_editor/evaluate_selection", TTR("Evaluate Selection"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::E);
24852493
ED_SHORTCUT("script_text_editor/toggle_word_wrap", TTR("Toggle Word Wrap"), KeyModifierMask::ALT | Key::Z);
24862494
ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::T);
2495+
ED_SHORTCUT("script_text_editor/trim_final_newlines", TTR("Trim Final Newlines"), Key::NONE);
24872496
ED_SHORTCUT("script_text_editor/convert_indent_to_spaces", TTR("Convert Indent to Spaces"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::Y);
24882497
ED_SHORTCUT("script_text_editor/convert_indent_to_tabs", TTR("Convert Indent to Tabs"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::I);
24892498
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
@@ -756,6 +756,7 @@ void TextShaderEditor::_apply_editor_settings() {
756756
code_editor->update_editor_settings();
757757

758758
trim_trailing_whitespace_on_save = EDITOR_GET("text_editor/behavior/files/trim_trailing_whitespace_on_save");
759+
trim_final_newlines_on_save = EDITOR_GET("text_editor/behavior/files/trim_final_newlines_on_save");
759760
}
760761

761762
void TextShaderEditor::_show_warnings_panel(bool p_show) {
@@ -920,6 +921,10 @@ void TextShaderEditor::save_external_data(const String &p_str) {
920921
trim_trailing_whitespace();
921922
}
922923

924+
if (trim_final_newlines_on_save) {
925+
trim_final_newlines();
926+
}
927+
923928
apply_shaders();
924929

925930
Ref<Shader> edited_shader = code_editor->get_edited_shader();
@@ -946,6 +951,10 @@ void TextShaderEditor::trim_trailing_whitespace() {
946951
code_editor->trim_trailing_whitespace();
947952
}
948953

954+
void TextShaderEditor::trim_final_newlines() {
955+
code_editor->trim_final_newlines();
956+
}
957+
949958
void TextShaderEditor::validate_script() {
950959
code_editor->_validate_script();
951960
}

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)