Skip to content

Commit bf76389

Browse files
committed
[lldb] Make repeat commands work for regex commands
Fix logic for repeat commands, so that regex commands (specificially `bt`) are given the opportunity to provide a repeat command. rdar://104562616 Differential Revision: https://reviews.llvm.org/D143695 (cherry picked from commit 5e0ee1b)
1 parent f38ebc7 commit bf76389

File tree

4 files changed

+38
-8
lines changed

4 files changed

+38
-8
lines changed

lldb/include/lldb/Interpreter/CommandInterpreter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,8 @@ class CommandInterpreter : public Broadcaster,
351351
CommandReturnObject &result);
352352

353353
bool HandleCommand(const char *command_line, LazyBool add_to_history,
354-
CommandReturnObject &result);
354+
CommandReturnObject &result,
355+
bool force_repeat_command = false);
355356

356357
bool WasInterrupted() const;
357358

lldb/source/Commands/CommandObjectRegexCommand.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ bool CommandObjectRegexCommand::DoExecute(llvm::StringRef command,
7373
result.GetOutputStream().Printf("%s\n", new_command->c_str());
7474
// We don't have to pass an override_context here, as the command that
7575
// called us should have set up the context appropriately.
76-
return m_interpreter.HandleCommand(new_command->c_str(),
77-
eLazyBoolNo, result);
76+
bool force_repeat_command = true;
77+
return m_interpreter.HandleCommand(new_command->c_str(), eLazyBoolNo,
78+
result, force_repeat_command);
7879
}
7980
}
8081
result.SetStatus(eReturnStatusFailed);

lldb/source/Interpreter/CommandInterpreter.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1885,8 +1885,8 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
18851885

18861886
bool CommandInterpreter::HandleCommand(const char *command_line,
18871887
LazyBool lazy_add_to_history,
1888-
CommandReturnObject &result) {
1889-
1888+
CommandReturnObject &result,
1889+
bool force_repeat_command) {
18901890
std::string command_string(command_line);
18911891
std::string original_command_string(command_line);
18921892

@@ -2015,17 +2015,26 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
20152015
// arguments.
20162016

20172017
if (cmd_obj != nullptr) {
2018+
bool generate_repeat_command = add_to_history;
20182019
// If we got here when empty_command was true, then this command is a
20192020
// stored "repeat command" which we should give a chance to produce it's
20202021
// repeat command, even though we don't add repeat commands to the history.
2021-
if (add_to_history || empty_command) {
2022+
generate_repeat_command |= empty_command;
2023+
// For `command regex`, the regex command (ex `bt`) is added to history, but
2024+
// the resolved command (ex `thread backtrace`) is _not_ added to history.
2025+
// However, the resolved command must be given the opportunity to provide a
2026+
// repeat command. `force_repeat_command` supports this case.
2027+
generate_repeat_command |= force_repeat_command;
2028+
if (generate_repeat_command) {
20222029
Args command_args(command_string);
20232030
llvm::Optional<std::string> repeat_command =
20242031
cmd_obj->GetRepeatCommand(command_args, 0);
2025-
if (repeat_command)
2032+
if (repeat_command) {
2033+
LLDB_LOGF(log, "Repeat command: %s", repeat_command->data());
20262034
m_repeat_command.assign(*repeat_command);
2027-
else
2035+
} else {
20282036
m_repeat_command.assign(original_command_string);
2037+
}
20292038
}
20302039

20312040
if (add_to_history)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import lldb
2+
from lldbsuite.test.lldbtest import TestBase
3+
from lldbsuite.test import lldbutil
4+
5+
6+
class TestCase(TestBase):
7+
def test(self):
8+
self.build()
9+
lldbutil.run_to_source_breakpoint(self, "return", lldb.SBFileSpec("main.c"))
10+
11+
# Expect "frame #0" but not "frame #1".
12+
self.expect("bt 1", inHistory=True, patterns=["frame #0", "^(?!.*frame #1)"])
13+
14+
# Run an empty command to run the repeat command for `bt`.
15+
# The repeat command for `bt N` lists the subsequent N frames.
16+
#
17+
# In this case, after printing the frame 0 with `bt 1`, the repeat
18+
# command will print "frame #1" (and won't print "frame #0").
19+
self.expect("", patterns=["^(?!.*frame #0)", "frame #1"])

0 commit comments

Comments
 (0)