File indexing completed on 2024-04-14 03:55:19
0001 /* 0002 SPDX-FileCopyrightText: 2008 Paul Giannaros <paul@giannaros.org> 0003 SPDX-FileCopyrightText: 2009-2018 Dominik Haumann <dhaumann@kde.org> 0004 SPDX-FileCopyrightText: 2010 Joseph Wenninger <jowenn@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "katescript.h" 0010 0011 #include "katepartdebug.h" 0012 #include "katescriptdocument.h" 0013 #include "katescripteditor.h" 0014 #include "katescripthelpers.h" 0015 #include "katescriptview.h" 0016 #include "kateview.h" 0017 0018 #include <KLocalizedString> 0019 #include <iostream> 0020 0021 #include <QFile> 0022 #include <QFileInfo> 0023 #include <QJSEngine> 0024 #include <QQmlEngine> 0025 0026 KateScript::KateScript(const QString &urlOrScript, enum InputType inputType) 0027 : m_url(inputType == InputURL ? urlOrScript : QString()) 0028 , m_inputType(inputType) 0029 , m_script(inputType == InputSCRIPT ? urlOrScript : QString()) 0030 { 0031 } 0032 0033 KateScript::~KateScript() 0034 { 0035 if (m_loadSuccessful) { 0036 // remove data... 0037 delete m_editor; 0038 delete m_document; 0039 delete m_view; 0040 delete m_engine; 0041 } 0042 } 0043 0044 QString KateScript::backtrace(const QJSValue &error, const QString &header) 0045 { 0046 QString bt; 0047 if (!header.isNull()) { 0048 bt += header + QLatin1String(":\n"); 0049 } 0050 if (error.isError()) { 0051 bt += error.toString() + QLatin1String("\nStrack trace:\n") + error.property(QStringLiteral("stack")).toString(); 0052 } 0053 0054 return bt; 0055 } 0056 0057 void KateScript::displayBacktrace(const QJSValue &error, const QString &header) 0058 { 0059 if (!m_engine) { 0060 std::cerr << "KateScript::displayBacktrace: no engine, cannot display error\n"; 0061 return; 0062 } 0063 std::cerr << "\033[31m" << qPrintable(backtrace(error, header)) << "\033[0m" << '\n'; 0064 } 0065 0066 void KateScript::clearExceptions() 0067 { 0068 if (!load()) { 0069 return; 0070 } 0071 } 0072 0073 QJSValue KateScript::global(const QString &name) 0074 { 0075 // load the script if necessary 0076 if (!load()) { 0077 return QJSValue::UndefinedValue; 0078 } 0079 return m_engine->globalObject().property(name); 0080 } 0081 0082 QJSValue KateScript::function(const QString &name) 0083 { 0084 QJSValue value = global(name); 0085 if (!value.isCallable()) { 0086 return QJSValue::UndefinedValue; 0087 } 0088 return value; 0089 } 0090 0091 bool KateScript::load() 0092 { 0093 if (m_loaded) { 0094 return m_loadSuccessful; 0095 } 0096 0097 m_loaded = true; 0098 m_loadSuccessful = false; // here set to false, and at end of function to true 0099 0100 // read the script file into memory 0101 QString source; 0102 if (m_inputType == InputURL) { 0103 if (!Kate::Script::readFile(m_url, source)) { 0104 return false; 0105 } 0106 } else { 0107 source = m_script; 0108 } 0109 0110 // create script engine, register meta types 0111 m_engine = new QJSEngine(); 0112 0113 // export read & require function and add the require guard object 0114 auto scriptHelper = new Kate::ScriptHelper(m_engine); 0115 QJSValue functions = m_engine->newQObject(scriptHelper); 0116 m_engine->globalObject().setProperty(QStringLiteral("functions"), functions); 0117 m_engine->globalObject().setProperty(QStringLiteral("read"), functions.property(QStringLiteral("read"))); 0118 m_engine->globalObject().setProperty(QStringLiteral("require"), functions.property(QStringLiteral("require"))); 0119 m_engine->globalObject().setProperty(QStringLiteral("require_guard"), m_engine->newObject()); 0120 0121 // View and Document expose JS Range objects in the API, which will fail to work 0122 // if Range is not included. range.js includes cursor.js 0123 scriptHelper->require(QStringLiteral("range.js")); 0124 0125 // export debug function 0126 m_engine->globalObject().setProperty(QStringLiteral("debug"), functions.property(QStringLiteral("debug"))); 0127 0128 // export translation functions 0129 m_engine->globalObject().setProperty(QStringLiteral("i18n"), functions.property(QStringLiteral("_i18n"))); 0130 m_engine->globalObject().setProperty(QStringLiteral("i18nc"), functions.property(QStringLiteral("_i18nc"))); 0131 m_engine->globalObject().setProperty(QStringLiteral("i18np"), functions.property(QStringLiteral("_i18np"))); 0132 m_engine->globalObject().setProperty(QStringLiteral("i18ncp"), functions.property(QStringLiteral("_i18ncp"))); 0133 0134 // register default styles as ds* global properties 0135 m_engine->globalObject().setProperty(QStringLiteral("dsNormal"), KSyntaxHighlighting::Theme::TextStyle::Normal); 0136 m_engine->globalObject().setProperty(QStringLiteral("dsKeyword"), KSyntaxHighlighting::Theme::TextStyle::Keyword); 0137 m_engine->globalObject().setProperty(QStringLiteral("dsFunction"), KSyntaxHighlighting::Theme::TextStyle::Function); 0138 m_engine->globalObject().setProperty(QStringLiteral("dsVariable"), KSyntaxHighlighting::Theme::TextStyle::Variable); 0139 m_engine->globalObject().setProperty(QStringLiteral("dsControlFlow"), KSyntaxHighlighting::Theme::TextStyle::ControlFlow); 0140 m_engine->globalObject().setProperty(QStringLiteral("dsOperator"), KSyntaxHighlighting::Theme::TextStyle::Operator); 0141 m_engine->globalObject().setProperty(QStringLiteral("dsBuiltIn"), KSyntaxHighlighting::Theme::TextStyle::BuiltIn); 0142 m_engine->globalObject().setProperty(QStringLiteral("dsExtension"), KSyntaxHighlighting::Theme::TextStyle::Extension); 0143 m_engine->globalObject().setProperty(QStringLiteral("dsPreprocessor"), KSyntaxHighlighting::Theme::TextStyle::Preprocessor); 0144 m_engine->globalObject().setProperty(QStringLiteral("dsAttribute"), KSyntaxHighlighting::Theme::TextStyle::Attribute); 0145 m_engine->globalObject().setProperty(QStringLiteral("dsChar"), KSyntaxHighlighting::Theme::TextStyle::Char); 0146 m_engine->globalObject().setProperty(QStringLiteral("dsSpecialChar"), KSyntaxHighlighting::Theme::TextStyle::SpecialChar); 0147 m_engine->globalObject().setProperty(QStringLiteral("dsString"), KSyntaxHighlighting::Theme::TextStyle::String); 0148 m_engine->globalObject().setProperty(QStringLiteral("dsVerbatimString"), KSyntaxHighlighting::Theme::TextStyle::VerbatimString); 0149 m_engine->globalObject().setProperty(QStringLiteral("dsSpecialString"), KSyntaxHighlighting::Theme::TextStyle::SpecialString); 0150 m_engine->globalObject().setProperty(QStringLiteral("dsImport"), KSyntaxHighlighting::Theme::TextStyle::Import); 0151 m_engine->globalObject().setProperty(QStringLiteral("dsDataType"), KSyntaxHighlighting::Theme::TextStyle::DataType); 0152 m_engine->globalObject().setProperty(QStringLiteral("dsDecVal"), KSyntaxHighlighting::Theme::TextStyle::DecVal); 0153 m_engine->globalObject().setProperty(QStringLiteral("dsBaseN"), KSyntaxHighlighting::Theme::TextStyle::BaseN); 0154 m_engine->globalObject().setProperty(QStringLiteral("dsFloat"), KSyntaxHighlighting::Theme::TextStyle::Float); 0155 m_engine->globalObject().setProperty(QStringLiteral("dsConstant"), KSyntaxHighlighting::Theme::TextStyle::Constant); 0156 m_engine->globalObject().setProperty(QStringLiteral("dsComment"), KSyntaxHighlighting::Theme::TextStyle::Comment); 0157 m_engine->globalObject().setProperty(QStringLiteral("dsDocumentation"), KSyntaxHighlighting::Theme::TextStyle::Documentation); 0158 m_engine->globalObject().setProperty(QStringLiteral("dsAnnotation"), KSyntaxHighlighting::Theme::TextStyle::Annotation); 0159 m_engine->globalObject().setProperty(QStringLiteral("dsCommentVar"), KSyntaxHighlighting::Theme::TextStyle::CommentVar); 0160 m_engine->globalObject().setProperty(QStringLiteral("dsRegionMarker"), KSyntaxHighlighting::Theme::TextStyle::RegionMarker); 0161 m_engine->globalObject().setProperty(QStringLiteral("dsInformation"), KSyntaxHighlighting::Theme::TextStyle::Information); 0162 m_engine->globalObject().setProperty(QStringLiteral("dsWarning"), KSyntaxHighlighting::Theme::TextStyle::Warning); 0163 m_engine->globalObject().setProperty(QStringLiteral("dsAlert"), KSyntaxHighlighting::Theme::TextStyle::Alert); 0164 m_engine->globalObject().setProperty(QStringLiteral("dsOthers"), KSyntaxHighlighting::Theme::TextStyle::Others); 0165 m_engine->globalObject().setProperty(QStringLiteral("dsError"), KSyntaxHighlighting::Theme::TextStyle::Error); 0166 0167 // register scripts itself 0168 QJSValue result = m_engine->evaluate(source, m_url); 0169 if (hasException(result, m_url)) { 0170 return false; 0171 } 0172 0173 // AFTER SCRIPT: set the view/document objects as necessary 0174 m_engine->globalObject().setProperty(QStringLiteral("editor"), m_engine->newQObject(m_editor = new KateScriptEditor())); 0175 m_engine->globalObject().setProperty(QStringLiteral("document"), m_engine->newQObject(m_document = new KateScriptDocument(m_engine))); 0176 m_engine->globalObject().setProperty(QStringLiteral("view"), m_engine->newQObject(m_view = new KateScriptView(m_engine))); 0177 0178 // yip yip! 0179 m_loadSuccessful = true; 0180 0181 return true; 0182 } 0183 0184 QJSValue KateScript::evaluate(const QString &program, const FieldMap &env) 0185 { 0186 if (!load()) { 0187 qCWarning(LOG_KTE) << "load of script failed:" << program; 0188 return QJSValue(); 0189 } 0190 0191 // Wrap the arguments in a function to avoid polluting the global object 0192 QString programWithContext = 0193 QLatin1String("(function(") + QStringList(env.keys()).join(QLatin1Char(',')) + QLatin1String(") { return ") + program + QLatin1String("})"); 0194 QJSValue programFunction = m_engine->evaluate(programWithContext); 0195 Q_ASSERT(programFunction.isCallable()); 0196 0197 QJSValueList args; 0198 args.reserve(env.size()); 0199 for (auto it = env.begin(); it != env.end(); it++) { 0200 args << it.value(); 0201 } 0202 0203 QJSValue result = programFunction.call(args); 0204 if (result.isError()) { 0205 qCWarning(LOG_KTE) << "Error evaluating script: " << result.toString(); 0206 } 0207 0208 return result; 0209 } 0210 0211 bool KateScript::hasException(const QJSValue &object, const QString &file) 0212 { 0213 if (object.isError()) { 0214 m_errorMessage = i18n("Error loading script %1", file); 0215 displayBacktrace(object, m_errorMessage); 0216 delete m_engine; 0217 m_engine = nullptr; 0218 m_loadSuccessful = false; 0219 return true; 0220 } 0221 return false; 0222 } 0223 0224 bool KateScript::setView(KTextEditor::ViewPrivate *view) 0225 { 0226 if (!load()) { 0227 return false; 0228 } 0229 // setup the stuff 0230 m_document->setDocument(view->doc()); 0231 m_view->setView(view); 0232 return true; 0233 } 0234 0235 void KateScript::setGeneralHeader(const KateScriptHeader &generalHeader) 0236 { 0237 m_generalHeader = generalHeader; 0238 } 0239 0240 KateScriptHeader &KateScript::generalHeader() 0241 { 0242 return m_generalHeader; 0243 }