llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

<details>
<summary>Changes</summary>

Implement ansi::StripAnsiTerminalCodes and fix a long standing bug where using 
format strings in lldb's prompt resulted in an incorrect prompt column width.

---
Full diff: https://github.com/llvm/llvm-project/pull/123430.diff


4 Files Affected:

- (modified) lldb/include/lldb/Utility/AnsiTerminal.h (+38) 
- (modified) lldb/source/Host/common/Editline.cpp (+3-1) 
- (modified) lldb/test/API/terminal/TestEditline.py (+16) 
- (modified) lldb/unittests/Utility/AnsiTerminalTest.cpp (+15) 


``````````diff
diff --git a/lldb/include/lldb/Utility/AnsiTerminal.h 
b/lldb/include/lldb/Utility/AnsiTerminal.h
index 67795971d2ca89..22601e873dfe9e 100644
--- a/lldb/include/lldb/Utility/AnsiTerminal.h
+++ b/lldb/include/lldb/Utility/AnsiTerminal.h
@@ -171,7 +171,45 @@ inline std::string FormatAnsiTerminalCodes(llvm::StringRef 
format,
   }
   return fmt;
 }
+
+inline std::string StripAnsiTerminalCodes(llvm::StringRef str) {
+  std::string stripped;
+  while (!str.empty()) {
+    llvm::StringRef left, right;
+
+    std::tie(left, right) = str.split(ANSI_ESC_START);
+    stripped += left;
+
+    // ANSI_ESC_START not found.
+    if (left == str && right.empty())
+      break;
+
+    auto end = llvm::StringRef::npos;
+    for (size_t i = 0; i < right.size(); i++) {
+      char c = right[i];
+      if (c == 'm' || c == 'G') {
+        end = i;
+        break;
+      }
+      if (isdigit(c) || c == ';')
+        continue;
+
+      break;
+    }
+
+    // ANSI_ESC_END not found.
+    if (end != llvm::StringRef::npos) {
+      str = right.substr(end + 1);
+      continue;
+    }
+
+    stripped += ANSI_ESC_START;
+    str = right;
+  }
+  return stripped;
 }
+
+} // namespace ansi
 } // namespace lldb_private
 
 #endif
diff --git a/lldb/source/Host/common/Editline.cpp 
b/lldb/source/Host/common/Editline.cpp
index 6e35b15d69651d..d31fe3af946b37 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -14,6 +14,7 @@
 #include "lldb/Host/Editline.h"
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Host/Host.h"
+#include "lldb/Utility/AnsiTerminal.h"
 #include "lldb/Utility/CompletionRequest.h"
 #include "lldb/Utility/FileSpec.h"
 #include "lldb/Utility/LLDBAssert.h"
@@ -85,7 +86,8 @@ bool IsOnlySpaces(const EditLineStringType &content) {
 }
 
 static size_t ColumnWidth(llvm::StringRef str) {
-  return llvm::sys::locale::columnWidth(str);
+  std::string stripped = ansi::StripAnsiTerminalCodes(str);
+  return llvm::sys::locale::columnWidth(stripped);
 }
 
 static int GetOperation(HistoryOperation op) {
diff --git a/lldb/test/API/terminal/TestEditline.py 
b/lldb/test/API/terminal/TestEditline.py
index aa7d827e599441..40f8a50e06bf6d 100644
--- a/lldb/test/API/terminal/TestEditline.py
+++ b/lldb/test/API/terminal/TestEditline.py
@@ -69,6 +69,22 @@ def test_prompt_color(self):
         # Column: 1....6.8
         self.child.expect(re.escape("\x1b[31m(lldb) \x1b[0m\x1b[8G"))
 
+    @skipIfAsan
+    @skipIfEditlineSupportMissing
+    def test_prompt_format_color(self):
+        """Test that we can change the prompt color with a format string."""
+        self.launch(use_colors=True)
+        # Clear the prefix and suffix setting to simplify the output.
+        self.child.send('settings set prompt-ansi-prefix ""\n')
+        self.child.send('settings set prompt-ansi-suffix ""\n')
+        self.child.send('settings set prompt 
"${ansi.fg.red}(lldb)${ansi.normal} "\n')
+        self.child.send("foo")
+        # Make sure this change is reflected immediately. Check that the color
+        # is set (31) and the cursor position (8) is correct.
+        # Prompt: (lldb) _
+        # Column: 1....6.8
+        self.child.expect(re.escape("\x1b[31m(lldb)\x1b[0m foo"))
+
     @skipIfAsan
     @skipIfEditlineSupportMissing
     def test_prompt_no_color(self):
diff --git a/lldb/unittests/Utility/AnsiTerminalTest.cpp 
b/lldb/unittests/Utility/AnsiTerminalTest.cpp
index a6dbfd61061420..1ba9565c3f6af3 100644
--- a/lldb/unittests/Utility/AnsiTerminalTest.cpp
+++ b/lldb/unittests/Utility/AnsiTerminalTest.cpp
@@ -16,16 +16,21 @@ TEST(AnsiTerminal, Empty) { EXPECT_EQ("", 
ansi::FormatAnsiTerminalCodes("")); }
 
 TEST(AnsiTerminal, WhiteSpace) {
   EXPECT_EQ(" ", ansi::FormatAnsiTerminalCodes(" "));
+  EXPECT_EQ(" ", ansi::StripAnsiTerminalCodes(" "));
 }
 
 TEST(AnsiTerminal, AtEnd) {
   EXPECT_EQ("abc\x1B[30m",
             ansi::FormatAnsiTerminalCodes("abc${ansi.fg.black}"));
+
+  EXPECT_EQ("abc", ansi::StripAnsiTerminalCodes("abc\x1B[30m"));
 }
 
 TEST(AnsiTerminal, AtStart) {
   EXPECT_EQ("\x1B[30mabc",
             ansi::FormatAnsiTerminalCodes("${ansi.fg.black}abc"));
+
+  EXPECT_EQ("abc", ansi::StripAnsiTerminalCodes("\x1B[30mabc"));
 }
 
 TEST(AnsiTerminal, KnownPrefix) {
@@ -45,10 +50,20 @@ TEST(AnsiTerminal, Incomplete) {
 TEST(AnsiTerminal, Twice) {
   EXPECT_EQ("\x1B[30m\x1B[31mabc",
             
ansi::FormatAnsiTerminalCodes("${ansi.fg.black}${ansi.fg.red}abc"));
+
+  EXPECT_EQ("abc", ansi::StripAnsiTerminalCodes("\x1B[30m\x1B[31mabc"));
 }
 
 TEST(AnsiTerminal, Basic) {
   EXPECT_EQ(
       "abc\x1B[31mabc\x1B[0mabc",
       ansi::FormatAnsiTerminalCodes("abc${ansi.fg.red}abc${ansi.normal}abc"));
+
+  EXPECT_EQ("abcabcabc",
+            ansi::StripAnsiTerminalCodes("abc\x1B[31mabc\x1B[0mabc"));
+}
+
+TEST(AnsiTerminal, InvalidEscapeCode) {
+  EXPECT_EQ("abc\x1B[31kabcabc",
+            ansi::StripAnsiTerminalCodes("abc\x1B[31kabc\x1B[0mabc"));
 }

``````````

</details>


https://github.com/llvm/llvm-project/pull/123430
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to