Index: lldb/include/lldb/Interpreter/CommandCompletions.h =================================================================== --- lldb/include/lldb/Interpreter/CommandCompletions.h +++ lldb/include/lldb/Interpreter/CommandCompletions.h @@ -40,10 +40,11 @@ eProcessPluginCompletion = (1u << 12), eProcessIDCompletion = (1u << 13), eFrameIndexCompletion = (1u << 14), + eThreadIndexCompletion = (1u << 15), // This item serves two purposes. It is the last element in the enum, so // you can add custom enums starting from here in your Option class. Also // if you & in this bit the base code will not process the option. - eCustomCompletion = (1u << 15) + eCustomCompletion = (1u << 16) }; static bool InvokeCommonCompletionCallbacks( @@ -107,6 +108,9 @@ static void FrameIndex(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher); + + static void ThreadIndex(CommandInterpreter &interpreter, + CompletionRequest &request, SearchFilter *searcher); }; } // namespace lldb_private Index: lldb/source/Commands/CommandCompletions.cpp =================================================================== --- lldb/source/Commands/CommandCompletions.cpp +++ lldb/source/Commands/CommandCompletions.cpp @@ -18,6 +18,7 @@ #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Variable.h" +#include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/FileSpec.h" @@ -63,6 +64,7 @@ {eProcessPluginCompletion, CommandCompletions::ProcessPluginNames}, {eProcessIDCompletion, CommandCompletions::ProcessIDs}, {eFrameIndexCompletion, CommandCompletions::FrameIndex}, + {eThreadIndexCompletion, CommandCompletions::ThreadIndex}, {eNoCompletion, nullptr} // This one has to be last in the list. }; @@ -649,4 +651,21 @@ frame_sp->Dump(&strm, false, true); request.TryCompleteCurrentArg(std::to_string(i), strm.GetString()); } -} \ No newline at end of file +} + +void CommandCompletions::ThreadIndex(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + const ExecutionContext &exe_ctx = interpreter.GetExecutionContext(); + if (!exe_ctx.HasProcessScope()) + return; + + ThreadList &threads = exe_ctx.GetProcessPtr()->GetThreadList(); + lldb::ThreadSP thread_sp; + for (uint32_t idx = 0; thread_sp = threads.GetThreadAtIndex(idx); ++idx) { + StreamString strm; + thread_sp->GetStatus(strm, 0, 1, 1, true); + request.TryCompleteCurrentArg(std::to_string(thread_sp->GetIndexID()), + strm.GetString()); + } +} Index: lldb/source/Commands/CommandObjectThread.cpp =================================================================== --- lldb/source/Commands/CommandObjectThread.cpp +++ lldb/source/Commands/CommandObjectThread.cpp @@ -541,6 +541,17 @@ ~CommandObjectThreadStepWithTypeAndScope() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_all_options; } protected: @@ -808,6 +819,14 @@ ~CommandObjectThreadContinue() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + bool DoExecute(Args &command, CommandReturnObject &result) override { bool synchronous_execution = m_interpreter.GetSynchronous(); @@ -1300,6 +1319,17 @@ ~CommandObjectThreadSelect() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Process *process = m_exe_ctx.GetProcessPtr(); @@ -1431,6 +1461,14 @@ ~CommandObjectThreadInfo() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_options; } bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { @@ -1475,6 +1513,14 @@ ~CommandObjectThreadException() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { ThreadSP thread_sp = m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); Index: lldb/test/API/functionalities/completion/TestCompletion.py =================================================================== --- lldb/test/API/functionalities/completion/TestCompletion.py +++ lldb/test/API/functionalities/completion/TestCompletion.py @@ -363,6 +363,22 @@ """Test that 'target va' completes to 'target variable '.""" self.complete_from_to('target va', 'target variable ') + def test_common_completion_thread_index(self): + subcommands = ['continue', 'info', 'exception', 'select', + 'step-in', 'step-inst', 'step-inst-over', 'step-out', 'step-over', 'step-script'] + + # Completion should not work without threads. + for subcommand in subcommands: + self.complete_from_to('thread ' + subcommand + ' ', + 'thread ' + subcommand + ' ') + + self.build() + lldbutil.run_to_source_breakpoint(self, '// Break here', lldb.SBFileSpec("main.cpp")) + + # At least we have the thread at the index of 1 now. + for subcommand in subcommands: + self.complete_from_to('thread ' + subcommand + ' ', ['1']) + def test_command_argument_completion(self): """Test completion of command arguments""" self.complete_from_to("watchpoint set variable -", ["-w", "-s"])