fix: 更好的代码填充和一些 Bug 修复;

This commit is contained in:
寂静的羽夏 2025-04-27 11:31:15 +08:00
parent 2ee3051a7d
commit cf3d4da8e8
24 changed files with 1811 additions and 1657 deletions

View File

@ -109,6 +109,15 @@ QString QConsoleWidget::getCommandLine() {
return code; return code;
} }
void QConsoleWidget::paste() {
QTextCursor textCursor = this->textCursor();
const QMimeData *const clipboard = QApplication::clipboard()->mimeData();
const QString text = clipboard->text();
if (!text.isNull()) {
textCursor.insertText(text, channelCharFormat(StandardInput));
}
}
void QConsoleWidget::handleReturnKey() { void QConsoleWidget::handleReturnKey() {
QString code = getCommandLine(); QString code = getCommandLine();
@ -189,12 +198,7 @@ void QConsoleWidget::keyPressEvent(QKeyEvent *e) {
// Allow paste only if the selection is in the interactive area ... // Allow paste only if the selection is in the interactive area ...
if (e->key() == Qt::Key_V && e->modifiers() == Qt::ControlModifier) { if (e->key() == Qt::Key_V && e->modifiers() == Qt::ControlModifier) {
if (selectionInEditZone || isCursorInEditZone()) { if (selectionInEditZone || isCursorInEditZone()) {
const QMimeData *const clipboard = paste();
QApplication::clipboard()->mimeData();
const QString text = clipboard->text();
if (!text.isNull()) {
textCursor.insertText(text, channelCharFormat(StandardInput));
}
} }
e->accept(); e->accept();

View File

@ -77,6 +77,8 @@ public:
// get the current command line // get the current command line
QString getCommandLine(); QString getCommandLine();
virtual void paste();
public slots: public slots:
// write to StandardOutput // write to StandardOutput
@ -94,6 +96,7 @@ signals:
protected: protected:
bool canPaste() const; bool canPaste() const;
bool canCut() const; bool canCut() const;
virtual void handleReturnKey(); virtual void handleReturnKey();
virtual void handleTabKey(); virtual void handleTabKey();
// reimp QPlainTextEdit functions // reimp QPlainTextEdit functions

View File

@ -253,8 +253,6 @@ set(CLASS_SRC
src/class/ascompletion.h src/class/ascompletion.h
src/class/asbuilder.h src/class/asbuilder.h
src/class/asbuilder.cpp src/class/asbuilder.cpp
src/class/ascontextmgr.h
src/class/ascontextmgr.cpp
src/class/clangformatmanager.h src/class/clangformatmanager.h
src/class/clangformatmanager.cpp src/class/clangformatmanager.cpp
src/class/aspreprocesser.h src/class/aspreprocesser.h

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,8 @@ AppManager::AppManager(int &argc, char *argv[])
: QtSingleApplication(argc, argv) { : QtSingleApplication(argc, argv) {
ASSERT_SINGLETON; ASSERT_SINGLETON;
_instance = this;
LanguageManager::instance(); LanguageManager::instance();
InspectQtLogHelper::instance().init(); InspectQtLogHelper::instance().init();
CrashHandler::instance().init(); CrashHandler::instance().init();
@ -102,6 +104,8 @@ AppManager::AppManager(int &argc, char *argv[])
his.add(cmd); his.add(cmd);
} }
_timer.start();
_w = new MainWindow(splash); _w = new MainWindow(splash);
setActivationWindow(_w); setActivationWindow(_w);
@ -133,7 +137,6 @@ AppManager::AppManager(int &argc, char *argv[])
connect(_w, &MainWindow::closed, this, connect(_w, &MainWindow::closed, this,
[]() { AppManager::instance()->exit(); }); []() { AppManager::instance()->exit(); });
_instance = this;
if (splash) if (splash)
splash->close(); splash->close();
@ -152,6 +155,8 @@ AppManager *AppManager::instance() { return _instance; }
MainWindow *AppManager::mainWindow() const { return _w; } MainWindow *AppManager::mainWindow() const { return _w; }
uint AppManager::currentMSecsSinceEpoch() { return _timer.elapsed(); }
void AppManager::openFile(const QString &file, bool autoDetect) { void AppManager::openFile(const QString &file, bool autoDetect) {
EditorView *editor = nullptr; EditorView *editor = nullptr;
Q_ASSERT(_w); Q_ASSERT(_w);

View File

@ -21,6 +21,8 @@
#include "dialog/mainwindow.h" #include "dialog/mainwindow.h"
#include "qtsingleapplication/src/qtsingleapplication.h" #include "qtsingleapplication/src/qtsingleapplication.h"
#include <QElapsedTimer>
class AppManager : public QtSingleApplication { class AppManager : public QtSingleApplication {
Q_OBJECT Q_OBJECT
public: public:
@ -36,6 +38,8 @@ public:
QApplication::tr("WingCloudStudio"); QApplication::tr("WingCloudStudio");
} }
uint currentMSecsSinceEpoch();
public slots: public slots:
void openFile(const QString &file, bool autoDetect = true); void openFile(const QString &file, bool autoDetect = true);
void openRawFile(const QString &file); void openRawFile(const QString &file);
@ -43,6 +47,8 @@ public slots:
private: private:
MainWindow *_w = nullptr; MainWindow *_w = nullptr;
QElapsedTimer _timer;
static AppManager *_instance; static AppManager *_instance;
}; };

View File

@ -25,6 +25,7 @@
#include "wingcodeedit.h" #include "wingcodeedit.h"
#include <QAbstractItemView> #include <QAbstractItemView>
#include <QApplication>
#include <QByteArray> #include <QByteArray>
#include <QDir> #include <QDir>
#include <QEvent> #include <QEvent>
@ -41,8 +42,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, LEFT_PARE_TRIGGER, ("("))
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, SEMI_COLON_TRIGGER, (";")) Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, SEMI_COLON_TRIGGER, (";"))
AsCompletion::AsCompletion(WingCodeEdit *p) AsCompletion::AsCompletion(WingCodeEdit *p)
: WingCompleter(p), parser(ScriptMachine::instance().engine()), : WingCompleter(p), parser(ScriptMachine::instance().engine()) {
m_parseDocument(true) {
setTriggerList({*DOT_TRIGGER, *DBL_COLON_TRIGGER, setTriggerList({*DOT_TRIGGER, *DBL_COLON_TRIGGER,
// unleash the power of call tips // unleash the power of call tips
*LEFT_PARE_TRIGGER, *LEFT_PARE_TRIGGER,
@ -126,10 +126,43 @@ void AsCompletion::applyClassNodes(QList<CodeInfoTip> &nodes) {
nodes = clsNodes; nodes = clsNodes;
} }
bool AsCompletion::parseDocument() const { return m_parseDocument; } int AsCompletion::includeCallBack(const QString &include, bool quotedInclude,
const QString &from, AsPreprocesser *builder,
void *userParam) {
Q_UNUSED(userParam);
void AsCompletion::setParseDocument(bool newParseDocument) { QFileInfo info(include);
m_parseDocument = newParseDocument; bool isAbsolute = info.isAbsolute();
bool hasNoExt = info.suffix().isEmpty();
QString inc;
if (quotedInclude) {
if (isAbsolute) {
inc = include;
} else {
auto pwd = QFileInfo(from).absoluteDir();
inc = pwd.absoluteFilePath(include);
}
} else {
// absolute include is not allowed in #include<>
if (isAbsolute) {
// ignored in code completion
return asSUCCESS;
}
QDir dir(qApp->applicationDirPath());
if (!dir.cd(QStringLiteral("aslib"))) {
// someone crash the software, ignored
return asSUCCESS;
}
inc = dir.absoluteFilePath(include);
}
if (hasNoExt) {
inc += QStringLiteral(".as");
}
builder->loadSectionFromFile(inc);
return asSUCCESS;
} }
void AsCompletion::clearFunctionTip() { emit onFunctionTip({}); } void AsCompletion::clearFunctionTip() { emit onFunctionTip({}); }
@ -235,10 +268,7 @@ bool AsCompletion::processTrigger(const QString &trigger,
return true; return true;
} }
QList<CodeInfoTip> docNodes; QList<CodeInfoTip> docNodes = parseDocument();
if (m_parseDocument) {
docNodes = parseDocument();
}
// if trigger is empty, it's making editing // if trigger is empty, it's making editing
if (trigger.isEmpty()) { if (trigger.isEmpty()) {
@ -383,8 +413,7 @@ QList<CodeInfoTip> AsCompletion::parseDocument() {
// first preprocess the code // first preprocess the code
AsPreprocesser prepc(engine); AsPreprocesser prepc(engine);
// TODO: set include callback prepc.setIncludeCallback(&AsCompletion::includeCallBack, this);
// prepc.setIncludeCallback();
auto r = prepc.loadSectionFromMemory(QStringLiteral("ASCOMPLETION"), auto r = prepc.loadSectionFromMemory(QStringLiteral("ASCOMPLETION"),
code.toUtf8()); code.toUtf8());
@ -396,99 +425,109 @@ QList<CodeInfoTip> AsCompletion::parseDocument() {
QList<CodeInfoTip> ret; QList<CodeInfoTip> ret;
for (auto &d : data) { for (auto &d : data) {
QAsCodeParser parser(engine); qsizetype offset = -1;
auto syms = if (d.section == QStringLiteral("ASCOMPLETION")) {
parser.parseAndIntell(editor->textCursor().position(), d.script); offset = editor->textCursor().position();
for (auto &sym : syms) {
CodeInfoTip tip;
tip.name = sym.name;
tip.nameSpace = QString::fromUtf8(sym.scope.join("::"));
switch (sym.symtype) {
case QAsCodeParser::SymbolType::Function:
case QAsCodeParser::SymbolType::FnDef:
tip.type = CodeInfoTip::Type::Function;
tip.addinfo.insert(CodeInfoTip::RetType,
QString::fromUtf8(sym.type));
tip.addinfo.insert(CodeInfoTip::Args,
QString::fromUtf8(sym.additonalInfo));
for (auto &var : sym.children) {
CodeInfoTip va;
va.dontAddGlobal = true;
va.name = var.name;
va.nameSpace = QString::fromUtf8(var.scope.join("::"));
va.addinfo.insert(CodeInfoTip::RetType, var.type);
va.type = CodeInfoTip::Type::Variable;
ret.append(va);
}
break;
case QAsCodeParser::SymbolType::Enum:
tip.type = CodeInfoTip::Type::Enum;
for (auto &e : sym.children) {
CodeInfoTip en;
en.dontAddGlobal = true;
en.name = e.name;
en.nameSpace = QString::fromUtf8(e.scope.join("::"));
en.type = CodeInfoTip::Type::Enumerater;
if (!e.additonalInfo.isEmpty()) {
en.addinfo.insert(CodeInfoTip::Comment,
en.name + QStringLiteral(" = ") +
e.additonalInfo);
}
ret.append(en);
}
break;
case QAsCodeParser::SymbolType::TypeDef:
tip.type = CodeInfoTip::Type::TypeDef;
break;
case QAsCodeParser::SymbolType::Variable:
tip.addinfo.insert(CodeInfoTip::RetType, sym.type);
tip.type = CodeInfoTip::Type::Variable;
break;
case QAsCodeParser::SymbolType::Class:
case QAsCodeParser::SymbolType::Interface:
for (auto &mem : sym.children) {
if (mem.vis != QAsCodeParser::Visiblity::Public) {
continue;
}
CodeInfoTip ctip;
ctip.name = mem.name;
ctip.nameSpace = QString::fromUtf8(mem.scope.join("::"));
if (mem.symtype == QAsCodeParser::SymbolType::Function) {
ctip.type = CodeInfoTip::Type::Function;
ctip.addinfo.insert(CodeInfoTip::RetType,
QString::fromUtf8(mem.type));
ctip.addinfo.insert(
CodeInfoTip::Args,
QString::fromUtf8(mem.additonalInfo));
for (auto &var : mem.children) {
CodeInfoTip va;
va.dontAddGlobal = true;
va.name = var.name;
va.nameSpace =
QString::fromUtf8(var.scope.join("::"));
va.addinfo.insert(CodeInfoTip::RetType, var.type);
va.type = CodeInfoTip::Type::Variable;
tip.children.append(va);
}
tip.children.append(ctip);
} else if (mem.symtype ==
QAsCodeParser::SymbolType::Variable) {
ctip.addinfo.insert(CodeInfoTip::RetType, mem.type);
ctip.type = CodeInfoTip::Type::Variable;
tip.children.append(ctip);
}
}
tip.type = CodeInfoTip::Type::Class;
break;
case QAsCodeParser::SymbolType::Invalid:
case QAsCodeParser::SymbolType::Import:
continue;
}
ret.append(tip);
} }
ret.append(parseScriptData(offset, d.script));
}
return ret;
}
QList<CodeInfoTip> AsCompletion::parseScriptData(qsizetype offset,
const QByteArray &code) {
QList<CodeInfoTip> ret;
auto engine = ScriptMachine::instance().engine();
QAsCodeParser parser(engine);
auto syms = parser.parseAndIntell(offset, code);
for (auto &sym : syms) {
CodeInfoTip tip;
tip.name = sym.name;
tip.nameSpace = QString::fromUtf8(sym.scope.join("::"));
switch (sym.symtype) {
case QAsCodeParser::SymbolType::Function:
case QAsCodeParser::SymbolType::FnDef:
tip.type = CodeInfoTip::Type::Function;
tip.addinfo.insert(CodeInfoTip::RetType,
QString::fromUtf8(sym.type));
tip.addinfo.insert(CodeInfoTip::Args,
QString::fromUtf8(sym.additonalInfo));
for (auto &var : sym.children) {
CodeInfoTip va;
va.dontAddGlobal = true;
va.name = var.name;
va.nameSpace = QString::fromUtf8(var.scope.join("::"));
va.addinfo.insert(CodeInfoTip::RetType, var.type);
va.type = CodeInfoTip::Type::Variable;
ret.append(va);
}
break;
case QAsCodeParser::SymbolType::Enum:
tip.type = CodeInfoTip::Type::Enum;
for (auto &e : sym.children) {
CodeInfoTip en;
en.dontAddGlobal = true;
en.name = e.name;
en.nameSpace = QString::fromUtf8(e.scope.join("::"));
en.type = CodeInfoTip::Type::Enumerater;
if (!e.additonalInfo.isEmpty()) {
en.addinfo.insert(CodeInfoTip::Comment,
en.name + QStringLiteral(" = ") +
e.additonalInfo);
}
ret.append(en);
}
break;
case QAsCodeParser::SymbolType::TypeDef:
tip.type = CodeInfoTip::Type::TypeDef;
break;
case QAsCodeParser::SymbolType::Variable:
tip.addinfo.insert(CodeInfoTip::RetType, sym.type);
tip.type = CodeInfoTip::Type::Variable;
break;
case QAsCodeParser::SymbolType::Class:
case QAsCodeParser::SymbolType::Interface:
for (auto &mem : sym.children) {
if (mem.vis != QAsCodeParser::Visiblity::Public) {
continue;
}
CodeInfoTip ctip;
ctip.name = mem.name;
ctip.nameSpace = QString::fromUtf8(mem.scope.join("::"));
if (mem.symtype == QAsCodeParser::SymbolType::Function) {
ctip.type = CodeInfoTip::Type::Function;
ctip.addinfo.insert(CodeInfoTip::RetType,
QString::fromUtf8(mem.type));
ctip.addinfo.insert(CodeInfoTip::Args,
QString::fromUtf8(mem.additonalInfo));
for (auto &var : mem.children) {
CodeInfoTip va;
va.dontAddGlobal = true;
va.name = var.name;
va.nameSpace = QString::fromUtf8(var.scope.join("::"));
va.addinfo.insert(CodeInfoTip::RetType, var.type);
va.type = CodeInfoTip::Type::Variable;
tip.children.append(va);
}
tip.children.append(ctip);
} else if (mem.symtype == QAsCodeParser::SymbolType::Variable) {
ctip.addinfo.insert(CodeInfoTip::RetType, mem.type);
ctip.type = CodeInfoTip::Type::Variable;
tip.children.append(ctip);
}
}
tip.type = CodeInfoTip::Type::Class;
break;
case QAsCodeParser::SymbolType::Invalid:
case QAsCodeParser::SymbolType::Import:
continue;
}
ret.append(tip);
} }
return ret; return ret;

View File

@ -21,6 +21,8 @@
#include "WingCodeEdit/wingcompleter.h" #include "WingCodeEdit/wingcompleter.h"
#include "class/asdatabase.h" #include "class/asdatabase.h"
class AsPreprocesser;
class AsCompletion : public WingCompleter { class AsCompletion : public WingCompleter {
Q_OBJECT Q_OBJECT
public: public:
@ -32,9 +34,6 @@ public:
public: public:
virtual QString wordSeperators() const override; virtual QString wordSeperators() const override;
bool parseDocument() const;
void setParseDocument(bool newParseDocument);
void clearFunctionTip(); void clearFunctionTip();
protected: protected:
@ -43,6 +42,9 @@ protected:
virtual QList<CodeInfoTip> parseDocument(); virtual QList<CodeInfoTip> parseDocument();
QList<CodeInfoTip> parseScriptData(qsizetype offset,
const QByteArray &code);
signals: signals:
void onFunctionTip(const QString &content); void onFunctionTip(const QString &content);
@ -55,9 +57,13 @@ private:
const QList<CodeInfoTip> &docNodes); const QList<CodeInfoTip> &docNodes);
void applyClassNodes(QList<CodeInfoTip> &nodes); void applyClassNodes(QList<CodeInfoTip> &nodes);
private:
static int includeCallBack(const QString &include, bool quotedInclude,
const QString &from, AsPreprocesser *builder,
void *userParam);
private: private:
ASDataBase parser; ASDataBase parser;
bool m_parseDocument;
}; };
#endif // _CPP_COMPLETION_H_ #endif // _CPP_COMPLETION_H_

View File

@ -17,9 +17,46 @@
#include "asconsolecompletion.h" #include "asconsolecompletion.h"
#include "class/qascodeparser.h"
#include "control/scriptingconsole.h" #include "control/scriptingconsole.h"
AsConsoleCompletion::AsConsoleCompletion(ScriptingConsole *p) AsConsoleCompletion::AsConsoleCompletion(ScriptingConsole *p)
: AsCompletion(p), _console(p) { : AsCompletion(p), _console(p) {}
setParseDocument(false);
QList<CodeInfoTip> AsConsoleCompletion::parseDocument() {
auto editor = _console;
if (editor == nullptr) {
return {};
}
auto code = editor->currentCodes();
auto engine = ScriptMachine::instance().engine();
QAsCodeParser parser(engine);
auto seg = parser.parse(code.toUtf8());
if (std::find_if(seg.begin(), seg.end(),
[](const QAsCodeParser::CodeSegment &seg) {
return seg.isValid();
}) == seg.end()) {
// wrap it to let code-completion work
code.prepend("void main(){").append('}');
}
// first preprocess the code
AsPreprocesser prepc(engine);
// including is not supported in console
auto r = prepc.loadSectionFromMemory(QStringLiteral("ASConCOMPLETION"),
code.toUtf8());
if (r <= 0) {
return {};
}
auto data = prepc.scriptData();
if (data.size() == 1) {
auto d = data[0];
return parseScriptData(d.script.length() - 1, d.script);
} else {
return {};
}
} }

View File

@ -28,6 +28,9 @@ public:
explicit AsConsoleCompletion(ScriptingConsole *p); explicit AsConsoleCompletion(ScriptingConsole *p);
virtual ~AsConsoleCompletion() = default; virtual ~AsConsoleCompletion() = default;
protected:
virtual QList<CodeInfoTip> parseDocument();
private: private:
ScriptingConsole *_console; ScriptingConsole *_console;
}; };

View File

@ -1,41 +0,0 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** 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 Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#include "ascontextmgr.h"
// copy from base class
struct SContextInfo {
asUINT sleepUntil;
std::vector<asIScriptContext *> coRoutines;
asUINT currentCoRoutine;
asIScriptContext *keepCtxAfterExecution;
};
asContextMgr::asContextMgr() : CContextMgr() {}
bool asContextMgr::findThreadWithUserData(asPWORD index, void *data) const {
for (auto &th : m_threads) {
auto ctx = th->keepCtxAfterExecution;
if (ctx) {
auto user = ctx->GetUserData(index);
if (user == data) {
return true;
}
}
}
return false;
}

View File

@ -1,30 +0,0 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** 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 Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#ifndef ASCONTEXTMGR_H
#define ASCONTEXTMGR_H
#include "AngelScript/sdk/add_on/contextmgr/contextmgr.h"
class asContextMgr : public CContextMgr {
public:
asContextMgr();
bool findThreadWithUserData(asPWORD index, void *data) const;
};
#endif // ASCONTEXTMGR_H

View File

@ -71,6 +71,9 @@ void asDebugger::takeCommands(asIScriptContext *ctx) {
void asDebugger::lineCallback(asIScriptContext *ctx) { void asDebugger::lineCallback(asIScriptContext *ctx) {
Q_ASSERT(ctx); Q_ASSERT(ctx);
// prevent UI freezing
qApp->processEvents();
// This should never happen, but it doesn't hurt to validate it // This should never happen, but it doesn't hurt to validate it
if (ctx == nullptr) if (ctx == nullptr)
return; return;

View File

@ -456,7 +456,7 @@ void CTypeParser::stripComments(QStringList &lines) const {
QStringLiteral("]"); QStringLiteral("]");
// search comment start // search comment start
while ((pos = line.indexOf(kSlash, pos)) != -1) { while ((pos = line.indexOf(char(kSlash), pos)) != -1) {
if (line.length() <= pos + 1) if (line.length() <= pos + 1)
break; // the 1st '/' is at the end of line, so not a comment break; // the 1st '/' is at the end of line, so not a comment
@ -1070,7 +1070,7 @@ bool CTypeParser::parseDeclaration(const QString &line,
if (line.isEmpty()) { if (line.isEmpty()) {
return false; return false;
} }
if (line[line.length() - 1] != kSemicolon) if (line[line.length() - 1] != char(kSemicolon))
return false; return false;
QStringList tokens; QStringList tokens;
@ -1090,7 +1090,7 @@ bool CTypeParser::parseDeclaration(const QString &line,
return false; return false;
} }
if (tokens[++index].at(0) == kAsterisk) { if (tokens[++index].at(0) == char(kAsterisk)) {
decl.is_pointer = true; decl.is_pointer = true;
// size of a pointer is 4 types on a 32-bit system // size of a pointer is 4 types on a 32-bit system
length = length =
@ -1148,14 +1148,14 @@ bool CTypeParser::parseEnumDeclaration(const QString &line, int &last_value,
break; break;
case 2: case 2:
if (kComma != tokens[1].at(0)) { if (char(kComma) != tokens[1].at(0)) {
return false; return false;
} }
decl.second = ++last_value; decl.second = ++last_value;
break; break;
case 3: case 3:
if (kEqual != tokens[1].at(0)) { if (char(kEqual) != tokens[1].at(0)) {
return false; return false;
} }
@ -1171,7 +1171,8 @@ bool CTypeParser::parseEnumDeclaration(const QString &line, int &last_value,
break; break;
case 4: case 4:
if (!(kEqual == tokens[1].at(0) && kComma == tokens[3].at(0))) { if (!(char(kEqual) == tokens[1].at(0) &&
char(kComma) == tokens[3].at(0))) {
return false; return false;
} }
@ -1208,8 +1209,8 @@ bool CTypeParser::parseAssignExpression(const QString &line) {
// only 4 tokens for an assignment expression: var = number; // only 4 tokens for an assignment expression: var = number;
if (4 == splitLineIntoTokens(line, tokens) && if (4 == splitLineIntoTokens(line, tokens) &&
kEqual == tokens[1].at(tokens[1].length() - 1) && char(kEqual) == tokens[1].at(tokens[1].length() - 1) &&
kSemicolon == tokens[3].at(tokens[3].length() - 1) && char(kSemicolon) == tokens[3].at(tokens[3].length() - 1) &&
isNumericToken(tokens[2], number)) { isNumericToken(tokens[2], number)) {
const_defs_.insert(tokens[0], number); const_defs_.insert(tokens[0], number);
return true; return true;
@ -1244,7 +1245,7 @@ bool CTypeParser::parsePreProcDirective(const QString &src, qsizetype &pos) {
} }
// only handle header file included with "" // only handle header file included with ""
if (kQuotation == token[token.length() - 1]) { if (char(kQuotation) == token[token.length() - 1]) {
// get included header file name // get included header file name
if (!getNextToken(src, pos, token, false)) { if (!getNextToken(src, pos, token, false)) {
return false; return false;
@ -1371,7 +1372,7 @@ bool CTypeParser::parseStructUnion(const bool is_struct, const bool is_typedef,
if (is_typedef) { if (is_typedef) {
// format 1 // format 1
if (!(getNextToken(src, pos, next_token) && if (!(getNextToken(src, pos, next_token) &&
kSemicolon == next_token.at(0))) { char(kSemicolon) == next_token.at(0))) {
return false; return false;
} }
@ -1392,7 +1393,7 @@ bool CTypeParser::parseStructUnion(const bool is_struct, const bool is_typedef,
type_maps_[type_name] = type_maps_[type_alias]; type_maps_[type_name] = type_maps_[type_alias];
} }
} else { // non-typedef } else { // non-typedef
if (kSemicolon == token.at(0)) { if (char(kSemicolon) == token.at(0)) {
// format 2 // format 2
is_decl = false; is_decl = false;
if (type_name.isEmpty()) { if (type_name.isEmpty()) {
@ -1547,7 +1548,7 @@ bool CTypeParser::parseEnum(const bool is_typedef, const QString &src,
if (is_typedef) { if (is_typedef) {
// format 1 // format 1
if (!(getNextToken(src, pos, next_token) && if (!(getNextToken(src, pos, next_token) &&
kSemicolon == next_token.at(0))) { char(kSemicolon) == next_token.at(0))) {
return false; return false;
} }
@ -1564,7 +1565,7 @@ bool CTypeParser::parseEnum(const bool is_typedef, const QString &src,
; ;
} }
} else { // non-typedef } else { // non-typedef
if (kSemicolon == token.at(0)) { if (char(kSemicolon) == token.at(0)) {
// format 2 // format 2
is_decl = false; is_decl = false;
if (type_name.isEmpty()) { if (type_name.isEmpty()) {

View File

@ -1194,7 +1194,7 @@ QList<QAsCodeParser::CodeSegment> QAsCodeParser::parseScript(bool inBlock) {
seg.offset = begin; seg.offset = begin;
seg.scope = currentNs; seg.scope = currentNs;
seg.type = SymbolType::Variable; seg.type = SymbolType::Variable;
seg.codes = _code.sliced(begin, end - begin + 1); seg.codes = _code.sliced(begin, end - begin);
rewindTo(&t1); rewindTo(&t1);
segs.append(seg); segs.append(seg);

View File

@ -29,6 +29,7 @@
#include "AngelScript/sdk/add_on/weakref/weakref.h" #include "AngelScript/sdk/add_on/weakref/weakref.h"
#include "angelobjstring.h" #include "angelobjstring.h"
#include "class/appmanager.h"
#include "class/asbuilder.h" #include "class/asbuilder.h"
#include "class/pluginsystem.h" #include "class/pluginsystem.h"
#include "class/qascodeparser.h" #include "class/qascodeparser.h"
@ -42,13 +43,7 @@
#include <QProcess> #include <QProcess>
#include <QScopeGuard> #include <QScopeGuard>
ScriptMachine::~ScriptMachine() { ScriptMachine::~ScriptMachine() { destoryMachine(); }
if (_ctxMgr) {
delete _ctxMgr;
}
destoryMachine();
}
bool ScriptMachine::init() { bool ScriptMachine::init() {
if (isInited()) { if (isInited()) {
@ -74,9 +69,7 @@ bool ScriptMachine::init() {
bool ScriptMachine::isInited() const { return _engine != nullptr; } bool ScriptMachine::isInited() const { return _engine != nullptr; }
bool ScriptMachine::isRunning(ConsoleMode mode) const { bool ScriptMachine::isRunning(ConsoleMode mode) const {
return _ctxMgr->findThreadWithUserData( return _ctx.value(mode) != nullptr;
AsUserDataType::UserData_ContextMode,
reinterpret_cast<void *>(asPWORD(mode)));
} }
bool ScriptMachine::configureEngine() { bool ScriptMachine::configureEngine() {
@ -171,9 +164,12 @@ bool ScriptMachine::configureEngine() {
return false; return false;
} }
// Setup the context manager and register the support for co-routines _ctxMgr = new CContextMgr;
_ctxMgr = new asContextMgr();
_ctxMgr->RegisterCoRoutineSupport(_engine); _ctxMgr->RegisterCoRoutineSupport(_engine);
_ctxMgr->SetGetTimeCallback([]() -> asUINT {
return AppManager::instance()->currentMSecsSinceEpoch();
});
_ctxMgr->RegisterThreadSupport(_engine);
// Tell the engine to use our context pool. This will also // Tell the engine to use our context pool. This will also
// allow us to debug internal script calls made by the engine // allow us to debug internal script calls made by the engine
@ -227,6 +223,9 @@ QString ScriptMachine::getCallStack(asIScriptContext *context) {
} }
void ScriptMachine::destoryMachine() { void ScriptMachine::destoryMachine() {
_ctxMgr->AbortAll();
delete _ctxMgr;
_debugger->setEngine(nullptr); _debugger->setEngine(nullptr);
_engine->ShutDownAndRelease(); _engine->ShutDownAndRelease();
_engine = nullptr; _engine = nullptr;
@ -389,9 +388,10 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
outputMessage(mode, info); outputMessage(mode, info);
} }
// Once we have the main function, we first need to initialize the global // Once we have the main function, we first need to initialize the
// variables Since we've set up the request context callback we will be able // global variables Since we've set up the request context callback we
// to debug the initialization without passing in a pre-created context // will be able to debug the initialization without passing in a
// pre-created context
r = mod->ResetGlobalVars(0); r = mod->ResetGlobalVars(0);
if (r < 0) { if (r < 0) {
MessageInfo info; MessageInfo info;
@ -405,9 +405,11 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
// The context manager will request the context from the // The context manager will request the context from the
// pool, which will automatically attach the debugger // pool, which will automatically attach the debugger
asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true); asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true);
_ctx[mode] = ctx;
ctx->SetUserData(reinterpret_cast<void *>(isDbg), ctx->SetUserData(reinterpret_cast<void *>(isDbg),
AsUserDataType::UserData_isDbg); AsUserDataType::UserData_isDbg);
mod->SetUserData(reinterpret_cast<void *>(isDbg), mod->SetUserData(reinterpret_cast<void *>(isDbg),
AsUserDataType::UserData_isDbg); AsUserDataType::UserData_isDbg);
@ -421,8 +423,11 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
// Execute the script until completion // Execute the script until completion
// The script may create co-routines. These will automatically // The script may create co-routines. These will automatically
// be managed by the context manager // be managed by the context manager
while (_ctxMgr->ExecuteScripts()) while (_ctxMgr->ExecuteScripts()) {
; qApp->processEvents();
}
_ctx[mode] = nullptr;
// Check if the main script finished normally // Check if the main script finished normally
r = ctx->GetState(); r = ctx->GetState();
@ -479,13 +484,24 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
return r >= 0; return r >= 0;
} }
void ScriptMachine::abortDbgScript(ConsoleMode mode) { void ScriptMachine::abortDbgScript() {
if (_debugger->getEngine()) { if (_debugger->getEngine()) {
_debugger->runDebugAction(asDebugger::ABORT); _debugger->runDebugAction(asDebugger::ABORT);
} }
} }
void ScriptMachine::abortScript() { _ctxMgr->AbortAll(); } void ScriptMachine::abortScript(ConsoleMode mode) {
auto ctx = _ctx.value(mode, nullptr);
if (ctx) {
ctx->Abort();
}
}
void ScriptMachine::abortScript() {
abortScript(ConsoleMode::Interactive);
abortScript(ConsoleMode::Scripting);
abortScript(ConsoleMode::Background);
}
void ScriptMachine::messageCallback(const asSMessageInfo *msg, void *param) { void ScriptMachine::messageCallback(const asSMessageInfo *msg, void *param) {
MessageType t = MessageType::Print; MessageType t = MessageType::Print;
@ -1805,16 +1821,6 @@ asDebugger *ScriptMachine::debugger() const { return _debugger; }
bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) { bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
asIScriptModule *mod = createModuleIfNotExist(mode); asIScriptModule *mod = createModuleIfNotExist(mode);
QScopeGuard guard([mod, mode]() {
if (mode != ConsoleMode::Interactive) {
// Before leaving, allow the engine to clean up remaining objects by
// discarding the module and doing a full garbage collection so that
// this can also be debugged if desired
mod->Discard();
}
});
_engine->SetEngineProperty(asEP_BUILD_WITHOUT_LINE_CUES, false); _engine->SetEngineProperty(asEP_BUILD_WITHOUT_LINE_CUES, false);
// first, preparse the code // first, preparse the code
@ -1824,28 +1830,30 @@ bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
asIScriptFunction *func = nullptr; asIScriptFunction *func = nullptr;
auto ret = parser.parse(ccode); auto ret = parser.parse(ccode);
// check whether there is any enum/class // check whether there is any enum/class
if (std::find_if(ret.begin(), ret.end(), if (std::find_if(ret.begin(), ret.end(),
[](const QAsCodeParser::CodeSegment &seg) { [](const QAsCodeParser::CodeSegment &seg) {
return seg.isValid(); switch (seg.type) {
}) == ret.end()) { case QAsCodeParser::SymbolType::Enum:
case QAsCodeParser::SymbolType::Class:
case QAsCodeParser::SymbolType::Function:
case QAsCodeParser::SymbolType::Interface:
case QAsCodeParser::SymbolType::Import:
case QAsCodeParser::SymbolType::Variable:
return false;
case QAsCodeParser::SymbolType::Invalid:
case QAsCodeParser::SymbolType::TypeDef:
case QAsCodeParser::SymbolType::FnDef:
return true;
}
return true;
}) != ret.end()) {
// ok, wrap the codes // ok, wrap the codes
ccode.prepend("void main(){").append("}"); ccode.prepend("void f(){").append("}");
// start to compile // start to compile
auto r = mod->CompileFunction(nullptr, ccode, -1, 0, &func); auto cr = mod->CompileFunction(nullptr, ccode, 0, 0, &func);
if (r < 0) { if (cr < 0) {
MessageInfo info;
info.mode = mode;
info.message = tr("Script failed to build");
info.type = MessageType::Error;
outputMessage(mode, info);
return false;
}
} else {
mod->AddScriptSection("Runner", ccode, ccode.size(), 0);
auto r = mod->Build();
if (r < 0) {
MessageInfo info; MessageInfo info;
info.mode = mode; info.mode = mode;
info.message = tr("Script failed to build"); info.message = tr("Script failed to build");
@ -1854,85 +1862,98 @@ bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
return false; return false;
} }
// Find the main function // Set up a context to execute the script
func = mod->GetFunctionByDecl("void main()"); // The context manager will request the context from the
if (func == nullptr) { // pool, which will automatically attach the debugger
// Try again with "int main()" asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true);
func = mod->GetFunctionByDecl("int main()"); _ctx[mode] = ctx;
asPWORD isDbg = 0;
ctx->SetUserData(reinterpret_cast<void *>(isDbg),
AsUserDataType::UserData_isDbg);
mod->SetUserData(reinterpret_cast<void *>(isDbg),
AsUserDataType::UserData_isDbg);
asPWORD umode = asPWORD(mode);
ctx->SetUserData(reinterpret_cast<void *>(umode),
AsUserDataType::UserData_ContextMode);
ctx->SetExceptionCallback(asMETHOD(ScriptMachine, exceptionCallback),
this, asCALL_THISCALL);
// Execute the script until completion
// The script may create co-routines. These will automatically
// be managed by the context manager
while (_ctxMgr->ExecuteScripts()) {
qApp->processEvents();
} }
if (func == nullptr) { _ctx[mode] = nullptr;
MessageInfo info;
info.mode = mode;
info.message = tr("Cannot find 'int main()' or 'void main()'");
info.type = MessageType::Error;
outputMessage(mode, info);
return false;
}
}
// Set up a context to execute the script // Check if the main script finished normally
// The context manager will request the context from the int r = ctx->GetState();
// pool, which will automatically attach the debugger if (r != asEXECUTION_FINISHED) {
asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true); if (r == asEXECUTION_EXCEPTION) {
MessageInfo info;
asPWORD isDbg = 0; info.mode = mode;
ctx->SetUserData(reinterpret_cast<void *>(isDbg), info.message =
AsUserDataType::UserData_isDbg); tr("The script failed with an exception") +
mod->SetUserData(reinterpret_cast<void *>(isDbg), QStringLiteral("\n") +
AsUserDataType::UserData_isDbg); QString::fromStdString(GetExceptionInfo(ctx, true));
info.type = MessageType::Error;
asPWORD umode = asPWORD(mode); outputMessage(mode, info);
ctx->SetUserData(reinterpret_cast<void *>(umode), r = -1;
AsUserDataType::UserData_ContextMode); } else if (r == asEXECUTION_ABORTED) {
MessageInfo info;
ctx->SetExceptionCallback(asMETHOD(ScriptMachine, exceptionCallback), this, info.mode = mode;
asCALL_THISCALL); info.message = tr("The script was aborted");
info.type = MessageType::Error;
// Execute the script until completion outputMessage(mode, info);
// The script may create co-routines. These will automatically r = -1;
// be managed by the context manager } else {
while (_ctxMgr->ExecuteScripts()) auto e = QMetaEnum::fromType<asEContextState>();
; MessageInfo info;
info.message = tr("The script terminated unexpectedly") +
// Check if the main script finished normally QStringLiteral(" (") + e.valueToKey(r) +
int r = ctx->GetState(); QStringLiteral(")");
if (r != asEXECUTION_FINISHED) { info.type = MessageType::Error;
if (r == asEXECUTION_EXCEPTION) { outputMessage(mode, info);
MessageInfo info; r = -1;
info.mode = mode; }
info.message = tr("The script failed with an exception") +
QStringLiteral("\n") +
QString::fromStdString(GetExceptionInfo(ctx, true));
info.type = MessageType::Error;
outputMessage(mode, info);
r = -1;
} else if (r == asEXECUTION_ABORTED) {
MessageInfo info;
info.mode = mode;
info.message = tr("The script was aborted");
info.type = MessageType::Error;
outputMessage(mode, info);
r = -1;
} else { } else {
auto e = QMetaEnum::fromType<asEContextState>(); r = 0;
MessageInfo info;
info.message = tr("The script terminated unexpectedly") +
QStringLiteral(" (") + e.valueToKey(r) +
QStringLiteral(")");
info.type = MessageType::Error;
outputMessage(mode, info);
r = -1;
} }
func->Release();
// Return the context after retrieving the return value
_ctxMgr->DoneWithContext(ctx);
_engine->GarbageCollect();
return r >= 0;
} else { } else {
r = 0; if (ret.length() == 1) {
auto s = ret.first();
if (s.type == QAsCodeParser::SymbolType::Variable) {
auto r = mod->CompileGlobalVar(nullptr, ccode, 0);
if (r < 0 || mod->ResetGlobalVars() < 0) {
MessageInfo info;
info.mode = mode;
info.message = tr("GlobalBadDecl");
info.type = MessageType::Error;
outputMessage(mode, info);
return false;
}
return true;
}
}
MessageInfo info;
info.mode = mode;
info.message = tr("ScriptRunUnsupported");
info.type = MessageType::Error;
outputMessage(mode, info);
} }
return false;
// Return the context after retrieving the return value
_ctxMgr->DoneWithContext(ctx);
_engine->GarbageCollect();
return r >= 0;
} }
QString ScriptMachine::scriptGetExceptionInfo() { QString ScriptMachine::scriptGetExceptionInfo() {

View File

@ -18,13 +18,15 @@
#ifndef SCRIPTMACHINE_H #ifndef SCRIPTMACHINE_H
#define SCRIPTMACHINE_H #define SCRIPTMACHINE_H
#include "AngelScript/sdk/add_on/contextmgr/contextmgr.h"
#include "AngelScript/sdk/angelscript/include/angelscript.h" #include "AngelScript/sdk/angelscript/include/angelscript.h"
#include "class/aspreprocesser.h" #include "class/aspreprocesser.h"
#include "asdebugger.h" #include "asdebugger.h"
#include "class/ascontextmgr.h"
#include <QObject> #include <QObject>
#include <QQueue>
class ScriptMachine : public QObject { class ScriptMachine : public QObject {
Q_OBJECT Q_OBJECT
@ -97,7 +99,7 @@ private:
explicit ScriptMachine(); explicit ScriptMachine();
Q_DISABLE_COPY_MOVE(ScriptMachine) Q_DISABLE_COPY_MOVE(ScriptMachine)
public: private:
asIScriptModule *createModule(ConsoleMode mode); asIScriptModule *createModule(ConsoleMode mode);
asIScriptModule *createModuleIfNotExist(ConsoleMode mode); asIScriptModule *createModuleIfNotExist(ConsoleMode mode);
asIScriptModule *module(ConsoleMode mode); asIScriptModule *module(ConsoleMode mode);
@ -143,7 +145,8 @@ public slots:
bool executeScript(ConsoleMode mode, const QString &script, bool executeScript(ConsoleMode mode, const QString &script,
bool isInDebug = false); bool isInDebug = false);
void abortDbgScript(ConsoleMode mode); void abortDbgScript();
void abortScript(ConsoleMode mode);
void abortScript(); void abortScript();
protected: protected:
@ -196,11 +199,13 @@ signals:
private: private:
asIScriptEngine *_engine = nullptr; asIScriptEngine *_engine = nullptr;
asDebugger *_debugger = nullptr; asDebugger *_debugger = nullptr;
asContextMgr *_ctxMgr = nullptr; CContextMgr *_ctxMgr = nullptr;
QVector<asIScriptContext *> _ctxPool;
QQueue<asIScriptContext *> _ctxPool;
QVector<asITypeInfo *> _rtypes; QVector<asITypeInfo *> _rtypes;
QMap<ConsoleMode, RegCallBacks> _regcalls; QMap<ConsoleMode, RegCallBacks> _regcalls;
QMap<ConsoleMode, asIScriptContext *> _ctx;
ConsoleMode _curMode = ConsoleMode::Background; ConsoleMode _curMode = ConsoleMode::Background;
}; };

View File

@ -250,16 +250,18 @@ ScriptManager::buildUpRibbonScriptRunner(RibbonButtonGroup *group) {
} }
void ScriptManager::runScript(const QString &filename) { void ScriptManager::runScript(const QString &filename) {
// ScriptMachine::instance().executeScript(filename); auto &ins = ScriptMachine::instance();
if (ins.isRunning(ScriptMachine::Background)) {
auto ret = QMessageBox::question(nullptr, tr("ScriptRunning"),
tr("ScriptRunningRequestLastStop?"));
if (ret == QMessageBox::Yes) {
ins.abortScript(ScriptMachine::Background);
} else {
return;
}
}
// Q_ASSERT(_console); ins.executeScript(ScriptMachine::Background, filename);
// _console->setMode(ScriptingConsole::Output);
// _console->stdWarn(tr("Excuting:") + filename);
// _console->newLine();
// // TODO
// // _console->machine()->executeScript(filename);
// _console->appendCommandPrompt();
// _console->setMode(ScriptingConsole::Input);
} }
QStringList ScriptManager::usrScriptsDbCats() const { QStringList ScriptManager::usrScriptsDbCats() const {

View File

@ -36,7 +36,7 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
constexpr qsizetype FILE_MAX_BUFFER = 0x6400000; // 100MB constexpr qsizetype FILE_MAX_BUFFER = 0x32000000; // 800MB
constexpr auto CLONE_LIMIT = 3; constexpr auto CLONE_LIMIT = 3;
constexpr auto VIEW_PROPERTY = "__VIEW__"; constexpr auto VIEW_PROPERTY = "__VIEW__";

View File

@ -17,7 +17,6 @@
#include "scriptingconsole.h" #include "scriptingconsole.h"
#include "QConsoleWidget/QConsoleIODevice.h" #include "QConsoleWidget/QConsoleIODevice.h"
#include "class/logger.h"
#include "class/scriptmachine.h" #include "class/scriptmachine.h"
#include "class/scriptsettings.h" #include "class/scriptsettings.h"
#include "class/skinmanager.h" #include "class/skinmanager.h"
@ -84,19 +83,15 @@ void ScriptingConsole::handleReturnKey() {
if (iodevice_->isOpen()) if (iodevice_->isOpen())
iodevice_->consoleWidgetInput(code); iodevice_->consoleWidgetInput(code);
emit consoleCommand(code); if (!_isWaitingRead) {
emit consoleCommand(code);
}
} }
} }
void ScriptingConsole::init() { void ScriptingConsole::init() {
_getInputFn = std::bind(&ScriptingConsole::getInput, this); _getInputFn = std::bind(&ScriptingConsole::getInput, this);
// _sp = new ScriptConsoleMachine(_getInputFn, this);
// connect(_sp, &ScriptConsoleMachine::onClearConsole, this,
// &ScriptingConsole::clear);
// connect(this, &ScriptingConsole::abortEvaluation, _sp,
// &ScriptConsoleMachine::abortScript);
connect(this, &QConsoleWidget::consoleCommand, this, connect(this, &QConsoleWidget::consoleCommand, this,
&ScriptingConsole::runConsoleCommand); &ScriptingConsole::runConsoleCommand);
@ -177,7 +172,7 @@ void ScriptingConsole::onOutput(const ScriptMachine::MessageInfo &message) {
flush(); flush();
break; break;
case ScriptMachine::MessageType::Print: case ScriptMachine::MessageType::Print:
if (lastInfo.first != message.type) { if (lastInfo.first != message.type && isNotBlockStart) {
newLine(); newLine();
} }
stdOut(message.message); stdOut(message.message);
@ -219,7 +214,13 @@ void ScriptingConsole::applyScriptSettings() {
void ScriptingConsole::runConsoleCommand(const QString &code) { void ScriptingConsole::runConsoleCommand(const QString &code) {
auto exec = code.trimmed(); auto exec = code.trimmed();
if (exec.endsWith('\\')) { if (exec == QStringLiteral("#ls")) {
} else if (exec == QStringLiteral("#del")) {
} else if (exec == QStringLiteral("#cls")) {
} else if (exec.endsWith('\\')) {
static QRegularExpression ex(QStringLiteral("[\\\\\\s]+$")); static QRegularExpression ex(QStringLiteral("[\\\\\\s]+$"));
_codes += exec.remove(ex); _codes += exec.remove(ex);
setMode(Output); setMode(Output);
@ -228,10 +229,8 @@ void ScriptingConsole::runConsoleCommand(const QString &code) {
} else { } else {
setMode(Output); setMode(Output);
_codes += exec; _codes += exec;
if (!ScriptMachine::instance().executeCode(ScriptMachine::Interactive, ScriptMachine::instance().executeCode(ScriptMachine::Interactive,
_codes)) { _codes);
// WingMessageBox::
}
_codes.clear(); _codes.clear();
appendCommandPrompt(); appendCommandPrompt();
setMode(Input); setMode(Input);
@ -239,11 +238,18 @@ void ScriptingConsole::runConsoleCommand(const QString &code) {
} }
QString ScriptingConsole::getInput() { QString ScriptingConsole::getInput() {
auto &s = consoleStream();
appendCommandPrompt(true); appendCommandPrompt(true);
setMode(Input); setMode(Input);
consoleStream().device()->waitForReadyRead(-1); s.status();
auto d = s.device();
auto ba = d->bytesAvailable();
d->skip(ba);
_isWaitingRead = true;
d->waitForReadyRead(-1);
QString instr; QString instr;
consoleStream() >> instr; s >> instr;
_isWaitingRead = false;
setMode(Output); setMode(Output);
return instr; return instr;
} }

View File

@ -68,6 +68,7 @@ protected slots:
private: private:
QString _codes; QString _codes;
bool _isWaitingRead = false;
std::function<QString(void)> _getInputFn; std::function<QString(void)> _getInputFn;
}; };

View File

@ -5,6 +5,7 @@ enum class CrashCode : int {
AlreadyStart, AlreadyStart,
LanguageFile, LanguageFile,
PluginSetting, PluginSetting,
ScriptInitFailed,
GenericCallNotSupported GenericCallNotSupported
}; };

View File

@ -40,6 +40,7 @@
#include "class/wingmessagebox.h" #include "class/wingmessagebox.h"
#include "class/wingupdater.h" #include "class/wingupdater.h"
#include "control/toast.h" #include "control/toast.h"
#include "define.h"
#include "encodingdialog.h" #include "encodingdialog.h"
#include "fileinfodialog.h" #include "fileinfodialog.h"
#include "finddialog.h" #include "finddialog.h"
@ -254,7 +255,11 @@ MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() {
std::placeholders::_1); std::placeholders::_1);
sm.registerCallBack(ScriptMachine::Background, callbacks); sm.registerCallBack(ScriptMachine::Background, callbacks);
} else { } else {
// TODO QMessageBox::critical(this, qAppName(),
tr("ScriptEngineInitFailed"));
set.setScriptEnabled(false);
set.save(SettingManager::SCRIPT);
throw CrashCode::ScriptInitFailed;
} }
// At this time, AngelScript service plugin has started // At this time, AngelScript service plugin has started
@ -1011,6 +1016,10 @@ MainWindow::buildUpScriptConsoleDock(ads::CDockManager *dock,
showStatus(QStringLiteral("<b><font color=\"gold\">") + showStatus(QStringLiteral("<b><font color=\"gold\">") +
content + QStringLiteral("</font></b>")); content + QStringLiteral("</font></b>"));
}); });
connect(
m_scriptConsole, &ScriptingConsole::abortEvaluation, this, [this]() {
ScriptMachine::instance().abortScript(ScriptMachine::Interactive);
});
auto dw = buildDockWidget(dock, QStringLiteral("ScriptConsole"), auto dw = buildDockWidget(dock, QStringLiteral("ScriptConsole"),
tr("ScriptConsole"), m_scriptConsole); tr("ScriptConsole"), m_scriptConsole);
@ -3167,16 +3176,29 @@ void MainWindow::connectEditorView(EditorView *editor) {
editor->setProperty("__RELOAD__", false); editor->setProperty("__RELOAD__", false);
connect(editor, &EditorView::need2Reload, this, [editor, this]() { connect(editor, &EditorView::need2Reload, this, [editor, this]() {
if (editor->isBigFile()) { if (editor->isBigFile()) {
editor->reload(); auto fileName = editor->fileName();
} if (!QFile::exists(fileName)) {
if (currentEditor() == editor) { editor->raise();
auto ret = WingMessageBox::question(this, tr("Reload"), WingMessageBox::critical(this, tr("Error"),
tr("ReloadNeededYesOrNo")); tr("FileCloseBigFile"));
if (ret == QMessageBox::Yes) { closeEditor(editor, true);
}
if (currentEditor() == editor) {
editor->reload(); editor->reload();
} else {
editor->setProperty("__RELOAD__", true);
} }
} else { } else {
editor->setProperty("__RELOAD__", true); editor->hexEditor()->document()->setDocSaved(false);
if (currentEditor() == editor) {
auto ret = WingMessageBox::question(this, tr("Reload"),
tr("ReloadNeededYesOrNo"));
if (ret == QMessageBox::Yes) {
editor->reload();
}
} else {
editor->setProperty("__RELOAD__", true);
}
} }
}); });
} }
@ -3207,10 +3229,14 @@ void MainWindow::swapEditor(EditorView *old, EditorView *cur) {
auto hexeditor = cur->hexEditor(); auto hexeditor = cur->hexEditor();
auto needReload = cur->property("__RELOAD__").toBool(); auto needReload = cur->property("__RELOAD__").toBool();
if (needReload) { if (needReload) {
auto ret = WingMessageBox::question(this, tr("Reload"), if (cur->isBigFile()) {
tr("ReloadNeededYesOrNo"));
if (ret == QMessageBox::Yes) {
cur->reload(); cur->reload();
} else {
auto ret = WingMessageBox::question(this, tr("Reload"),
tr("ReloadNeededYesOrNo"));
if (ret == QMessageBox::Yes) {
cur->reload();
}
} }
cur->setProperty("__RELOAD__", false); cur->setProperty("__RELOAD__", false);
} }