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:
David Schulz
2021-04-20 14:25:18 +02:00
parent d9862a767b
commit c8f8513c8d
3 changed files with 68 additions and 40 deletions

View File

@@ -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, "&nbsp;");
message.append("<br><code>" + detail + "<br>");
for (int i = 0; i < pos; ++i)
message.append("&nbsp;");
message.append("^</code>");
return message;
}
// --------------------------------------------------------------------
// Snippet:
// --------------------------------------------------------------------
@@ -189,7 +205,12 @@ QString Snippet::generateTip() const
{'<', "&lt;"},
{'>', "&gt;"}};
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>");
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<ParsedSnippet>(result), success);
QCOMPARE(result.text, text);
QCOMPARE(result.success, success);
QCOMPARE(result.ranges.count(), ranges_start.count());
ParsedSnippet snippet = Utils::get<ParsedSnippet>(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));
}
}

View File

@@ -28,6 +28,7 @@
#include <texteditor/texteditor_global.h>
#include <utils/id.h>
#include <utils/variant.h>
#include <QChar>
#include <QList>
@@ -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<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
{
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;

View File

@@ -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<SnippetParseError>(result)) {
const auto &error = Utils::get<SnippetParseError>(result);
QMessageBox::warning(this, QLatin1String("Snippet Parse Error"), error.htmlMessage());
return;
}
QTC_ASSERT(Utils::holds_alternative<ParsedSnippet>(result), return);
ParsedSnippet data = Utils::get<ParsedSnippet>(result);
QTextCursor cursor = cursor_arg;
cursor.beginEditBlock();