mirror of
https://github.com/lubosz/overte.git
synced 2025-08-08 03:27:48 +02:00
JS scripting console auto-complete
This commit is contained in:
parent
2e4fc5e58c
commit
0f7f58417b
8 changed files with 285 additions and 56 deletions
|
@ -349,6 +349,16 @@ endif()
|
||||||
|
|
||||||
add_bugsplat()
|
add_bugsplat()
|
||||||
|
|
||||||
|
# generate the JSDoc JSON for the JSConsole auto-completer
|
||||||
|
add_custom_command(TARGET ${TARGET_NAME} #POST_BUILD
|
||||||
|
COMMAND npm install
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tools/jsdoc
|
||||||
|
)
|
||||||
|
add_custom_command(TARGET ${TARGET_NAME}
|
||||||
|
COMMAND node_modules/.bin/jsdoc . -c config.json
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tools/jsdoc
|
||||||
|
)
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
set(EXTRA_DEPLOY_OPTIONS "--qmldir \"${PROJECT_SOURCE_DIR}/resources/qml\"")
|
set(EXTRA_DEPLOY_OPTIONS "--qmldir \"${PROJECT_SOURCE_DIR}/resources/qml\"")
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,11 @@
|
||||||
#include "JSConsole.h"
|
#include "JSConsole.h"
|
||||||
|
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
#include <QKeyEvent>
|
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QtConcurrent/QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
#include <QStringListModel>
|
||||||
|
#include <QListView>
|
||||||
|
|
||||||
#include <shared/QtHelpers.h>
|
#include <shared/QtHelpers.h>
|
||||||
#include <ScriptEngines.h>
|
#include <ScriptEngines.h>
|
||||||
|
@ -61,12 +62,64 @@ void _writeLines(const QString& filename, const QList<QString>& lines) {
|
||||||
QTextStream(&file) << json;
|
QTextStream(&file) << json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JSConsole::readAPI() {
|
||||||
|
QFile file(PathUtils::resourcesPath() + "auto-complete/export.json");
|
||||||
|
file.open(QFile::ReadOnly);
|
||||||
|
auto json = QTextStream(&file).readAll().toUtf8();
|
||||||
|
_apiDocs = QJsonDocument::fromJson(json).array();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStandardItem* getAutoCompleteItem(QJsonValue propertyObject) {
|
||||||
|
auto propertyItem = new QStandardItem(propertyObject.toObject().value("name").toString());
|
||||||
|
propertyItem->setData(propertyObject.toVariant());
|
||||||
|
return propertyItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStandardItemModel* JSConsole::getAutoCompleteModel(const QString& memberOf) {
|
||||||
|
QString memberOfProperty = nullptr;
|
||||||
|
|
||||||
|
auto model = new QStandardItemModel(this);
|
||||||
|
|
||||||
|
if (memberOf != nullptr) {
|
||||||
|
foreach(auto doc, _apiDocs) {
|
||||||
|
auto object = doc.toObject();
|
||||||
|
if (object.value("name").toString() == memberOf && object.value("scope").toString() == "global" &&
|
||||||
|
object.value("kind").toString() == "namespace") {
|
||||||
|
|
||||||
|
memberOfProperty = object.value("longname").toString();
|
||||||
|
|
||||||
|
auto properties = doc.toObject().value("properties").toArray();
|
||||||
|
foreach(auto propertyObject, properties) {
|
||||||
|
model->appendRow(getAutoCompleteItem(propertyObject));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (memberOfProperty == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(auto doc, _apiDocs) {
|
||||||
|
auto object = doc.toObject();
|
||||||
|
auto scope = object.value("scope");
|
||||||
|
if ((memberOfProperty == nullptr && scope.toString() == "global" && object.value("kind").toString() == "namespace") || (memberOfProperty != nullptr && object.value("memberof").toString() == memberOfProperty)) {
|
||||||
|
model->appendRow(getAutoCompleteItem(doc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model->sort(0);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
JSConsole::JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine) :
|
JSConsole::JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
_ui(new Ui::Console),
|
_ui(new Ui::Console),
|
||||||
_currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND),
|
_currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND),
|
||||||
_savedHistoryFilename(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + HISTORY_FILENAME),
|
_savedHistoryFilename(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + HISTORY_FILENAME),
|
||||||
_commandHistory(_readLines(_savedHistoryFilename)) {
|
_commandHistory(_readLines(_savedHistoryFilename)),
|
||||||
|
_completer(new QCompleter(this)) {
|
||||||
|
|
||||||
|
readAPI();
|
||||||
|
|
||||||
_ui->setupUi(this);
|
_ui->setupUi(this);
|
||||||
_ui->promptTextEdit->setLineWrapMode(QTextEdit::NoWrap);
|
_ui->promptTextEdit->setLineWrapMode(QTextEdit::NoWrap);
|
||||||
_ui->promptTextEdit->setWordWrapMode(QTextOption::NoWrap);
|
_ui->promptTextEdit->setWordWrapMode(QTextOption::NoWrap);
|
||||||
|
@ -78,38 +131,75 @@ JSConsole::JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine) :
|
||||||
setStyleSheet(styleSheet.readAll());
|
setStyleSheet(styleSheet.readAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(_ui->scrollArea->verticalScrollBar(), SIGNAL(rangeChanged(int, int)), this, SLOT(scrollToBottom()));
|
connect(_ui->scrollArea->verticalScrollBar(), &QScrollBar::rangeChanged, this, &JSConsole::scrollToBottom);
|
||||||
connect(_ui->promptTextEdit, SIGNAL(textChanged()), this, SLOT(resizeTextInput()));
|
connect(_ui->promptTextEdit, &QTextEdit::textChanged, this, &JSConsole::resizeTextInput);
|
||||||
|
|
||||||
|
_completer->setWidget(_ui->promptTextEdit);
|
||||||
|
_completer->setModel(getAutoCompleteModel(nullptr));
|
||||||
|
_completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
|
||||||
|
_completer->setMaxVisibleItems(12);
|
||||||
|
_completer->setFilterMode(Qt::MatchStartsWith);
|
||||||
|
_completer->setWrapAround(false);
|
||||||
|
_completer->setCompletionMode(QCompleter::PopupCompletion);
|
||||||
|
_completer->setCaseSensitivity(Qt::CaseSensitive);
|
||||||
|
|
||||||
|
QListView *listView = new QListView();
|
||||||
|
listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
|
listView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
listView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
listView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
listView->setModelColumn(_completer->completionColumn());
|
||||||
|
|
||||||
|
_completer->setPopup(listView);
|
||||||
|
_completer->popup()->installEventFilter(this);
|
||||||
|
QObject::connect(_completer, static_cast<void(QCompleter::*)(const QModelIndex&)>(&QCompleter::activated), this,
|
||||||
|
&JSConsole::insertCompletion);
|
||||||
|
|
||||||
|
QObject::connect(_completer, static_cast<void(QCompleter::*)(const QModelIndex&)>(&QCompleter::highlighted), this,
|
||||||
|
&JSConsole::highlightedCompletion);
|
||||||
|
|
||||||
setScriptEngine(scriptEngine);
|
setScriptEngine(scriptEngine);
|
||||||
|
|
||||||
resizeTextInput();
|
resizeTextInput();
|
||||||
|
|
||||||
connect(&_executeWatcher, SIGNAL(finished()), this, SLOT(commandFinished()));
|
connect(&_executeWatcher, &QFutureWatcher<QScriptValue>::finished, this, &JSConsole::commandFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::insertCompletion(const QModelIndex& completion) {
|
||||||
|
auto completionString = completion.data().toString();
|
||||||
|
QTextCursor tc = _ui->promptTextEdit->textCursor();
|
||||||
|
int extra = completionString.length() - _completer->completionPrefix().length();
|
||||||
|
tc.movePosition(QTextCursor::Left);
|
||||||
|
tc.movePosition(QTextCursor::EndOfWord);
|
||||||
|
tc.insertText(completionString.right(extra));
|
||||||
|
_ui->promptTextEdit->setTextCursor(tc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::highlightedCompletion(const QModelIndex& completion) {
|
||||||
|
qDebug() << "Highlighted " << completion.data().toString();
|
||||||
|
auto jsdocObject = QJsonValue::fromVariant(completion.data(Qt::UserRole + 1)).toObject();
|
||||||
|
|
||||||
|
// qDebug() << "Highlighted data " << QJsonDocument(jsdocObject).toJson(QJsonDocument::Compact);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSConsole::~JSConsole() {
|
JSConsole::~JSConsole() {
|
||||||
if (_scriptEngine) {
|
if (_scriptEngine) {
|
||||||
disconnect(_scriptEngine.data(), SIGNAL(printedMessage(const QString&)), this, SLOT(handlePrint(const QString&)));
|
disconnect(_scriptEngine.data(), nullptr, this, nullptr);
|
||||||
disconnect(_scriptEngine.data(), SIGNAL(errorMessage(const QString&)), this, SLOT(handleError(const QString&)));
|
|
||||||
_scriptEngine.reset();
|
_scriptEngine.reset();
|
||||||
}
|
}
|
||||||
delete _ui;
|
delete _ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JSConsole::setScriptEngine(const ScriptEnginePointer& scriptEngine) {
|
void JSConsole::setScriptEngine(const ScriptEnginePointer& scriptEngine) {
|
||||||
if (_scriptEngine == scriptEngine && scriptEngine != NULL) {
|
if (_scriptEngine == scriptEngine && scriptEngine != nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_scriptEngine != NULL) {
|
if (_scriptEngine != nullptr) {
|
||||||
disconnect(_scriptEngine.data(), &ScriptEngine::printedMessage, this, &JSConsole::handlePrint);
|
disconnect(_scriptEngine.data(), nullptr, this, nullptr);
|
||||||
disconnect(_scriptEngine.data(), &ScriptEngine::infoMessage, this, &JSConsole::handleInfo);
|
|
||||||
disconnect(_scriptEngine.data(), &ScriptEngine::warningMessage, this, &JSConsole::handleWarning);
|
|
||||||
disconnect(_scriptEngine.data(), &ScriptEngine::errorMessage, this, &JSConsole::handleError);
|
|
||||||
_scriptEngine.reset();
|
_scriptEngine.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if scriptEngine is NULL then create one and keep track of it using _ownScriptEngine
|
// if scriptEngine is nullptr then create one and keep track of it using _ownScriptEngine
|
||||||
if (scriptEngine.isNull()) {
|
if (scriptEngine.isNull()) {
|
||||||
_scriptEngine = DependencyManager::get<ScriptEngines>()->loadScript(_consoleFileName, false);
|
_scriptEngine = DependencyManager::get<ScriptEngines>()->loadScript(_consoleFileName, false);
|
||||||
} else {
|
} else {
|
||||||
|
@ -199,45 +289,132 @@ void JSConsole::showEvent(QShowEvent* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JSConsole::eventFilter(QObject* sender, QEvent* event) {
|
bool JSConsole::eventFilter(QObject* sender, QEvent* event) {
|
||||||
if (sender == _ui->promptTextEdit) {
|
if ((sender == _ui->promptTextEdit || sender == _completer->popup()) && event->type() == QEvent::KeyPress) {
|
||||||
if (event->type() == QEvent::KeyPress) {
|
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
int key = keyEvent->key();
|
||||||
int key = keyEvent->key();
|
|
||||||
|
|
||||||
if ((key == Qt::Key_Return || key == Qt::Key_Enter)) {
|
if (_completer->popup()->isVisible()) {
|
||||||
if (keyEvent->modifiers() & Qt::ShiftModifier) {
|
// The following keys are forwarded by the completer to the widget
|
||||||
// If the shift key is being used then treat it as a regular return/enter. If this isn't done,
|
switch (key) {
|
||||||
// a new QTextBlock isn't created.
|
case Qt::Key_Space:
|
||||||
keyEvent->setModifiers(keyEvent->modifiers() & ~Qt::ShiftModifier);
|
case Qt::Key_Enter:
|
||||||
} else {
|
case Qt::Key_Return:
|
||||||
QString command = _ui->promptTextEdit->toPlainText().replace("\r\n","\n").trimmed();
|
insertCompletion(_completer->currentIndex());
|
||||||
|
_completer->popup()->hide();
|
||||||
if (!command.isEmpty()) {
|
return true;
|
||||||
QTextCursor cursor = _ui->promptTextEdit->textCursor();
|
case Qt::Key_Escape:
|
||||||
_ui->promptTextEdit->clear();
|
case Qt::Key_Tab:
|
||||||
|
case Qt::Key_Backtab:
|
||||||
executeCommand(command);
|
qDebug() << "test";
|
||||||
}
|
keyEvent->ignore();//setAccepted(false);
|
||||||
|
return false; // let the completer do default behavior
|
||||||
return true;
|
default:
|
||||||
}
|
return false;
|
||||||
} else if (key == Qt::Key_Down) {
|
|
||||||
// Go to the next command in history if the cursor is at the last line of the current command.
|
|
||||||
int blockNumber = _ui->promptTextEdit->textCursor().blockNumber();
|
|
||||||
int blockCount = _ui->promptTextEdit->document()->blockCount();
|
|
||||||
if (blockNumber == blockCount - 1) {
|
|
||||||
setToNextCommandInHistory();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (key == Qt::Key_Up) {
|
|
||||||
// Go to the previous command in history if the cursor is at the first line of the current command.
|
|
||||||
int blockNumber = _ui->promptTextEdit->textCursor().blockNumber();
|
|
||||||
if (blockNumber == 0) {
|
|
||||||
setToPreviousCommandInHistory();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((key == Qt::Key_Return || key == Qt::Key_Enter)) {
|
||||||
|
if (keyEvent->modifiers() & Qt::ShiftModifier) {
|
||||||
|
// If the shift key is being used then treat it as a regular return/enter. If this isn't done,
|
||||||
|
// a new QTextBlock isn't created.
|
||||||
|
keyEvent->setModifiers(keyEvent->modifiers() & ~Qt::ShiftModifier);
|
||||||
|
} else {
|
||||||
|
QString command = _ui->promptTextEdit->toPlainText().replace("\r\n", "\n").trimmed();
|
||||||
|
|
||||||
|
if (!command.isEmpty()) {
|
||||||
|
QTextCursor cursor = _ui->promptTextEdit->textCursor();
|
||||||
|
_ui->promptTextEdit->clear();
|
||||||
|
|
||||||
|
executeCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (key == Qt::Key_Down) {
|
||||||
|
// Go to the next command in history if the cursor is at the last line of the current command.
|
||||||
|
int blockNumber = _ui->promptTextEdit->textCursor().blockNumber();
|
||||||
|
int blockCount = _ui->promptTextEdit->document()->blockCount();
|
||||||
|
if (blockNumber == blockCount - 1) {
|
||||||
|
setToNextCommandInHistory();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (key == Qt::Key_Up) {
|
||||||
|
// Go to the previous command in history if the cursor is at the first line of the current command.
|
||||||
|
int blockNumber = _ui->promptTextEdit->textCursor().blockNumber();
|
||||||
|
if (blockNumber == 0) {
|
||||||
|
setToPreviousCommandInHistory();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((sender == _ui->promptTextEdit || sender == _completer->popup()) && event->type() == QEvent::KeyRelease) {
|
||||||
|
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||||
|
int key = keyEvent->key();
|
||||||
|
|
||||||
|
// completer shortcut (CTRL + SPACE)
|
||||||
|
bool isCompleterShortcut = ((keyEvent->modifiers() & Qt::ControlModifier) && key == Qt::Key_Space) ||
|
||||||
|
key == Qt::Key_Period;
|
||||||
|
if (_completer->popup()->isVisible() || isCompleterShortcut) {
|
||||||
|
|
||||||
|
const bool ctrlOrShift = keyEvent->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
|
||||||
|
if (ctrlOrShift && keyEvent->text().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString eow("~!@#$%^&*()+{}|:\"<>?,/;'[]\\-="); // end of word
|
||||||
|
bool hasModifier = (keyEvent->modifiers() != Qt::NoModifier) && !ctrlOrShift;
|
||||||
|
|
||||||
|
|
||||||
|
if (!isCompleterShortcut && (!keyEvent->text().isEmpty() && eow.contains(keyEvent->text().right(1)))) {
|
||||||
|
qDebug() << "eow contains " << keyEvent->text().right(1) << " full text: " << keyEvent->text();
|
||||||
|
_completer->popup()->hide();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
qDebug() << "auto completing";
|
||||||
|
|
||||||
|
auto textCursor = _ui->promptTextEdit->textCursor();
|
||||||
|
|
||||||
|
textCursor.select(QTextCursor::WordUnderCursor);
|
||||||
|
|
||||||
|
QString completionPrefix = textCursor.selectedText();
|
||||||
|
|
||||||
|
auto leftOfCursor = _ui->promptTextEdit->toPlainText().left(textCursor.position());
|
||||||
|
qDebug() << "leftOfCursor" << leftOfCursor;
|
||||||
|
|
||||||
|
// RegEx [3] [4]
|
||||||
|
// (Module.subModule).(property/subModule)
|
||||||
|
|
||||||
|
const int MODULE_INDEX = 3;
|
||||||
|
const int PROPERTY_INDEX = 4;
|
||||||
|
// TODO: disallow invalid characters on left of property
|
||||||
|
QRegExp regExp("((([A-Za-z0-9_\\.]+)\\.)|(?!\\.))([a-zA-Z0-9_]*)$");
|
||||||
|
int pos = regExp.indexIn(leftOfCursor);
|
||||||
|
auto rexExpCapturedTexts = regExp.capturedTexts();
|
||||||
|
auto memberOf = rexExpCapturedTexts[MODULE_INDEX];
|
||||||
|
completionPrefix = rexExpCapturedTexts[PROPERTY_INDEX];
|
||||||
|
bool switchedModule = false;
|
||||||
|
if (memberOf != _completerModule) {
|
||||||
|
_completerModule = memberOf;
|
||||||
|
auto autoCompleteModel = getAutoCompleteModel(memberOf);
|
||||||
|
if (autoCompleteModel == nullptr) {
|
||||||
|
_completer->popup()->hide();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_completer->setModel(autoCompleteModel);
|
||||||
|
_completer->popup()->installEventFilter(this);
|
||||||
|
switchedModule = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switchedModule || completionPrefix != _completer->completionPrefix()) {
|
||||||
|
_completer->setCompletionPrefix(completionPrefix);
|
||||||
|
qDebug() << "Set completion prefix to:" << completionPrefix;
|
||||||
|
_completer->popup()->setCurrentIndex(_completer->completionModel()->index(0, 0));
|
||||||
|
}
|
||||||
|
auto cursorRect = _ui->promptTextEdit->cursorRect();
|
||||||
|
cursorRect.setWidth(_completer->popup()->sizeHintForColumn(0) +
|
||||||
|
_completer->popup()->verticalScrollBar()->sizeHint().width());
|
||||||
|
_completer->complete(cursorRect);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -321,7 +498,7 @@ void JSConsole::appendMessage(const QString& gutter, const QString& message) {
|
||||||
|
|
||||||
void JSConsole::clear() {
|
void JSConsole::clear() {
|
||||||
QLayoutItem* item;
|
QLayoutItem* item;
|
||||||
while ((item = _ui->logArea->layout()->takeAt(0)) != NULL) {
|
while ((item = _ui->logArea->layout()->takeAt(0)) != nullptr) {
|
||||||
delete item->widget();
|
delete item->widget();
|
||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,11 @@
|
||||||
#ifndef hifi_JSConsole_h
|
#ifndef hifi_JSConsole_h
|
||||||
#define hifi_JSConsole_h
|
#define hifi_JSConsole_h
|
||||||
|
|
||||||
#include <QDialog>
|
|
||||||
#include <QEvent>
|
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QWidget>
|
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
#include <QCompleter>
|
||||||
|
#include <QtCore/QJsonArray>
|
||||||
|
|
||||||
#include "ui_console.h"
|
#include "ui_console.h"
|
||||||
#include "ScriptEngine.h"
|
#include "ScriptEngine.h"
|
||||||
|
@ -54,12 +53,20 @@ protected slots:
|
||||||
void handleError(const QString& message, const QString& scriptName);
|
void handleError(const QString& message, const QString& scriptName);
|
||||||
void commandFinished();
|
void commandFinished();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void insertCompletion(const QModelIndex& completion);
|
||||||
|
void highlightedCompletion(const QModelIndex& completion);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void appendMessage(const QString& gutter, const QString& message);
|
void appendMessage(const QString& gutter, const QString& message);
|
||||||
void setToNextCommandInHistory();
|
void setToNextCommandInHistory();
|
||||||
void setToPreviousCommandInHistory();
|
void setToPreviousCommandInHistory();
|
||||||
void resetCurrentCommandHistory();
|
void resetCurrentCommandHistory();
|
||||||
|
|
||||||
|
void readAPI();
|
||||||
|
|
||||||
|
QStandardItemModel* getAutoCompleteModel(const QString& memberOf = nullptr);
|
||||||
|
|
||||||
QFutureWatcher<QScriptValue> _executeWatcher;
|
QFutureWatcher<QScriptValue> _executeWatcher;
|
||||||
Ui::Console* _ui;
|
Ui::Console* _ui;
|
||||||
int _currentCommandInHistory;
|
int _currentCommandInHistory;
|
||||||
|
@ -68,6 +75,9 @@ private:
|
||||||
QString _rootCommand;
|
QString _rootCommand;
|
||||||
ScriptEnginePointer _scriptEngine;
|
ScriptEnginePointer _scriptEngine;
|
||||||
static const QString _consoleFileName;
|
static const QString _consoleFileName;
|
||||||
|
QJsonArray _apiDocs;
|
||||||
|
QCompleter* _completer;
|
||||||
|
QString _completerModule {""};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -150,7 +150,7 @@ signals:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Notifies scripts that a user has disconnected from the domain
|
* Notifies scripts that a user has disconnected from the domain
|
||||||
* @function Users.avatar.avatarDisconnected
|
* @function Users.avatarDisconnected
|
||||||
* @param {nodeID} NodeID The session ID of the avatar that has disconnected
|
* @param {nodeID} NodeID The session ID of the avatar that has disconnected
|
||||||
*/
|
*/
|
||||||
void avatarDisconnected(const QUuid& nodeID);
|
void avatarDisconnected(const QUuid& nodeID);
|
||||||
|
|
|
@ -4,5 +4,8 @@
|
||||||
"outputSourceFiles": false
|
"outputSourceFiles": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"plugins": ["plugins/hifi"]
|
"plugins": [
|
||||||
|
"plugins/hifi",
|
||||||
|
"plugins/hifiJSONExport"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
7
tools/jsdoc/package.json
Normal file
7
tools/jsdoc/package.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"name": "hifiJSDoc",
|
||||||
|
"dependencies": {
|
||||||
|
"jsdoc": "^3.5.5"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
|
@ -47,5 +47,13 @@ exports.handlers = {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fs.writeFile("out/hifiJSDoc.js", e.source, function(err) {
|
||||||
|
if (err) {
|
||||||
|
return console.log(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("The Hifi JSDoc JS was saved!");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
14
tools/jsdoc/plugins/hifiJSONExport.js
Normal file
14
tools/jsdoc/plugins/hifiJSONExport.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
exports.handlers = {
|
||||||
|
processingComplete: function(e) {
|
||||||
|
var doclets = e.doclets.map(doclet => Object.assign({}, doclet));
|
||||||
|
const fs = require('fs');
|
||||||
|
doclets.map(doclet => {delete doclet.meta; delete doclet.comment});
|
||||||
|
fs.writeFile("out/hifiJSDoc.json", JSON.stringify(doclets, null, 4), function(err) {
|
||||||
|
if (err) {
|
||||||
|
return console.log(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("The Hifi JSDoc JSON was saved!");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in a new issue