forked from qt-creator/qt-creator
Snippets: Split error messages out of the parsed snippet
Change-Id: Ic5d6664c86405c558e8bb133b854521e4eaef58a Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -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("<br><code>" + detail + "<br>");
|
||||||
|
for (int i = 0; i < pos; ++i)
|
||||||
|
message.append(" ");
|
||||||
|
message.append("^</code>");
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
// Snippet:
|
// 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<SnippetParseError>(result))
|
||||||
|
return Utils::get<SnippetParseError>(result).htmlMessage();
|
||||||
|
QTC_ASSERT(Utils::holds_alternative<ParsedSnippet>(result), return {});
|
||||||
|
auto parsedSnippet = Utils::get<ParsedSnippet>(result);
|
||||||
|
|
||||||
QString tip("<nobr>");
|
QString tip("<nobr>");
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
@@ -215,7 +236,7 @@ QString Snippet::generateTip() const
|
|||||||
return tip;
|
return tip;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParsedSnippet Snippet::parse(const QString &snippet)
|
SnippetParseResult Snippet::parse(const QString &snippet)
|
||||||
{
|
{
|
||||||
static UppercaseMangler ucMangler;
|
static UppercaseMangler ucMangler;
|
||||||
static LowercaseMangler lcMangler;
|
static LowercaseMangler lcMangler;
|
||||||
@@ -228,15 +249,10 @@ ParsedSnippet Snippet::parse(const QString &snippet)
|
|||||||
= Utils::TemplateEngine::processText(Utils::globalMacroExpander(), snippet,
|
= Utils::TemplateEngine::processText(Utils::globalMacroExpander(), snippet,
|
||||||
&errorMessage);
|
&errorMessage);
|
||||||
|
|
||||||
result.success = errorMessage.isEmpty();
|
if (!errorMessage.isEmpty())
|
||||||
if (!result.success) {
|
return {SnippetParseError{errorMessage, {}, -1}};
|
||||||
result.text = snippet;
|
|
||||||
result.errorMessage = errorMessage;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int count = preprocessedSnippet.count();
|
const int count = preprocessedSnippet.count();
|
||||||
bool success = true;
|
|
||||||
int start = -1;
|
int start = -1;
|
||||||
NameMangler *mangler = nullptr;
|
NameMangler *mangler = nullptr;
|
||||||
|
|
||||||
@@ -260,8 +276,9 @@ ParsedSnippet Snippet::parse(const QString &snippet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mangler) {
|
if (mangler) {
|
||||||
success = false;
|
return SnippetParseResult{SnippetParseError{tr("Expected delimiter after mangler id"),
|
||||||
break;
|
preprocessedSnippet,
|
||||||
|
i}};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current == QLatin1Char(':') && start >= 0) {
|
if (current == QLatin1Char(':') && start >= 0) {
|
||||||
@@ -272,8 +289,11 @@ ParsedSnippet Snippet::parse(const QString &snippet)
|
|||||||
} else if (next == QLatin1Char('c')) {
|
} else if (next == QLatin1Char('c')) {
|
||||||
mangler = &tcMangler;
|
mangler = &tcMangler;
|
||||||
} else {
|
} else {
|
||||||
success = false;
|
return SnippetParseResult{
|
||||||
break;
|
SnippetParseError{tr("Expected mangler id 'l'(lowercase), 'u'(uppercase), "
|
||||||
|
"or 'c'(titlecase) after colon"),
|
||||||
|
preprocessedSnippet,
|
||||||
|
i}};
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
continue;
|
continue;
|
||||||
@@ -288,17 +308,12 @@ ParsedSnippet Snippet::parse(const QString &snippet)
|
|||||||
result.text.append(current);
|
result.text.append(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start >= 0)
|
if (start >= 0) {
|
||||||
success = false;
|
return SnippetParseResult{
|
||||||
|
SnippetParseError{tr("Missing closing variable delimiter"), result.text, start}};
|
||||||
result.success = success;
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
result.ranges.clear();
|
|
||||||
result.text = preprocessedSnippet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return SnippetParseResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_TESTS
|
#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_length.count()); // sanity check for the test data
|
||||||
Q_ASSERT(ranges_start.count() == ranges_mangler.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<ParsedSnippet>(result), success);
|
||||||
|
|
||||||
QCOMPARE(result.text, text);
|
ParsedSnippet snippet = Utils::get<ParsedSnippet>(result);
|
||||||
QCOMPARE(result.success, success);
|
|
||||||
QCOMPARE(result.ranges.count(), ranges_start.count());
|
QCOMPARE(snippet.text, text);
|
||||||
|
QCOMPARE(snippet.ranges.count(), ranges_start.count());
|
||||||
for (int i = 0; i < ranges_start.count(); ++i) {
|
for (int i = 0; i < ranges_start.count(); ++i) {
|
||||||
QCOMPARE(result.ranges.at(i).start, ranges_start.at(i));
|
QCOMPARE(snippet.ranges.at(i).start, ranges_start.at(i));
|
||||||
QCOMPARE(result.ranges.at(i).length, ranges_length.at(i));
|
QCOMPARE(snippet.ranges.at(i).length, ranges_length.at(i));
|
||||||
Utils::Id id = NOMANGLER_ID;
|
Utils::Id id = NOMANGLER_ID;
|
||||||
if (result.ranges.at(i).mangler)
|
if (snippet.ranges.at(i).mangler)
|
||||||
id = result.ranges.at(i).mangler->id();
|
id = snippet.ranges.at(i).mangler->id();
|
||||||
QCOMPARE(id, ranges_mangler.at(i));
|
QCOMPARE(id, ranges_mangler.at(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include <texteditor/texteditor_global.h>
|
#include <texteditor/texteditor_global.h>
|
||||||
|
|
||||||
#include <utils/id.h>
|
#include <utils/id.h>
|
||||||
|
#include <utils/variant.h>
|
||||||
|
|
||||||
#include <QChar>
|
#include <QChar>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
@@ -48,8 +49,6 @@ class TEXTEDITOR_EXPORT ParsedSnippet
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QString text;
|
QString text;
|
||||||
QString errorMessage;
|
|
||||||
bool success;
|
|
||||||
struct Range {
|
struct Range {
|
||||||
Range(int s, int l, NameMangler *m) : start(s), length(l), mangler(m) { }
|
Range(int s, int l, NameMangler *m) : start(s), length(l), mangler(m) { }
|
||||||
int start;
|
int start;
|
||||||
@@ -59,8 +58,21 @@ public:
|
|||||||
QList<Range> ranges;
|
QList<Range> ranges;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TEXTEDITOR_EXPORT SnippetParseError
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QString errorMessage;
|
||||||
|
QString text;
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
QString htmlMessage() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
using SnippetParseResult = Utils::variant<ParsedSnippet, SnippetParseError>;
|
||||||
|
|
||||||
class TEXTEDITOR_EXPORT Snippet
|
class TEXTEDITOR_EXPORT Snippet
|
||||||
{
|
{
|
||||||
|
Q_DECLARE_TR_FUNCTIONS(Snippet)
|
||||||
public:
|
public:
|
||||||
explicit Snippet(const QString &groupId = QString(), const QString &id = QString());
|
explicit Snippet(const QString &groupId = QString(), const QString &id = QString());
|
||||||
~Snippet();
|
~Snippet();
|
||||||
@@ -91,7 +103,7 @@ public:
|
|||||||
static const QChar kVariableDelimiter;
|
static const QChar kVariableDelimiter;
|
||||||
static const QChar kEscapeChar;
|
static const QChar kEscapeChar;
|
||||||
|
|
||||||
static ParsedSnippet parse(const QString &snippet);
|
static SnippetParseResult parse(const QString &snippet);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_isRemoved = false;
|
bool m_isRemoved = false;
|
||||||
|
@@ -2700,15 +2700,14 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
|||||||
|
|
||||||
void TextEditorWidget::insertCodeSnippet(const QTextCursor &cursor_arg, const QString &snippet)
|
void TextEditorWidget::insertCodeSnippet(const QTextCursor &cursor_arg, const QString &snippet)
|
||||||
{
|
{
|
||||||
ParsedSnippet data = Snippet::parse(snippet);
|
SnippetParseResult result = Snippet::parse(snippet);
|
||||||
|
if (Utils::holds_alternative<SnippetParseError>(result)) {
|
||||||
if (!data.success) {
|
const auto &error = Utils::get<SnippetParseError>(result);
|
||||||
QString message = QString::fromLatin1("Cannot parse snippet \"%1\".").arg(snippet);
|
QMessageBox::warning(this, QLatin1String("Snippet Parse Error"), error.htmlMessage());
|
||||||
if (!data.errorMessage.isEmpty())
|
|
||||||
message += QLatin1String("\nParse error: ") + data.errorMessage;
|
|
||||||
QMessageBox::warning(this, QLatin1String("Snippet Parse Error"), message);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
QTC_ASSERT(Utils::holds_alternative<ParsedSnippet>(result), return);
|
||||||
|
ParsedSnippet data = Utils::get<ParsedSnippet>(result);
|
||||||
|
|
||||||
QTextCursor cursor = cursor_arg;
|
QTextCursor cursor = cursor_arg;
|
||||||
cursor.beginEditBlock();
|
cursor.beginEditBlock();
|
||||||
|
Reference in New Issue
Block a user