Commit c4d18c57 authored by Ivan Lakhtanov's avatar Ivan Lakhtanov
Browse files

Documentation for Julia backend stuff

Differential Revision: https://phabricator.kde.org/D2507
parent 8da94fe3
......@@ -17,6 +17,7 @@ Available Backends
- R Project for Statistical Computing: http://r-project.org/
- Sage Mathematics Software: http://sagemath.org/
- Scilab for Numerical Computation: http://scilab.org/
- Julia programming language: http://julialang.org/
How To Build and Install Cantor
-=-=-=-=-=-=-=-=-=-=-=-=-=
......
......@@ -17,6 +17,7 @@ Backends.
- R Project for Statistical Computing: http://r-project.org/
- Sage Mathematics Software: http://sagemath.org/
- Scilab for Numerical Computation: http://scilab.org/
- Julia programming language: http://julialang.org/
## How To Build and Install Cantor
......
......@@ -21,24 +21,66 @@
#include "backend.h"
/**
* Backend for Julia language
*
* @see http://julialang.org/
* @see JuliaServer
*/
class JuliaBackend: public Cantor::Backend
{
Q_OBJECT
public:
/**
* Constructs julia backend
*
* @param parent QObject parent. Defaults to nullptr.
* @param args Additional arguments for the backend.
* Defaults to QList<QVariant>().
*/
explicit JuliaBackend(
QObject *parent = 0,
const QList<QVariant> &args = QList<QVariant>());
virtual ~JuliaBackend() {}
/**
* @see Cantor::Backend::id
*/
virtual QString id() const override;
/**
* @see Cantor::Backend::createSession
*/
virtual Cantor::Session *createSession() override;
/**
* @see Cantor::Backend::capabilities
*/
virtual Cantor::Backend::Capabilities capabilities() const override;
/**
* @see Cantor::Backend::description
*/
virtual QString description() const override;
/**
* @see Cantor::Backend::helpUrl
*/
virtual QUrl helpUrl() const override;
/**
* @see Cantor::Backend::requirementsFullfilled
*/
virtual bool requirementsFullfilled() const override;
/**
* @see Cantor::Backend::settingsWidget
*/
virtual QWidget *settingsWidget(QWidget *parent) const override;
/**
* @see Cantor::Backend::config
*/
virtual KConfigSkeleton *config() const override;
};
......@@ -24,16 +24,39 @@
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 commmand
* @param session current session
*/
JuliaCompletionObject(const QString &cmd, int index, JuliaSession *session);
~JuliaCompletionObject();
protected:
/**
* @see Cantor::CompletionObject::mayIdentifierContain
*/
virtual bool mayIdentifierContain(QChar c) const;
virtual bool mayIdentifierBeginWith(QChar c) const;
/**
* @see Cantor::CompletionObject::mayIdentifierBeginWith
*/
protected Q_SLOTS:
/**
* @see Cantor::CompletionObject::fetchCompletions
*/
void fetchCompletions();
};
......@@ -38,8 +38,10 @@ void JuliaExpression::evaluate()
setStatus(Cantor::Expression::Computing);
auto juliaSession = dynamic_cast<JuliaSession *>(session());
// Plots integration
m_plot_filename.clear();
if (juliaSession->integratePlots() and checkPlotShowingCommands()) {
// Simply add plot saving command to the end of execution
QStringList inlinePlotFormats;
inlinePlotFormats << QLatin1String("svg");
inlinePlotFormats << QLatin1String("eps");
......@@ -73,6 +75,7 @@ void JuliaExpression::finalize()
} else {
if (not m_plot_filename.isEmpty()
and QFileInfo(m_plot_filename).exists()) {
// If we have plot in result, show it
setResult(
new Cantor::ImageResult(QUrl::fromLocalFile(m_plot_filename)));
QDir().remove(m_plot_filename);
......
......@@ -21,19 +21,48 @@
#include "expression.h"
/**
* Expression of Julia language
*/
class JuliaExpression: public Cantor::Expression
{
Q_OBJECT
public:
/**
* Creates new JuliaExpression
*
* @param session session to bound expression to
*/
JuliaExpression(Cantor::Session *session);
virtual ~JuliaExpression() {};
/**
* @see Cantor::Expression::evaluate
*/
virtual void evaluate() override;
/**
* @see Cantor::Expression::interrupt
*/
virtual void interrupt() override;
/**
* Call this function from session when JuliaServer ends evaluation of
* this expression.
*
* This checks inline plots, exceptions and set appropriate result
*/
void finalize();
private:
/// If not empty, it's a filename of plot image file expression is awaiting
/// to get
QString m_plot_filename;
/**
* @return bool indicator if current expression contains command that
* shows plot
*/
bool checkPlotShowingCommands();
};
......@@ -25,81 +25,180 @@
~Julia##name##Extension();
/**
* Implementation of linear algebra wizards for Julia
*/
class JuliaLinearAlgebraExtension: public Cantor::LinearAlgebraExtension
{
public:
JULIA_EXT_CDTOR_DECL(LinearAlgebra)
/**
* @see Cantor::LinearAlgebraExtension::createVector
*/
virtual QString createVector(
const QStringList &entries,
VectorType type) override;
/**
* @see Cantor::LinearAlgebraExtension::nullVector
*/
virtual QString nullVector(int size, VectorType type) override;
/**
* @see Cantor::LinearAlgebraExtension::createMatrix
*/
virtual QString createMatrix(
const Cantor::LinearAlgebraExtension::Matrix &matrix) override;
/**
* @see Cantor::LinearAlgebraExtension::identityMatrix
*/
virtual QString identityMatrix(int size) override;
/**
* @see Cantor::LinearAlgebraExtension::nullMatrix
*/
virtual QString nullMatrix(int rows, int columns) override;
/**
* @see Cantor::LinearAlgebraExtension::rank
*/
virtual QString rank(const QString &matrix) override;
/**
* @see Cantor::LinearAlgebraExtension::invertMatrix
*/
virtual QString invertMatrix(const QString &matrix) override;
/**
* @see Cantor::LinearAlgebraExtension::charPoly
*/
virtual QString charPoly(const QString &matrix) override;
/**
* @see Cantor::LinearAlgebraExtension::eigenVectors
*/
virtual QString eigenVectors(const QString &matrix) override;
/**
* @see Cantor::LinearAlgebraExtension::eigenValues
*/
virtual QString eigenValues(const QString &matrix) override;
};
/**
* Implementation of packaging wizards for Julia
*/
class JuliaPackagingExtension: public Cantor::PackagingExtension
{
public:
JULIA_EXT_CDTOR_DECL(Packaging)
/**
* @see Cantor::PackagingExtension::importPackage
*/
virtual QString importPackage(const QString &module) override;
};
/**
* Implementation of plot wizards for Julia
*
* Plotting is based on GR package
*/
class JuliaPlotExtension: public Cantor::PlotExtension
{
public:
JULIA_EXT_CDTOR_DECL(Plot)
/**
* @see Cantor::PlotExtension::plotFunction2d
*/
virtual QString plotFunction2d(
const QString &function,
const QString &variable,
const QString &left,
const QString &right) override;
/**
* @see Cantor::PlotExtension::plotFunction3d
*/
virtual QString plotFunction3d(
const QString &function,
VariableParameter var1,
VariableParameter var2) override;
};
/**
* Implementation of script wizard for Julia
*/
class JuliaScriptExtension: public Cantor::ScriptExtension
{
public:
JULIA_EXT_CDTOR_DECL(Script)
/**
* @see Cantor::ScriptExtension::scriptFileFilter
*/
virtual QString scriptFileFilter() override;
/**
* @see Cantor::ScriptExtension::highlightingMode
*/
virtual QString highlightingMode() override;
/**
* @see Cantor::ScriptExtension::runExternalScript
*/
virtual QString runExternalScript(const QString &path) override;
};
/**
* Julia variable management extension
*
* Based on JLD package for loading/saving variables
*/
class JuliaVariableManagementExtension: public Cantor::VariableManagementExtension
{
public:
JULIA_EXT_CDTOR_DECL(VariableManagement)
// There is no way to completely delete object from scope:
// http://docs.julialang.org/en/release-0.4/manual/faq/#how-do-i-delete-an-object-in-memory
// So we are saving special marker to variable to mark it as removed
static const QString REMOVED_VARIABLE_MARKER;
/**
* @see Cantor::VariableManagementExtension::addVariable
*/
virtual QString addVariable(
const QString &name,
const QString &value) override;
/**
* @see Cantor::VariableManagementExtension::setValue
*/
virtual QString setValue(
const QString &name,
const QString &value) override;
/**
* @see Cantor::VariableManagementExtension::removeVariable
*/
virtual QString removeVariable(const QString &name) override;
/**
* @see Cantor::VariableManagementExtension::saveVariables
*/
virtual QString saveVariables(const QString &fileName) override;
/**
* @see Cantor::VariableManagementExtension::loadVariables
*/
virtual QString loadVariables(const QString &fileName) override;
/**
* @see Cantor::VariableManagementExtension::clearVariables
*/
virtual QString clearVariables() override;
};
......@@ -41,11 +41,19 @@ void JuliaHighlighter::highlightBlock(const QString &text)
// Do some backend independent highlighting (brackets etc.)
DefaultHighlighter::highlightBlock(text);
// Now we are about to make corrent strings and comments highlighting
//
// Main idea: as soon as string starts comment or anything else cant start
// until current string ends. The same with comment, except '#' comment
// that ends by newline
//
// To pass information to next block, we are using next states
const int IN_MULTILINE_COMMENT = 1;
const int IN_CHARACTER = 2;
const int IN_SINGLE_QUOTE_STRING = 4;
const int IN_TRIPLE_QUOTE_STRING = 8;
// Markers of scopes start, ends
QRegExp multiLineCommentStart(QLatin1String("#="));
QRegExp multiLineCommentEnd(QLatin1String("=#"));
QRegExp characterStartEnd(QLatin1String("'"));
......@@ -53,11 +61,14 @@ void JuliaHighlighter::highlightBlock(const QString &text)
QRegExp tripleQuoteStringStartEnd(QLatin1String("\"\"\""));
QRegExp singleLineCommentStart(QLatin1String("#(?!=)"));
// Get current state
int state = previousBlockState();
if (state == -1) {
state = 0;
}
// This 4 arrays establish matching between state, start marker, end marker
// and format to apply
QList<int> flags = {
IN_TRIPLE_QUOTE_STRING,
IN_SINGLE_QUOTE_STRING,
......@@ -83,7 +94,7 @@ void JuliaHighlighter::highlightBlock(const QString &text)
commentFormat()
};
int pos = 0;
int pos = 0; // current position in block
while (pos < text.length()) {
// Trying to close current environments
bool triggered = false;
......@@ -91,27 +102,33 @@ void JuliaHighlighter::highlightBlock(const QString &text)
int flag = flags[i];
QRegExp &regexp = regexps_ends[i];
QTextCharFormat &format = formats[i];
if (state & flag) {
if (state & flag) { // Found current state
// find where end marker is
int new_pos = regexp.indexIn(text, pos);
int length;
if (new_pos == -1) {
// not in this block, highlight till the end
length = text.length() - pos;
} else {
// highlight untill the marker and modify state
length = new_pos - pos + regexp.matchedLength();
state -= flag;
}
// Apply format to the found area
setFormat(pos, length, format);
pos = pos + length;
triggered = true;
}
}
if (triggered) {
if (triggered) { // We have done something move to next iteration
continue;
}
QRegExp *minRegexp = nullptr;
int minPos = INT_MAX;
int minIdx = -1;
// Now we should found the scope that start the closest to current
// position
QRegExp *minRegexp = nullptr; // closest marker
int minPos = INT_MAX; // closest pos
int minIdx = -1; // closest scope index
for (int i = 0; i < regexps_starts.size(); i++) {
QRegExp &regexp = regexps_starts[i];
int newPos = regexp.indexIn(text, pos);
......@@ -122,18 +139,21 @@ void JuliaHighlighter::highlightBlock(const QString &text)
}
}
// Check where single line comment starts
int singleLineCommentStartPos =
singleLineCommentStart.indexIn(text, pos);
if (singleLineCommentStartPos != -1
and singleLineCommentStartPos < minPos) {
// single line comment starts earlier
setFormat(pos, text.length() - pos, commentFormat());
break;
} else if (minRegexp) {
// We are going to another scope
state += flags[minIdx];
pos = minPos + minRegexp->matchedLength();
setFormat(minPos, minRegexp->matchedLength(), formats[minIdx]);
} else {
} else { // There is nothing to highlight
break;
}
}
......@@ -143,14 +163,15 @@ void JuliaHighlighter::highlightBlock(const QString &text)
void JuliaHighlighter::updateHighlight()
{
// Remove rules for outdated variables and functions
for (const auto &var : JuliaKeywords::instance()->removedVariables()) {
removeRule(var);
}
for (const auto &func : JuliaKeywords::instance()->removedFunctions()) {
removeRule(func);
}
// Add actual variables and function
addVariables(JuliaKeywords::instance()->variables());
addFunctions(JuliaKeywords::instance()->functions());
rehighlight();
......
......@@ -21,18 +21,40 @@
#include "defaulthighlighter.h"
/**
* Implementation of JuliaHighlighter
*
* Takes into account loaded symbols from scope and predefined keywords.
* There is no common regexps that bound to fail with such syntax-overloaded
* languages as Julia
*/
class JuliaHighlighter: public Cantor::DefaultHighlighter
{
Q_OBJECT
public:
/**
* Constructs JuliaHighlighter
*
* @param parent QObject parent
*/
JuliaHighlighter(QObject *parent);
virtual ~JuliaHighlighter() {}
public Q_SLOTS:
/**
* Call this to update highlighter to the current state of keywords storage
*/
void updateHighlight();
protected:
/**
* @see Cantor::DefaultHighlighter::highlightBlock
*/
virtual void highlightBlock(const QString &text) override;
/**
* @see Cantor::DefaultHighlighter::nonSeparatingCharacters
*/
virtual QString nonSeparatingCharacters() const override;
};
......@@ -21,37 +21,88 @@
#include <QStringList>
/**
* Keywords storage for Julia session
*
* Class is implemented with singleton pattern
*/
class JuliaKeywords
{
public:
/**
* @return singleton instance pointer
*/
static JuliaKeywords *instance();
/**
* @return list of Julia language predefined keywords
*/
const QStringList &keywords() const { return m_keywords; }
/**
* @return list of predefined commands, that are capable to show plot
*/
const QStringList &plotShowingCommands() const
{
return m_plotShowingCommands;
}
/**
* @return list of known variable names
*/
const QStringList &variables() const { return m_variables; }
/**
* @return list of variables removed during the last clearVariables() call
*/
const QStringList &removedVariables() const { return m_removedVariables; }
/**
* Clears all known variables
*/
void clearVariables();
/**
* Add new variable to the known list
*
* @param variable name of the variable to add
*/
void addVariable(const QString &variable);
/**
* @return list of known function names
*/
const QStringList &functions() const { return m_functions; }
/**
* @return list of functions removed during the last clearFunctions() call
*/
const QStringList &removedFunctions() const { return m_removedFunctions; }
/**
* Clears all known functions
*/
void clearFunctions();
/**
* Add new function to the known list
*
* @param function name of the function to add
*/
void addFunction(const QString &function);
private:
QStringList m_keywords;
QStringList m_plotShowingCommands;
QStringList m_variables;
QStringList m_removedVariables;
QStringList m_functions;
QStringList m_removedFunctions;
QStringList m_keywords; //< list of predefined keywords
QStringList m_plotShowingCommands; //< list of predefined plot showing cmds
QStringList m_variables; //< list of variables known at the moment
QStringList m_removedVariables; //< list of variables removed during cleaning
QStringList m_functions; //< list of known function at the moment
QStringList m_removedFunctions; //< list of functions removed during cleaning