History

jsdoc info on selected auto-complete entry

Thijs Wenker committed 8 years ago

Commit 179c21a1 parent c46a1151 file · +134 −11Browse files

Showing the changes to interface/src/ui/JSConsole.cpp (1 of 1 file). Show all

Unified · Split

interface/src/ui/JSConsole.cpp+134−11
@@ -17,6 +17,7 @@ · 16 unmodified lines
17#include <QtConcurrent/QtConcurrentRun>17#include <QtConcurrent/QtConcurrentRun>
18#include <QStringListModel>18#include <QStringListModel>
19#include <QListView>19#include <QListView>
20#include <QToolTip>
20 21
21#include <shared/QtHelpers.h>22#include <shared/QtHelpers.h>
22#include <ScriptEngines.h>23#include <ScriptEngines.h>
@@ -39,6 +40,21 @@ const QString RESULT_ERROR_STYLE = "color: #d13b22;"; · 16 unmodified lines
39const QString GUTTER_PREVIOUS_COMMAND = "<span style=\"color: #57b8bb;\">&lt;</span>";40const QString GUTTER_PREVIOUS_COMMAND = "<span style=\"color: #57b8bb;\">&lt;</span>";
40const QString GUTTER_ERROR = "<span style=\"color: #d13b22;\">X</span>";41const QString GUTTER_ERROR = "<span style=\"color: #d13b22;\">X</span>";
41 42
43const QString JSDOC_LINE_SEPARATOR = "\r";
44
45const QString JSDOC_STYLE =
46 "<style type=\"text/css\"> \
47 .code { \
48 font-family: Consolas, Monaco, 'Andale Mono', monospace \
49 } \
50 pre, code { \
51 display: inline; \
52 } \
53 .no-wrap { \
54 white-space: nowrap; \
55 } \
56 </style>";
57
42const QString JSConsole::_consoleFileName { "about:console" };58const QString JSConsole::_consoleFileName { "about:console" };
43 59
44const QString JSON_KEY = "entries";60const QString JSON_KEY = "entries";
@@ -50,7 +66,7 @@ QList<QString> _readLines(const QString& filename) { · 5 unmodified lines
50 // TODO: check root["version"]66 // TODO: check root["version"]
51 return root[JSON_KEY].toVariant().toStringList();67 return root[JSON_KEY].toVariant().toStringList();
52}68}
53 69
54void _writeLines(const QString& filename, const QList<QString>& lines) {70void _writeLines(const QString& filename, const QList<QString>& lines) {
55 QFile file(filename);71 QFile file(filename);
56 file.open(QFile::WriteOnly);72 file.open(QFile::WriteOnly);
@@ -62,6 +78,10 @@ void _writeLines(const QString& filename, const QList<QString>& lines) { · 5 unmodified lines
62 QTextStream(&file) << json;78 QTextStream(&file) << json;
63}79}
64 80
81QString _jsdocTypeToString(QJsonValue jsdocType) {
82 return jsdocType.toObject().value("names").toVariant().toStringList().join("/");
83}
84
65void JSConsole::readAPI() {85void JSConsole::readAPI() {
66 QFile file(PathUtils::resourcesPath() + "auto-complete/hifiJSDoc.json");86 QFile file(PathUtils::resourcesPath() + "auto-complete/hifiJSDoc.json");
67 file.open(QFile::ReadOnly);87 file.open(QFile::ReadOnly);
@@ -102,7 +122,10 @@ QStandardItemModel* JSConsole::getAutoCompleteModel(const QString& memberOf) { · 34 unmodified lines
102 foreach(auto doc, _apiDocs) {122 foreach(auto doc, _apiDocs) {
103 auto object = doc.toObject();123 auto object = doc.toObject();
104 auto scope = object.value("scope");124 auto scope = object.value("scope");
105 if ((memberOfProperty == nullptr && scope.toString() == "global" && object.value("kind").toString() == "namespace") || (memberOfProperty != nullptr && object.value("memberof").toString() == memberOfProperty)) {125 if ((memberOfProperty == nullptr && scope.toString() == "global" && object.value("kind").toString() == "namespace") ||
126 (memberOfProperty != nullptr && object.value("memberof").toString() == memberOfProperty &&
127 object.value("kind").toString() != "typedef")) {
128
106 model->appendRow(getAutoCompleteItem(doc));129 model->appendRow(getAutoCompleteItem(doc));
107 }130 }
108 }131 }
@@ -166,20 +189,119 @@ JSConsole::JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine) : · 57 unmodified lines
166}189}
167 190
168void JSConsole::insertCompletion(const QModelIndex& completion) {191void JSConsole::insertCompletion(const QModelIndex& completion) {
192 auto jsdocObject = QJsonValue::fromVariant(completion.data(Qt::UserRole + 1)).toObject();
193 auto kind = jsdocObject.value("kind").toString();
169 auto completionString = completion.data().toString();194 auto completionString = completion.data().toString();
170 QTextCursor tc = _ui->promptTextEdit->textCursor();195 if (kind == "function") {
196 auto params = jsdocObject.value("params").toArray();
197 // automatically add the parenthesis/parentheses for the functions
198 completionString += params.isEmpty() ? "()" : "(";
199 }
200 QTextCursor textCursor = _ui->promptTextEdit->textCursor();
171 int extra = completionString.length() - _completer->completionPrefix().length();201 int extra = completionString.length() - _completer->completionPrefix().length();
172 tc.movePosition(QTextCursor::Left);202 textCursor.movePosition(QTextCursor::Left);
173 tc.movePosition(QTextCursor::EndOfWord);203 textCursor.movePosition(QTextCursor::EndOfWord);
174 tc.insertText(completionString.right(extra));204 textCursor.insertText(completionString.right(extra));
175 _ui->promptTextEdit->setTextCursor(tc);205 _ui->promptTextEdit->setTextCursor(textCursor);
176}206}
177 207
178void JSConsole::highlightedCompletion(const QModelIndex& completion) {208void JSConsole::highlightedCompletion(const QModelIndex& completion) {
179 qDebug() << "Highlighted " << completion.data().toString();
180 auto jsdocObject = QJsonValue::fromVariant(completion.data(Qt::UserRole + 1)).toObject();209 auto jsdocObject = QJsonValue::fromVariant(completion.data(Qt::UserRole + 1)).toObject();
181 210 QString memberOf = "";
182 // qDebug() << "Highlighted data " << QJsonDocument(jsdocObject).toJson(QJsonDocument::Compact);211 if (!_completerModule.isEmpty()) {
212 memberOf = _completerModule + ".";
213 }
214 auto name = memberOf + "<b>" + jsdocObject.value("name").toString() + "</b>";
215 auto description = jsdocObject.value("description").toString();
216 auto examples = jsdocObject.value("examples").toArray();
217 auto kind = jsdocObject.value("kind").toString();
218 QString returnTypeText = "";
219
220 QString paramsTable = "";
221 if (kind == "function") {
222 auto params = jsdocObject.value("params").toArray();
223 auto returns = jsdocObject.value("returns");
224 if (!returns.isUndefined()) {
225 returnTypeText = _jsdocTypeToString(jsdocObject.value("returns").toArray().at(0).toObject().value("type")) + " ";
226 }
227 name += "(";
228 if (!params.isEmpty()) {
229 bool hasDefaultParam = false;
230 bool hasOptionalParam = false;
231 bool firstItem = true;
232 foreach(auto param, params) {
233 auto paramObject = param.toObject();
234 if (!hasOptionalParam && paramObject.value("optional").toBool(false)) {
235 hasOptionalParam = true;
236 name += "<i>[";
237 }
238 if (!firstItem) {
239 name += ", ";
240 } else {
241 firstItem = false;
242 }
243 name += paramObject.value("name").toString();
244 if (!hasDefaultParam && !paramObject.value("defaultvalue").isUndefined()) {
245 hasDefaultParam = true;
246 }
247 }
248 if (hasOptionalParam) {
249 name += "]</i>";
250 }
251
252 paramsTable += "<table border=\"1\" cellpadding=\"10\"><thead><tr><th>Name</th><th>Type</th>";
253 if (hasDefaultParam) {
254 paramsTable += "<th>Default</th>";
255 }
256 paramsTable += "<th>Description</th></tr></thead><tbody>";
257 foreach(auto param, params) {
258 auto paramObject = param.toObject();
259 paramsTable += "<tr><td>" + paramObject.value("name").toString() + "</td><td>" +
260 _jsdocTypeToString(paramObject.value("type")) + "</td><td>";
261 if (hasDefaultParam) {
262 paramsTable += paramObject.value("defaultvalue").toVariant().toString() + "</td><td>";
263 }
264 paramsTable += paramObject.value("description").toString() + "</td></tr>";
265 }
266
267 paramsTable += "</tbody></table>";
268 }
269 name += ")";
270 } else if (!jsdocObject.value("type").isUndefined()){
271 returnTypeText = _jsdocTypeToString(jsdocObject.value("type")) + " ";
272 }
273 auto popupText = JSDOC_STYLE + "<span class=\"no-wrap\">" + returnTypeText + name + "</span>";
274 auto descriptionText = "<p>" + description.replace(JSDOC_LINE_SEPARATOR, "<br>") + "</p>";
275
276 popupText += descriptionText;
277 popupText += paramsTable;
278 auto returns = jsdocObject.value("returns");
279 if (!returns.isUndefined()) {
280 foreach(auto returnEntry, returns.toArray()) {
281 auto returnsObject = returnEntry.toObject();
282 auto returnsDescription = returnsObject.value("description").toString().replace(JSDOC_LINE_SEPARATOR, "<br>");
283 popupText += "<h4>Returns</h4><p>" + returnsDescription + "</p><h5>Type</h5><pre><code>" +
284 _jsdocTypeToString(returnsObject.value("type")) + "</code></pre>";
285 }
286 }
287
288 if (!examples.isEmpty()) {
289 popupText += "<h4>Examples</h4>";
290 foreach(auto example, examples) {
291 auto exampleText = example.toString();
292 auto exampleLines = exampleText.split(JSDOC_LINE_SEPARATOR);
293 foreach(auto exampleLine, exampleLines) {
294 if (exampleLine.contains("<caption>")) {
295 popupText += exampleLine.replace("caption>", "h5>");
296 } else {
297 popupText += "<pre><code>" + exampleLine + "\n</code></pre>";
298 }
299 }
300 }
301 }
302
303 QToolTip::showText(QPoint(_completer->popup()->pos().x() + _completer->popup()->width(), _completer->popup()->pos().y()),
304 popupText, _completer->popup());
183}305}
184 306
185JSConsole::~JSConsole() {307JSConsole::~JSConsole() {
@@ -299,7 +421,7 @@ bool JSConsole::eventFilter(QObject* sender, QEvent* event) { · 113 unmodified lines
299 case Qt::Key_Space:421 case Qt::Key_Space:
300 case Qt::Key_Enter:422 case Qt::Key_Enter:
301 case Qt::Key_Return:423 case Qt::Key_Return:
302 insertCompletion(_completer->currentIndex());424 insertCompletion(_completer->popup()->currentIndex());
303 _completer->popup()->hide();425 _completer->popup()->hide();
304 return true;426 return true;
305 default:427 default:
@@ -401,6 +523,7 @@ bool JSConsole::eventFilter(QObject* sender, QEvent* event) { · 95 unmodified lines
401 cursorRect.setWidth(_completer->popup()->sizeHintForColumn(0) +523 cursorRect.setWidth(_completer->popup()->sizeHintForColumn(0) +
402 _completer->popup()->verticalScrollBar()->sizeHint().width());524 _completer->popup()->verticalScrollBar()->sizeHint().width());
403 _completer->complete(cursorRect);525 _completer->complete(cursorRect);
526 highlightedCompletion(_completer->popup()->currentIndex());
404 return false;527 return false;
405 }528 }
406 }529 }