aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/sqlitestudiocli/clicompleter.cpp
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@ubuntu.com>2014-12-06 17:33:25 -0500
committerLibravatarUnit 193 <unit193@ubuntu.com>2014-12-06 17:33:25 -0500
commit7167ce41b61d2ba2cdb526777a4233eb84a3b66a (patch)
treea35c14143716e1f2c98f808c81f89426045a946f /SQLiteStudio3/sqlitestudiocli/clicompleter.cpp
Imported Upstream version 2.99.6upstream/2.99.6
Diffstat (limited to 'SQLiteStudio3/sqlitestudiocli/clicompleter.cpp')
-rw-r--r--SQLiteStudio3/sqlitestudiocli/clicompleter.cpp173
1 files changed, 173 insertions, 0 deletions
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 <QString>
+#include <QDebug>
+
+#if defined(Q_OS_WIN32)
+#include "readline.h"
+#elif defined(Q_OS_UNIX)
+#include <readline/readline.h>
+#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<ExpectedTokenPtr> 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;
+}