m_partial_parsed_line.Shift();
}
- void SetCursorIndex(int i) { m_cursor_index = i; }
- int GetCursorIndex() const { return m_cursor_index; }
+ void SetCursorIndex(size_t i) { m_cursor_index = i; }
+ size_t GetCursorIndex() const { return m_cursor_index; }
void SetCursorCharPosition(int pos) { m_cursor_char_position = pos; }
int GetCursorCharPosition() const { return m_cursor_char_position; }
/// The command line until the cursor position parsed as arguments.
Args m_partial_parsed_line;
/// The index of the argument in which the completion cursor is.
- int m_cursor_index;
+ size_t m_cursor_index;
/// The cursor position in the argument indexed by m_cursor_index.
int m_cursor_char_position;
const size_t argc = request.GetParsedLine().GetArgumentCount();
const char *arg = nullptr;
- int setting_var_idx;
- for (setting_var_idx = 0; setting_var_idx < static_cast<int>(argc);
- ++setting_var_idx) {
+ size_t setting_var_idx;
+ for (setting_var_idx = 0; setting_var_idx < argc; ++setting_var_idx) {
arg = request.GetParsedLine().GetArgumentAtIndex(setting_var_idx);
if (arg && arg[0] != '-')
break; // We found our setting variable name index
// For any of the command completions a unique match will be a complete word.
- if (request.GetCursorIndex() == -1) {
+ if (request.GetPartialParsedLine().GetArgumentCount() == 0) {
// We got nothing on the command line, so return the list of commands
bool include_aliases = true;
StringList new_matches, descriptions;
new_matches.DeleteStringAtIndex(0);
new_descriptions.DeleteStringAtIndex(0);
request.GetParsedLine().AppendArgument(llvm::StringRef());
- request.SetCursorIndex(request.GetCursorIndex() + 1);
+ request.SetCursorIndex(request.GetCursorIndex() + 1U);
request.SetCursorCharPosition(0);
}
}
llvm::StringRef cur_opt_str = request.GetCursorArgumentPrefix();
for (size_t i = 0; i < opt_element_vector.size(); i++) {
- int opt_pos = opt_element_vector[i].opt_pos;
- int opt_arg_pos = opt_element_vector[i].opt_arg_pos;
+ size_t opt_pos = static_cast<size_t>(opt_element_vector[i].opt_pos);
+ size_t opt_arg_pos = static_cast<size_t>(opt_element_vector[i].opt_arg_pos);
int opt_defs_index = opt_element_vector[i].opt_defs_index;
if (opt_pos == request.GetCursorIndex()) {
// We're completing the option itself.
// parsed_line is the one containing the cursor, and the cursor is after the
// last character.
m_parsed_line = Args(command_line);
- m_partial_parsed_line = Args(command_line.substr(0, raw_cursor_pos));
+ llvm::StringRef partial_command(command_line.substr(0, raw_cursor_pos));
+ m_partial_parsed_line = Args(partial_command);
- m_cursor_index = m_partial_parsed_line.GetArgumentCount() - 1;
-
- if (m_cursor_index == -1)
+ if (m_partial_parsed_line.GetArgumentCount() == 0) {
+ m_cursor_index = 0;
m_cursor_char_position = 0;
- else
+ } else {
+ m_cursor_index = m_partial_parsed_line.GetArgumentCount() - 1U;
m_cursor_char_position =
strlen(m_partial_parsed_line.GetArgumentAtIndex(m_cursor_index));
+ }
- const char *cursor = command_line.data() + raw_cursor_pos;
- if (raw_cursor_pos > 0 && cursor[-1] == ' ') {
- // We are just after a space. If we are in an argument, then we will
- // continue parsing, but if we are between arguments, then we have to
- // complete whatever the next element would be. We can distinguish the two
- // cases because if we are in an argument (e.g. because the space is
- // protected by a quote) then the space will also be in the parsed
- // argument...
-
- const char *current_elem =
- m_partial_parsed_line.GetArgumentAtIndex(m_cursor_index);
- if (m_cursor_char_position == 0 ||
- current_elem[m_cursor_char_position - 1] != ' ') {
- m_parsed_line.InsertArgumentAtIndex(m_cursor_index + 1, llvm::StringRef(),
- '\0');
- m_cursor_index++;
- m_cursor_char_position = 0;
- }
+ // The cursor is after a space but the space is not part of the argument.
+ // Let's add an empty fake argument to the end to make sure the completion
+ // code Note: The space could be part of the last argument when it's quoted.
+ if (partial_command.endswith(" ") &&
+ !GetCursorArgumentPrefix().endswith(" ")) {
+ m_parsed_line.AppendArgument(llvm::StringRef());
+ m_partial_parsed_line.AppendArgument(llvm::StringRef());
+ // Set the cursor to the start of the fake argument.
+ m_cursor_index++;
+ m_cursor_char_position = 0;
}
}
TEST(CompletionRequest, Constructor) {
std::string command = "a bad c";
const unsigned cursor_pos = 3;
- const int arg_index = 1;
+ const size_t arg_index = 1;
const int arg_cursor_pos = 1;
StringList matches;
CompletionResult result;
EXPECT_STREQ(request.GetPartialParsedLine().GetArgumentAtIndex(1), "b");
}
+TEST(CompletionRequest, FakeLastArg) {
+ // We insert an empty fake argument into the argument list when the
+ // cursor is after a space.
+ std::string command = "a bad c ";
+ const unsigned cursor_pos = command.size();
+ CompletionResult result;
+
+ CompletionRequest request(command, cursor_pos, result);
+
+ EXPECT_STREQ(request.GetRawLine().str().c_str(), command.c_str());
+ EXPECT_EQ(request.GetRawCursorPos(), cursor_pos);
+ EXPECT_EQ(request.GetCursorIndex(), 3U);
+ EXPECT_EQ(request.GetCursorCharPosition(), 0);
+
+ EXPECT_EQ(request.GetPartialParsedLine().GetArgumentCount(), 4U);
+ EXPECT_STREQ(request.GetPartialParsedLine().GetArgumentAtIndex(3), "");
+}
+
TEST(CompletionRequest, TryCompleteCurrentArgGood) {
std::string command = "a bad c";
StringList matches, descriptions;
TEST(CompletionRequest, ShiftArguments) {
std::string command = "a bad c";
const unsigned cursor_pos = 3;
- const int arg_index = 1;
+ const size_t arg_index = 1;
const int arg_cursor_pos = 1;
StringList matches;
CompletionResult result;