From 67a4b35838584c776dcdf38f63b16b648de0d771 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 30 May 2020 14:59:35 -0700 Subject: [PATCH] Migrate cached_layouts into layout_cache_t --- src/env_dispatch.cpp | 2 +- src/fish_tests.cpp | 24 +++++++++++++----------- src/screen.cpp | 16 +++++++++------- src/screen.h | 18 +++++++++++------- 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/env_dispatch.cpp b/src/env_dispatch.cpp index 17969add7..aa6cd8385 100644 --- a/src/env_dispatch.cpp +++ b/src/env_dispatch.cpp @@ -482,7 +482,7 @@ static void init_curses(const environment_t &vars) { tigetflag(const_cast("xenl")) == 1; // does terminal have the eat_newline_glitch update_fish_color_support(vars); // Invalidate the cached escape sequences since they may no longer be valid. - cached_layouts.clear(); + layout_cache_t::shared.clear(); curses_initialized = true; } diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 70a5af99c..36978e988 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -1686,28 +1686,30 @@ static void test_feature_flags() { static void test_escape_sequences() { say(L"Testing escape_sequences"); - if (escape_code_length(L"") != 0) err(L"test_escape_sequences failed on line %d\n", __LINE__); - if (escape_code_length(L"abcd") != 0) + layout_cache_t lc; + if (lc.escape_code_length(L"") != 0) err(L"test_escape_sequences failed on line %d\n", __LINE__); - if (escape_code_length(L"\x1B[2J") != 4) + if (lc.escape_code_length(L"abcd") != 0) err(L"test_escape_sequences failed on line %d\n", __LINE__); - if (escape_code_length(L"\x1B[38;5;123mABC") != std::strlen("\x1B[38;5;123m")) + if (lc.escape_code_length(L"\x1B[2J") != 4) err(L"test_escape_sequences failed on line %d\n", __LINE__); - if (escape_code_length(L"\x1B@") != 2) + if (lc.escape_code_length(L"\x1B[38;5;123mABC") != std::strlen("\x1B[38;5;123m")) + err(L"test_escape_sequences failed on line %d\n", __LINE__); + if (lc.escape_code_length(L"\x1B@") != 2) err(L"test_escape_sequences failed on line %d\n", __LINE__); // iTerm2 escape sequences. - if (escape_code_length(L"\x1B]50;CurrentDir=test/foo\x07NOT_PART_OF_SEQUENCE") != 25) + if (lc.escape_code_length(L"\x1B]50;CurrentDir=test/foo\x07NOT_PART_OF_SEQUENCE") != 25) err(L"test_escape_sequences failed on line %d\n", __LINE__); - if (escape_code_length(L"\x1B]50;SetMark\x07NOT_PART_OF_SEQUENCE") != 13) + if (lc.escape_code_length(L"\x1B]50;SetMark\x07NOT_PART_OF_SEQUENCE") != 13) err(L"test_escape_sequences failed on line %d\n", __LINE__); - if (escape_code_length(L"\x1B]6;1;bg;red;brightness;255\x07NOT_PART_OF_SEQUENCE") != 28) + if (lc.escape_code_length(L"\x1B]6;1;bg;red;brightness;255\x07NOT_PART_OF_SEQUENCE") != 28) err(L"test_escape_sequences failed on line %d\n", __LINE__); - if (escape_code_length(L"\x1B]Pg4040ff\x1B\\NOT_PART_OF_SEQUENCE") != 12) + if (lc.escape_code_length(L"\x1B]Pg4040ff\x1B\\NOT_PART_OF_SEQUENCE") != 12) err(L"test_escape_sequences failed on line %d\n", __LINE__); - if (escape_code_length(L"\x1B]blahblahblah\x1B\\") != 16) + if (lc.escape_code_length(L"\x1B]blahblahblah\x1B\\") != 16) err(L"test_escape_sequences failed on line %d\n", __LINE__); - if (escape_code_length(L"\x1B]blahblahblah\x07") != 15) + if (lc.escape_code_length(L"\x1B]blahblahblah\x07") != 15) err(L"test_escape_sequences failed on line %d\n", __LINE__); } diff --git a/src/screen.cpp b/src/screen.cpp index 3f0e8bf98..c66931bf6 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -60,7 +60,7 @@ class scoped_buffer_t { // Singleton of the cached escape sequences seen in prompts and similar strings. // Note this is deliberately exported so that init_curses can clear it. -layout_cache_t cached_layouts; +layout_cache_t layout_cache_t::shared; /// Tests if the specified narrow character sequence is present at the specified position of the /// specified wide character string. All of \c seq must match, but str may be longer than seq. @@ -239,11 +239,11 @@ static bool is_visual_escape_seq(const wchar_t *code, size_t *resulting_length) /// Returns the number of characters in the escape code starting at 'code'. We only handle sequences /// that begin with \x1B. If it doesn't we return zero. We also return zero if we don't recognize /// the escape sequence based on querying terminfo and other heuristics. -size_t escape_code_length(const wchar_t *code) { +size_t layout_cache_t::escape_code_length(const wchar_t *code) { assert(code != nullptr); if (*code != L'\x1B') return 0; - size_t esc_seq_len = cached_layouts.find_escape_code(code); + size_t esc_seq_len = this->find_escape_code(code); if (esc_seq_len) return esc_seq_len; bool found = is_color_escape_seq(code, &esc_seq_len); @@ -253,7 +253,7 @@ size_t escape_code_length(const wchar_t *code) { if (!found) found = is_three_byte_escape_seq(code, &esc_seq_len); if (!found) found = is_csi_style_escape_seq(code, &esc_seq_len); if (!found) found = is_two_byte_escape_seq(code, &esc_seq_len); - if (found) cached_layouts.add_escape_code(wcstring(code, esc_seq_len)); + if (found) this->add_escape_code(wcstring(code, esc_seq_len)); return esc_seq_len; } @@ -293,7 +293,7 @@ static prompt_layout_t calc_prompt_layout(const wcstring &prompt_str, layout_cac for (size_t j = 0; prompt[j]; j++) { if (prompt[j] == L'\x1B') { // This is the start of an escape code. Skip over it if it's at least one char long. - size_t len = escape_code_length(&prompt[j]); + size_t len = cache.escape_code_length(&prompt[j]); if (len > 0) j += len - 1; } else if (prompt[j] == L'\t') { current_line_width = next_tab_stop(current_line_width); @@ -322,8 +322,8 @@ static size_t calc_prompt_lines(const wcstring &prompt) { // appear in an escape sequence, so if we detect a newline we have to defer to // calc_prompt_width_and_lines. size_t result = 1; - if (prompt.find(L'\n') != wcstring::npos || prompt.find(L'\f') != wcstring::npos) { - result = calc_prompt_layout(prompt, cached_layouts).line_count; + if (prompt.find_first_of(L"\n\f") != wcstring::npos) { + result = calc_prompt_layout(prompt, layout_cache_t::shared).line_count; } return result; } @@ -604,6 +604,7 @@ static void invalidate_soft_wrap(screen_t *scr) { scr->soft_wrap_location = none /// Update the screen to match the desired output. static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring &right_prompt) { + layout_cache_t &cached_layouts = layout_cache_t::shared; const environment_t &vars = env_stack_t::principal(); const scoped_buffer_t buffering(*scr); const size_t left_prompt_width = @@ -862,6 +863,7 @@ static screen_layout_t compute_layout(screen_t *s, size_t screen_width, const wchar_t *right_prompt = right_prompt_str.c_str(); const wchar_t *autosuggestion = autosuggestion_str.c_str(); + layout_cache_t &cached_layouts = layout_cache_t::shared; prompt_layout_t left_prompt_layout = calc_prompt_layout(left_prompt_str, cached_layouts); prompt_layout_t right_prompt_layout = calc_prompt_layout(right_prompt_str, cached_layouts); diff --git a/src/screen.h b/src/screen.h index 612827241..8cdd61752 100644 --- a/src/screen.h +++ b/src/screen.h @@ -214,9 +214,6 @@ void s_reset(screen_t *s, screen_reset_mode_t mode); /// Issues an immediate clr_eos. void screen_force_clear_to_end(); -/// Returns the length of an escape code. Exposed for testing purposes only. -size_t escape_code_length(const wchar_t *code); - // Information about the layout of a prompt. struct prompt_layout_t { size_t line_count; // how many lines the prompt consumes @@ -250,6 +247,9 @@ class layout_cache_t { } } + /// \return the length of an escape code, accessing and perhaps populating the cache. + size_t escape_code_length(const wchar_t *code); + /// \return the length of a string that matches a prefix of \p entry. size_t find_escape_code(const wchar_t *entry) const { // Do a binary search and see if the escape code right before our entry is a prefix of our @@ -275,10 +275,14 @@ class layout_cache_t { esc_cache_.clear(); prompt_cache_.clear(); } + + // Singleton that is exposed so that the cache can be invalidated when terminal related + // variables change by calling `cached_esc_sequences.clear()`. + static layout_cache_t shared; + + layout_cache_t() = default; + layout_cache_t(const layout_cache_t &) = delete; + void operator=(const layout_cache_t &) = delete; }; -// Singleton that is exposed so that the cache can be invalidated when terminal related variables -// change by calling `cached_esc_sequences.clear()`. -extern layout_cache_t cached_layouts; - #endif