Skip to content

Commit

Permalink
Implement simple completer for Modelica annotations (task#5333)
Browse files Browse the repository at this point in the history
Fetches completions from OpenModelica.AutoCompletion.Annotations

Belonging to [master]:
  - #115
  • Loading branch information
atrosinenko authored and OpenModelica-Hudson committed Apr 8, 2019
1 parent 5ea05e7 commit 69bdc32
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 1 deletion.
5 changes: 5 additions & 0 deletions OMEdit/OMEdit/OMEditGUI/Editors/BaseEditor.cpp
Expand Up @@ -769,6 +769,11 @@ CompleterItem::CompleterItem(const QString &key, const QString &value, const QSt
}
}

CompleterItem::CompleterItem(const QString &key, const QString &value, const QString &select, const QString &description)
: mKey(key), mValue(value), mSelect(select), mDescription(description)
{
}

CompleterItem::CompleterItem(const QString &value, const QString &description)
: mKey(value), mValue(value), mSelect(value), mDescription(description)
{
Expand Down
1 change: 1 addition & 0 deletions OMEdit/OMEdit/OMEditGUI/Editors/BaseEditor.h
Expand Up @@ -215,6 +215,7 @@ class CompleterItem
public:
CompleterItem() {}
CompleterItem(const QString &key, const QString &value, const QString &select);
CompleterItem(const QString &key, const QString &value, const QString &select, const QString &description);
CompleterItem(const QString &value, const QString &description);
QString mKey;
QString mValue;
Expand Down
117 changes: 117 additions & 0 deletions OMEdit/OMEdit/OMEditGUI/Editors/ModelicaEditor.cpp
Expand Up @@ -93,6 +93,10 @@ void ModelicaEditor::popUpCompleter()
mpPlainTextEdit->insertCompleterSymbols(classes, ":/Resources/icons/completerClass.svg");
mpPlainTextEdit->insertCompleterSymbols(components, ":/Resources/icons/completerComponent.svg");

QList<CompleterItem> annotations;
getCompletionAnnotations(stringAfterWord("annotation"), annotations);
mpPlainTextEdit->insertCompleterSymbols(annotations, ":/Resources/icons/completerAnnotation.svg");

QCompleter *completer = mpPlainTextEdit->completer();
QRect cr = mpPlainTextEdit->cursorRect();
cr.setWidth(completer->popup()->sizeHintForColumn(0)+ completer->popup()->verticalScrollBar()->sizeHint().width());
Expand Down Expand Up @@ -165,6 +169,22 @@ QString ModelicaEditor::wordUnderCursor()
return mpPlainTextEdit->document()->toPlainText().mid(begin, end - begin);
}

/*!
* \brief Returns the substring from the last occurrence of `word` to the cursor position
* \param word Starting word of the substring
* \return Resulting substring or Null QString if no `word` occurrence found up to the cursor position
*/
QString ModelicaEditor::stringAfterWord(const QString &word)
{
int pos = mpPlainTextEdit->textCursor().position();
QString plainText = mpPlainTextEdit->document()->toPlainText();
int index = plainText.lastIndexOf(word, pos);
if (index == -1)
return QString();
else
return plainText.mid(index, pos - index);
}

void ModelicaEditor::getCompletionSymbols(QString word, QList<CompleterItem> &classes, QList<CompleterItem> &components)
{
QStringList nameComponents = word.split('.');
Expand All @@ -183,6 +203,103 @@ void ModelicaEditor::getCompletionSymbols(QString word, QList<CompleterItem> &cl
}
}

/*!
* \brief Looks up the root for annotation auto completion information
*/
LibraryTreeItem *ModelicaEditor::getAnnotationCompletionRoot()
{
LibraryTreeItem *pLibraryRoot = MainWindow::instance()->getLibraryWidget()->getLibraryTreeModel()->getRootLibraryTreeItem();
LibraryTreeItem *pModelicaReference = 0;

for (int i = 0; i < pLibraryRoot->childrenSize(); ++i) {
if (pLibraryRoot->childAt(i)->getName() == "OpenModelica")
pModelicaReference = pLibraryRoot->childAt(i);
}

if (pModelicaReference) {
return deepResolve(pModelicaReference, QStringList() << "AutoCompletion" << "Annotations");
} else {
return 0;
}
}

/*!
* \brief Returns a collection of completion items for the parsed `stack` of nested annotations
* \param stack A stack of nested annotations (f.e. "annotation(uses(Modelica(ver|" becomes ["uses", "Modelica"]
* \param annotations Resulting collection of compeltion items
*/
void ModelicaEditor::getCompletionAnnotations(const QStringList &stack, QList<CompleterItem> &annotations)
{
LibraryTreeItem *pReference = getAnnotationCompletionRoot();
if (pReference) {
LibraryTreeItem *pAnnotation = deepResolve(pReference, stack);
if (pAnnotation) {
for (int i = 0; i < pAnnotation->childrenSize(); ++i) {
QString name = pAnnotation->childAt(i)->getName();
annotations << CompleterItem(name, name + "(", name, pAnnotation->childAt(i)->getHTMLDescription());
}
QList<ComponentInfo *> components = pAnnotation->getComponentsList();
for (int i = 0; i < components.size(); ++i) {
annotations << CompleterItem(components[i]->getName() + " = ", components[i]->getHTMLDescription());
}
}
}
}

/*!
* \brief Resolves the annotation under cursor as a stack of nested names and returns completions
* \param str A string starting with the "annotation" word up to the cursor position
* \param annotations Resulting collection of completion items
*/
void ModelicaEditor::getCompletionAnnotations(const QString &str, QList<CompleterItem> &annotations)
{
QStringList stack;
int lastWordStart = 0;
bool insideWord = false;

if (str.isEmpty())
return;

for (int i = 0; i < str.size(); ++i) {
QChar ch = str[i];

// First, handle string literals
if (ch == '"') {
for (++i; i < str.size() && str[i] != '"'; ++i) {
if (str[i] == '\\')
++i;
}
// skipped, restarting as usual
--i;
continue;
}

// Now, handle the stack of annotations
if (ch == '(') {
stack << str.mid(lastWordStart, i - lastWordStart).trimmed();
}
if (ch == ')') {
if (stack.isEmpty()) {
return; // not in an annotation at all
}
stack.pop_back();
}

// Last, account for boundaries of words to be placed in stack
bool partOfLiteral = ch.isLetterOrNumber() || ch == '_';
if (!insideWord && partOfLiteral) {
lastWordStart = i;
}
insideWord = partOfLiteral;
}

if (stack.isEmpty()) {
return;
}
stack.pop_front(); // pop 'annotation'
getCompletionAnnotations(stack, annotations);
}

/*!
* \brief ModelicaEditor::getClassNames
* Uses the OMC parseString API to check the class names inside the Modelica Text
Expand Down
4 changes: 4 additions & 0 deletions OMEdit/OMEdit/OMEditGUI/Editors/ModelicaEditor.h
Expand Up @@ -58,10 +58,14 @@ class ModelicaEditor : public BaseEditor
bool isTextChanged() {return mTextChanged;}
virtual void popUpCompleter();
QString wordUnderCursor();
QString stringAfterWord(const QString &word);
static LibraryTreeItem *deepResolve(LibraryTreeItem *pItem, QStringList nameComponents);
QList<LibraryTreeItem *> getCandidateContexts(QStringList nameComponents);
static void tryToCompleteInSingleContext(QStringList &result, LibraryTreeItem *pItem, QString lastPart);
void getCompletionSymbols(QString word, QList<CompleterItem> &classes, QList<CompleterItem> &components);
LibraryTreeItem *getAnnotationCompletionRoot();
void getCompletionAnnotations(const QStringList &stack, QList<CompleterItem> &annotations);
void getCompletionAnnotations(const QString &str, QList<CompleterItem> &annotations);
static QList<CompleterItem> getCodeSnippets();
private:
QString mLastValidText;
Expand Down
2 changes: 1 addition & 1 deletion OMEdit/OMEdit/OMEditGUI/Modeling/LibraryTreeWidget.h
Expand Up @@ -191,14 +191,14 @@ class LibraryTreeItem : public QObject
OMCInterface::getClassInformation_res mClassInformation;
SimulationOptions mSimulationOptions;
OMSSimulationOptions mOMSSimulationOptions;
const QList<ComponentInfo *> &getComponentsList();
private:
bool mIsRootItem;
LibraryTreeItem *mpParentLibraryTreeItem;
QList<LibraryTreeItem*> mChildren;
QList<LibraryTreeItem*> mInheritedClasses;
QList<ComponentInfo*> mComponents;
bool mComponentsLoaded;
const QList<ComponentInfo *> &getComponentsList();
LibraryType mLibraryType;
bool mSystemLibrary;
ModelWidget *mpModelWidget;
Expand Down
1 change: 1 addition & 0 deletions OMEdit/OMEdit/OMEditGUI/resource_omedit.qrc
Expand Up @@ -209,5 +209,6 @@
<file>Resources/icons/instantiate.svg</file>
<file>Resources/icons/completerComponent.svg</file>
<file>Resources/icons/completerClass.svg</file>
<file>Resources/icons/completerAnnotation.svg</file>
</qresource>
</RCC>
63 changes: 63 additions & 0 deletions OMEdit/OMEditGUI/Resources/icons/completerAnnotation.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 69bdc32

Please sign in to comment.