From 14c6a12782e890d2c53b949a654e5c28fb2be02a Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Tue, 4 Feb 2020 12:47:44 +0100 Subject: [PATCH] Use accessor functions for editable_line_t::{text,position} This is paving the way for undo, where we want to have one central place for modifying an editable_line_t. --- src/pager.cpp | 10 +- src/reader.cpp | 241 +++++++++++++++++++++++++------------------------ src/reader.h | 27 ++++-- 3 files changed, 143 insertions(+), 135 deletions(-) diff --git a/src/pager.cpp b/src/pager.cpp index 4c6d4219f..c8a0622b6 100644 --- a/src/pager.cpp +++ b/src/pager.cpp @@ -347,7 +347,7 @@ bool pager_t::completion_info_passes_filter(const comp_t &info) const { // If we have no filter, everything passes. if (!search_field_shown || this->search_field_line.empty()) return true; - const wcstring &needle = this->search_field_line.text; + const wcstring &needle = this->search_field_line.text(); // We do full fuzzy matching just like the completion code itself. const fuzzy_match_type_t limit = fuzzy_match_none; @@ -515,7 +515,7 @@ bool pager_t::completion_try_print(size_t cols, const wcstring &prefix, const co } // Add the search field. - wcstring search_field_text = search_field_line.text; + wcstring search_field_text = search_field_line.text(); // Append spaces to make it at least the required width. if (search_field_text.size() < PAGER_SEARCH_FIELD_WIDTH) { search_field_text.append(PAGER_SEARCH_FIELD_WIDTH - search_field_text.size(), L' '); @@ -581,8 +581,8 @@ void pager_t::update_rendering(page_rendering_t *rendering) const { rendering->selected_completion_idx != this->visual_selected_completion_index(rendering->rows, rendering->cols) || rendering->search_field_shown != this->search_field_shown || - rendering->search_field_line.text != this->search_field_line.text || - rendering->search_field_line.position != this->search_field_line.position || + rendering->search_field_line.text() != this->search_field_line.text() || + rendering->search_field_line.position() != this->search_field_line.position() || (rendering->remaining_to_disclose > 0 && this->fully_disclosed)) { *rendering = this->render(); } @@ -848,7 +848,7 @@ void pager_t::set_search_field_shown(bool flag) { this->search_field_shown = fla bool pager_t::is_search_field_shown() const { return this->search_field_shown; } size_t pager_t::cursor_position() const { - size_t result = std::wcslen(SEARCH_FIELD_PROMPT) + this->search_field_line.position; + size_t result = std::wcslen(SEARCH_FIELD_PROMPT) + this->search_field_line.position(); // Clamp it to the right edge. if (available_term_width > 0 && result + 1 > available_term_width) { result = available_term_width - 1; diff --git a/src/reader.cpp b/src/reader.cpp index 42203746a..5cbe9fa22 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -150,8 +150,8 @@ void editable_line_t::insert_string(const wcstring &str, size_t start, size_t le start = std::min(start, string_length); //!OCLINT(parameter reassignment) len = std::min(len, string_length - start); //!OCLINT(parameter reassignment) - this->text.insert(this->position, str, start, len); - this->position += len; + this->text().insert(this->position(), str, start, len); + this->position() += len; } namespace { @@ -598,7 +598,7 @@ wcstring combine_command_and_autosuggestion(const wcstring &cmdline, /// Update the cursor position. void reader_data_t::update_buff_pos(editable_line_t *el, size_t buff_pos) { - el->position = buff_pos; + el->position() = buff_pos; if (el == &command_line && sel_active) { if (sel_begin_pos <= buff_pos) { sel_start_pos = sel_begin_pos; @@ -615,14 +615,14 @@ void reader_data_t::update_buff_pos(editable_line_t *el, size_t buff_pos) { void reader_data_t::repaint() { editable_line_t *cmd_line = &command_line; // Update the indentation. - indents = parse_util_compute_indents(cmd_line->text); + indents = parse_util_compute_indents(cmd_line->text()); wcstring full_line; if (silent) { - full_line = wcstring(cmd_line->text.length(), get_obfuscation_read_char()); + full_line = wcstring(cmd_line->text().length(), get_obfuscation_read_char()); } else { // Combine the command and autosuggestion into one string. - full_line = combine_command_and_autosuggestion(cmd_line->text, autosuggestion); + full_line = combine_command_and_autosuggestion(cmd_line->text(), autosuggestion); } size_t len = full_line.size(); @@ -650,7 +650,7 @@ void reader_data_t::repaint() { pager.update_rendering(¤t_page_rendering); bool focused_on_pager = active_edit_line() == &pager.search_field_line; - size_t cursor_position = focused_on_pager ? pager.cursor_position() : cmd_line->position; + size_t cursor_position = focused_on_pager ? pager.cursor_position() : cmd_line->position(); // Prepend the mode prompt to the left prompt. s_write(&screen, mode_prompt_buff + left_prompt_buff, right_prompt_buff, full_line, @@ -662,7 +662,7 @@ void reader_data_t::repaint() { /// Internal helper function for handling killing parts of text. void reader_data_t::kill(editable_line_t *el, size_t begin_idx, size_t length, int mode, int newv) { - const wchar_t *begin = el->text.c_str() + begin_idx; + const wchar_t *begin = el->text().c_str() + begin_idx; if (newv) { kill_item = wcstring(begin, length); kill_add(kill_item); @@ -678,14 +678,14 @@ void reader_data_t::kill(editable_line_t *el, size_t begin_idx, size_t length, i kill_replace(old, kill_item); } - if (el->position > begin_idx) { + if (el->position() > begin_idx) { // Move the buff position back by the number of characters we deleted, but don't go past // buff_pos. - size_t backtrack = std::min(el->position - begin_idx, length); - update_buff_pos(el, el->position - backtrack); + size_t backtrack = std::min(el->position() - begin_idx, length); + update_buff_pos(el, el->position() - backtrack); } - el->text.erase(begin_idx, length); + el->text().erase(begin_idx, length); command_line_changed(el); super_highlight_me_plenty(); @@ -815,15 +815,15 @@ bool reader_data_t::expand_abbreviation_as_necessary(size_t cursor_backtrack) { if (expand_abbreviations && el == &command_line) { // Try expanding abbreviations. - size_t cursor_pos = el->position - std::min(el->position, cursor_backtrack); + size_t cursor_pos = el->position() - std::min(el->position(), cursor_backtrack); if (auto new_cmdline = - reader_expand_abbreviation_in_command(el->text, cursor_pos, vars())) { + reader_expand_abbreviation_in_command(el->text(), cursor_pos, vars())) { // We expanded an abbreviation! The cursor moves by the difference in the command line // lengths. - size_t new_buff_pos = el->position + new_cmdline->size() - el->text.size(); + size_t new_buff_pos = el->position() + new_cmdline->size() - el->text().size(); - el->text = std::move(*new_cmdline); + el->text() = std::move(*new_cmdline); update_buff_pos(el, new_buff_pos); command_line_changed(el); result = true; @@ -1096,16 +1096,16 @@ static bool command_ends_history_search(readline_cmd_t c) { void reader_data_t::remove_backward() { editable_line_t *el = active_edit_line(); - if (el->position <= 0) return; + if (el->position() <= 0) return; // Fake composed character sequences by continuing to delete until we delete a character of // width at least 1. int width; do { - update_buff_pos(el, el->position - 1); - width = fish_wcwidth(el->text.at(el->position)); - el->text.erase(el->position, 1); - } while (width == 0 && el->position > 0); + update_buff_pos(el, el->position() - 1); + width = fish_wcwidth(el->text().at(el->position())); + el->text().erase(el->position(), 1); + } while (width == 0 && el->position() > 0); command_line_changed(el); suppress_autosuggestion = true; @@ -1120,7 +1120,7 @@ bool reader_data_t::insert_string(editable_line_t *el, const wcstring &str) { if (str.empty()) return false; el->insert_string(str, 0, str.size()); - update_buff_pos(el, el->position); + update_buff_pos(el, el->position()); command_line_changed(el); if (el == &command_line) { @@ -1128,7 +1128,7 @@ bool reader_data_t::insert_string(editable_line_t *el, const wcstring &str) { // Syntax highlight. Note we must have that buff_pos > 0 because we just added something // nonzero to its length. - assert(el->position > 0); + assert(el->position() > 0); super_highlight_me_plenty(-1); } @@ -1261,12 +1261,12 @@ void reader_data_t::completion_insert(const wchar_t *val, size_t token_end, editable_line_t *el = active_edit_line(); // Move the cursor to the end of the token. - if (el->position != token_end) { + if (el->position() != token_end) { update_buff_pos(el, token_end); // repaint() is done later } - size_t cursor = el->position; - wcstring new_command_line = completion_apply_to_command_line(val, flags, el->text, &cursor, + size_t cursor = el->position(); + wcstring new_command_line = completion_apply_to_command_line(val, flags, el->text(), &cursor, false /* not append only */); set_buffer_maintaining_pager(new_command_line, cursor); } @@ -1343,13 +1343,13 @@ bool reader_data_t::can_autosuggest() const { const editable_line_t *el = active_edit_line(); const wchar_t *whitespace = L" \t\r\n\v"; return allow_autosuggestion && !suppress_autosuggestion && history_search.is_at_end() && - el == &command_line && el->text.find_first_not_of(whitespace) != wcstring::npos; + el == &command_line && el->text().find_first_not_of(whitespace) != wcstring::npos; } // Called after an autosuggestion has been computed on a background thread void reader_data_t::autosuggest_completed(autosuggestion_result_t result) { if (!result.suggestion.empty() && can_autosuggest() && - result.search_string == command_line.text && + result.search_string == command_line.text() && string_prefixes_string_case_insensitive(result.search_string, result.suggestion)) { // Autosuggestion is active and the search term has not changed, so we're good to go. autosuggestion = std::move(result.suggestion); @@ -1364,7 +1364,8 @@ void reader_data_t::update_autosuggestion() { autosuggestion.clear(); if (can_autosuggest()) { const editable_line_t *el = active_edit_line(); - auto performer = get_autosuggestion_performer(parser(), el->text, el->position, history); + auto performer = + get_autosuggestion_performer(parser(), el->text(), el->position(), history); auto shared_this = this->shared_from_this(); iothread_perform(performer, [shared_this](autosuggestion_result_t result) { shared_this->autosuggest_completed(std::move(result)); @@ -1382,14 +1383,14 @@ void reader_data_t::accept_autosuggestion(bool full, move_word_style_t style) { // Accept the autosuggestion. if (full) { // Just take the whole thing. - command_line.text = autosuggestion; + command_line.text() = autosuggestion; } else { // Accept characters according to the specified style. move_word_state_machine_t state(style); for (size_t idx = command_line.size(); idx < autosuggestion.size(); idx++) { wchar_t wc = autosuggestion.at(idx); if (!state.consume_char(wc)) break; - command_line.text.push_back(wc); + command_line.text().push_back(wc); } } update_buff_pos(&command_line, command_line.size()); @@ -1418,7 +1419,7 @@ void reader_data_t::select_completion_in_direction(selection_motion_t dir) { void reader_data_t::flash() { struct timespec pollint; editable_line_t *el = &command_line; - for (size_t i = 0; i < el->position; i++) { + for (size_t i = 0; i < el->position(); i++) { colors.at(i) = highlight_spec_t::make_background(highlight_role_t::search_match); } @@ -1500,7 +1501,7 @@ bool reader_data_t::handle_completions(const completion_list_t &comp, size_t tok bool success = false; const editable_line_t *el = &command_line; - const wcstring tok(el->text.c_str() + token_begin, token_end - token_begin); + const wcstring tok(el->text().c_str() + token_begin, token_end - token_begin); // Check trivial cases. size_t size = comp.size(); @@ -1825,7 +1826,7 @@ static void reader_interactive_destroy() { } void reader_data_t::sanity_check() const { - if (command_line.position > command_line.size()) sanity_lose(); + if (command_line.position() > command_line.size()) sanity_lose(); if (colors.size() != command_line.size()) sanity_lose(); if (indents.size() != command_line.size()) sanity_lose(); } @@ -1833,7 +1834,7 @@ void reader_data_t::sanity_check() const { /// Set the specified string as the current buffer. void reader_data_t::set_command_line_and_position(editable_line_t *el, const wcstring &new_str, size_t pos) { - el->text = new_str; + el->text() = new_str; update_buff_pos(el, pos); command_line_changed(el); super_highlight_me_plenty(); @@ -1846,8 +1847,8 @@ void reader_data_t::replace_current_token(const wcstring &new_token) { // Find current token. editable_line_t *el = active_edit_line(); - const wchar_t *buff = el->text.c_str(); - parse_util_token_extent(buff, el->position, &begin, &end, nullptr, nullptr); + const wchar_t *buff = el->text().c_str(); + parse_util_token_extent(buff, el->position(), &begin, &end, nullptr, nullptr); if (!begin || !end) return; @@ -1883,14 +1884,14 @@ void reader_data_t::move_word(editable_line_t *el, bool move_right, bool erase, enum move_word_style_t style, bool newv) { // Return if we are already at the edge. const size_t boundary = move_right ? el->size() : 0; - if (el->position == boundary) return; + if (el->position() == boundary) return; // When moving left, a value of 1 means the character at index 0. move_word_state_machine_t state(style); - const wchar_t *const command_line = el->text.c_str(); - const size_t start_buff_pos = el->position; + const wchar_t *const command_line = el->text().c_str(); + const size_t start_buff_pos = el->position(); - size_t buff_pos = el->position; + size_t buff_pos = el->position(); while (buff_pos != boundary) { size_t idx = (move_right ? buff_pos : buff_pos - 1); wchar_t c = command_line[idx]; @@ -1925,7 +1926,7 @@ void reader_data_t::set_buffer_maintaining_pager(const wcstring &b, size_t pos) // Callers like to pass us pointers into ourselves, so be careful! I don't know if we can use // operator= with a pointer to our interior, so use an intermediate. size_t command_line_len = b.size(); - command_line.text = b; + command_line.text() = b; command_line_changed(&command_line); // Don't set a position past the command line length. @@ -2015,7 +2016,7 @@ void reader_data_t::highlight_search() { } const wcstring &needle = history_search.search_string(); const editable_line_t *el = &command_line; - size_t match_pos = el->text.find(needle); + size_t match_pos = el->text().find(needle); if (match_pos != wcstring::npos) { size_t end = match_pos + needle.size(); for (size_t i = match_pos; i < end; i++) { @@ -2026,7 +2027,7 @@ void reader_data_t::highlight_search() { void reader_data_t::highlight_complete(highlight_result_t result) { ASSERT_IS_MAIN_THREAD(); - if (result.text == command_line.text) { + if (result.text == command_line.text()) { // The data hasn't changed, so swap in our colors. The colors may not have changed, so do // nothing if they have not. assert(result.colors.size() == command_line.size()); @@ -2066,13 +2067,13 @@ static std::function get_highlight_performer( void reader_data_t::super_highlight_me_plenty(int match_highlight_pos_adjust, bool no_io) { const editable_line_t *el = &command_line; assert(el != nullptr); - long match_highlight_pos = static_cast(el->position) + match_highlight_pos_adjust; + long match_highlight_pos = static_cast(el->position()) + match_highlight_pos_adjust; assert(match_highlight_pos >= 0); sanity_check(); auto highlight_performer = get_highlight_performer( - parser(), el->text, match_highlight_pos, no_io ? highlight_shell_no_io : highlight_func); + parser(), el->text(), match_highlight_pos, no_io ? highlight_shell_no_io : highlight_func); if (no_io) { // Highlighting without IO, we just do it. highlight_complete(highlight_performer()); @@ -2088,7 +2089,7 @@ void reader_data_t::super_highlight_me_plenty(int match_highlight_pos_adjust, bo // Here's a hack. Check to see if our autosuggestion still applies; if so, don't recompute it. // Since the autosuggestion computation is asynchronous, this avoids "flashing" as you type into // the autosuggestion. - const wcstring &cmd = el->text, &suggest = autosuggestion; + const wcstring &cmd = el->text(), &suggest = autosuggestion; if (can_autosuggest() && !suggest.empty() && string_prefixes_string_case_insensitive(cmd, suggest)) { // the autosuggestion is still reasonable, so do nothing @@ -2297,7 +2298,7 @@ static int read_i(parser_t &parser) { } else if (tmp) { const wcstring command = tmp.acquire(); data->update_buff_pos(&data->command_line, 0); - data->command_line.text.clear(); + data->command_line.text().clear(); data->command_line_changed(&data->command_line); wcstring_list_t argv(1, command); event_fire_generic(parser, L"fish_preexec", &argv); @@ -2454,19 +2455,18 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // Go to beginning of line. case rl::beginning_of_line: { editable_line_t *el = active_edit_line(); - while (el->position > 0 && el->text.at(el->position - 1) != L'\n') { - update_buff_pos(el, el->position - 1); + while (el->position() > 0 && el->text().at(el->position() - 1) != L'\n') { + update_buff_pos(el, el->position() - 1); } - reader_repaint_needed(); break; } case rl::end_of_line: { editable_line_t *el = active_edit_line(); - if (el->position < el->size()) { - const wchar_t *buff = el->text.c_str(); - while (buff[el->position] && buff[el->position] != L'\n') { - update_buff_pos(el, el->position + 1); + if (el->position() < el->size()) { + const wchar_t *buff = el->text().c_str(); + while (buff[el->position()] && buff[el->position()] != L'\n') { + update_buff_pos(el, el->position() + 1); } } else { accept_autosuggestion(true); @@ -2539,23 +2539,23 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // Either the user hit tab only once, or we had no visible completion list. // Remove a trailing backslash. This may trigger an extra repaint, but this is // rare. - if (is_backslashed(el->text, el->position)) { + if (is_backslashed(el->text(), el->position())) { remove_backward(); } // Get the string; we have to do this after removing any trailing backslash. - const wchar_t *const buff = el->text.c_str(); + const wchar_t *const buff = el->text().c_str(); // Figure out the extent of the command substitution surrounding the cursor. // This is because we only look at the current command substitution to form // completions - stuff happening outside of it is not interesting. const wchar_t *cmdsub_begin, *cmdsub_end; - parse_util_cmdsubst_extent(buff, el->position, &cmdsub_begin, &cmdsub_end); + parse_util_cmdsubst_extent(buff, el->position(), &cmdsub_begin, &cmdsub_end); // Figure out the extent of the token within the command substitution. Note we // pass cmdsub_begin here, not buff. const wchar_t *token_begin, *token_end; - parse_util_token_extent(cmdsub_begin, el->position - (cmdsub_begin - buff), + parse_util_token_extent(cmdsub_begin, el->position() - (cmdsub_begin - buff), &token_begin, &token_end, nullptr, nullptr); // Hack: the token may extend past the end of the command substitution, e.g. in @@ -2573,14 +2573,14 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // User-supplied completions may have changed the commandline - prevent buffer // overflow. - if (token_begin > buff + el->text.size()) token_begin = buff + el->text.size(); - if (token_end > buff + el->text.size()) token_end = buff + el->text.size(); + if (token_begin > buff + el->text().size()) token_begin = buff + el->text().size(); + if (token_end > buff + el->text().size()) token_end = buff + el->text().size(); // Munge our completions. completions_sort_and_prioritize(&rls.comp); // Record our cycle_command_line. - cycle_command_line = el->text; + cycle_command_line = el->text(); cycle_cursor_pos = token_end - buff; bool cont_after_prefix_insertion = (c == rl::complete_and_search); @@ -2611,8 +2611,8 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } case rl::kill_line: { editable_line_t *el = active_edit_line(); - const wchar_t *buff = el->text.c_str(); - const wchar_t *begin = &buff[el->position]; + const wchar_t *buff = el->text().c_str(); + const wchar_t *begin = &buff[el->position()]; const wchar_t *end = begin; while (*end && *end != L'\n') end++; @@ -2627,11 +2627,11 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } case rl::backward_kill_line: { editable_line_t *el = active_edit_line(); - if (el->position <= 0) { + if (el->position() <= 0) { break; } - const wchar_t *buff = el->text.c_str(); - const wchar_t *end = &buff[el->position]; + const wchar_t *buff = el->text().c_str(); + const wchar_t *end = &buff[el->position()]; const wchar_t *begin = end; begin--; // make sure we delete at least one character (see issue #580) @@ -2651,19 +2651,19 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // We match the emacs behavior here: "kills the entire line including the following // newline". editable_line_t *el = active_edit_line(); - const wchar_t *buff = el->text.c_str(); + const wchar_t *buff = el->text().c_str(); // Back up to the character just past the previous newline, or go to the beginning // of the command line. Note that if the position is on a newline, visually this // looks like the cursor is at the end of a line. Therefore that newline is NOT the // beginning of a line; this justifies the -1 check. - size_t begin = el->position; + size_t begin = el->position(); while (begin > 0 && buff[begin - 1] != L'\n') { begin--; } // Push end forwards to just past the next newline, or just past the last char. - size_t end = el->position; + size_t end = el->position(); while (buff[end] != L'\0') { end++; if (buff[end - 1] == L'\n') { @@ -2702,8 +2702,8 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // Remove the current character in the character buffer and on the screen using // syntax highlighting, etc. editable_line_t *el = active_edit_line(); - if (el->position < el->size()) { - update_buff_pos(el, el->position + 1); + if (el->position() < el->size()) { + update_buff_pos(el, el->position() + 1); remove_backward(); } else if (c == rl::delete_or_exit && el->empty()) { reader_set_end_loop(true); @@ -2731,19 +2731,20 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // Allow backslash-escaped newlines. bool continue_on_next_line = false; - if (el->position >= el->size()) { + if (el->position() >= el->size()) { // We're at the end of the text and not in a comment (issue #1225). continue_on_next_line = - is_backslashed(el->text, el->position) && !text_ends_in_comment(el->text); + is_backslashed(el->text(), el->position()) && !text_ends_in_comment(el->text()); } else { // Allow mid line split if the following character is whitespace (issue #613). - if (is_backslashed(el->text, el->position) && iswspace(el->text.at(el->position))) { + if (is_backslashed(el->text(), el->position()) && + iswspace(el->text().at(el->position()))) { continue_on_next_line = true; // Check if the end of the line is backslashed (issue #4467). - } else if (is_backslashed(el->text, el->size()) && - !text_ends_in_comment(el->text)) { + } else if (is_backslashed(el->text(), el->size()) && + !text_ends_in_comment(el->text())) { // Move the cursor to the end of the line. - el->position = el->size(); + el->set_position(el->size()); continue_on_next_line = true; } } @@ -2754,7 +2755,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } // See if this command is valid. - int command_test_result = test_func(parser(), el->text); + int command_test_result = test_func(parser(), el->text()); if (command_test_result == 0 || command_test_result == PARSER_TEST_INCOMPLETE) { // This command is valid, but an abbreviation may make it invalid. If so, we // will have to test again. @@ -2762,7 +2763,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat if (abbreviation_expanded) { // It's our reponsibility to rehighlight and repaint. But everything we do // below triggers a repaint. - command_test_result = test_func(parser(), el->text); + command_test_result = test_func(parser(), el->text()); // If the command is OK, then we're going to execute it. We still want to do // syntax highlighting, but a synchronous variant that performs no I/O, so @@ -2776,8 +2777,8 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // Finished command, execute it. Don't add items that start with a leading // space. const editable_line_t *el = &command_line; - if (history != nullptr && !el->empty() && el->text.at(0) != L' ') { - history->add_pending_with_file_detection(el->text, vars.get_pwd_slash()); + if (history != nullptr && !el->empty() && el->text().at(0) != L' ') { + history->add_pending_with_file_detection(el->text(), vars.get_pwd_slash()); } rls.finished = true; update_buff_pos(&command_line, command_line.size()); @@ -2814,8 +2815,8 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat if (mode == reader_history_search_t::token) { // Searching by token. const wchar_t *begin, *end; - const wchar_t *buff = el->text.c_str(); - parse_util_token_extent(buff, el->position, &begin, &end, nullptr, nullptr); + const wchar_t *buff = el->text().c_str(); + parse_util_token_extent(buff, el->position(), &begin, &end, nullptr, nullptr); if (begin) { wcstring token(begin, end); history_search.reset_to_mode(token, history, @@ -2826,7 +2827,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } } else { // Searching by line. - history_search.reset_to_mode(el->text, history, mode); + history_search.reset_to_mode(el->text(), history, mode); // Skip the autosuggestion in the history unless it was truncated. const wcstring &suggest = autosuggestion; @@ -2851,8 +2852,8 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat editable_line_t *el = active_edit_line(); if (is_navigating_pager_contents()) { select_completion_in_direction(selection_motion_t::west); - } else if (el->position > 0) { - update_buff_pos(el, el->position - 1); + } else if (el->position() > 0) { + update_buff_pos(el, el->position() - 1); reader_repaint_needed(); } break; @@ -2861,8 +2862,8 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat editable_line_t *el = active_edit_line(); if (is_navigating_pager_contents()) { select_completion_in_direction(selection_motion_t::east); - } else if (el->position < el->size()) { - update_buff_pos(el, el->position + 1); + } else if (el->position() < el->size()) { + update_buff_pos(el, el->position() + 1); reader_repaint_needed(); } else { accept_autosuggestion(true); @@ -2907,7 +2908,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat auto move_style = (c == rl::forward_word) ? move_word_style_punctuation : move_word_style_whitespace; editable_line_t *el = active_edit_line(); - if (el->position < el->size()) { + if (el->position() < el->size()) { move_word(el, MOVE_DIR_RIGHT, false /* do not erase */, move_style, false); } else { accept_autosuggestion(false, move_style); @@ -2955,7 +2956,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } else { // Not navigating the pager contents. editable_line_t *el = active_edit_line(); - int line_old = parse_util_get_line_from_offset(el->text, el->position); + int line_old = parse_util_get_line_from_offset(el->text(), el->position()); int line_new; if (c == rl::up_line) @@ -2963,7 +2964,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat else line_new = line_old + 1; - int line_count = parse_util_lineno(el->text.c_str(), el->size()) - 1; + int line_count = parse_util_lineno(el->text().c_str(), el->size()) - 1; if (line_new >= 0 && line_new <= line_count) { size_t base_pos_new; @@ -2974,18 +2975,18 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat size_t line_offset_old; size_t total_offset_new; - base_pos_new = parse_util_get_offset_from_line(el->text, line_new); + base_pos_new = parse_util_get_offset_from_line(el->text(), line_new); - base_pos_old = parse_util_get_offset_from_line(el->text, line_old); + base_pos_old = parse_util_get_offset_from_line(el->text(), line_old); assert(base_pos_new != (size_t)(-1) && base_pos_old != (size_t)(-1)); indent_old = indents.at(base_pos_old); indent_new = indents.at(base_pos_new); line_offset_old = - el->position - parse_util_get_offset_from_line(el->text, line_old); + el->position() - parse_util_get_offset_from_line(el->text(), line_old); total_offset_new = parse_util_get_offset( - el->text, line_new, line_offset_old - 4 * (indent_new - indent_old)); + el->text(), line_new, line_offset_old - 4 * (indent_new - indent_old)); update_buff_pos(el, total_offset_new); reader_repaint_needed(); } @@ -3009,32 +3010,32 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } // If the cursor is at the end, transpose the last two characters of the line. - if (el->position == el->size()) { - update_buff_pos(el, el->position - 1); + if (el->position() == el->size()) { + update_buff_pos(el, el->position() - 1); } // Drag the character before the cursor forward over the character at the cursor, // moving the cursor forward as well. - if (el->position > 0) { - wcstring local_cmd = el->text; - std::swap(local_cmd.at(el->position), local_cmd.at(el->position - 1)); - set_command_line_and_position(el, local_cmd, el->position + 1); + if (el->position() > 0) { + wcstring local_cmd = el->text(); + std::swap(local_cmd.at(el->position()), local_cmd.at(el->position() - 1)); + set_command_line_and_position(el, std::move(local_cmd), el->position() + 1); } break; } case rl::transpose_words: { editable_line_t *el = active_edit_line(); size_t len = el->size(); - const wchar_t *buff = el->text.c_str(); + const wchar_t *buff = el->text().c_str(); const wchar_t *tok_begin, *tok_end, *prev_begin, *prev_end; // If we are not in a token, look for one ahead. - size_t buff_pos = el->position; + size_t buff_pos = el->position(); while (buff_pos != len && !iswalnum(buff[buff_pos])) buff_pos++; update_buff_pos(el, buff_pos); - parse_util_token_extent(buff, el->position, &tok_begin, &tok_end, &prev_begin, + parse_util_token_extent(buff, el->position(), &tok_begin, &tok_end, &prev_begin, &prev_end); // In case we didn't find a token at or after the cursor... @@ -3070,10 +3071,10 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat bool capitalized_first = false; // We apply the operation from the current location to the end of the word. - size_t pos = el->position; + size_t pos = el->position(); move_word(el, MOVE_DIR_RIGHT, false, move_word_style_punctuation, false); - for (; pos < el->position; pos++) { - wchar_t chr = el->text.at(pos); + for (; pos < el->position(); pos++) { + wchar_t chr = el->text().at(pos); // We always change the case; this decides whether we go uppercase (true) or // lowercase (false). @@ -3089,7 +3090,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat else chr = towlower(chr); - command_line.text.at(pos) = chr; + command_line.text().at(pos) = chr; capitalized_first = capitalized_first || make_uppercase; } command_line_changed(el); @@ -3099,13 +3100,13 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } case rl::begin_selection: case rl::end_selection: { - sel_start_pos = command_line.position; + sel_start_pos = command_line.position(); if (c == rl::begin_selection) { - sel_stop_pos = command_line.position + 1; + sel_stop_pos = command_line.position() + 1; sel_active = true; - sel_begin_pos = command_line.position; + sel_begin_pos = command_line.position(); } else { - sel_stop_pos = command_line.position; + sel_stop_pos = command_line.position(); sel_active = false; } @@ -3114,8 +3115,8 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat case rl::swap_selection_start_stop: { if (!sel_active) break; size_t tmp = sel_begin_pos; - sel_begin_pos = command_line.position; - sel_start_pos = command_line.position; + sel_begin_pos = command_line.position(); + sel_start_pos = command_line.position(); editable_line_t *el = active_edit_line(); update_buff_pos(el, tmp); break; @@ -3352,7 +3353,7 @@ maybe_t reader_data_t::readline(int nchars_or_0) { outputter_t::stdoutput().set_color(rgb_color_t::reset(), rgb_color_t::reset()); } - return rls.finished ? maybe_t{command_line.text} : none(); + return rls.finished ? maybe_t{command_line.text()} : none(); } bool reader_data_t::jump(jump_direction_t dir, jump_precision_t precision, editable_line_t *el, @@ -3365,7 +3366,7 @@ bool reader_data_t::jump(jump_direction_t dir, jump_precision_t precision, edita switch (dir) { case jump_direction_t::backward: { - size_t tmp_pos = el->position; + size_t tmp_pos = el->position(); while (tmp_pos--) { if (el->at(tmp_pos) == target) { @@ -3380,7 +3381,7 @@ bool reader_data_t::jump(jump_direction_t dir, jump_precision_t precision, edita break; } case jump_direction_t::forward: { - for (size_t tmp_pos = el->position + 1; tmp_pos < el->size(); tmp_pos++) { + for (size_t tmp_pos = el->position() + 1; tmp_pos < el->size(); tmp_pos++) { if (el->at(tmp_pos) == target) { if (precision == jump_precision_t::till && tmp_pos) { tmp_pos--; @@ -3453,7 +3454,7 @@ void reader_react_to_color_change() { const wchar_t *reader_get_buffer() { ASSERT_IS_MAIN_THREAD(); reader_data_t *data = current_data_or_null(); - return data ? data->command_line.text.c_str() : nullptr; + return data ? data->command_line.text().c_str() : nullptr; } history_t *reader_get_history() { @@ -3481,7 +3482,7 @@ size_t reader_get_cursor_pos() { reader_data_t *data = current_data_or_null(); if (!data) return static_cast(-1); - return data->command_line.position; + return data->command_line.position(); } bool reader_get_selection(size_t *start, size_t *len) { diff --git a/src/reader.h b/src/reader.h index a60883711..663b48f2d 100644 --- a/src/reader.h +++ b/src/reader.h @@ -22,27 +22,34 @@ class parser_t; /// Helper class for storing a command line. class editable_line_t { - public: /// The command line. - wcstring text; + wcstring text_; /// The current position of the cursor in the command line. - size_t position; + size_t position_; - const wcstring &get_text() const { return text; } + public: + const wcstring &text() const { return text_; } + + size_t position() const { return position_; } + void set_position(size_t position) { position_ = position; } + + // TODO remove these overloads! + wcstring &text() { return text_; } + size_t &position() { return position_; } // Gets the length of the text. - size_t size() const { return text.size(); } + size_t size() const { return text().size(); } - bool empty() const { return text.empty(); } + bool empty() const { return text().empty(); } void clear() { - text.clear(); - position = 0; + text_.clear(); + set_position(0); } - wchar_t at(size_t idx) { return text.at(idx); } + wchar_t at(size_t idx) { return text().at(idx); } - editable_line_t() : text(), position(0) {} + editable_line_t() : text_(), position_(0) {} /// Inserts a substring of str given by start, len at the cursor position. void insert_string(const wcstring &str, size_t start = 0, size_t len = wcstring::npos);