diff --git a/lldb/include/lldb/Interpreter/CommandCompletions.h b/lldb/include/lldb/Interpreter/CommandCompletions.h --- a/lldb/include/lldb/Interpreter/CommandCompletions.h +++ b/lldb/include/lldb/Interpreter/CommandCompletions.h @@ -42,10 +42,11 @@ eFrameIndexCompletion = (1u << 14), eModuleUUIDCompletion = (1u << 15), eStopHookIDCompletion = (1u << 16), + eThreadIndexCompletion = (1u << 17), // 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 << 17) + eCustomCompletion = (1u << 18) }; static bool InvokeCommonCompletionCallbacks( @@ -115,6 +116,9 @@ static void StopHookIDs(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher); + + static void ThreadIndexes(CommandInterpreter &interpreter, + CompletionRequest &request, SearchFilter *searcher); }; } // namespace lldb_private diff --git a/lldb/source/Commands/CommandCompletions.cpp b/lldb/source/Commands/CommandCompletions.cpp --- a/lldb/source/Commands/CommandCompletions.cpp +++ b/lldb/source/Commands/CommandCompletions.cpp @@ -19,6 +19,7 @@ #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Variable.h" #include "lldb/Target/Language.h" +#include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/FileSpec.h" @@ -66,6 +67,7 @@ {eTypeLanguageCompletion, CommandCompletions::TypeLanguages}, {eFrameIndexCompletion, CommandCompletions::FrameIndexes}, {eStopHookIDCompletion, CommandCompletions::StopHookIDs}, + {eThreadIndexCompletion, CommandCompletions::ThreadIndexes}, {eNoCompletion, nullptr} // This one has to be last in the list. }; @@ -678,3 +680,20 @@ strm.GetString()); } } + +void CommandCompletions::ThreadIndexes(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()); + } +} diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -549,6 +549,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: @@ -815,6 +826,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(); @@ -1307,6 +1326,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(); @@ -1438,6 +1468,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 { @@ -1482,6 +1520,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); diff --git a/lldb/test/API/functionalities/completion/TestCompletion.py b/lldb/test/API/functionalities/completion/TestCompletion.py --- a/lldb/test/API/functionalities/completion/TestCompletion.py +++ b/lldb/test/API/functionalities/completion/TestCompletion.py @@ -388,6 +388,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 do nothing 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"])