diff --git a/src/plugins/texteditor/snippets/snippet.cpp b/src/plugins/texteditor/snippets/snippet.cpp
index 4d2c1a54ef0..ea4671596cf 100644
--- a/src/plugins/texteditor/snippets/snippet.cpp
+++ b/src/plugins/texteditor/snippets/snippet.cpp
@@ -70,6 +70,22 @@ public:
}
};
+QString SnippetParseError::htmlMessage() const
+{
+ QString message = errorMessage;
+ if (pos < 0 || pos > 50)
+ return message;
+ QString detail = text.left(50);
+ if (detail != text)
+ detail.append("...");
+ detail.replace(QChar::Space, " ");
+ message.append("
" + detail + "
");
+ for (int i = 0; i < pos; ++i)
+ message.append(" ");
+ message.append("^
");
+ return message;
+}
+
// --------------------------------------------------------------------
// Snippet:
// --------------------------------------------------------------------
@@ -189,7 +205,12 @@ QString Snippet::generateTip() const
{'<', "<"},
{'>', ">"}};
- ParsedSnippet parsedSnippet = Snippet::parse(m_content);
+ SnippetParseResult result = Snippet::parse(m_content);
+
+ if (Utils::holds_alternative(result))
+ return Utils::get(result).htmlMessage();
+ QTC_ASSERT(Utils::holds_alternative(result), return {});
+ auto parsedSnippet = Utils::get(result);
QString tip("");
int pos = 0;
@@ -215,7 +236,7 @@ QString Snippet::generateTip() const
return tip;
}
-ParsedSnippet Snippet::parse(const QString &snippet)
+SnippetParseResult Snippet::parse(const QString &snippet)
{
static UppercaseMangler ucMangler;
static LowercaseMangler lcMangler;
@@ -228,15 +249,10 @@ ParsedSnippet Snippet::parse(const QString &snippet)
= Utils::TemplateEngine::processText(Utils::globalMacroExpander(), snippet,
&errorMessage);
- result.success = errorMessage.isEmpty();
- if (!result.success) {
- result.text = snippet;
- result.errorMessage = errorMessage;
- return result;
- }
+ if (!errorMessage.isEmpty())
+ return {SnippetParseError{errorMessage, {}, -1}};
const int count = preprocessedSnippet.count();
- bool success = true;
int start = -1;
NameMangler *mangler = nullptr;
@@ -260,8 +276,9 @@ ParsedSnippet Snippet::parse(const QString &snippet)
}
if (mangler) {
- success = false;
- break;
+ return SnippetParseResult{SnippetParseError{tr("Expected delimiter after mangler id"),
+ preprocessedSnippet,
+ i}};
}
if (current == QLatin1Char(':') && start >= 0) {
@@ -272,8 +289,11 @@ ParsedSnippet Snippet::parse(const QString &snippet)
} else if (next == QLatin1Char('c')) {
mangler = &tcMangler;
} else {
- success = false;
- break;
+ return SnippetParseResult{
+ SnippetParseError{tr("Expected mangler id 'l'(lowercase), 'u'(uppercase), "
+ "or 'c'(titlecase) after colon"),
+ preprocessedSnippet,
+ i}};
}
++i;
continue;
@@ -288,17 +308,12 @@ ParsedSnippet Snippet::parse(const QString &snippet)
result.text.append(current);
}
- if (start >= 0)
- success = false;
-
- result.success = success;
-
- if (!success) {
- result.ranges.clear();
- result.text = preprocessedSnippet;
+ if (start >= 0) {
+ return SnippetParseResult{
+ SnippetParseError{tr("Missing closing variable delimiter"), result.text, start}};
}
- return result;
+ return SnippetParseResult(result);
}
#ifdef WITH_TESTS
@@ -418,17 +433,19 @@ void Internal::TextEditorPlugin::testSnippetParsing()
Q_ASSERT(ranges_start.count() == ranges_length.count()); // sanity check for the test data
Q_ASSERT(ranges_start.count() == ranges_mangler.count()); // sanity check for the test data
- ParsedSnippet result = Snippet::parse(input);
+ SnippetParseResult result = Snippet::parse(input);
+ QCOMPARE(Utils::holds_alternative(result), success);
- QCOMPARE(result.text, text);
- QCOMPARE(result.success, success);
- QCOMPARE(result.ranges.count(), ranges_start.count());
+ ParsedSnippet snippet = Utils::get(result);
+
+ QCOMPARE(snippet.text, text);
+ QCOMPARE(snippet.ranges.count(), ranges_start.count());
for (int i = 0; i < ranges_start.count(); ++i) {
- QCOMPARE(result.ranges.at(i).start, ranges_start.at(i));
- QCOMPARE(result.ranges.at(i).length, ranges_length.at(i));
+ QCOMPARE(snippet.ranges.at(i).start, ranges_start.at(i));
+ QCOMPARE(snippet.ranges.at(i).length, ranges_length.at(i));
Utils::Id id = NOMANGLER_ID;
- if (result.ranges.at(i).mangler)
- id = result.ranges.at(i).mangler->id();
+ if (snippet.ranges.at(i).mangler)
+ id = snippet.ranges.at(i).mangler->id();
QCOMPARE(id, ranges_mangler.at(i));
}
}
diff --git a/src/plugins/texteditor/snippets/snippet.h b/src/plugins/texteditor/snippets/snippet.h
index 40c152c4831..34e8ac51bc2 100644
--- a/src/plugins/texteditor/snippets/snippet.h
+++ b/src/plugins/texteditor/snippets/snippet.h
@@ -28,6 +28,7 @@
#include
#include
+#include
#include
#include
@@ -48,8 +49,6 @@ class TEXTEDITOR_EXPORT ParsedSnippet
{
public:
QString text;
- QString errorMessage;
- bool success;
struct Range {
Range(int s, int l, NameMangler *m) : start(s), length(l), mangler(m) { }
int start;
@@ -59,8 +58,21 @@ public:
QList ranges;
};
+class TEXTEDITOR_EXPORT SnippetParseError
+{
+public:
+ QString errorMessage;
+ QString text;
+ int pos;
+
+ QString htmlMessage() const;
+};
+
+using SnippetParseResult = Utils::variant;
+
class TEXTEDITOR_EXPORT Snippet
{
+ Q_DECLARE_TR_FUNCTIONS(Snippet)
public:
explicit Snippet(const QString &groupId = QString(), const QString &id = QString());
~Snippet();
@@ -91,7 +103,7 @@ public:
static const QChar kVariableDelimiter;
static const QChar kEscapeChar;
- static ParsedSnippet parse(const QString &snippet);
+ static SnippetParseResult parse(const QString &snippet);
private:
bool m_isRemoved = false;
diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp
index 4a0862d69d5..81459f90cd2 100644
--- a/src/plugins/texteditor/texteditor.cpp
+++ b/src/plugins/texteditor/texteditor.cpp
@@ -2700,15 +2700,14 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
void TextEditorWidget::insertCodeSnippet(const QTextCursor &cursor_arg, const QString &snippet)
{
- ParsedSnippet data = Snippet::parse(snippet);
-
- if (!data.success) {
- QString message = QString::fromLatin1("Cannot parse snippet \"%1\".").arg(snippet);
- if (!data.errorMessage.isEmpty())
- message += QLatin1String("\nParse error: ") + data.errorMessage;
- QMessageBox::warning(this, QLatin1String("Snippet Parse Error"), message);
+ SnippetParseResult result = Snippet::parse(snippet);
+ if (Utils::holds_alternative(result)) {
+ const auto &error = Utils::get(result);
+ QMessageBox::warning(this, QLatin1String("Snippet Parse Error"), error.htmlMessage());
return;
}
+ QTC_ASSERT(Utils::holds_alternative(result), return);
+ ParsedSnippet data = Utils::get(result);
QTextCursor cursor = cursor_arg;
cursor.beginEditBlock();