Skip to content

Commit 9746dd9

Browse files
console: implement bash-style history editing
- Edit any history line during UP/DOWN navigation, edits persist - Pressing Enter appends edited version as new history entry - Original line stay untouched in their positions
1 parent 12e6e08 commit 9746dd9

File tree

1 file changed

+48
-15
lines changed

1 file changed

+48
-15
lines changed

common/console.cpp

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,9 @@ namespace console {
665665
bool is_special_char = false;
666666
bool end_of_stream = false;
667667
size_t history_index = history.size();
668+
std::string original_backup;
669+
std::string prompt_backup;
670+
size_t backup_index = SIZE_MAX;
668671

669672
size_t byte_pos = 0; // current byte index
670673
size_t char_pos = 0; // current character index (one char can be multiple bytes)
@@ -673,6 +676,11 @@ namespace console {
673676
while (true) {
674677
assert(char_pos <= byte_pos);
675678
assert(char_pos <= widths.size());
679+
auto sync_history_line = [&]() {
680+
if (history_index < history.size()) {
681+
history[history_index] = line;
682+
}
683+
};
676684

677685
fflush(out); // Ensure all output is displayed before waiting for input
678686
input_char = getchar32();
@@ -732,17 +740,27 @@ namespace console {
732740
// up/down
733741
if (!history.empty()) {
734742
if (code == 'A' && history_index > 0) {
743+
sync_history_line();
744+
const bool from_end = history_index == history.size();
745+
if (from_end) {
746+
prompt_backup = line;
747+
}
735748
history_index--;
749+
original_backup = history[history_index];
750+
backup_index = history_index;
736751
set_line_contents(history[history_index], line, widths, char_pos, byte_pos);
737752
is_special_char = false;
738753
} else if (code == 'B') {
754+
sync_history_line();
739755
if (history_index + 1 < history.size()) {
740756
history_index++;
757+
original_backup = history[history_index];
758+
backup_index = history_index;
741759
set_line_contents(history[history_index], line, widths, char_pos, byte_pos);
742760
is_special_char = false;
743761
} else if (history_index < history.size()) {
744762
history_index = history.size();
745-
set_line_contents("", line, widths, char_pos, byte_pos);
763+
set_line_contents(prompt_backup, line, widths, char_pos, byte_pos);
746764
is_special_char = false;
747765
}
748766
}
@@ -801,20 +819,31 @@ namespace console {
801819
move_to_line_end(char_pos, byte_pos, widths, line);
802820
} else if (input_char == KEY_DELETE) {
803821
delete_at_cursor(line, widths, char_pos, byte_pos);
804-
} else if (input_char == KEY_ARROW_UP || input_char == KEY_ARROW_DOWN) {
805-
if (!history.empty()) {
806-
if (input_char == KEY_ARROW_UP && history_index > 0) {
807-
history_index--;
808-
set_line_contents(history[history_index], line, widths, char_pos, byte_pos);
809-
is_special_char = false;
810-
} else if (input_char == KEY_ARROW_DOWN) {
811-
if (history_index + 1 < history.size()) {
812-
history_index++;
813-
set_line_contents(history[history_index], line, widths, char_pos, byte_pos);
814-
is_special_char = false;
815-
} else if (history_index < history.size()) {
816-
history_index = history.size();
817-
set_line_contents("", line, widths, char_pos, byte_pos);
822+
sync_history_line();
823+
} else if (input_char == KEY_ARROW_UP || input_char == KEY_ARROW_DOWN) {
824+
if (!history.empty()) {
825+
if (input_char == KEY_ARROW_UP && history_index > 0) {
826+
sync_history_line();
827+
const bool from_end = history_index == history.size();
828+
if (from_end) {
829+
prompt_backup = line;
830+
}
831+
history_index--;
832+
original_backup = history[history_index];
833+
backup_index = history_index;
834+
set_line_contents(history[history_index], line, widths, char_pos, byte_pos);
835+
is_special_char = false;
836+
} else if (input_char == KEY_ARROW_DOWN) {
837+
sync_history_line();
838+
if (history_index + 1 < history.size()) {
839+
history_index++;
840+
original_backup = history[history_index];
841+
backup_index = history_index;
842+
set_line_contents(history[history_index], line, widths, char_pos, byte_pos);
843+
is_special_char = false;
844+
} else if (history_index < history.size()) {
845+
history_index = history.size();
846+
set_line_contents(prompt_backup, line, widths, char_pos, byte_pos);
818847
is_special_char = false;
819848
}
820849
}
@@ -848,6 +877,7 @@ namespace console {
848877
fputc(' ', out);
849878
}
850879
move_cursor(-(tail_width + w));
880+
sync_history_line();
851881
}
852882
} else {
853883
// insert character
@@ -925,6 +955,9 @@ namespace console {
925955
}
926956

927957
if (!end_of_stream && !line.empty()) {
958+
if (backup_index < history.size()) {
959+
history[backup_index] = original_backup;
960+
}
928961
std::string history_entry = line;
929962
if (!history_entry.empty() && history_entry.back() == '\n') {
930963
history_entry.pop_back();

0 commit comments

Comments
 (0)