diff --git a/src/backends/julia/juliacompletionobject.cpp b/src/backends/julia/juliacompletionobject.cpp index e59b8ac3..25d83763 100644 --- a/src/backends/julia/juliacompletionobject.cpp +++ b/src/backends/julia/juliacompletionobject.cpp @@ -1,101 +1,132 @@ /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * --- * Copyright (C) 2016 Ivan Lakhtanov */ #include "juliacompletionobject.h" #include "juliasession.h" #include "juliakeywords.h" #include "result.h" #include #include JuliaCompletionObject::JuliaCompletionObject( const QString &command, int index, JuliaSession *session) - : Cantor::CompletionObject(session) + : Cantor::CompletionObject(session), + m_expression(nullptr) { setLine(command, index); } void JuliaCompletionObject::fetchCompletions() { if (session()->status() == Cantor::Session::Disable) { QStringList allCompletions; allCompletions << JuliaKeywords::instance()->keywords(); allCompletions << JuliaKeywords::instance()->variables(); allCompletions << JuliaKeywords::instance()->functions(); allCompletions << JuliaKeywords::instance()->plotShowingCommands(); setCompletions(allCompletions); emit fetchingDone(); } else { + if (m_expression) + return; + QString completionCommand; #if QT_VERSION_CHECK(JULIA_VERSION_MAJOR, JULIA_VERSION_MINOR, 0) >= QT_VERSION_CHECK(0, 7, 0) completionCommand = QString::fromLatin1( "using REPL; " "join(" "map(REPL.REPLCompletions.completion_text, REPL.REPLCompletions.completions(\"%1\", %2)[1])," "\"__CANTOR_DELIM__\")" ); #else completionCommand = QString::fromLatin1( "join(" "Base.REPL.REPLCompletions.completions(\"%1\", %2)[1]," "\"__CANTOR_DELIM__\")" ); #endif - auto julia_session = static_cast(session()); - julia_session->runJuliaCommand(completionCommand.arg(command()).arg(command().size())); - auto result = julia_session->getOutput(); - result.chop(1); - result.remove(0, 1); - QStringList completions = result.split(QLatin1String("__CANTOR_DELIM__")); - if (command().contains(QLatin1Char('.'))) - for(QString& word : completions) - { - const int i = command().lastIndexOf(QLatin1Char('.')); - const QString& prefix = command().remove(i, command().size()-i) + QLatin1Char('.'); - if (!word.startsWith(prefix)) - word.prepend(prefix); - } - - setCompletions(completions); - emit fetchingDone(); + const QString cmd = completionCommand.arg(command()).arg(command().size()); + m_expression = session()->evaluateExpression(cmd, Cantor::Expression::FinishingBehavior::DoNotDelete, true); + connect(m_expression, &Cantor::Expression::statusChanged, this, &JuliaCompletionObject::extractCompletions); } } +void JuliaCompletionObject::extractCompletions(Cantor::Expression::Status status) +{ + if (!m_expression) + return; + + switch(status) + { + case Cantor::Expression::Done: + { + auto result = m_expression->result()->data().toString(); + result.chop(1); + result.remove(0, 1); + QStringList completions = result.split(QLatin1String("__CANTOR_DELIM__")); + if (command().contains(QLatin1Char('.'))) + for(QString& word : completions) + { + const int i = command().lastIndexOf(QLatin1Char('.')); + const QString& prefix = command().remove(i, command().size()-i) + QLatin1Char('.'); + if (!word.startsWith(prefix)) + word.prepend(prefix); + } + + setCompletions(completions); + break; + } + case Cantor::Expression::Interrupted: + case Cantor::Expression::Error: + { + qDebug() << "fetching expression finished with status" << (status == Cantor::Expression::Error? "Error" : "Interrupted"); + + break; + } + default: + return; + } + + m_expression->deleteLater(); + m_expression = nullptr; + emit fetchingDone(); +} + bool JuliaCompletionObject::mayIdentifierContain(QChar c) const { return c.isLetter() || c.isDigit() || c == QLatin1Char('_') || c == QLatin1Char('%') || c == QLatin1Char('$') || c == QLatin1Char('.'); } bool JuliaCompletionObject::mayIdentifierBeginWith(QChar c) const { return c.isLetter() || c == QLatin1Char('_') || c == QLatin1Char('%') || c == QLatin1Char('$'); } diff --git a/src/backends/julia/juliacompletionobject.h b/src/backends/julia/juliacompletionobject.h index bd9a58e6..00c10157 100644 --- a/src/backends/julia/juliacompletionobject.h +++ b/src/backends/julia/juliacompletionobject.h @@ -1,62 +1,67 @@ /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * --- * Copyright (C) 2016 Ivan Lakhtanov */ #pragma once #include "completionobject.h" +#include "expression.h" class JuliaSession; /** * Implements code completion for Julia language * * Uses Julia's Base.REPL.REPLCompletions.completions command to get * context-aware completions like in native Julia REPL */ class JuliaCompletionObject : public Cantor::CompletionObject { public: /** * Constructs JuliaCompletionObject * * @param cmd command piece to generate completion * @param index index of cursor in command * @param session current session */ JuliaCompletionObject(const QString &cmd, int index, JuliaSession *session); ~JuliaCompletionObject() override = default; protected: /** * @see Cantor::CompletionObject::mayIdentifierContain */ bool mayIdentifierContain(QChar c) const override; bool mayIdentifierBeginWith(QChar c) const override; /** * @see Cantor::CompletionObject::mayIdentifierBeginWith */ protected Q_SLOTS: /** * @see Cantor::CompletionObject::fetchCompletions */ void fetchCompletions() override; + void extractCompletions(Cantor::Expression::Status status); + +private: + Cantor::Expression* m_expression; }; diff --git a/src/backends/julia/juliasession.h b/src/backends/julia/juliasession.h index 2aa61c2c..243506a2 100644 --- a/src/backends/julia/juliasession.h +++ b/src/backends/julia/juliasession.h @@ -1,146 +1,144 @@ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. --- Copyright (C) 2016 Ivan Lakhtanov */ #pragma once #include #include #include "session.h" class JuliaExpression; class JuliaCompletionObject; class JuliaVariableModel; class KProcess; class QDBusInterface; namespace Cantor { class DefaultVariableModel; } /** * Implements a Cantor session for the Julia backend * * It communicates through DBus interface with JuliaServer */ class JuliaSession: public Cantor::Session { Q_OBJECT public: /** * Constructs session * * @param backend owning backend */ explicit JuliaSession(Cantor::Backend *backend); /** * @see Cantor::Session::login */ void login() override; /** * @see Cantor::Session::logout */ void logout() override; /** * @see Cantor::Session::interrupt */ void interrupt() override; /** * @see Cantor::Session::evaluateExpression */ Cantor::Expression *evaluateExpression( const QString &command, Cantor::Expression::FinishingBehavior behave = Cantor::Expression::FinishingBehavior::DoNotDelete, bool internal = false) override; /** * @see Cantor::Session::completionFor */ Cantor::CompletionObject *completionFor( const QString &cmd, int index = -1) override; /** * @see Cantor::Session::syntaxHighlighter */ QSyntaxHighlighter *syntaxHighlighter(QObject *parent) override; /** * @return indicator if config says to integrate plots into worksheet */ bool integratePlots(); private Q_SLOTS: /** * Called when async call to JuliaServer is finished */ void onResultReady(); private: KProcess *m_process; //< process to run JuliaServer inside QDBusInterface *m_interface; //< interface to JuliaServer /// Cache to speedup modules whos calls QMap m_whos_cache; - friend JuliaCompletionObject; - void runFirstExpression() override; /** * Runs Julia piece of code in synchronous mode * * @param command command to execute */ void runJuliaCommand(const QString &command) const; /** * Runs Julia piece of code in asynchronous mode. When finished * onResultReady is called * * @param command command to execute */ void runJuliaCommandAsync(const QString &command); /** * Helper method to get QString returning function result * * @param method DBus method to call * @return result of the method */ QString getStringFromServer(const QString &method); /** * @return stdout of the last executed command */ QString getOutput(); /** * @return stderr of the last executed command */ QString getError(); /** * @return indicator of exception occurred during the last command execution */ bool getWasException(); };