From 558ce124eb9787beae314effe12b3c17568625e1 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Wed, 30 Jun 2010 05:02:46 +0000 Subject: [PATCH] Add a source file completer to the CommandCompleters. Add a way for the completers to say whether the completed argument should have a space inserted after is or not. Added the file name completer to the "file" command. llvm-svn: 107247 --- .../lldb/Interpreter/CommandCompletions.h | 35 ++- .../lldb/Interpreter/CommandInterpreter.h | 3 + lldb/include/lldb/Interpreter/CommandObject.h | 93 ++++++- .../lldb/Interpreter/CommandObjectMultiword.h | 1 + lldb/include/lldb/Interpreter/Options.h | 14 +- lldb/source/Commands/CommandCompletions.cpp | 236 +++++++++++++++++- lldb/source/Commands/CommandObjectFile.cpp | 27 ++ lldb/source/Commands/CommandObjectFile.h | 12 + lldb/source/Commands/CommandObjectHelp.cpp | 7 +- lldb/source/Commands/CommandObjectHelp.h | 1 + lldb/source/Commands/CommandObjectImage.cpp | 4 + .../Commands/CommandObjectMultiword.cpp | 11 +- .../source/Interpreter/CommandInterpreter.cpp | 16 +- lldb/source/Interpreter/CommandObject.cpp | 3 + lldb/source/Interpreter/Options.cpp | 6 + 15 files changed, 436 insertions(+), 33 deletions(-) diff --git a/lldb/include/lldb/Interpreter/CommandCompletions.h b/lldb/include/lldb/Interpreter/CommandCompletions.h index f870490c79e4..5d3f47cbd950 100644 --- a/lldb/include/lldb/Interpreter/CommandCompletions.h +++ b/lldb/include/lldb/Interpreter/CommandCompletions.h @@ -34,15 +34,17 @@ public: int match_start_point, // This is the point in the list of matches that you should start returning elements int max_return_elements, // This is the number of matches requested. lldb_private::SearchFilter *searcher,// A search filter to limit the search... + bool &word_complete, lldb_private::StringList &matches); // The array of matches we return. typedef enum { - eNoCompletion = 0, - eSourceFileCompletion = (1 << 0), - eDiskFileCompletion = (1 << 1), - eSymbolCompletion = (1 << 2), - eModuleCompletion = (1 << 3), - eCustomCompletion = (1 << 4) // This item serves two purposes. It is the last element in the enum, + eNoCompletion = 0, + eSourceFileCompletion = (1 << 0), + eDiskFileCompletion = (1 << 1), + eDiskDirectoryCompletion = (1 << 2), + eSymbolCompletion = (1 << 3), + eModuleCompletion = (1 << 4), + eCustomCompletion = (1 << 5) // 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. @@ -60,17 +62,36 @@ public: int match_start_point, int max_return_elements, SearchFilter *searcher, + bool &word_complete, StringList &matches); //---------------------------------------------------------------------- // These are the generic completer functions: //---------------------------------------------------------------------- + static int + DiskFiles (CommandInterpreter &interpreter, + const char *partial_file_name, + int match_start_point, + int max_return_elements, + SearchFilter *searcher, + bool &word_complete, + StringList &matches); + static int + DiskDirectories (CommandInterpreter &interpreter, + const char *partial_file_name, + int match_start_point, + int max_return_elements, + SearchFilter *searcher, + bool &word_complete, + StringList &matches); + static int SourceFiles (CommandInterpreter &interpreter, const char *partial_file_name, int match_start_point, int max_return_elements, SearchFilter *searcher, + bool &word_complete, StringList &matches); static int @@ -79,6 +100,7 @@ public: int match_start_point, int max_return_elements, SearchFilter *searcher, + bool &word_complete, lldb_private::StringList &matches); static int @@ -87,6 +109,7 @@ public: int match_start_point, int max_return_elements, SearchFilter *searcher, + bool &word_complete, lldb_private::StringList &matches); //---------------------------------------------------------------------- diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h b/lldb/include/lldb/Interpreter/CommandInterpreter.h index 26ff3abaf448..7443c5e6856c 100644 --- a/lldb/include/lldb/Interpreter/CommandInterpreter.h +++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -116,6 +116,8 @@ public: // This version just returns matches, and doesn't compute the substring. It is here so the // Help command can call it for the first argument. + // word_complete tells whether a the completions are considered a "complete" response (so the + // completer should complete the quote & put a space after the word. int HandleCompletionMatches (Args &input, @@ -123,6 +125,7 @@ public: int &cursor_char_position, int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches); diff --git a/lldb/include/lldb/Interpreter/CommandObject.h b/lldb/include/lldb/Interpreter/CommandObject.h index 24e43cbd3b45..6cb996fc2c99 100644 --- a/lldb/include/lldb/Interpreter/CommandObject.h +++ b/lldb/include/lldb/Interpreter/CommandObject.h @@ -122,13 +122,46 @@ public: static int AddNamesMatchingPartialString (CommandMap &in_map, const char *cmd_str, StringList &matches); - // The input array contains a parsed version of the line. The insertion - // point is given by cursor_index (the index in input of the word containing - // the cursor) and cursor_char_position (the position of the cursor in that word.) - // This default version handles calling option argument completions and then calls - // HandleArgumentCompletion if the cursor is on an argument, not an option. - // Don't override this method, override HandleArgumentCompletion instead unless - // you have special reasons. + //------------------------------------------------------------------ + /// The input array contains a parsed version of the line. The insertion + /// point is given by cursor_index (the index in input of the word containing + /// the cursor) and cursor_char_position (the position of the cursor in that word.) + /// This default version handles calling option argument completions and then calls + /// HandleArgumentCompletion if the cursor is on an argument, not an option. + /// Don't override this method, override HandleArgumentCompletion instead unless + /// you have special reasons. + /// + /// @param[in] interpreter + /// The command interpreter doing the completion. + /// + /// @param[in] input + /// The command line parsed into words + /// + /// @param[in] cursor_index + /// The index in \ainput of the word in which the cursor lies. + /// + /// @param[in] cursor_char_pos + /// The character position of the cursor in its argument word. + /// + /// @param[in] match_start_point + /// @param[in] match_return_elements + /// FIXME: Not yet implemented... If there is a match that is expensive to compute, these are + /// here to allow you to compute the completions in batches. Start the completion from \amatch_start_point, + /// and return \amatch_return_elements elements. + /// + /// @param[out] word_complete + /// \btrue if this is a complete option value (a space will be inserted after the + /// completion.) \bfalse otherwise. + /// + /// @param[out] matches + /// The array of matches returned. + /// + /// FIXME: This is the wrong return value, since we also need to make a distinction between + /// total number of matches, and the window the user wants returned. + /// + /// @return + /// \btrue if we were in an option, \bfalse otherwise. + //------------------------------------------------------------------ virtual int HandleCompletion (CommandInterpreter &interpreter, Args &input, @@ -136,13 +169,48 @@ public: int &cursor_char_position, int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches); - // The input array contains a parsed version of the line. The insertion - // point is given by cursor_index (the index in input of the word containing - // the cursor) and cursor_char_position (the position of the cursor in that word.) - // We've constructed the map of options and their arguments as well if that is - // helpful for the completion. + //------------------------------------------------------------------ + /// The input array contains a parsed version of the line. The insertion + /// point is given by cursor_index (the index in input of the word containing + /// the cursor) and cursor_char_position (the position of the cursor in that word.) + /// We've constructed the map of options and their arguments as well if that is + /// helpful for the completion. + /// + /// @param[in] interpreter + /// The command interpreter doing the completion. + /// + /// @param[in] input + /// The command line parsed into words + /// + /// @param[in] cursor_index + /// The index in \ainput of the word in which the cursor lies. + /// + /// @param[in] cursor_char_pos + /// The character position of the cursor in its argument word. + /// + /// @param[in] opt_element_vector + /// The results of the options parse of \a input. + /// + /// @param[in] match_start_point + /// @param[in] match_return_elements + /// See CommandObject::HandleCompletions for a description of how these work. + /// + /// @param[out] word_complete + /// \btrue if this is a complete option value (a space will be inserted after the + /// completion.) \bfalse otherwise. + /// + /// @param[out] matches + /// The array of matches returned. + /// + /// FIXME: This is the wrong return value, since we also need to make a distinction between + /// total number of matches, and the window the user wants returned. + /// + /// @return + /// \btrue if we were in an option, \bfalse otherwise. + //------------------------------------------------------------------ virtual int HandleArgumentCompletion (CommandInterpreter &interpreter, @@ -152,6 +220,7 @@ public: OptionElementVector &opt_element_vector, int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches) { return 0; diff --git a/lldb/include/lldb/Interpreter/CommandObjectMultiword.h b/lldb/include/lldb/Interpreter/CommandObjectMultiword.h index b065a296bfd0..d32e7f9b9f12 100644 --- a/lldb/include/lldb/Interpreter/CommandObjectMultiword.h +++ b/lldb/include/lldb/Interpreter/CommandObjectMultiword.h @@ -64,6 +64,7 @@ public: int &cursor_char_position, int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches); CommandObject::CommandMap m_subcommand_dict; diff --git a/lldb/include/lldb/Interpreter/Options.h b/lldb/include/lldb/Interpreter/Options.h index 438d0c93f886..b11ad23b712d 100644 --- a/lldb/include/lldb/Interpreter/Options.h +++ b/lldb/include/lldb/Interpreter/Options.h @@ -208,6 +208,10 @@ public: /// @param[in] interpreter /// The interpreter that's doing the completing. /// + /// @param[out] word_complete + /// \btrue if this is a complete option value (a space will be inserted after the + /// completion.) \bfalse otherwise. + /// /// @param[out] matches /// The array of matches returned. /// @@ -225,12 +229,16 @@ public: int char_pos, int match_start_point, int max_return_elements, + bool &word_complete, lldb_private::StringList &matches); //------------------------------------------------------------------ /// Handles the generic bits of figuring out whether we are in an option, and if so completing /// it. /// + /// @param[in] interpreter + /// The command interpreter doing the completion. + /// /// @param[in] input /// The command line parsed into words /// @@ -250,8 +258,9 @@ public: /// @param[in] match_return_elements /// See CommandObject::HandleCompletions for a description of how these work. /// - /// @param[in] interpreter - /// The interpreter that's doing the completing. + /// @param[out] word_complete + /// \btrue if this is a complete option value (a space will be inserted after the + /// completion.) \bfalse otherwise. /// /// @param[out] matches /// The array of matches returned. @@ -271,6 +280,7 @@ public: int opt_element_index, int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches); protected: diff --git a/lldb/source/Commands/CommandCompletions.cpp b/lldb/source/Commands/CommandCompletions.cpp index 5d42229917b6..9a3a8bf09669 100644 --- a/lldb/source/Commands/CommandCompletions.cpp +++ b/lldb/source/Commands/CommandCompletions.cpp @@ -9,6 +9,11 @@ // C Includes +#include +#include +#include +#include + // C++ Includes // Other libraries and framework includes // Project includes @@ -24,12 +29,13 @@ using namespace lldb_private; CommandCompletions::CommonCompletionElement CommandCompletions::g_common_completions[] = { - {eCustomCompletion, NULL}, - {eSourceFileCompletion, CommandCompletions::SourceFiles}, - {eDiskFileCompletion, NULL}, - {eSymbolCompletion, CommandCompletions::Symbols}, - {eModuleCompletion, CommandCompletions::Modules}, - {eNoCompletion, NULL} // This one has to be last in the list. + {eCustomCompletion, NULL}, + {eSourceFileCompletion, CommandCompletions::SourceFiles}, + {eDiskFileCompletion, CommandCompletions::DiskFiles}, + {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories}, + {eSymbolCompletion, CommandCompletions::Symbols}, + {eModuleCompletion, CommandCompletions::Modules}, + {eNoCompletion, NULL} // This one has to be last in the list. }; bool @@ -41,6 +47,7 @@ CommandCompletions::InvokeCommonCompletionCallbacks int match_start_point, int max_return_elements, SearchFilter *searcher, + bool &word_complete, StringList &matches ) { @@ -62,6 +69,7 @@ CommandCompletions::InvokeCommonCompletionCallbacks match_start_point, max_return_elements, searcher, + word_complete, matches); } } @@ -76,9 +84,11 @@ CommandCompletions::SourceFiles int match_start_point, int max_return_elements, SearchFilter *searcher, + bool &word_complete, StringList &matches ) { + word_complete = true; // Find some way to switch "include support files..." SourceFileCompleter completer (interpreter, false, @@ -100,6 +110,216 @@ CommandCompletions::SourceFiles return matches.GetSize(); } +static int +DiskFilesOrDirectories +( + const char *partial_file_name, + bool only_directories, + bool &saw_directory, + StringList &matches +) +{ + // I'm going to use the "glob" function with GLOB_TILDE for user directory expansion. + // If it is not defined on your host system, you'll need to implement it yourself... + + int partial_name_len = strlen(partial_file_name); + + if (partial_name_len >= PATH_MAX) + return matches.GetSize(); + + // This copy of the string will be cut up into the directory part, and the remainder. end_ptr + // below will point to the place of the remainder in this string. Then when we've resolved the + // containing directory, and opened it, we'll read the directory contents and overwrite the + // partial_name_copy starting from end_ptr with each of the matches. Thus we will preserve + // the form the user originally typed. + + char partial_name_copy[PATH_MAX]; + bcopy (partial_file_name, partial_name_copy, partial_name_len); + partial_name_copy[partial_name_len] = '\0'; + + // We'll need to save a copy of the remainder for comparision, which we do here. + char remainder[PATH_MAX]; + + // end_ptr will point past the last / in partial_name_copy, or if there is no slash to the beginning of the string. + char *end_ptr; + + end_ptr = strrchr(partial_name_copy, '/'); + + // This will store the resolved form of the containing directory + char containing_part[PATH_MAX]; + + if (end_ptr == NULL) + { + // There's no directory. If the thing begins with a "~" then this is a bare + // user name. + if (*partial_name_copy == '~') + { + // Nothing here but the user name. We could just put a slash on the end, + // but for completeness sake we'll glob the user name and only put a slash + // on the end if it exists. + glob_t glob_buf; + if (glob (partial_name_copy, GLOB_TILDE, NULL, &glob_buf) != 0) + return matches.GetSize(); + + //The thing exists, put a '/' on the end, and return it... + // FIXME: complete user names here: + partial_name_copy[partial_name_len] = '/'; + partial_name_copy[partial_name_len+1] = '\0'; + matches.AppendString(partial_name_copy); + globfree(&glob_buf); + saw_directory == true; + return matches.GetSize(); + } + else + { + // The containing part is the CWD, and the whole string is the remainder. + containing_part[0] = '.'; + containing_part[1] = '\0'; + strcpy(remainder, partial_name_copy); + end_ptr = partial_name_copy; + } + } + else + { + if (end_ptr == partial_name_copy) + { + // We're completing a file or directory in the root volume. + containing_part[0] = '/'; + containing_part[1] = '\0'; + } + else + { + size_t len = end_ptr - partial_name_copy; + memcpy(containing_part, partial_name_copy, len); + containing_part[len] = '\0'; + } + // Push end_ptr past the final "/" and set remainder. + end_ptr++; + strcpy(remainder, end_ptr); + } + + // Look for a user name in the containing part, and if it's there, glob containing_part and stick the + // result back into the containing_part: + + if (*partial_name_copy == '~') + { + glob_t glob_buf; + + // User name doesn't exist, we're not getting any further... + if (glob (containing_part, GLOB_TILDE, NULL, &glob_buf) != 0) + return matches.GetSize(); + + if (glob_buf.gl_pathc != 1) + { + // I'm not really sure how this would happen? + globfree(&glob_buf); + return matches.GetSize(); + } + strcpy(containing_part, glob_buf.gl_pathv[0]); + globfree(&glob_buf); + } + + // Okay, containing_part is now the directory we want to open and look for files: + + DIR *dir_stream; + + dir_stream = opendir(containing_part); + if (dir_stream == NULL) + return matches.GetSize(); + + struct dirent *dirent_buf; + + size_t baselen = end_ptr - partial_name_copy; + + while ((dirent_buf = readdir(dir_stream)) != NULL) + { + char *name = dirent_buf->d_name; + + // Omit ".", ".." and any . files if the match string doesn't start with . + if (name[0] == '.') + { + if (name[1] == '\0') + continue; + else if (name[1] == '.' && name[2] == '\0') + continue; + else if (remainder[0] != '.') + continue; + } + + if (remainder[0] == '\0' || strstr(dirent_buf->d_name, remainder) == name) + { + if (strlen(name) + baselen >= PATH_MAX) + continue; + + strcpy(end_ptr, name); + + bool isa_directory = false; + if (dirent_buf->d_type & DT_DIR) + isa_directory = true; + else if (dirent_buf->d_type & DT_LNK) + { + struct stat stat_buf; + if ((stat(partial_name_copy, &stat_buf) == 0) && (stat_buf.st_mode & S_IFDIR)) + isa_directory = true; + } + + if (isa_directory) + { + saw_directory = true; + size_t len = strlen(partial_name_copy); + partial_name_copy[len] = '/'; + partial_name_copy[len + 1] = '\0'; + } + if (only_directories && !isa_directory) + continue; + matches.AppendString(partial_name_copy); + } + } + + return matches.GetSize(); +} + +int +CommandCompletions::DiskFiles +( + CommandInterpreter &interpreter, + const char *partial_file_name, + int match_start_point, + int max_return_elements, + SearchFilter *searcher, + bool &word_complete, + StringList &matches +) +{ + + int ret_val = DiskFilesOrDirectories (partial_file_name, + false, + word_complete, + matches); + word_complete = !word_complete; + return ret_val; +} + +int +CommandCompletions::DiskDirectories +( + CommandInterpreter &interpreter, + const char *partial_file_name, + int match_start_point, + int max_return_elements, + SearchFilter *searcher, + bool &word_complete, + StringList &matches +) +{ + int ret_val = DiskFilesOrDirectories (partial_file_name, + true, + word_complete, + matches); + word_complete = false; + return ret_val; +} + int CommandCompletions::Modules ( @@ -108,9 +328,11 @@ CommandCompletions::Modules int match_start_point, int max_return_elements, SearchFilter *searcher, + bool &word_complete, StringList &matches ) { + word_complete = true; ModuleCompleter completer (interpreter, partial_file_name, match_start_point, @@ -138,8 +360,10 @@ CommandCompletions::Symbols int match_start_point, int max_return_elements, SearchFilter *searcher, + bool &word_complete, StringList &matches) { + word_complete = true; SymbolCompleter completer (interpreter, partial_file_name, match_start_point, diff --git a/lldb/source/Commands/CommandObjectFile.cpp b/lldb/source/Commands/CommandObjectFile.cpp index bdaf67cc8149..2700e2075ec9 100644 --- a/lldb/source/Commands/CommandObjectFile.cpp +++ b/lldb/source/Commands/CommandObjectFile.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Target/Process.h" using namespace lldb; @@ -166,3 +167,29 @@ CommandObjectFile::Execute return result.Succeeded(); } + +int +CommandObjectFile::HandleArgumentCompletion (CommandInterpreter &interpreter, + Args &input, + int &cursor_index, + int &cursor_char_position, + OptionElementVector &opt_element_vector, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches) +{ + std::string completion_str (input.GetArgumentAtIndex(cursor_index)); + completion_str.erase (cursor_char_position); + + CommandCompletions::InvokeCommonCompletionCallbacks (interpreter, + CommandCompletions::eDiskFileCompletion, + completion_str.c_str(), + match_start_point, + max_return_elements, + NULL, + word_complete, + matches); + return matches.GetSize(); + +} \ No newline at end of file diff --git a/lldb/source/Commands/CommandObjectFile.h b/lldb/source/Commands/CommandObjectFile.h index 23f4761983da..b42f753ada12 100644 --- a/lldb/source/Commands/CommandObjectFile.h +++ b/lldb/source/Commands/CommandObjectFile.h @@ -67,6 +67,18 @@ public: ArchSpec m_arch; }; + + virtual int + HandleArgumentCompletion (CommandInterpreter &interpreter, + Args &input, + int &cursor_index, + int &cursor_char_position, + OptionElementVector &opt_element_vector, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches); + private: CommandOptions m_options; diff --git a/lldb/source/Commands/CommandObjectHelp.cpp b/lldb/source/Commands/CommandObjectHelp.cpp index 8a037e948166..363bbc4675ab 100644 --- a/lldb/source/Commands/CommandObjectHelp.cpp +++ b/lldb/source/Commands/CommandObjectHelp.cpp @@ -144,19 +144,22 @@ CommandObjectHelp::HandleCompletion int &cursor_char_position, int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches ) { // Return the completions of the commands in the help system: if (cursor_index == 0) { - return interpreter.HandleCompletionMatches(input, cursor_index, cursor_char_position, match_start_point, max_return_elements, matches); + return interpreter.HandleCompletionMatches(input, cursor_index, cursor_char_position, match_start_point, + max_return_elements, word_complete, matches); } else { CommandObject *cmd_obj = interpreter.GetCommandObject (input.GetArgumentAtIndex(0), true, false); input.Shift(); cursor_index--; - return cmd_obj->HandleCompletion (interpreter, input, cursor_index, cursor_char_position, match_start_point, max_return_elements, matches); + return cmd_obj->HandleCompletion (interpreter, input, cursor_index, cursor_char_position, match_start_point, + max_return_elements, word_complete, matches); } } diff --git a/lldb/source/Commands/CommandObjectHelp.h b/lldb/source/Commands/CommandObjectHelp.h index 881b67d71410..cf16e5d35a24 100644 --- a/lldb/source/Commands/CommandObjectHelp.h +++ b/lldb/source/Commands/CommandObjectHelp.h @@ -43,6 +43,7 @@ public: int &cursor_char_position, int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches); }; diff --git a/lldb/source/Commands/CommandObjectImage.cpp b/lldb/source/Commands/CommandObjectImage.cpp index 0bf339c01658..909b36d09c25 100644 --- a/lldb/source/Commands/CommandObjectImage.cpp +++ b/lldb/source/Commands/CommandObjectImage.cpp @@ -422,6 +422,7 @@ public: OptionElementVector &opt_element_vector, int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches) { // Arguments are the standard module completer. @@ -434,6 +435,7 @@ public: match_start_point, max_return_elements, NULL, + word_complete, matches); return matches.GetSize(); } @@ -463,6 +465,7 @@ public: OptionElementVector &opt_element_vector, int match_start_point, int max_return_elements, + bool word_complete, StringList &matches) { // Arguments are the standard source file completer. @@ -475,6 +478,7 @@ public: match_start_point, max_return_elements, NULL, + word_complete, matches); return matches.GetSize(); } diff --git a/lldb/source/Commands/CommandObjectMultiword.cpp b/lldb/source/Commands/CommandObjectMultiword.cpp index d8e8f546a533..88c3eedb048a 100644 --- a/lldb/source/Commands/CommandObjectMultiword.cpp +++ b/lldb/source/Commands/CommandObjectMultiword.cpp @@ -219,9 +219,14 @@ CommandObjectMultiword::HandleCompletion int &cursor_char_position, int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches ) { + // Any of the command matches will provide a complete word, otherwise the individual + // completers will override this. + word_complete = true; + if (cursor_index == 0) { CommandObject::AddNamesMatchingPartialString (m_subcommand_dict, @@ -245,7 +250,8 @@ CommandObjectMultiword::HandleCompletion input, cursor_index, cursor_char_position, match_start_point, - max_return_elements, + max_return_elements, + word_complete, matches); } else @@ -273,7 +279,8 @@ CommandObjectMultiword::HandleCompletion cursor_index, cursor_char_position, match_start_point, - max_return_elements, + max_return_elements, + word_complete, matches); } diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index c4abb8da0fec..f37e985e4a29 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -653,11 +653,13 @@ CommandInterpreter::HandleCommand int num_matches; int cursor_index = command_args.GetArgumentCount() - 1; int cursor_char_position = strlen (command_args.GetArgumentAtIndex(command_args.GetArgumentCount() - 1)); + bool word_complete; num_matches = HandleCompletionMatches (command_args, cursor_index, cursor_char_position, 0, -1, + word_complete, matches); if (num_matches > 0) @@ -692,11 +694,15 @@ CommandInterpreter::HandleCompletionMatches (Args &parsed_line, int &cursor_char_position, int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches) { int num_command_matches = 0; bool include_aliases = true; bool look_for_subcommand = false; + + // For any of the command completions a unique match will be a complete word. + word_complete = true; if (cursor_index == -1) { @@ -743,7 +749,8 @@ CommandInterpreter::HandleCompletionMatches (Args &parsed_line, cursor_index, cursor_char_position, match_start_point, - max_return_elements, + max_return_elements, + word_complete, matches); } } @@ -781,11 +788,13 @@ CommandInterpreter::HandleCompletion (const char *current_line, // Only max_return_elements == -1 is supported at present: assert (max_return_elements == -1); + bool word_complete; num_command_matches = HandleCompletionMatches (parsed_line, cursor_index, cursor_char_position, match_start_point, - max_return_elements, + max_return_elements, + word_complete, matches); if (num_command_matches <= 0) @@ -809,7 +818,8 @@ CommandInterpreter::HandleCompletion (const char *current_line, int partial_name_len = command_partial_str.size(); // If we matched a unique single command, add a space... - if (num_command_matches == 1) + // Only do this if the completer told us this was a complete word, however... + if (num_command_matches == 1 && word_complete) { char quote_char = parsed_line.GetArgumentQuoteCharAtIndex(cursor_index); if (quote_char != '\0') diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp index 2813ac163668..7ee9137b0e1d 100644 --- a/lldb/source/Interpreter/CommandObject.cpp +++ b/lldb/source/Interpreter/CommandObject.cpp @@ -304,6 +304,7 @@ CommandObject::HandleCompletion int &cursor_char_position, int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches ) { @@ -345,6 +346,7 @@ CommandObject::HandleCompletion cursor_char_position, match_start_point, max_return_elements, + word_complete, matches); if (handled_by_options) return matches.GetSize(); @@ -358,6 +360,7 @@ CommandObject::HandleCompletion opt_element_vector, match_start_point, max_return_elements, + word_complete, matches); } } diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp index 5698b28c958f..28f292257931 100644 --- a/lldb/source/Interpreter/Options.cpp +++ b/lldb/source/Interpreter/Options.cpp @@ -538,9 +538,12 @@ Options::HandleOptionCompletion int char_pos, int match_start_point, int max_return_elements, + bool &word_complete, lldb_private::StringList &matches ) { + word_complete = true; + // For now we just scan the completions to see if the cursor position is in // an option or its argument. Otherwise we'll call HandleArgumentCompletion. // In the future we can use completion to validate options as well if we want. @@ -658,6 +661,7 @@ Options::HandleOptionCompletion i, match_start_point, max_return_elements, + word_complete, matches); return true; } @@ -688,6 +692,7 @@ Options::HandleOptionArgumentCompletion int opt_element_index, int match_start_point, int max_return_elements, + bool &word_complete, lldb_private::StringList &matches ) { @@ -754,6 +759,7 @@ Options::HandleOptionArgumentCompletion match_start_point, max_return_elements, filter_ap.get(), + word_complete, matches); }