From b64cec1d7e2baaea44d14dd587f8347ecc5dae26 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Mon, 25 Jul 2022 19:18:53 +0200 Subject: [PATCH] Use Unicode symbols for rendering control characters in pager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The history pager will show multiline commands in single-line cells. We escape newline characters as \\n but that looks awkward if the next line starts with a letter. Let's render control characters using their corresponding symbol from the Control Pictures Unicode block. This means there is also no need to escape backslashes, which further improves the history pager - now the rendering has exactly as many backslashes as the eventual command. This means that (multiline) commands in the history pager will be rendered with the same amount of characters as are in the actual command (unless they contain funny nonprintables). This makes it easy for the next commit to highlight multiline commands correctly in the history pager. The font size for these symbols (for example ␉) is quite small, but that's okay since for the proposed uses it's not so important that they readable. The important thing is that the stand out from surrounding text. --- src/common.cpp | 47 ++++++++++++++++++++++++++++++++--------------- src/common.h | 4 +++- src/pager.cpp | 4 ++-- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/common.cpp b/src/common.cpp index 5627862a5..b6029b933 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -883,6 +883,8 @@ static void escape_string_script(const wchar_t *orig_in, size_t in_len, wcstring const bool no_quoted = static_cast(flags & ESCAPE_NO_QUOTED); const bool no_tilde = static_cast(flags & ESCAPE_NO_TILDE); const bool no_qmark = feature_test(features_t::qmark_noglob); + const bool symbolic = static_cast(flags & ESCAPE_SYMBOLIC) && (MB_CUR_MAX > 1); + assert((!symbolic || !escape_printables) && "symbolic implies escape-no-printables"); bool need_escape = false; bool need_complex_escape = false; @@ -911,47 +913,57 @@ static void escape_string_script(const wchar_t *orig_in, size_t in_len, wcstring wchar_t c = *in; switch (c) { case L'\t': { - out += L'\\'; - out += L't'; + if (symbolic) + out += L'␉'; + else + out += L"\\t"; need_escape = need_complex_escape = true; break; } case L'\n': { - out += L'\\'; - out += L'n'; + if (symbolic) + out += L'␤'; + else + out += L"\\n"; need_escape = need_complex_escape = true; break; } case L'\b': { - out += L'\\'; - out += L'b'; + if (symbolic) + out += L'␈'; + else + out += L"\\b"; need_escape = need_complex_escape = true; break; } case L'\r': { - out += L'\\'; - out += L'r'; + if (symbolic) + out += L'␍'; + else + out += L"\\r"; need_escape = need_complex_escape = true; break; } case L'\x1B': { - out += L'\\'; - out += L'e'; + if (symbolic) + out += L'␛'; + else + out += L"\\e"; need_escape = need_complex_escape = true; break; } case L'\x7F': { - out += L'\\'; - out += L'x'; - out += L'7'; - out += L'f'; + if (symbolic) + out += L'␡'; + else + out += L"\\x7f"; need_escape = need_complex_escape = true; break; } case L'\\': case L'\'': { need_escape = need_complex_escape = true; - if (escape_printables || c == L'\\') out += L'\\'; + if (escape_printables || (c == L'\\' && !symbolic)) out += L'\\'; out += *in; break; } @@ -1001,6 +1013,11 @@ static void escape_string_script(const wchar_t *orig_in, size_t in_len, wcstring if (*in >= 0 && *in < 32) { need_escape = need_complex_escape = true; + if (symbolic) { + out += L'\u2400' + *in; + break; + } + if (*in < 27 && *in != 0) { out += L'\\'; out += L'c'; diff --git a/src/common.h b/src/common.h index e19cb4db9..46ebac2ae 100644 --- a/src/common.h +++ b/src/common.h @@ -148,7 +148,9 @@ enum { /// string. ESCAPE_NO_QUOTED = 1 << 1, /// Do not escape tildes. - ESCAPE_NO_TILDE = 1 << 2 + ESCAPE_NO_TILDE = 1 << 2, + /// Replace nonprintable control characters with Unicode symbols. + ESCAPE_SYMBOLIC = 1 << 3 }; typedef unsigned int escape_flags_t; diff --git a/src/pager.cpp b/src/pager.cpp index 8294603b4..14d841016 100644 --- a/src/pager.cpp +++ b/src/pager.cpp @@ -313,8 +313,8 @@ static comp_info_list_t process_completions_into_infos(const completion_list_t & comp_t *comp_info = &result.at(i); // Append the single completion string. We may later merge these into multiple. - comp_info->comp.push_back( - escape_string(comp.completion, ESCAPE_NO_PRINTABLES | ESCAPE_NO_QUOTED)); + comp_info->comp.push_back(escape_string( + comp.completion, ESCAPE_NO_PRINTABLES | ESCAPE_NO_QUOTED | ESCAPE_SYMBOLIC)); // Append the mangled description. comp_info->desc = comp.description;