From 8e57d2573f9ac72e94eeaaccbbf1e16327f08f24 Mon Sep 17 00:00:00 2001 From: Sergei Barannikov Date: Sat, 4 Apr 2026 00:14:55 +0300 Subject: [PATCH 1/6] [lldb] Fix output of `help format` The output currently contains ``` "unicode32" 'u' or "unsigned decimal" 'p' or "pointer" "char[]" "int8_t[]" ``` The 'p' and "pointer" are supposed to appear on the same line. When we're about to print "pointer," we check whether it would exceed the column limit (in which case, we insert a line feed). This check only checks for spaces as separators, but in the case of `help format`, the "words" are separated by newlines. Look for them as well. --- lldb/source/Interpreter/CommandInterpreter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index eeb1ae0ff3eb8..b1baab3272968 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -3174,7 +3174,7 @@ void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text, uint32_t chars_left = max_columns; auto nextWordLength = [](llvm::StringRef S) { - size_t pos = S.find(' '); + size_t pos = S.find_first_of(" \n"); return pos == llvm::StringRef::npos ? S.size() : pos; }; From 2964268f4361cb8d5d9e43ad7b2d84353c3c0066 Mon Sep 17 00:00:00 2001 From: Sergei Barannikov Date: Sat, 4 Apr 2026 01:13:18 +0300 Subject: [PATCH 2/6] Better fix and test --- lldb/source/Interpreter/CommandInterpreter.cpp | 6 +++--- lldb/test/API/commands/help/TestHelp.py | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index b1baab3272968..a467a9cc57f0c 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -3173,14 +3173,14 @@ void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text, uint32_t chars_left = max_columns; - auto nextWordLength = [](llvm::StringRef S) { - size_t pos = S.find_first_of(" \n"); + auto nextChunkLength = [](llvm::StringRef S) { + size_t pos = S.find_first_of(" \n", S.find_first_not_of(' ')); return pos == llvm::StringRef::npos ? S.size() : pos; }; while (!text.empty()) { if (text.front() == '\n' || - (text.front() == ' ' && nextWordLength(text.ltrim(' ')) > chars_left)) { + (text.front() == ' ' && nextChunkLength(text) > chars_left)) { strm.EOL(); strm.Indent(); chars_left = max_columns - indent_size; diff --git a/lldb/test/API/commands/help/TestHelp.py b/lldb/test/API/commands/help/TestHelp.py index 8423d410ca306..e5256840dea30 100644 --- a/lldb/test/API/commands/help/TestHelp.py +++ b/lldb/test/API/commands/help/TestHelp.py @@ -239,7 +239,7 @@ def test_help_unknown_flag(self): def test_help_format_output(self): """Test that help output reaches TerminalWidth and wraps to the next line if needed.""" - self.runCmd("settings set term-width 118") + self.runCmd("settings set term-width 105") self.expect( "help format", matching=True, @@ -249,9 +249,9 @@ def test_help_format_output(self): ], ) - # The length of the first line will not be exactly 108 because we split + # The length of the first line will not be exactly 105 because we split # at the last whitespace point before the limit. - self.runCmd("settings set term-width 108") + self.runCmd("settings set term-width 104") self.expect( "help format", matching=True, @@ -271,6 +271,17 @@ def test_help_format_output(self): ], ) + # Check that line splitting works with newline characters too. The raw input after the word "pointer" does not + # contain spaces among the more than one hundred subsequent characters, the words are separated with newlines. + self.runCmd("settings set term-width 80") + self.expect( + "help format", + matching=True, + substrs=[ + "'p' or \"pointer\"" + ], + ) + @no_debug_info_test def test_help_option_group_format_options_usage(self): """Test that help on commands that use OptionGroupFormat options provide relevant help specific to that command.""" From 41c05be7bf3da1ab3725af40ae2cf256adf3a9eb Mon Sep 17 00:00:00 2001 From: Sergei Barannikov Date: Sat, 4 Apr 2026 01:23:07 +0300 Subject: [PATCH 3/6] Reflow python comment and reformat --- lldb/test/API/commands/help/TestHelp.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lldb/test/API/commands/help/TestHelp.py b/lldb/test/API/commands/help/TestHelp.py index e5256840dea30..c8f87c7af27de 100644 --- a/lldb/test/API/commands/help/TestHelp.py +++ b/lldb/test/API/commands/help/TestHelp.py @@ -271,15 +271,14 @@ def test_help_format_output(self): ], ) - # Check that line splitting works with newline characters too. The raw input after the word "pointer" does not - # contain spaces among the more than one hundred subsequent characters, the words are separated with newlines. + # Check that line splitting works with newline characters too. The raw + # input after the word "pointer" does not contain spaces among more than + # a hundred subsequent characters, the words are separated by newlines. self.runCmd("settings set term-width 80") self.expect( "help format", matching=True, - substrs=[ - "'p' or \"pointer\"" - ], + substrs=["'p' or \"pointer\""], ) @no_debug_info_test From e947cb804f6b918d2aad4bc1d6ad25ff2b4f9c69 Mon Sep 17 00:00:00 2001 From: Sergei Barannikov Date: Sat, 4 Apr 2026 01:26:21 +0300 Subject: [PATCH 4/6] Rename the lambda to comply with the coding standard --- lldb/source/Interpreter/CommandInterpreter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index a467a9cc57f0c..b045a3ba3f6ce 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -3173,14 +3173,14 @@ void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text, uint32_t chars_left = max_columns; - auto nextChunkLength = [](llvm::StringRef S) { + auto next_chunk_length = [](llvm::StringRef S) { size_t pos = S.find_first_of(" \n", S.find_first_not_of(' ')); return pos == llvm::StringRef::npos ? S.size() : pos; }; while (!text.empty()) { if (text.front() == '\n' || - (text.front() == ' ' && nextChunkLength(text) > chars_left)) { + (text.front() == ' ' && next_chunk_length(text) > chars_left)) { strm.EOL(); strm.Indent(); chars_left = max_columns - indent_size; From 6a16f77d4213cb72635f9b85e32324ddb390d8a2 Mon Sep 17 00:00:00 2001 From: Sergei Barannikov Date: Sat, 4 Apr 2026 16:10:13 +0300 Subject: [PATCH 5/6] Refactor formatting loop, add comments --- .../source/Interpreter/CommandInterpreter.cpp | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index b045a3ba3f6ce..e7f8cf1f017b1 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -3173,26 +3173,41 @@ void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text, uint32_t chars_left = max_columns; - auto next_chunk_length = [](llvm::StringRef S) { - size_t pos = S.find_first_of(" \n", S.find_first_not_of(' ')); - return pos == llvm::StringRef::npos ? S.size() : pos; + auto start_new_line = [&] { + strm.EOL(); + strm.Indent(); + chars_left = max_columns - indent_size; }; while (!text.empty()) { - if (text.front() == '\n' || - (text.front() == ' ' && next_chunk_length(text) > chars_left)) { - strm.EOL(); - strm.Indent(); - chars_left = max_columns - indent_size; - if (text.front() == '\n') - text = text.drop_front(); - else - text = text.ltrim(' '); - } else { - strm.PutChar(text.front()); - --chars_left; + if (text.starts_with('\n')) { text = text.drop_front(); + start_new_line(); + continue; } + + // Calculate the size of the next fragment. A fragment is defined as zero + // or more spaces followed by a word (which is sequence of non-whitespace + // characters). It is assumed that the only possible whitespaces in the + // input text are ' ' and '\n'. + size_t word_start_pos = text.find_first_not_of(' '); + size_t word_end_pos = text.find_first_of(" \n", /*from=*/word_start_pos); + size_t fragment_size = + word_end_pos == llvm::StringRef::npos ? text.size() : word_end_pos; + + if (fragment_size > chars_left && text.starts_with(' ')) { + // The fragment doesn't fit on the current line, but it starts with + // a space. Break the line at the beginning of the next word. + text = text.drop_front(word_start_pos); + start_new_line(); + continue; + } + + // Print out the fragment. It fits on the current line or does not contain + // spaces where it could be broken. + strm.PutCString(text.take_front(fragment_size)); + text = text.drop_front(fragment_size); + chars_left = fragment_size > chars_left ? 0 : chars_left - fragment_size; } strm.EOL(); From 77c573d20427cfe62b746104dfea934a24b3c3f3 Mon Sep 17 00:00:00 2001 From: Sergei Barannikov Date: Sat, 4 Apr 2026 16:20:36 +0300 Subject: [PATCH 6/6] Minor comment tweaks --- lldb/source/Interpreter/CommandInterpreter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index e7f8cf1f017b1..3e4345727c89b 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -3196,15 +3196,15 @@ void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text, word_end_pos == llvm::StringRef::npos ? text.size() : word_end_pos; if (fragment_size > chars_left && text.starts_with(' ')) { - // The fragment doesn't fit on the current line, but it starts with - // a space. Break the line at the beginning of the next word. + // The fragment does not fit on the current line, but begins with a space. + // Break the line at the beginning of the word contained in the fragment. text = text.drop_front(word_start_pos); start_new_line(); continue; } // Print out the fragment. It fits on the current line or does not contain - // spaces where it could be broken. + // spaces where we could break the line. strm.PutCString(text.take_front(fragment_size)); text = text.drop_front(fragment_size); chars_left = fragment_size > chars_left ? 0 : chars_left - fragment_size;