KTextEditor

katescript.cpp
1/*
2 SPDX-FileCopyrightText: 2008 Paul Giannaros <paul@giannaros.org>
3 SPDX-FileCopyrightText: 2009-2018 Dominik Haumann <dhaumann@kde.org>
4 SPDX-FileCopyrightText: 2010 Joseph Wenninger <jowenn@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "katescript.h"
10
11#include "katepartdebug.h"
12#include "katescriptdocument.h"
13#include "katescripteditor.h"
14#include "katescripthelpers.h"
15#include "katescriptview.h"
16#include "kateview.h"
17
18#include <KLocalizedString>
19#include <iostream>
20
21#include <QFile>
22#include <QFileInfo>
23#include <QJSEngine>
24#include <QQmlEngine>
25
26KateScript::KateScript(const QString &urlOrScript, enum InputType inputType)
27 : m_url(inputType == InputURL ? urlOrScript : QString())
28 , m_inputType(inputType)
29 , m_script(inputType == InputSCRIPT ? urlOrScript : QString())
30{
31}
32
33KateScript::~KateScript()
34{
35 if (m_loadSuccessful) {
36 // remove data...
37 delete m_editor;
38 delete m_document;
39 delete m_view;
40 delete m_engine;
41 }
42}
43
44QString KateScript::backtrace(const QJSValue &error, const QString &header)
45{
46 QString bt;
47 if (!header.isNull()) {
48 bt += header + QLatin1String(":\n");
49 }
50 if (error.isError()) {
51 bt += error.toString() + QLatin1String("\nStrack trace:\n") + error.property(QStringLiteral("stack")).toString();
52 }
53
54 return bt;
55}
56
57void KateScript::displayBacktrace(const QJSValue &error, const QString &header)
58{
59 if (!m_engine) {
60 std::cerr << "KateScript::displayBacktrace: no engine, cannot display error\n";
61 return;
62 }
63 std::cerr << "\033[31m" << qPrintable(backtrace(error, header)) << "\033[0m" << '\n';
64}
65
67{
68 if (!load()) {
69 return;
70 }
71}
72
74{
75 // load the script if necessary
76 if (!load()) {
78 }
79 return m_engine->globalObject().property(name);
80}
81
83{
84 QJSValue value = global(name);
85 if (!value.isCallable()) {
87 }
88 return value;
89}
90
92{
93 if (m_loaded) {
94 return m_loadSuccessful;
95 }
96
97 m_loaded = true;
98 m_loadSuccessful = false; // here set to false, and at end of function to true
99
100 // read the script file into memory
101 QString source;
102 if (m_inputType == InputURL) {
103 if (!Kate::Script::readFile(m_url, source)) {
104 return false;
105 }
106 } else {
107 source = m_script;
108 }
109
110 // create script engine, register meta types
111 m_engine = new QJSEngine();
112
113 // export read & require function and add the require guard object
114 auto scriptHelper = new Kate::ScriptHelper(m_engine);
115 QJSValue functions = m_engine->newQObject(scriptHelper);
116 m_engine->globalObject().setProperty(QStringLiteral("functions"), functions);
117 m_engine->globalObject().setProperty(QStringLiteral("read"), functions.property(QStringLiteral("read")));
118 m_engine->globalObject().setProperty(QStringLiteral("require"), functions.property(QStringLiteral("require")));
119 m_engine->globalObject().setProperty(QStringLiteral("require_guard"), m_engine->newObject());
120
121 // View and Document expose JS Range objects in the API, which will fail to work
122 // if Range is not included. range.js includes cursor.js
123 scriptHelper->require(QStringLiteral("range.js"));
124
125 // export debug function
126 m_engine->globalObject().setProperty(QStringLiteral("debug"), functions.property(QStringLiteral("debug")));
127
128 // export translation functions
129 m_engine->globalObject().setProperty(QStringLiteral("i18n"), functions.property(QStringLiteral("_i18n")));
130 m_engine->globalObject().setProperty(QStringLiteral("i18nc"), functions.property(QStringLiteral("_i18nc")));
131 m_engine->globalObject().setProperty(QStringLiteral("i18np"), functions.property(QStringLiteral("_i18np")));
132 m_engine->globalObject().setProperty(QStringLiteral("i18ncp"), functions.property(QStringLiteral("_i18ncp")));
133
134 // register default styles as ds* global properties
135 m_engine->globalObject().setProperty(QStringLiteral("dsNormal"), KSyntaxHighlighting::Theme::TextStyle::Normal);
136 m_engine->globalObject().setProperty(QStringLiteral("dsKeyword"), KSyntaxHighlighting::Theme::TextStyle::Keyword);
137 m_engine->globalObject().setProperty(QStringLiteral("dsFunction"), KSyntaxHighlighting::Theme::TextStyle::Function);
138 m_engine->globalObject().setProperty(QStringLiteral("dsVariable"), KSyntaxHighlighting::Theme::TextStyle::Variable);
139 m_engine->globalObject().setProperty(QStringLiteral("dsControlFlow"), KSyntaxHighlighting::Theme::TextStyle::ControlFlow);
140 m_engine->globalObject().setProperty(QStringLiteral("dsOperator"), KSyntaxHighlighting::Theme::TextStyle::Operator);
141 m_engine->globalObject().setProperty(QStringLiteral("dsBuiltIn"), KSyntaxHighlighting::Theme::TextStyle::BuiltIn);
142 m_engine->globalObject().setProperty(QStringLiteral("dsExtension"), KSyntaxHighlighting::Theme::TextStyle::Extension);
143 m_engine->globalObject().setProperty(QStringLiteral("dsPreprocessor"), KSyntaxHighlighting::Theme::TextStyle::Preprocessor);
144 m_engine->globalObject().setProperty(QStringLiteral("dsAttribute"), KSyntaxHighlighting::Theme::TextStyle::Attribute);
145 m_engine->globalObject().setProperty(QStringLiteral("dsChar"), KSyntaxHighlighting::Theme::TextStyle::Char);
146 m_engine->globalObject().setProperty(QStringLiteral("dsSpecialChar"), KSyntaxHighlighting::Theme::TextStyle::SpecialChar);
147 m_engine->globalObject().setProperty(QStringLiteral("dsString"), KSyntaxHighlighting::Theme::TextStyle::String);
148 m_engine->globalObject().setProperty(QStringLiteral("dsVerbatimString"), KSyntaxHighlighting::Theme::TextStyle::VerbatimString);
149 m_engine->globalObject().setProperty(QStringLiteral("dsSpecialString"), KSyntaxHighlighting::Theme::TextStyle::SpecialString);
150 m_engine->globalObject().setProperty(QStringLiteral("dsImport"), KSyntaxHighlighting::Theme::TextStyle::Import);
151 m_engine->globalObject().setProperty(QStringLiteral("dsDataType"), KSyntaxHighlighting::Theme::TextStyle::DataType);
152 m_engine->globalObject().setProperty(QStringLiteral("dsDecVal"), KSyntaxHighlighting::Theme::TextStyle::DecVal);
153 m_engine->globalObject().setProperty(QStringLiteral("dsBaseN"), KSyntaxHighlighting::Theme::TextStyle::BaseN);
154 m_engine->globalObject().setProperty(QStringLiteral("dsFloat"), KSyntaxHighlighting::Theme::TextStyle::Float);
155 m_engine->globalObject().setProperty(QStringLiteral("dsConstant"), KSyntaxHighlighting::Theme::TextStyle::Constant);
156 m_engine->globalObject().setProperty(QStringLiteral("dsComment"), KSyntaxHighlighting::Theme::TextStyle::Comment);
157 m_engine->globalObject().setProperty(QStringLiteral("dsDocumentation"), KSyntaxHighlighting::Theme::TextStyle::Documentation);
158 m_engine->globalObject().setProperty(QStringLiteral("dsAnnotation"), KSyntaxHighlighting::Theme::TextStyle::Annotation);
159 m_engine->globalObject().setProperty(QStringLiteral("dsCommentVar"), KSyntaxHighlighting::Theme::TextStyle::CommentVar);
160 m_engine->globalObject().setProperty(QStringLiteral("dsRegionMarker"), KSyntaxHighlighting::Theme::TextStyle::RegionMarker);
161 m_engine->globalObject().setProperty(QStringLiteral("dsInformation"), KSyntaxHighlighting::Theme::TextStyle::Information);
162 m_engine->globalObject().setProperty(QStringLiteral("dsWarning"), KSyntaxHighlighting::Theme::TextStyle::Warning);
163 m_engine->globalObject().setProperty(QStringLiteral("dsAlert"), KSyntaxHighlighting::Theme::TextStyle::Alert);
164 m_engine->globalObject().setProperty(QStringLiteral("dsOthers"), KSyntaxHighlighting::Theme::TextStyle::Others);
165 m_engine->globalObject().setProperty(QStringLiteral("dsError"), KSyntaxHighlighting::Theme::TextStyle::Error);
166
167 // register scripts itself
168 QJSValue result = m_engine->evaluate(source, m_url);
169 if (hasException(result, m_url)) {
170 return false;
171 }
172
173 // AFTER SCRIPT: set the view/document objects as necessary
174 m_engine->globalObject().setProperty(QStringLiteral("editor"), m_engine->newQObject(m_editor = new KateScriptEditor()));
175 m_engine->globalObject().setProperty(QStringLiteral("document"), m_engine->newQObject(m_document = new KateScriptDocument(m_engine)));
176 m_engine->globalObject().setProperty(QStringLiteral("view"), m_engine->newQObject(m_view = new KateScriptView(m_engine)));
177
178 // yip yip!
179 m_loadSuccessful = true;
180
181 return true;
182}
183
185{
186 if (!load()) {
187 qCWarning(LOG_KTE) << "load of script failed:" << program;
188 return QJSValue();
189 }
190
191 // Wrap the arguments in a function to avoid polluting the global object
192 QString programWithContext =
193 QLatin1String("(function(") + QStringList(env.keys()).join(QLatin1Char(',')) + QLatin1String(") { return ") + program + QLatin1String("})");
194 QJSValue programFunction = m_engine->evaluate(programWithContext);
195 Q_ASSERT(programFunction.isCallable());
196
197 QJSValueList args;
198 args.reserve(env.size());
199 for (auto it = env.begin(); it != env.end(); it++) {
200 args << it.value();
201 }
202
203 QJSValue result = programFunction.call(args);
204 if (result.isError()) {
205 qCWarning(LOG_KTE) << "Error evaluating script: " << result.toString();
206 }
207
208 return result;
209}
210
211bool KateScript::hasException(const QJSValue &object, const QString &file)
212{
213 if (object.isError()) {
214 m_errorMessage = i18n("Error loading script %1", file);
215 displayBacktrace(object, m_errorMessage);
216 delete m_engine;
217 m_engine = nullptr;
218 m_loadSuccessful = false;
219 return true;
220 }
221 return false;
222}
223
224bool KateScript::setView(KTextEditor::ViewPrivate *view)
225{
226 if (!load()) {
227 return false;
228 }
229 // setup the stuff
230 m_document->setDocument(view->doc());
231 m_view->setView(view);
232 return true;
233}
234
235void KateScript::setGeneralHeader(const KateScriptHeader &generalHeader)
236{
237 m_generalHeader = generalHeader;
238}
239
240KateScriptHeader &KateScript::generalHeader()
241{
242 return m_generalHeader;
243}
Thinish wrapping around KTextEditor::DocumentPrivate, exposing the methods we want exposed and adding...
This class wraps the global editor instance KateGlobal, exposing some helper methods such as the clip...
Thinish wrapping around KTextEditor::ViewPrivate, exposing the methods we want exposed and adding som...
QJSValue global(const QString &name)
Get a QJSValue for a global item in the script given its name, or an invalid QJSValue if no such glob...
QJSEngine * m_engine
The Qt interpreter for this script.
Definition katescript.h:196
KateScriptHeader & generalHeader()
Return the general header.
void displayBacktrace(const QJSValue &error, const QString &header=QString())
Displays the backtrace when a script has errored out.
bool setView(KTextEditor::ViewPrivate *view)
set view for this script for the execution will trigger load!
void clearExceptions()
Clears any uncaught exceptions in the script engine.
QJSValue evaluate(const QString &program, const FieldMap &env=FieldMap())
Execute a piece of code.
static QString backtrace(const QJSValue &error, const QString &header=QString())
Returns the backtrace when a script has errored out.
bool load()
Load the script.
void setGeneralHeader(const KateScriptHeader &generalHeader)
set the general header after construction of the script
QJSValue function(const QString &name)
Return a function in the script of the given name, or an invalid QJSValue if no such function exists.
bool hasException(const QJSValue &object, const QString &file)
Checks for exception and gives feedback on the console.
KateScript(const QString &urlOrScript, enum InputType inputType=InputURL)
Create a new script representation, passing either a file or the script content urlOrScript to it.
QString i18n(const char *text, const TYPE &arg...)
bool readFile(const QString &sourceUrl, QString &sourceCode)
read complete file contents, helper
QJSValue evaluate(const QString &program, const QString &fileName, int lineNumber, QStringList *exceptionStackTrace)
QJSValue globalObject() const const
QJSValue newObject()
QJSValue newQObject(QObject *object)
QJSValue call(const QJSValueList &args) const const
bool isCallable() const const
bool isError() const const
QJSValue property(const QString &name) const const
void setProperty(const QString &name, const QJSValue &value)
QString toString() const const
iterator begin()
iterator end()
QList< Key > keys() const const
size_type size() const const
bool isNull() const const
QString join(QChar separator) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:15:44 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.