Fix bash completion when dir/file contains single quote
Also a few other improvements in bash completion code
This commit is contained in:
parent
73d42c287c
commit
72426e2d4c
|
@ -691,18 +691,19 @@ void ArgumentParser::printBashCompletion(int argc, const char *const *argv, unsi
|
||||||
lastDetectedArgPath = lastDetectedArg->path(lastDetectedArg->occurrences() - 1);
|
lastDetectedArgPath = lastDetectedArg->path(lastDetectedArg->occurrences() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nextArgumentOrValue;
|
// determine last arg, omitting trailing empty args
|
||||||
const char *const *lastSpecifiedArg;
|
const char *const *lastSpecifiedArg;
|
||||||
unsigned int lastSpecifiedArgIndex;
|
unsigned int lastSpecifiedArgIndex;
|
||||||
if(argc) {
|
if(argc) {
|
||||||
// determine last arg omitting trailing empty args
|
|
||||||
lastSpecifiedArgIndex = static_cast<unsigned int>(argc) - 1;
|
lastSpecifiedArgIndex = static_cast<unsigned int>(argc) - 1;
|
||||||
lastSpecifiedArg = argv + lastSpecifiedArgIndex;
|
lastSpecifiedArg = argv + lastSpecifiedArgIndex;
|
||||||
for(; lastSpecifiedArg >= argv && **lastSpecifiedArg == '\0'; --lastSpecifiedArg, --lastSpecifiedArgIndex);
|
for(; lastSpecifiedArg >= argv && **lastSpecifiedArg == '\0'; --lastSpecifiedArg, --lastSpecifiedArgIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// determine arguments relevant for completion
|
||||||
|
bool nextArgumentOrValue;
|
||||||
if(lastDetectedArg && lastDetectedArg->isPresent()) {
|
if(lastDetectedArg && lastDetectedArg->isPresent()) {
|
||||||
if((nextArgumentOrValue = currentWordIndex > lastDetectedArgIndex)) {
|
if((nextArgumentOrValue = (currentWordIndex > lastDetectedArgIndex))) {
|
||||||
// parameter values of the last arg are possible completions
|
// parameter values of the last arg are possible completions
|
||||||
auto currentValueCount = lastDetectedArg->values(lastDetectedArg->occurrences() - 1).size();
|
auto currentValueCount = lastDetectedArg->values(lastDetectedArg->occurrences() - 1).size();
|
||||||
if(currentValueCount) {
|
if(currentValueCount) {
|
||||||
|
@ -740,6 +741,7 @@ void ArgumentParser::printBashCompletion(int argc, const char *const *argv, unsi
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// no arguments detected -> just use main arguments for completion
|
||||||
nextArgumentOrValue = true;
|
nextArgumentOrValue = true;
|
||||||
insertSiblings(m_mainArgs, relevantArgs);
|
insertSiblings(m_mainArgs, relevantArgs);
|
||||||
}
|
}
|
||||||
|
@ -790,27 +792,37 @@ void ArgumentParser::printBashCompletion(int argc, const char *const *argv, unsi
|
||||||
if(argc && currentWordIndex <= lastSpecifiedArgIndex && opening) {
|
if(argc && currentWordIndex <= lastSpecifiedArgIndex && opening) {
|
||||||
if(openingDenotationType == Value) {
|
if(openingDenotationType == Value) {
|
||||||
bool wordStart = true, ok = false, equationSignAlreadyPresent = false;
|
bool wordStart = true, ok = false, equationSignAlreadyPresent = false;
|
||||||
int wordIndex = 0;
|
size_t wordIndex = 0;
|
||||||
for(const char *i = arg->preDefinedCompletionValues(), *end = opening + openingLen; *i;) {
|
for(const char *i = arg->preDefinedCompletionValues(), *end = opening + openingLen; *i;) {
|
||||||
if(wordStart) {
|
if(wordStart) {
|
||||||
const char *i1 = i, *i2 = opening;
|
const char *i1 = i, *i2 = opening;
|
||||||
for(; *i1 && i2 != end && *i1 == *i2; ++i1, ++i2);
|
for(; *i1 && i2 != end && *i1 == *i2; ++i1, ++i2);
|
||||||
ok = (i2 == end);
|
if((ok = (i2 == end))) {
|
||||||
|
cout << '\'';
|
||||||
|
}
|
||||||
wordStart = false;
|
wordStart = false;
|
||||||
wordIndex = 0;
|
wordIndex = 0;
|
||||||
} else if((wordStart = (*i == ' ') || (*i == '\n'))) {
|
} else if((wordStart = (*i == ' ') || (*i == '\n'))) {
|
||||||
equationSignAlreadyPresent = false;
|
equationSignAlreadyPresent = false;
|
||||||
|
if(ok) {
|
||||||
|
cout << '\'' << ' ';
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
continue;
|
||||||
} else if(*i == '=') {
|
} else if(*i == '=') {
|
||||||
equationSignAlreadyPresent = true;
|
equationSignAlreadyPresent = true;
|
||||||
}
|
}
|
||||||
if(ok) {
|
if(ok) {
|
||||||
if(!compoundOpeningStartLen || wordIndex >= compoundOpeningStartLen) {
|
if(!compoundOpeningStartLen || wordIndex >= compoundOpeningStartLen) {
|
||||||
|
if(*i == '\'') {
|
||||||
|
cout << "'\"'\"'";
|
||||||
|
}
|
||||||
cout << *i;
|
cout << *i;
|
||||||
}
|
}
|
||||||
++i, ++wordIndex;
|
++i, ++wordIndex;
|
||||||
if(appendEquationSign && !equationSignAlreadyPresent) {
|
switch(*i) {
|
||||||
switch(*i) {
|
case ' ': case '\n': case '\0':
|
||||||
case ' ': case '\n': case '\0':
|
if(appendEquationSign && !equationSignAlreadyPresent) {
|
||||||
cout << '=';
|
cout << '=';
|
||||||
noWhitespace = true;
|
noWhitespace = true;
|
||||||
equationSignAlreadyPresent = false;
|
equationSignAlreadyPresent = false;
|
||||||
|
@ -822,23 +834,33 @@ void ArgumentParser::printBashCompletion(int argc, const char *const *argv, unsi
|
||||||
}
|
}
|
||||||
cout << ' ';
|
cout << ' ';
|
||||||
}
|
}
|
||||||
} else if(appendEquationSign) {
|
} else if(const char *i = arg->preDefinedCompletionValues()) {
|
||||||
bool equationSignAlreadyPresent = false;
|
bool equationSignAlreadyPresent = false;
|
||||||
for(const char *i = arg->preDefinedCompletionValues(); *i;) {
|
cout << '\'';
|
||||||
cout << *i;
|
while(*i) {
|
||||||
|
if(*i == '\'') {
|
||||||
|
cout << "'\"'\"'";
|
||||||
|
} else {
|
||||||
|
cout << *i;
|
||||||
|
}
|
||||||
switch(*(++i)) {
|
switch(*(++i)) {
|
||||||
case '=':
|
case '=':
|
||||||
equationSignAlreadyPresent = true;
|
equationSignAlreadyPresent = true;
|
||||||
break;
|
break;
|
||||||
case ' ': case '\n': case '\0':
|
case ' ': case '\n': case '\0':
|
||||||
if(!equationSignAlreadyPresent) {
|
if(appendEquationSign && !equationSignAlreadyPresent) {
|
||||||
cout << '=';
|
cout << '=';
|
||||||
equationSignAlreadyPresent = false;
|
equationSignAlreadyPresent = false;
|
||||||
}
|
}
|
||||||
|
if(*i != '\0') {
|
||||||
|
cout << '\'';
|
||||||
|
if(*(++i)) {
|
||||||
|
cout << ' ' << '\'';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
cout << '\'' << ' ';
|
||||||
cout << arg->preDefinedCompletionValues() << ' ';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -861,11 +883,11 @@ void ArgumentParser::printBashCompletion(int argc, const char *const *argv, unsi
|
||||||
}
|
}
|
||||||
|
|
||||||
if(openingDenotationType == Abbreviation && opening) {
|
if(openingDenotationType == Abbreviation && opening) {
|
||||||
cout << '-' << opening << arg->abbreviation() << ' ';
|
cout << '\'' << '-' << opening << arg->abbreviation() << '\'' << ' ';
|
||||||
} else if(arg->denotesOperation() && (!actualArgumentCount() || (currentWordIndex == 0 && (!lastDetectedArg || (lastDetectedArg->isPresent() && lastDetectedArgIndex == 0))))) {
|
} else if(arg->denotesOperation() && (!actualArgumentCount() || (currentWordIndex == 0 && (!lastDetectedArg || (lastDetectedArg->isPresent() && lastDetectedArgIndex == 0))))) {
|
||||||
cout << arg->name() << ' ';
|
cout << '\'' << arg->name() << '\'' << ' ';
|
||||||
} else {
|
} else {
|
||||||
cout << '-' << '-' << arg->name() << ' ';
|
cout << '\'' << '-' << '-' << arg->name() << '\'' << ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -> completions for files and dirs
|
// -> completions for files and dirs
|
||||||
|
@ -873,7 +895,7 @@ void ArgumentParser::printBashCompletion(int argc, const char *const *argv, unsi
|
||||||
string actualDir, actualFile;
|
string actualDir, actualFile;
|
||||||
bool haveFileOrDirCompletions = false;
|
bool haveFileOrDirCompletions = false;
|
||||||
if(argc && currentWordIndex == lastSpecifiedArgIndex && opening) {
|
if(argc && currentWordIndex == lastSpecifiedArgIndex && opening) {
|
||||||
// the "opening" might contain escaped characters which need to be unescaped first
|
// the "opening" might contain escaped characters which need to be unescaped first (let's hope this covers all possible escapings)
|
||||||
string unescapedOpening(opening);
|
string unescapedOpening(opening);
|
||||||
findAndReplace<string>(unescapedOpening, "\\ ", " ");
|
findAndReplace<string>(unescapedOpening, "\\ ", " ");
|
||||||
findAndReplace<string>(unescapedOpening, "\\,", ",");
|
findAndReplace<string>(unescapedOpening, "\\,", ",");
|
||||||
|
@ -882,6 +904,9 @@ void ArgumentParser::printBashCompletion(int argc, const char *const *argv, unsi
|
||||||
findAndReplace<string>(unescapedOpening, "\\!", "!");
|
findAndReplace<string>(unescapedOpening, "\\!", "!");
|
||||||
findAndReplace<string>(unescapedOpening, "\\#", "#");
|
findAndReplace<string>(unescapedOpening, "\\#", "#");
|
||||||
findAndReplace<string>(unescapedOpening, "\\$", "$");
|
findAndReplace<string>(unescapedOpening, "\\$", "$");
|
||||||
|
findAndReplace<string>(unescapedOpening, "\\'", "'");
|
||||||
|
findAndReplace<string>(unescapedOpening, "\\\"", "\"");
|
||||||
|
findAndReplace<string>(unescapedOpening, "\\\\", "\\");
|
||||||
// determine the "directory" part
|
// determine the "directory" part
|
||||||
string dir = directory(unescapedOpening);
|
string dir = directory(unescapedOpening);
|
||||||
if(dir.empty()) {
|
if(dir.empty()) {
|
||||||
|
@ -905,42 +930,35 @@ void ArgumentParser::printBashCompletion(int argc, const char *const *argv, unsi
|
||||||
}
|
}
|
||||||
actualFile = move(file);
|
actualFile = move(file);
|
||||||
}
|
}
|
||||||
// -> completion for files
|
|
||||||
|
// -> completion for files and dirs
|
||||||
|
DirectoryEntryType entryTypes = DirectoryEntryType::None;
|
||||||
if(completeFiles) {
|
if(completeFiles) {
|
||||||
if(argc && currentWordIndex <= lastSpecifiedArgIndex && opening) {
|
entryTypes |= DirectoryEntryType::File;
|
||||||
for(const string &dirEntry : directoryEntries(actualDir.c_str(), DirectoryEntryType::File)) {
|
|
||||||
if(startsWith(dirEntry, actualFile)) {
|
|
||||||
cout << '\'';
|
|
||||||
if(actualDir != ".") {
|
|
||||||
cout << actualDir;
|
|
||||||
}
|
|
||||||
cout << dirEntry << '\'' << ' ';
|
|
||||||
haveFileOrDirCompletions = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(const string &dirEntry : directoryEntries(".", DirectoryEntryType::File)) {
|
|
||||||
cout << dirEntry << ' ';
|
|
||||||
haveFileOrDirCompletions = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// -> completion for dirs
|
|
||||||
if(completeDirs) {
|
if(completeDirs) {
|
||||||
|
entryTypes |= DirectoryEntryType::Directory;
|
||||||
|
}
|
||||||
|
if(entryTypes != DirectoryEntryType::None) {
|
||||||
|
const string replace("'"), with("'\"'\"'");
|
||||||
if(argc && currentWordIndex <= lastSpecifiedArgIndex && opening) {
|
if(argc && currentWordIndex <= lastSpecifiedArgIndex && opening) {
|
||||||
for(const string &dirEntry : directoryEntries(actualDir.c_str(), DirectoryEntryType::Directory)) {
|
list<string> entries = directoryEntries(actualDir.c_str(), entryTypes);
|
||||||
|
findAndReplace(actualDir, replace, with);
|
||||||
|
for(string &dirEntry : entries) {
|
||||||
if(startsWith(dirEntry, actualFile)) {
|
if(startsWith(dirEntry, actualFile)) {
|
||||||
cout << '\'';
|
cout << '\'';
|
||||||
if(actualDir != ".") {
|
if(actualDir != ".") {
|
||||||
cout << actualDir;
|
cout << actualDir;
|
||||||
}
|
}
|
||||||
|
findAndReplace(dirEntry, replace, with);
|
||||||
cout << dirEntry << '\'' << ' ';
|
cout << dirEntry << '\'' << ' ';
|
||||||
haveFileOrDirCompletions = true;
|
haveFileOrDirCompletions = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for(const string &dirEntry : directoryEntries(".", DirectoryEntryType::Directory)) {
|
for(string &dirEntry : directoryEntries(".", entryTypes)) {
|
||||||
cout << '\'' << dirEntry << '/' << '\'' << ' ';
|
findAndReplace(dirEntry, replace, with);
|
||||||
|
cout << '\'' << dirEntry << '\'' << ' ';
|
||||||
haveFileOrDirCompletions = true;
|
haveFileOrDirCompletions = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,8 +238,7 @@ private:
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the name of the argument.
|
* \brief Returns the name of the argument.
|
||||||
*
|
*
|
||||||
* The parser compares the name with the characters following a "--" prefix to
|
* The parser compares the name with the characters following a "--" prefix to identify arguments.
|
||||||
* identify arguments.
|
|
||||||
*/
|
*/
|
||||||
inline const char *Argument::name() const
|
inline const char *Argument::name() const
|
||||||
{
|
{
|
||||||
|
@ -249,17 +248,17 @@ inline const char *Argument::name() const
|
||||||
/*!
|
/*!
|
||||||
* \brief Sets the name of the argument.
|
* \brief Sets the name of the argument.
|
||||||
*
|
*
|
||||||
* The name mustn't be empty or contain white spaces or equation chars.
|
* The name mustn't be empty, start with a minus or contain white spaces, equation chars, quotes and newlines.
|
||||||
*
|
*
|
||||||
* The parser compares the name with the characters following a "--" prefix to
|
* The parser compares the name with the characters following a "--" prefix to identify arguments.
|
||||||
* identify arguments.
|
|
||||||
*/
|
*/
|
||||||
inline void Argument::setName(const char *name)
|
inline void Argument::setName(const char *name)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_BUILD
|
#ifdef DEBUG_BUILD
|
||||||
if(name && *name) {
|
if(name && *name) {
|
||||||
|
assert(*name != '-');
|
||||||
for(const char *c = name; *c; ++c) {
|
for(const char *c = name; *c; ++c) {
|
||||||
assert(*c != ' ' && *c != '=');
|
assert(*c != ' ' && *c != '=' && *c != '\'' && *c != '\"' && *c != '\n' && *c != '\r');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -269,8 +268,7 @@ inline void Argument::setName(const char *name)
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the abbreviation of the argument.
|
* \brief Returns the abbreviation of the argument.
|
||||||
*
|
*
|
||||||
* The parser compares the abbreviation with the characters following a "-" prefix to
|
* The parser compares the abbreviation with the characters following a "-" prefix to identify arguments.
|
||||||
* identify arguments.
|
|
||||||
*/
|
*/
|
||||||
inline char Argument::abbreviation() const
|
inline char Argument::abbreviation() const
|
||||||
{
|
{
|
||||||
|
@ -280,15 +278,14 @@ inline char Argument::abbreviation() const
|
||||||
/*!
|
/*!
|
||||||
* \brief Sets the abbreviation of the argument.
|
* \brief Sets the abbreviation of the argument.
|
||||||
*
|
*
|
||||||
* The abbreviation might be empty but mustn't contain any white spaces or
|
* The abbreviation might be empty but mustn't be white spaces, equation char, single quote, double quote or newline.
|
||||||
* equation chars when provided.
|
|
||||||
*
|
*
|
||||||
* The parser compares the abbreviation with the characters following a "-" prefix to
|
* The parser compares the abbreviation with the characters following a "-" prefix to identify arguments.
|
||||||
* identify arguments.
|
|
||||||
*/
|
*/
|
||||||
inline void Argument::setAbbreviation(char abbreviation)
|
inline void Argument::setAbbreviation(char abbreviation)
|
||||||
{
|
{
|
||||||
IF_DEBUG_BUILD(assert(abbreviation != ' ' && abbreviation != '='));
|
IF_DEBUG_BUILD(assert(abbreviation != ' ' && abbreviation != '=' && abbreviation != '-'
|
||||||
|
&& abbreviation != '\'' && abbreviation != '"' && abbreviation != '\n' && abbreviation != '\r'));
|
||||||
m_abbreviation = abbreviation;
|
m_abbreviation = abbreviation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,11 @@ constexpr DirectoryEntryType operator|(DirectoryEntryType lhs, DirectoryEntryTyp
|
||||||
return static_cast<DirectoryEntryType>(static_cast<unsigned char>(lhs) | static_cast<unsigned char>(rhs));
|
return static_cast<DirectoryEntryType>(static_cast<unsigned char>(lhs) | static_cast<unsigned char>(rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr DirectoryEntryType &operator|=(DirectoryEntryType &lhs, DirectoryEntryType rhs)
|
||||||
|
{
|
||||||
|
return (lhs = static_cast<DirectoryEntryType>(static_cast<unsigned char>(lhs) | static_cast<unsigned char>(rhs)));
|
||||||
|
}
|
||||||
|
|
||||||
constexpr DirectoryEntryType operator&(DirectoryEntryType lhs, DirectoryEntryType rhs)
|
constexpr DirectoryEntryType operator&(DirectoryEntryType lhs, DirectoryEntryType rhs)
|
||||||
{
|
{
|
||||||
return static_cast<DirectoryEntryType>(static_cast<unsigned char>(lhs) & static_cast<unsigned char>(rhs));
|
return static_cast<DirectoryEntryType>(static_cast<unsigned char>(lhs) & static_cast<unsigned char>(rhs));
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -399,7 +399,7 @@ void ArgumentParserTests::testBashCompletion()
|
||||||
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv1 + 1, lastDetectedArg, true);
|
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv1 + 1, lastDetectedArg, true);
|
||||||
parser.printBashCompletion(1, argv1, 0, lastDetectedArg);
|
parser.printBashCompletion(1, argv1, 0, lastDetectedArg);
|
||||||
cout.rdbuf(regularCoutBuffer);
|
cout.rdbuf(regularCoutBuffer);
|
||||||
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=(set )\n"), buffer.str());
|
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=('set' )\n"), buffer.str());
|
||||||
|
|
||||||
// argument is already specified
|
// argument is already specified
|
||||||
const char *const argv2[] = {"set"};
|
const char *const argv2[] = {"set"};
|
||||||
|
@ -409,7 +409,7 @@ void ArgumentParserTests::testBashCompletion()
|
||||||
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv2 + 1, lastDetectedArg, true);
|
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv2 + 1, lastDetectedArg, true);
|
||||||
parser.printBashCompletion(1, argv2, 0, lastDetectedArg);
|
parser.printBashCompletion(1, argv2, 0, lastDetectedArg);
|
||||||
cout.rdbuf(regularCoutBuffer);
|
cout.rdbuf(regularCoutBuffer);
|
||||||
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=(set )\n"), buffer.str());
|
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=('set' )\n"), buffer.str());
|
||||||
|
|
||||||
// advance the cursor position -> the completion should propose the next argument
|
// advance the cursor position -> the completion should propose the next argument
|
||||||
index = 0, lastDetectedArg = nullptr, buffer.str(string()), setArg.reset();
|
index = 0, lastDetectedArg = nullptr, buffer.str(string()), setArg.reset();
|
||||||
|
@ -418,7 +418,7 @@ void ArgumentParserTests::testBashCompletion()
|
||||||
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv2 + 1, lastDetectedArg, true);
|
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv2 + 1, lastDetectedArg, true);
|
||||||
parser.printBashCompletion(1, argv2, 1, lastDetectedArg);
|
parser.printBashCompletion(1, argv2, 1, lastDetectedArg);
|
||||||
cout.rdbuf(regularCoutBuffer);
|
cout.rdbuf(regularCoutBuffer);
|
||||||
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=(--files --values )\n"), buffer.str());
|
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=('--files' '--values' )\n"), buffer.str());
|
||||||
|
|
||||||
// specifying no args should propose all main arguments
|
// specifying no args should propose all main arguments
|
||||||
index = 0, lastDetectedArg = nullptr, buffer.str(string()), getArg.reset(), setArg.reset();
|
index = 0, lastDetectedArg = nullptr, buffer.str(string()), getArg.reset(), setArg.reset();
|
||||||
|
@ -427,7 +427,7 @@ void ArgumentParserTests::testBashCompletion()
|
||||||
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, nullptr, lastDetectedArg, true);
|
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, nullptr, lastDetectedArg, true);
|
||||||
parser.printBashCompletion(0, nullptr, 0, lastDetectedArg);
|
parser.printBashCompletion(0, nullptr, 0, lastDetectedArg);
|
||||||
cout.rdbuf(regularCoutBuffer);
|
cout.rdbuf(regularCoutBuffer);
|
||||||
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=(display-file-info get set --help )\n"), buffer.str());
|
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=('display-file-info' 'get' 'set' '--help' )\n"), buffer.str());
|
||||||
|
|
||||||
// values
|
// values
|
||||||
const char *const argv3[] = {"get", "--fields"};
|
const char *const argv3[] = {"get", "--fields"};
|
||||||
|
@ -437,7 +437,7 @@ void ArgumentParserTests::testBashCompletion()
|
||||||
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv3 + 2, lastDetectedArg, true);
|
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv3 + 2, lastDetectedArg, true);
|
||||||
parser.printBashCompletion(2, argv3, 2, lastDetectedArg);
|
parser.printBashCompletion(2, argv3, 2, lastDetectedArg);
|
||||||
cout.rdbuf(regularCoutBuffer);
|
cout.rdbuf(regularCoutBuffer);
|
||||||
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=(title album artist trackpos --files )\n"), buffer.str());
|
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=('title' 'album' 'artist' 'trackpos' '--files' )\n"), buffer.str());
|
||||||
|
|
||||||
// values with equation sign, one letter already present
|
// values with equation sign, one letter already present
|
||||||
const char *const argv4[] = {"set", "--values", "a"};
|
const char *const argv4[] = {"set", "--values", "a"};
|
||||||
|
@ -447,11 +447,14 @@ void ArgumentParserTests::testBashCompletion()
|
||||||
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv4 + 3, lastDetectedArg, true);
|
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv4 + 3, lastDetectedArg, true);
|
||||||
parser.printBashCompletion(3, argv4, 2, lastDetectedArg);
|
parser.printBashCompletion(3, argv4, 2, lastDetectedArg);
|
||||||
cout.rdbuf(regularCoutBuffer);
|
cout.rdbuf(regularCoutBuffer);
|
||||||
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=(album= artist= ); compopt -o nospace\n"), buffer.str());
|
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=('album=' 'artist=' ); compopt -o nospace\n"), buffer.str());
|
||||||
|
|
||||||
// file names
|
// file names
|
||||||
string iniFilePath = TestUtilities::testFilePath("test.ini");
|
string iniFilePath = TestUtilities::testFilePath("test.ini");
|
||||||
iniFilePath.resize(iniFilePath.size() - 3);
|
iniFilePath.resize(iniFilePath.size() - 4);
|
||||||
|
string mkvFilePath = TestUtilities::testFilePath("test 'with quote'.mkv");
|
||||||
|
mkvFilePath.resize(mkvFilePath.size() - 17);
|
||||||
|
TestUtilities::testFilePath("t.aac");
|
||||||
const char *const argv5[] = {"get", "--files", iniFilePath.c_str()};
|
const char *const argv5[] = {"get", "--files", iniFilePath.c_str()};
|
||||||
index = 0, lastDetectedArg = nullptr, buffer.str(string()), getArg.reset(), setArg.reset();
|
index = 0, lastDetectedArg = nullptr, buffer.str(string()), getArg.reset(), setArg.reset();
|
||||||
cout.rdbuf(buffer.rdbuf());
|
cout.rdbuf(buffer.rdbuf());
|
||||||
|
@ -459,7 +462,7 @@ void ArgumentParserTests::testBashCompletion()
|
||||||
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv5 + 3, lastDetectedArg, true);
|
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv5 + 3, lastDetectedArg, true);
|
||||||
parser.printBashCompletion(3, argv5, 2, lastDetectedArg);
|
parser.printBashCompletion(3, argv5, 2, lastDetectedArg);
|
||||||
cout.rdbuf(regularCoutBuffer);
|
cout.rdbuf(regularCoutBuffer);
|
||||||
CPPUNIT_ASSERT_EQUAL("COMPREPLY=('" + iniFilePath + "ini' ); compopt -o filenames\n", buffer.str());
|
CPPUNIT_ASSERT_EQUAL("COMPREPLY=('" + mkvFilePath + " '\"'\"'with quote'\"'\"'.mkv' '" + iniFilePath + ".ini' ); compopt -o filenames\n", buffer.str());
|
||||||
|
|
||||||
// sub arguments
|
// sub arguments
|
||||||
const char *const argv6[] = {"set", "--"};
|
const char *const argv6[] = {"set", "--"};
|
||||||
|
@ -469,7 +472,7 @@ void ArgumentParserTests::testBashCompletion()
|
||||||
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv6 + 2, lastDetectedArg, true);
|
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv6 + 2, lastDetectedArg, true);
|
||||||
parser.printBashCompletion(2, argv6, 1, lastDetectedArg);
|
parser.printBashCompletion(2, argv6, 1, lastDetectedArg);
|
||||||
cout.rdbuf(regularCoutBuffer);
|
cout.rdbuf(regularCoutBuffer);
|
||||||
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=(--files --values )\n"), buffer.str());
|
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=('--files' '--values' )\n"), buffer.str());
|
||||||
|
|
||||||
// nested sub arguments
|
// nested sub arguments
|
||||||
const char *const argv7[] = {"-i", "--sub", "--"};
|
const char *const argv7[] = {"-i", "--sub", "--"};
|
||||||
|
@ -479,7 +482,7 @@ void ArgumentParserTests::testBashCompletion()
|
||||||
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv7 + 3, lastDetectedArg, true);
|
parser.readSpecifiedArgs(parser.m_mainArgs, index, argv, argv7 + 3, lastDetectedArg, true);
|
||||||
parser.printBashCompletion(3, argv7, 2, lastDetectedArg);
|
parser.printBashCompletion(3, argv7, 2, lastDetectedArg);
|
||||||
cout.rdbuf(regularCoutBuffer);
|
cout.rdbuf(regularCoutBuffer);
|
||||||
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=(--files --nested-sub --verbose )\n"), buffer.str());
|
CPPUNIT_ASSERT_EQUAL(string("COMPREPLY=('--files' '--nested-sub' '--verbose' )\n"), buffer.str());
|
||||||
|
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
cout.rdbuf(regularCoutBuffer);
|
cout.rdbuf(regularCoutBuffer);
|
||||||
|
|
Loading…
Reference in New Issue