| 741 | } history; |
| 742 | |
| 743 | static bool readline_advanced(std::string & line, bool multiline_input) { |
| 744 | if (out != stdout) { |
| 745 | fflush(stdout); |
| 746 | } |
| 747 | |
| 748 | line.clear(); |
| 749 | std::vector<int> widths; |
| 750 | bool is_special_char = false; |
| 751 | bool end_of_stream = false; |
| 752 | |
| 753 | size_t byte_pos = 0; // current byte index |
| 754 | size_t char_pos = 0; // current character index (one char can be multiple bytes) |
| 755 | |
| 756 | char32_t input_char; |
| 757 | while (true) { |
| 758 | assert(char_pos <= byte_pos); |
| 759 | assert(char_pos <= widths.size()); |
| 760 | auto history_prev = [&]() { |
| 761 | if (!history.is_viewing()) { |
| 762 | history.begin_viewing(line); |
| 763 | } |
| 764 | std::string new_line; |
| 765 | if (!history.prev(new_line)) { |
| 766 | return; |
| 767 | } |
| 768 | set_line_contents(new_line, line, widths, char_pos, byte_pos); |
| 769 | }; |
| 770 | auto history_next = [&]() { |
| 771 | if (history.is_viewing()) { |
| 772 | std::string new_line; |
| 773 | if (!history.next(new_line)) { |
| 774 | return; |
| 775 | } |
| 776 | set_line_contents(new_line, line, widths, char_pos, byte_pos); |
| 777 | } |
| 778 | }; |
| 779 | |
| 780 | fflush(out); // Ensure all output is displayed before waiting for input |
| 781 | input_char = getchar32(); |
| 782 | |
| 783 | if (input_char == '\r' || input_char == '\n') { |
| 784 | break; |
| 785 | } |
| 786 | |
| 787 | if (input_char == (char32_t) WEOF || input_char == 0x04 /* Ctrl+D */) { |
| 788 | end_of_stream = true; |
| 789 | break; |
| 790 | } |
| 791 | |
| 792 | if (is_special_char) { |
| 793 | replace_last(line.back()); |
| 794 | is_special_char = false; |
| 795 | } |
| 796 | |
| 797 | if (input_char == '\033') { // Escape sequence |
| 798 | char32_t code = getchar32(); |
| 799 | if (code == '[') { |
| 800 | std::string params; |
no test coverage detected