Fix tab completion for command arguments containing spaces

If a command argument contains a space then it have to be escaped with
backslash signs so the argument parsing logic can parse it properly.
This CL fixes the tab completion code for the arguments to create
complitions with correctly escaped strings.

Differential revision: http://reviews.llvm.org/D12531

llvm-svn: 246639
This commit is contained in:
Tamas Berghammer 2015-09-02 10:35:27 +00:00
parent e6035de11e
commit 89d3f090b2
6 changed files with 72 additions and 3 deletions

View File

@ -424,6 +424,9 @@ public:
static void
ExpandEscapedCharacters (const char *src, std::string &dst);
static std::string
EscapeLLDBCommandArgument (const std::string& arg, char quote_char);
// This one isn't really relevant to Arguments per se, but we're using the Args as a
// general strings container, so...
void

View File

@ -1668,3 +1668,33 @@ Args::ExpandEscapedCharacters (const char *src, std::string &dst)
}
}
std::string
Args::EscapeLLDBCommandArgument (const std::string& arg, char quote_char)
{
const char* chars_to_escape = nullptr;
switch (quote_char)
{
case '\0':
chars_to_escape = " \t\\'\"`";
break;
case '\'':
chars_to_escape = "";
break;
case '"':
chars_to_escape = "$\"`\\";
break;
default:
assert(false && "Unhandled quote character");
}
std::string res;
res.reserve(arg.size());
for (char c : arg)
{
if (::strchr(chars_to_escape, c))
res.push_back('\\');
res.push_back(c);
}
return res;
}

View File

@ -2021,18 +2021,18 @@ CommandInterpreter::HandleCompletion (const char *current_line,
std::string common_prefix;
matches.LongestCommonPrefix (common_prefix);
const size_t partial_name_len = command_partial_str.size();
common_prefix.erase (0, partial_name_len);
// If we matched a unique single command, add a space...
// 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);
common_prefix = Args::EscapeLLDBCommandArgument(common_prefix, quote_char);
if (quote_char != '\0')
common_prefix.push_back(quote_char);
common_prefix.push_back(' ');
}
common_prefix.erase (0, partial_name_len);
matches.InsertStringAtIndex(0, common_prefix.c_str());
}
return num_command_matches;

View File

@ -0,0 +1,5 @@
LEVEL = ../../make
CXX_SOURCES := main.cpp
include $(LEVEL)/Makefile.rules

View File

@ -219,6 +219,23 @@ class CommandLineCompletionTestCase(TestBase):
"""Test that 'target va' completes to 'target variable '."""
self.complete_from_to('target va', 'target variable ')
@skipUnlessDarwin
@dsym_test
def test_symbol_name_dsym(self):
self.buildDsym()
self.complete_from_to('''file a.out
breakpoint set -n Fo''',
'breakpoint set -n Foo::Bar(int,\\ int)',
turn_off_re_match=True)
@dwarf_test
def test_symbol_name_dwarf(self):
self.buildDwarf()
self.complete_from_to('''file a.out
breakpoint set -n Fo''',
'breakpoint set -n Foo::Bar(int,\\ int)',
turn_off_re_match=True)
def complete_from_to(self, str_input, patterns, turn_off_re_match=False):
"""Test that the completion mechanism completes str_input to patterns,
where patterns could be a pattern-string or a list of pattern-strings"""

View File

@ -0,0 +1,14 @@
class Foo
{
public:
int Bar(int x, int y)
{
return x + y;
}
};
int main()
{
Foo f;
f.Bar(1, 2);
}