From 7167ce41b61d2ba2cdb526777a4233eb84a3b66a Mon Sep 17 00:00:00 2001 From: Unit 193 Date: Sat, 6 Dec 2014 17:33:25 -0500 Subject: Imported Upstream version 2.99.6 --- SQLiteStudio3/sqlitestudiocli/clicompleter.cpp | 173 +++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 SQLiteStudio3/sqlitestudiocli/clicompleter.cpp (limited to 'SQLiteStudio3/sqlitestudiocli/clicompleter.cpp') diff --git a/SQLiteStudio3/sqlitestudiocli/clicompleter.cpp b/SQLiteStudio3/sqlitestudiocli/clicompleter.cpp new file mode 100644 index 0000000..1c3c99c --- /dev/null +++ b/SQLiteStudio3/sqlitestudiocli/clicompleter.cpp @@ -0,0 +1,173 @@ +#include "clicompleter.h" +#include "completionhelper.h" +#include "cli.h" +#include "cli_config.h" +#include "common/unused.h" +#include "commands/clicommand.h" +#include "parser/lexer.h" +#include "commands/clicommandfactory.h" +#include +#include + +#if defined(Q_OS_WIN32) +#include "readline.h" +#elif defined(Q_OS_UNIX) +#include +#endif + +CliCompleter* CliCompleter::instance = nullptr; + +CliCompleter::CliCompleter() +{ +} + +void CliCompleter::init(CLI* value) +{ + rl_attempted_completion_function = CliCompleter::complete; + cli = value; +} + +CliCompleter* CliCompleter::getInstance() +{ + if (!instance) + instance = new CliCompleter(); + + return instance; +} + +char** CliCompleter::complete(const char* text, int start, int end) +{ + UNUSED(start); + +#ifdef Q_OS_UNIX + // Unix readline needs this to disable the completion using rl_completion_entry_function + rl_attempted_completion_over = 1; +#endif + + return toCharArray(getInstance()->completeInternal(QString::fromLocal8Bit(text), QString::fromLocal8Bit(rl_line_buffer), end)); +} + +QStringList CliCompleter::completeInternal(const QString& toBeReplaced, const QString& text, int curPos) +{ + QString str; + if (!cli->getLine().isEmpty()) + { + str += cli->getLine(); + curPos += str.length(); + } + + str += text; + + QStringList list; + if (str.startsWith(CFG_CLI.Console.CommandPrefixChar.get())) + list = completeCommand(str, curPos); + else + list = completeQuery(toBeReplaced, str, curPos); + + list.removeDuplicates(); + +#ifdef Q_OS_WIN + if (list.size() == 1) + list[0] += " "; +#endif + +#ifdef Q_OS_UNIX + // Unix readline treats first element in the list as a common value of all elements + if (list.size() > 0) + list.prepend(longestCommonPart(list)); +#endif + + return list; +} + +QStringList CliCompleter::completeCommand(const QString& str, int curPos) +{ + QStringList results; + QString text = str.mid(0, curPos); + + QStringList cmdWords = tokenizeArgs(text); + if (cmdWords.size() == 0) + return results; + + if (text[text.length()-1].isSpace()) + cmdWords << ""; + + QString cmdStr = cmdWords[0].mid(1); + if (cmdWords.size() > 1) + { + CliCommand* command = CliCommandFactory::getCommand(cmdStr); + if (!command) + return results; + + command->setup(cli); + results = command->complete(cmdWords.mid(1)).filter(QRegExp("^"+cmdWords.last()+".*")); + } + else + { + QStringList cmdNames = CliCommandFactory::getCommandNames().filter(QRegExp("^"+cmdStr+".*")); + cmdNames.sort(Qt::CaseInsensitive); + foreach (const QString& cmdName, cmdNames) + results << CFG_CLI.Console.CommandPrefixChar.get() + cmdName; + } + + return results; +} + +QStringList CliCompleter::completeQuery(const QString& toBeReplaced, const QString& str, int curPos) +{ + QStringList list; + if (!cli->getCurrentDb()) + return list; + + bool keepOriginalStr = doKeepOriginalStr(str, curPos); + + CompletionHelper completer(str, curPos, cli->getCurrentDb()); + QList expectedTokens = completer.getExpectedTokens().filtered(); + + foreach (const ExpectedTokenPtr& token, expectedTokens) + list << token->value; + + list.removeAll(""); + if (list.size() > 1) + list.removeOne(";"); // we don't want it together with other proposals, cause it introduces problems when proposed by completer + + if (keepOriginalStr) + { + QMutableStringListIterator it(list); + while (it.hasNext()) + it.next().prepend(toBeReplaced); + } + return list; +} + +bool CliCompleter::doKeepOriginalStr(const QString& str, int curPos) +{ + Dialect dialect = Dialect::Sqlite3; + if (cli->getCurrentDb()) + dialect = cli->getCurrentDb()->getDialect(); + + TokenList tokens = Lexer::tokenize(str.mid(0, curPos), dialect); + if (tokens.size() == 0) + return false; + + return tokens.last()->isSeparating(); +} + +char** CliCompleter::toCharArray(const QStringList& list) +{ + if (list.size() == 0) + return nullptr; + + char** array = (char**)malloc((list.size() + 1) * sizeof(char*)); + array[list.size()] = nullptr; + + int i = 0; + foreach (const QString& str, list) +#if defined(Q_OS_WIN) + array[i++] = _strdup(str.toLocal8Bit().data()); +#elif defined(Q_OS_UNIX) + array[i++] = strdup(str.toLocal8Bit().data()); +#endif + + return array; +} -- cgit v1.2.3