Skip to content

Commit b3d7f66

Browse files
author
PucklaMotzer09
committed
Add Duplicate Lines shortcut to CodeTextEditor
This keyboard shortcut has been made with inspiration from the VS Code keyboard shortcut editor.action.copyLinesDownAction. It duplicates all selected lines and inserts them below no matter where the caret is within the line.
1 parent 467038d commit b3d7f66

11 files changed

Lines changed: 174 additions & 0 deletions

File tree

doc/classes/CodeEdit.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@
152152
Perform an indent as if the user activated the "ui_text_indent" action.
153153
</description>
154154
</method>
155+
<method name="duplicate_lines">
156+
<return type="void" />
157+
<description>
158+
Duplicates all lines currently selected with any caret. Duplicates the entire line beneath the current one no matter where the caret is within the line.
159+
</description>
160+
</method>
155161
<method name="fold_all_lines">
156162
<return type="void" />
157163
<description>

editor/code_editor.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,11 @@ void CodeTextEditor::input(const Ref<InputEvent> &event) {
805805
accept_event();
806806
return;
807807
}
808+
if (ED_IS_SHORTCUT("script_text_editor/duplicate_lines", key_event)) {
809+
text_editor->duplicate_lines();
810+
accept_event();
811+
return;
812+
}
808813
}
809814

810815
void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) {

editor/plugins/script_text_editor.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,9 @@ void ScriptTextEditor::_edit_option(int p_op) {
13061306
case EDIT_DUPLICATE_SELECTION: {
13071307
code_editor->duplicate_selection();
13081308
} break;
1309+
case EDIT_DUPLICATE_LINES: {
1310+
code_editor->get_text_editor()->duplicate_lines();
1311+
} break;
13091312
case EDIT_TOGGLE_FOLD_LINE: {
13101313
int previous_line = -1;
13111314
for (int caret_idx : tx->get_caret_index_edit_order()) {
@@ -2173,6 +2176,7 @@ void ScriptTextEditor::_enable_code_editor() {
21732176
edit_menu->get_popup()->add_separator();
21742177
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_select_all"), EDIT_SELECT_ALL);
21752178
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION);
2179+
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_lines"), EDIT_DUPLICATE_LINES);
21762180
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE);
21772181
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_word_wrap"), EDIT_TOGGLE_WORD_WRAP);
21782182
edit_menu->get_popup()->add_separator();
@@ -2395,6 +2399,8 @@ void ScriptTextEditor::register_editor() {
23952399
ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), Key::NONE);
23962400
ED_SHORTCUT("script_text_editor/duplicate_selection", TTR("Duplicate Selection"), KeyModifierMask::SHIFT | KeyModifierMask::CTRL | Key::D);
23972401
ED_SHORTCUT_OVERRIDE("script_text_editor/duplicate_selection", "macos", KeyModifierMask::SHIFT | KeyModifierMask::META | Key::C);
2402+
ED_SHORTCUT("script_text_editor/duplicate_lines", TTR("Duplicate Lines"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::DOWN);
2403+
ED_SHORTCUT_OVERRIDE("script_text_editor/duplicate_lines", "macos", KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::DOWN);
23982404
ED_SHORTCUT("script_text_editor/evaluate_selection", TTR("Evaluate Selection"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::E);
23992405
ED_SHORTCUT("script_text_editor/toggle_word_wrap", TTR("Toggle Word Wrap"), KeyModifierMask::ALT | Key::Z);
24002406
ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::T);

editor/plugins/script_text_editor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ class ScriptTextEditor : public ScriptEditorBase {
126126
EDIT_UNINDENT,
127127
EDIT_DELETE_LINE,
128128
EDIT_DUPLICATE_SELECTION,
129+
EDIT_DUPLICATE_LINES,
129130
EDIT_PICK_COLOR,
130131
EDIT_TO_UPPERCASE,
131132
EDIT_TO_LOWERCASE,

editor/plugins/text_editor.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,9 @@ void TextEditor::_edit_option(int p_op) {
392392
case EDIT_DUPLICATE_SELECTION: {
393393
code_editor->duplicate_selection();
394394
} break;
395+
case EDIT_DUPLICATE_LINES: {
396+
code_editor->get_text_editor()->duplicate_lines();
397+
} break;
395398
case EDIT_TOGGLE_FOLD_LINE: {
396399
int previous_line = -1;
397400
for (int caret_idx : tx->get_caret_index_edit_order()) {
@@ -651,6 +654,7 @@ TextEditor::TextEditor() {
651654
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
652655
edit_menu->get_popup()->add_separator();
653656
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION);
657+
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_lines"), EDIT_DUPLICATE_LINES);
654658
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_word_wrap"), EDIT_TOGGLE_WORD_WRAP);
655659
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE);
656660
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);

editor/plugins/text_editor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class TextEditor : public ScriptEditorBase {
7171
EDIT_UNINDENT,
7272
EDIT_DELETE_LINE,
7373
EDIT_DUPLICATE_SELECTION,
74+
EDIT_DUPLICATE_LINES,
7475
EDIT_TO_UPPERCASE,
7576
EDIT_TO_LOWERCASE,
7677
EDIT_CAPITALIZE,

editor/plugins/text_shader_editor.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,9 @@ void TextShaderEditor::_menu_option(int p_option) {
671671
case EDIT_DUPLICATE_SELECTION: {
672672
shader_editor->duplicate_selection();
673673
} break;
674+
case EDIT_DUPLICATE_LINES: {
675+
shader_editor->get_text_editor()->duplicate_lines();
676+
} break;
674677
case EDIT_TOGGLE_WORD_WRAP: {
675678
TextEdit::LineWrappingMode wrap = shader_editor->get_text_editor()->get_line_wrapping_mode();
676679
shader_editor->get_text_editor()->set_line_wrapping_mode(wrap == TextEdit::LINE_WRAPPING_BOUNDARY ? TextEdit::LINE_WRAPPING_NONE : TextEdit::LINE_WRAPPING_BOUNDARY);
@@ -1122,6 +1125,7 @@ TextShaderEditor::TextShaderEditor() {
11221125
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE);
11231126
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
11241127
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION);
1128+
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_lines"), EDIT_DUPLICATE_LINES);
11251129
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_word_wrap"), EDIT_TOGGLE_WORD_WRAP);
11261130
edit_menu->get_popup()->add_separator();
11271131
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_completion_query"), EDIT_COMPLETE);

editor/plugins/text_shader_editor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ class TextShaderEditor : public MarginContainer {
120120
EDIT_UNINDENT,
121121
EDIT_DELETE_LINE,
122122
EDIT_DUPLICATE_SELECTION,
123+
EDIT_DUPLICATE_LINES,
123124
EDIT_TOGGLE_WORD_WRAP,
124125
EDIT_TOGGLE_COMMENT,
125126
EDIT_COMPLETE,

scene/gui/code_edit.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2399,6 +2399,68 @@ void CodeEdit::set_symbol_lookup_word_as_valid(bool p_valid) {
23992399
}
24002400
}
24012401

2402+
/* Text manipulation */
2403+
void CodeEdit::duplicate_lines() {
2404+
begin_complex_operation();
2405+
2406+
Vector<int> caret_edit_order = get_caret_index_edit_order();
2407+
for (const int &caret_index : caret_edit_order) {
2408+
// The text that will be inserted. All lines in one string.
2409+
String insert_text;
2410+
2411+
// The new line position of the caret after the operation.
2412+
int new_caret_line = get_caret_line(caret_index);
2413+
// The new column position of the caret after the operation.
2414+
int new_caret_column = get_caret_column(caret_index);
2415+
// The caret positions of the selection. Stays -1 if there is no selection.
2416+
int select_from_line = -1;
2417+
int select_to_line = -1;
2418+
int select_from_column = -1;
2419+
int select_to_column = -1;
2420+
// Number of lines of the selection.
2421+
int select_num_lines = -1;
2422+
2423+
if (has_selection(caret_index)) {
2424+
select_from_line = get_selection_from_line(caret_index);
2425+
select_to_line = get_selection_to_line(caret_index);
2426+
select_from_column = get_selection_from_column(caret_index);
2427+
select_to_column = get_selection_to_column(caret_index);
2428+
select_num_lines = select_to_line - select_from_line + 1;
2429+
2430+
for (int i = select_from_line; i <= select_to_line; i++) {
2431+
insert_text += "\n" + get_line(i);
2432+
unfold_line(i);
2433+
}
2434+
new_caret_line = select_to_line + select_num_lines;
2435+
} else {
2436+
insert_text = "\n" + get_line(new_caret_line);
2437+
new_caret_line++;
2438+
2439+
unfold_line(get_caret_line(caret_index));
2440+
}
2441+
2442+
// The text will be inserted at the end of the current line.
2443+
set_caret_column(get_line(get_caret_line(caret_index)).length(), false, caret_index);
2444+
2445+
deselect(caret_index);
2446+
2447+
insert_text_at_caret(insert_text, caret_index);
2448+
set_caret_line(new_caret_line, false, true, 0, caret_index);
2449+
set_caret_column(new_caret_column, true, caret_index);
2450+
2451+
if (select_from_line != -1) {
2452+
// Advance the selection by the number of duplicated lines.
2453+
select_from_line += select_num_lines;
2454+
select_to_line += select_num_lines;
2455+
2456+
select(select_from_line, select_from_column, select_to_line, select_to_column, caret_index);
2457+
}
2458+
}
2459+
2460+
end_complex_operation();
2461+
queue_redraw();
2462+
}
2463+
24022464
/* Visual */
24032465
Color CodeEdit::_get_brace_mismatch_color() const {
24042466
return theme_cache.brace_mismatch_color;
@@ -2598,6 +2660,9 @@ void CodeEdit::_bind_methods() {
25982660

25992661
ClassDB::bind_method(D_METHOD("set_symbol_lookup_word_as_valid", "valid"), &CodeEdit::set_symbol_lookup_word_as_valid);
26002662

2663+
/* Text manipulation */
2664+
ClassDB::bind_method(D_METHOD("duplicate_lines"), &CodeEdit::duplicate_lines);
2665+
26012666
/* Inspector */
26022667
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "symbol_lookup_on_click"), "set_symbol_lookup_on_click_enabled", "is_symbol_lookup_on_click_enabled");
26032668
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "line_folding"), "set_line_folding_enabled", "is_line_folding_enabled");

scene/gui/code_edit.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,9 @@ class CodeEdit : public TextEdit {
486486

487487
void set_symbol_lookup_word_as_valid(bool p_valid);
488488

489+
/* Text manipulation */
490+
void duplicate_lines();
491+
489492
CodeEdit();
490493
~CodeEdit();
491494
};

0 commit comments

Comments
 (0)