forked from qt-creator/qt-creator
first iteration of snippet support for qml
Done with Thorbjorn and Roberto
This commit is contained in:
96
share/qtcreator/snippets/qml.xml
Normal file
96
share/qtcreator/snippets/qml.xml
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<snippets>
|
||||||
|
<snippet>property <tab>name</tab> <tab>name</tab> : <tab>name</tab>
|
||||||
|
</snippet>
|
||||||
|
<snippet>Item {
|
||||||
|
id: <tab>name</tab>
|
||||||
|
|
||||||
|
}
|
||||||
|
</snippet>
|
||||||
|
<snippet>BorderImage {
|
||||||
|
id: <tab>name</tab>
|
||||||
|
width: <tab>name</tab>; height: <tab>name</tab>
|
||||||
|
border.left: <tab>name</tab>; border.top: <tab>name</tab>
|
||||||
|
border.right: <tab>name</tab>; border.bottom: <tab>name</tab>
|
||||||
|
source: "<tab>name</tab>"
|
||||||
|
}
|
||||||
|
</snippet>
|
||||||
|
|
||||||
|
<snippet>Image {
|
||||||
|
id: <tab>name</tab>
|
||||||
|
source: "<tab>name</tab>"
|
||||||
|
}
|
||||||
|
</snippet>
|
||||||
|
|
||||||
|
<snippet>Text {
|
||||||
|
id: <tab>name</tab>
|
||||||
|
text: "<tab>name</tab>"
|
||||||
|
}
|
||||||
|
</snippet>
|
||||||
|
|
||||||
|
<snippet>states: [
|
||||||
|
State {
|
||||||
|
name: "<tab>name</tab>"
|
||||||
|
PropertyChanges {
|
||||||
|
target: <tab>name</tab>
|
||||||
|
<tab/>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</snippet>
|
||||||
|
|
||||||
|
<snippet>State {
|
||||||
|
name: "<tab>name</tab>"
|
||||||
|
PropertyChanges {
|
||||||
|
target: <tab>name</tab>
|
||||||
|
<tab/>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</snippet>
|
||||||
|
|
||||||
|
<snippet>transitions: [
|
||||||
|
Transition {
|
||||||
|
from: "<tab>name</tab>"
|
||||||
|
to: "<tab>name</tab>"
|
||||||
|
<tab/>
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</snippet>
|
||||||
|
|
||||||
|
<snippet>Transition {
|
||||||
|
from: "<tab>name</tab>"
|
||||||
|
to: "<tab>name</tab>"
|
||||||
|
<tab/>
|
||||||
|
}
|
||||||
|
</snippet>
|
||||||
|
|
||||||
|
<snippet>PropertyChanges {
|
||||||
|
target: <tab>name</tab>
|
||||||
|
<tab/>
|
||||||
|
}
|
||||||
|
</snippet>
|
||||||
|
|
||||||
|
<snippet description="matchTargets">NumberAnimation { matchTargets: "<tab>name</tab>"; matchProperties: "<tab>name</tab>"; duration: <tab>200</tab> }
|
||||||
|
</snippet>
|
||||||
|
<snippet description="target">NumberAnimation { target: "<tab>name</tab>"; property: "<tab>name</tab>"; value: <tab>name</tab>; duration: <tab>200</tab> }
|
||||||
|
</snippet>
|
||||||
|
<snippet>PropertyAction { matchTargets: "<tab>name</tab>"; matchProperties: "<tab>name</tab>"; duration: <tab>200</tab> }
|
||||||
|
</snippet>
|
||||||
|
<snippet>PropertyAction { target: "<tab>name</tab>"; property: "<tab>name</tab>"; value: <tab>name</tab>; duration: <tab>200</tab> }
|
||||||
|
</snippet>
|
||||||
|
<snippet>PauseAnimation { duration: <tab>name</tab>}
|
||||||
|
</snippet>
|
||||||
|
<snippet>ColorAnimation { from: <tab>name</tab>; to: <tab>name</tab>; duration: <tab>200</tab> }
|
||||||
|
</snippet>
|
||||||
|
<snippet>effect: Colorize { color: "<tab>name</tab>" }
|
||||||
|
</snippet>
|
||||||
|
<snippet>effect: Blur { blurRadius: "<tab>200</tab>" }
|
||||||
|
</snippet>
|
||||||
|
<snippet>effect: DropShadow {
|
||||||
|
blurRadius: <tab>200</tab>
|
||||||
|
offset.x: <tab>200</tab>
|
||||||
|
offset.y: <tab>200</tab>
|
||||||
|
}
|
||||||
|
</snippet>
|
||||||
|
|
||||||
|
</snippets>
|
||||||
@@ -37,6 +37,12 @@
|
|||||||
#include <qmljs/qmljssymbol.h>
|
#include <qmljs/qmljssymbol.h>
|
||||||
#include <texteditor/basetexteditor.h>
|
#include <texteditor/basetexteditor.h>
|
||||||
|
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
|
#include <QtCore/QFile>
|
||||||
|
#include <QtCore/QFileInfo>
|
||||||
|
#include <QtCore/QXmlStreamReader>
|
||||||
|
|
||||||
#include <QtDebug>
|
#include <QtDebug>
|
||||||
|
|
||||||
using namespace QmlJSEditor;
|
using namespace QmlJSEditor;
|
||||||
@@ -134,61 +140,9 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateSnippets();
|
||||||
|
|
||||||
// snippets completion
|
m_completions.append(m_snippets);
|
||||||
TextEditor::CompletionItem item(this);
|
|
||||||
item.text = QLatin1String("Rectangle - declaration");
|
|
||||||
item.data = QVariant::fromValue(QString("Rectangle {\nwidth: $100$;\nheight: 100;\n$$\n}"));
|
|
||||||
m_completions.append(item);
|
|
||||||
|
|
||||||
item.text = QLatin1String("Item - declaration");
|
|
||||||
item.data = QVariant::fromValue(QString("Item {\nwidth: $100$;\nheight: 100;\n$$\n}"));
|
|
||||||
m_completions.append(item);
|
|
||||||
|
|
||||||
item.text = QLatin1String("BorderImage - declaration");
|
|
||||||
item.data = QLatin1String("BorderImage {\n"
|
|
||||||
"id: $name$;\n"
|
|
||||||
"width: $100$; height: $100$;\n"
|
|
||||||
"border.left: $2$; border.top: $2$;\n"
|
|
||||||
"border.right: $2$; border.bottom: $2$;\n"
|
|
||||||
"source: \"$name$\";\n"
|
|
||||||
"}\n");
|
|
||||||
m_completions.append(item);
|
|
||||||
|
|
||||||
item.text = QLatin1String("State - declaration");
|
|
||||||
item.data = QLatin1String("State {\n"
|
|
||||||
"name: \"$state$;\"\n"
|
|
||||||
"PropertyChanges {\n"
|
|
||||||
"target: $target$;\n"
|
|
||||||
"$$\n"
|
|
||||||
"}\n"
|
|
||||||
"}\n");
|
|
||||||
m_completions.append(item);
|
|
||||||
|
|
||||||
item.text = QLatin1String("states - declaration");
|
|
||||||
item.data = QLatin1String("states: [\n"
|
|
||||||
"State {\n"
|
|
||||||
"name: \"$state$\";\n"
|
|
||||||
"PropertyChanges {\n"
|
|
||||||
"target: $target$;\n"
|
|
||||||
"$$\n"
|
|
||||||
"}\n"
|
|
||||||
"}\n"
|
|
||||||
"]\n");
|
|
||||||
m_completions.append(item);
|
|
||||||
|
|
||||||
item.text = QLatin1String("property - declaration");
|
|
||||||
item.data = QLatin1String("property $var$ $name$: $value$;\n");
|
|
||||||
m_completions.append(item);
|
|
||||||
|
|
||||||
item.text = QLatin1String("readonly property - declaration");
|
|
||||||
item.data = QLatin1String("readonly property $var$ $name$: $value$;\n");
|
|
||||||
m_completions.append(item);
|
|
||||||
|
|
||||||
item.text = QLatin1String("NumericAnimation - declaration");
|
|
||||||
item.data = QLatin1String("NumberAnimation { matchTargets: \"$target$\"; matchProperties: \"$properties$\"; duration: $1000$ }\n");
|
|
||||||
m_completions.append(item);
|
|
||||||
|
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,3 +253,65 @@ void QmlCodeCompletion::cleanup()
|
|||||||
m_completions.clear();
|
m_completions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void QmlCodeCompletion::updateSnippets()
|
||||||
|
{
|
||||||
|
QString qmlsnippets = Core::ICore::instance()->resourcePath() + QLatin1String("/snippets/qml.xml");
|
||||||
|
if (!QFile::exists(qmlsnippets))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QDateTime lastModified = QFileInfo(qmlsnippets).lastModified();
|
||||||
|
if (!m_snippetFileLastModified.isNull() && lastModified == m_snippetFileLastModified)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_snippetFileLastModified = lastModified;
|
||||||
|
QFile file(qmlsnippets);
|
||||||
|
file.open(QIODevice::ReadOnly);
|
||||||
|
QXmlStreamReader xml(&file);
|
||||||
|
while (!xml.atEnd() && xml.readNextStartElement()) {
|
||||||
|
if (xml.name() == QLatin1String("snippets")) {
|
||||||
|
while (xml.readNextStartElement()) {
|
||||||
|
if (xml.name() == QLatin1String("snippet")) {
|
||||||
|
TextEditor::CompletionItem item(this);
|
||||||
|
QString title, data;
|
||||||
|
QString description = xml.attributes().value("description").toString();
|
||||||
|
|
||||||
|
while (!xml.atEnd()) {
|
||||||
|
xml.readNext();
|
||||||
|
if (xml.isEndElement()) {
|
||||||
|
int i = 0;
|
||||||
|
while (i < data.size() && data.at(i).isLetterOrNumber())
|
||||||
|
++i;
|
||||||
|
title = data.left(i);
|
||||||
|
item.text = title;
|
||||||
|
if (!description.isEmpty()) {
|
||||||
|
item.text += QLatin1Char(' ');
|
||||||
|
item.text += description;
|
||||||
|
}
|
||||||
|
item.data = QVariant::fromValue(data);
|
||||||
|
m_snippets.append(item);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xml.isCharacters())
|
||||||
|
data += xml.text();
|
||||||
|
else if (xml.isStartElement()) {
|
||||||
|
if (xml.name() != QLatin1String("tab"))
|
||||||
|
xml.raiseError(QLatin1String("invalid snippets file"));
|
||||||
|
else {
|
||||||
|
data += QChar::ObjectReplacementCharacter;
|
||||||
|
data += xml.readElementText();
|
||||||
|
data += QChar::ObjectReplacementCharacter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (xml.hasError())
|
||||||
|
qWarning() << qmlsnippets << xml.errorString();
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include <qmljs/qmljstypesystem.h>
|
#include <qmljs/qmljstypesystem.h>
|
||||||
#include <texteditor/icompletioncollector.h>
|
#include <texteditor/icompletioncollector.h>
|
||||||
|
#include <QtCore/QDateTime>
|
||||||
|
|
||||||
namespace TextEditor {
|
namespace TextEditor {
|
||||||
class ITextEditable;
|
class ITextEditable;
|
||||||
@@ -69,6 +70,10 @@ private:
|
|||||||
QList<TextEditor::CompletionItem> m_completions;
|
QList<TextEditor::CompletionItem> m_completions;
|
||||||
Qt::CaseSensitivity m_caseSensitivity;
|
Qt::CaseSensitivity m_caseSensitivity;
|
||||||
QmlJS::TypeSystem *m_typeSystem;
|
QmlJS::TypeSystem *m_typeSystem;
|
||||||
|
|
||||||
|
QList<TextEditor::CompletionItem> m_snippets;
|
||||||
|
QDateTime m_snippetFileLastModified;
|
||||||
|
void updateSnippets();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -960,11 +960,15 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e)
|
|||||||
d->m_lastEventWasBlockSelectionEvent = false;
|
d->m_lastEventWasBlockSelectionEvent = false;
|
||||||
|
|
||||||
if (e->key() == Qt::Key_Escape) {
|
if (e->key() == Qt::Key_Escape) {
|
||||||
e->accept();
|
if (d->m_snippetOverlay->isVisible()) {
|
||||||
QTextCursor cursor = textCursor();
|
e->accept();
|
||||||
cursor.clearSelection();
|
d->m_snippetOverlay->hide();
|
||||||
setTextCursor(cursor);
|
d->m_snippetOverlay->clear();
|
||||||
return;
|
QTextCursor cursor = textCursor();
|
||||||
|
cursor.clearSelection();
|
||||||
|
setTextCursor(cursor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ro = isReadOnly();
|
bool ro = isReadOnly();
|
||||||
@@ -996,6 +1000,17 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e)
|
|||||||
|| (!d->m_lineSeparatorsAllowed && e == QKeySequence::InsertLineSeparator))
|
|| (!d->m_lineSeparatorsAllowed && e == QKeySequence::InsertLineSeparator))
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
if (d->m_snippetOverlay->isVisible()) {
|
||||||
|
e->accept();
|
||||||
|
d->m_snippetOverlay->hide();
|
||||||
|
d->m_snippetOverlay->clear();
|
||||||
|
QTextCursor cursor = textCursor();
|
||||||
|
cursor.movePosition(QTextCursor::EndOfBlock);
|
||||||
|
setTextCursor(cursor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QTextCursor cursor = textCursor();
|
QTextCursor cursor = textCursor();
|
||||||
if (d->m_inBlockSelectionMode)
|
if (d->m_inBlockSelectionMode)
|
||||||
cursor.clearSelection();
|
cursor.clearSelection();
|
||||||
@@ -1190,9 +1205,10 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d->m_snippetOverlay->isVisible() &&
|
if (d->m_snippetOverlay->isVisible()
|
||||||
(e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace))
|
&& (e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace)) {
|
||||||
d->snippetCheckCursor(textCursor());
|
d->snippetCheckCursor(textCursor());
|
||||||
|
}
|
||||||
|
|
||||||
if (ro || e->text().isEmpty() || !e->text().at(0).isPrint()) {
|
if (ro || e->text().isEmpty() || !e->text().at(0).isPrint()) {
|
||||||
QPlainTextEdit::keyPressEvent(e);
|
QPlainTextEdit::keyPressEvent(e);
|
||||||
@@ -1263,21 +1279,21 @@ void BaseTextEditor::insertCodeSnippet(const QString &snippet)
|
|||||||
QMap<int, int> positions;
|
QMap<int, int> positions;
|
||||||
|
|
||||||
while (pos < snippet.size()) {
|
while (pos < snippet.size()) {
|
||||||
if (snippet.at(pos) != QLatin1Char('$')) {
|
if (snippet.at(pos) != QChar::ObjectReplacementCharacter) {
|
||||||
const int start = pos;
|
const int start = pos;
|
||||||
do { ++pos; }
|
do { ++pos; }
|
||||||
while (pos < snippet.size() && snippet.at(pos) != QLatin1Char('$'));
|
while (pos < snippet.size() && snippet.at(pos) != QChar::ObjectReplacementCharacter);
|
||||||
cursor.insertText(snippet.mid(start, pos - start));
|
cursor.insertText(snippet.mid(start, pos - start));
|
||||||
} else {
|
} else {
|
||||||
// the start of a place holder.
|
// the start of a place holder.
|
||||||
const int start = ++pos;
|
const int start = ++pos;
|
||||||
for (; pos < snippet.size(); ++pos) {
|
for (; pos < snippet.size(); ++pos) {
|
||||||
if (snippet.at(pos) == QLatin1Char('$'))
|
if (snippet.at(pos) == QChar::ObjectReplacementCharacter)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_ASSERT(pos < snippet.size());
|
Q_ASSERT(pos < snippet.size());
|
||||||
Q_ASSERT(snippet.at(pos) == QLatin1Char('$'));
|
Q_ASSERT(snippet.at(pos) == QChar::ObjectReplacementCharacter);
|
||||||
|
|
||||||
const QString textToInsert = snippet.mid(start, pos - start);
|
const QString textToInsert = snippet.mid(start, pos - start);
|
||||||
|
|
||||||
@@ -1319,7 +1335,12 @@ void BaseTextEditor::insertCodeSnippet(const QString &snippet)
|
|||||||
const QTextEdit::ExtraSelection &selection = selections.first();
|
const QTextEdit::ExtraSelection &selection = selections.first();
|
||||||
|
|
||||||
cursor = textCursor();
|
cursor = textCursor();
|
||||||
cursor.setPosition(selection.cursor.anchor() + 1);
|
if (selection.cursor.hasSelection()) {
|
||||||
|
cursor.setPosition(selection.cursor.selectionStart()+1);
|
||||||
|
cursor.setPosition(selection.cursor.selectionEnd(), QTextCursor::KeepAnchor);
|
||||||
|
} else {
|
||||||
|
cursor.setPosition(selection.cursor.position());
|
||||||
|
}
|
||||||
setTextCursor(cursor);
|
setTextCursor(cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1416,8 +1437,13 @@ bool BaseTextEditor::event(QEvent *e)
|
|||||||
d->m_contentsChanged = false;
|
d->m_contentsChanged = false;
|
||||||
switch (e->type()) {
|
switch (e->type()) {
|
||||||
case QEvent::ShortcutOverride:
|
case QEvent::ShortcutOverride:
|
||||||
|
if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape && d->m_snippetOverlay->isVisible()) {
|
||||||
|
e->accept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
e->ignore(); // we are a really nice citizen
|
e->ignore(); // we are a really nice citizen
|
||||||
return true;
|
return true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1746,7 +1772,8 @@ void BaseTextEditorPrivate::snippetTabOrBacktab(bool forward)
|
|||||||
if (forward) {
|
if (forward) {
|
||||||
for (int i = 0; i < m_snippetOverlay->m_selections.count(); ++i){
|
for (int i = 0; i < m_snippetOverlay->m_selections.count(); ++i){
|
||||||
const OverlaySelection &selection = m_snippetOverlay->m_selections.at(i);
|
const OverlaySelection &selection = m_snippetOverlay->m_selections.at(i);
|
||||||
if (selection.m_cursor_begin.position() > cursor.position()) {
|
if (selection.m_cursor_begin.position() >= cursor.position()
|
||||||
|
&& selection.m_cursor_end.position() > cursor.position()) {
|
||||||
final = selection;
|
final = selection;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ public:
|
|||||||
bool isVisible() const { return m_visible; }
|
bool isVisible() const { return m_visible; }
|
||||||
void setVisible(bool b);
|
void setVisible(bool b);
|
||||||
|
|
||||||
|
inline void hide() { setVisible(false); }
|
||||||
|
inline void show() { setVisible(true); }
|
||||||
|
|
||||||
void setBorderWidth(int bw) {m_borderWidth = bw; }
|
void setBorderWidth(int bw) {m_borderWidth = bw; }
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|||||||
Reference in New Issue
Block a user