diff options
5 files changed, 53 insertions, 9 deletions
diff --git a/lldb/include/lldb/Utility/CompletionRequest.h b/lldb/include/lldb/Utility/CompletionRequest.h index 88ee3344a3f..28ac78a8756 100644 --- a/lldb/include/lldb/Utility/CompletionRequest.h +++ b/lldb/include/lldb/Utility/CompletionRequest.h @@ -17,7 +17,15 @@ namespace lldb_private { enum class CompletionMode { + // The current token has been completed. Normal, + // The current token has been partially completed. This means that we found + // a completion, but that the completed token is still incomplete. Examples + // for this are file paths, where we want to complete "/bi" to "/bin/", but + // the file path token is still incomplete after the completion. Clients + // should not indicate to the user that this is a full completion (e.g. by + // not inserting the usual trailing space after a successful completion). + Partial, // The full line has been rewritten by the completion. RewriteLine, }; diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/completion/TestCompletion.py b/lldb/packages/Python/lldbsuite/test/functionalities/completion/TestCompletion.py index b95d490c887..0b5b3a416a0 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/completion/TestCompletion.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/completion/TestCompletion.py @@ -137,6 +137,13 @@ class CommandLineCompletionTestCase(TestBase): self.complete_from_to('log enable lldb expr -f ' + src_dir, ['main.cpp']) + @skipIfFreeBSD # timing out on the FreeBSD buildbot + def test_log_file(self): + # Complete in our source directory which contains a 'main.cpp' file. + src_dir = os.path.dirname(os.path.realpath(__file__)) + self.complete_from_to('log enable lldb expr -f ' + src_dir, + [src_dir + "/"]) + # <rdar://problem/11052829> @skipIfFreeBSD # timing out on the FreeBSD buildbot def test_infinite_loop_while_completing(self): diff --git a/lldb/packages/Python/lldbsuite/test/iohandler/completion/TestIOHandlerCompletion.py b/lldb/packages/Python/lldbsuite/test/iohandler/completion/TestIOHandlerCompletion.py index 26805bfb07c..a6748c65619 100644 --- a/lldb/packages/Python/lldbsuite/test/iohandler/completion/TestIOHandlerCompletion.py +++ b/lldb/packages/Python/lldbsuite/test/iohandler/completion/TestIOHandlerCompletion.py @@ -2,6 +2,8 @@ Test completion in our IOHandlers. """ +import os + import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * @@ -48,6 +50,18 @@ class IOHandlerCompletionTest(TestBase): self.expect_string(prompt + "register") self.child.send("\n") + # Try tab completing directories and files. Also tests the partial + # completion where LLDB shouldn't print a space after the directory + # completion (as it didn't completed the full token). + dir_without_slashes = os.path.realpath(os.path.dirname(__file__)).rstrip("/") + self.child.send("file " + dir_without_slashes + "\t") + self.expect_string("iohandler/completion/") + # If we get a correct partial completion without a trailing space, then this + # should complete the current test file. + self.child.send("TestIOHandler\t") + self.expect_string("TestIOHandlerCompletion.py") + self.child.send("\n") + # Start tab completion and abort showing more commands with 'n'. self.child.send("\t") self.expect_string("More (Y/n/a)") diff --git a/lldb/source/Commands/CommandCompletions.cpp b/lldb/source/Commands/CommandCompletions.cpp index a06f9a4db53..f00a35d3d81 100644 --- a/lldb/source/Commands/CommandCompletions.cpp +++ b/lldb/source/Commands/CommandCompletions.cpp @@ -87,10 +87,9 @@ void CommandCompletions::SourceFiles(CommandInterpreter &interpreter, } static void DiskFilesOrDirectories(const llvm::Twine &partial_name, - bool only_directories, StringList &matches, + bool only_directories, + CompletionRequest &request, TildeExpressionResolver &Resolver) { - matches.Clear(); - llvm::SmallString<256> CompletionBuffer; llvm::SmallString<256> Storage; partial_name.toVector(CompletionBuffer); @@ -124,7 +123,7 @@ static void DiskFilesOrDirectories(const llvm::Twine &partial_name, for (const auto &S : MatchSet) { Resolved = S.getKey(); path::append(Resolved, path::get_separator()); - matches.AppendString(Resolved); + request.AddCompletion(Resolved, "", CompletionMode::Partial); } } return; @@ -136,7 +135,7 @@ static void DiskFilesOrDirectories(const llvm::Twine &partial_name, if (FirstSep == llvm::StringRef::npos) { // Make sure it ends with a separator. path::append(CompletionBuffer, path::get_separator()); - matches.AppendString(CompletionBuffer); + request.AddCompletion(CompletionBuffer, "", CompletionMode::Partial); return; } @@ -217,17 +216,27 @@ static void DiskFilesOrDirectories(const llvm::Twine &partial_name, path::append(CompletionBuffer, path::get_separator()); } - matches.AppendString(CompletionBuffer); + CompletionMode mode = + is_dir ? CompletionMode::Partial : CompletionMode::Normal; + request.AddCompletion(CompletionBuffer, "", mode); } } +static void DiskFilesOrDirectories(const llvm::Twine &partial_name, + bool only_directories, StringList &matches, + TildeExpressionResolver &Resolver) { + CompletionResult result; + std::string partial_name_str = partial_name.str(); + CompletionRequest request(partial_name_str, partial_name_str.size(), result); + DiskFilesOrDirectories(partial_name, only_directories, request, Resolver); + result.GetMatches(matches); +} + static void DiskFilesOrDirectories(CompletionRequest &request, bool only_directories) { StandardTildeExpressionResolver resolver; - StringList matches; DiskFilesOrDirectories(request.GetCursorArgumentPrefix(), only_directories, - matches, resolver); - request.AddCompletions(matches); + request, resolver); } void CommandCompletions::DiskFiles(CommandInterpreter &interpreter, diff --git a/lldb/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp index a2e8773f8f1..0a95dffa40e 100644 --- a/lldb/source/Host/common/Editline.cpp +++ b/lldb/source/Host/common/Editline.cpp @@ -954,6 +954,12 @@ unsigned char Editline::TabCommand(int ch) { el_insertstr(m_editline, to_add.c_str()); break; } + case CompletionMode::Partial: { + std::string to_add = completion.GetCompletion(); + to_add = to_add.substr(request.GetCursorArgumentPrefix().size()); + el_insertstr(m_editline, to_add.c_str()); + break; + } case CompletionMode::RewriteLine: { el_deletestr(m_editline, line_info->cursor - line_info->buffer); el_insertstr(m_editline, completion.GetCompletion().c_str()); |