diff --git a/pglab/CodeEditor.cpp b/pglab/CodeEditor.cpp index 6c8c44d..64a1df8 100644 --- a/pglab/CodeEditor.cpp +++ b/pglab/CodeEditor.cpp @@ -17,6 +17,7 @@ CodeEditor::CodeEditor(QWidget *parent) connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateGutterAreaWidth(int))); connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateGutterArea(QRect,int))); connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine())); + connect(this, SIGNAL(textChanged()), this, SLOT(onTextChanged())); updateGutterAreaWidth(0); highlightCurrentLine(); @@ -31,7 +32,7 @@ int CodeEditor::gutterAreaWidth() ++digits; } - int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits; + int space = 3 + fontMetrics().width(QLatin1Char('9')) * (digits + 2); return space; } @@ -61,20 +62,55 @@ void CodeEditor::resizeEvent(QResizeEvent *e) } void CodeEditor::highlightCurrentLine() +{ + QTextEdit::ExtraSelection selection; + QColor lineColor = QColor(Qt::yellow).lighter(160); + selection.format.setBackground(lineColor); + selection.format.setProperty(QTextFormat::FullWidthSelection, true); + selection.cursor = textCursor(); + selection.cursor.clearSelection(); + currentLine = selection; + + updateExtraSelections(); +} + +void CodeEditor::onTextChanged() +{ + clearErrorMarkers(); +} + +void CodeEditor::addErrorMarker(int position, int length) +{ + QTextEdit::ExtraSelection selection; + QColor lineColor = QColor(Qt::red).lighter(160); + selection.format.setBackground(lineColor); + selection.format.setFontItalic(true); + selection.cursor = textCursor(); + selection.cursor.setPosition(position); + int lineno = selection.cursor.blockNumber(); + errorLines.insert(lineno); + selection.cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, length); + errorMarkers.append(selection); + + update(); + + updateExtraSelections(); +} + +void CodeEditor::clearErrorMarkers() +{ + errorMarkers.clear(); + errorLines.clear(); + update(); + updateExtraSelections(); +} + +void CodeEditor::updateExtraSelections() { QList extraSelections; - - if (!isReadOnly()) { - QTextEdit::ExtraSelection selection; - - QColor lineColor = QColor(Qt::yellow).lighter(160); - - selection.format.setBackground(lineColor); - selection.format.setProperty(QTextFormat::FullWidthSelection, true); - selection.cursor = textCursor(); - selection.cursor.clearSelection(); - extraSelections.append(selection); - } + extraSelections.append(currentLine); + for (auto e : errorMarkers) + extraSelections.append(e); setExtraSelections(extraSelections); } @@ -102,6 +138,12 @@ void CodeEditor::gutterAreaPaintEvent(QPaintEvent *event) painter.setPen(Qt::black); painter.drawText(0, top, gutterArea->width(), fontMetrics().height(), Qt::AlignRight, number); + + if (errorLines.count(blockNumber) > 0) { + int s = fontMetrics().height() - 8; + painter.setBrush(QBrush(Qt::red)); + painter.drawEllipse(4, top + 4, s, s); + } } block = block.next(); diff --git a/pglab/CodeEditor.h b/pglab/CodeEditor.h index f2a86d4..62b97bb 100644 --- a/pglab/CodeEditor.h +++ b/pglab/CodeEditor.h @@ -2,6 +2,7 @@ #define CODEEDITOR_H #include +#include class CodeEditor : public QPlainTextEdit { @@ -12,6 +13,8 @@ public: void gutterAreaPaintEvent(QPaintEvent *event); int gutterAreaWidth(); + void addErrorMarker(int position, int length); + void clearErrorMarkers(); protected: void resizeEvent(QResizeEvent *event) override; @@ -23,9 +26,17 @@ private slots: void updateGutterAreaWidth(int newBlockCount); void highlightCurrentLine(); void updateGutterArea(const QRect &, int); + void onTextChanged(); private: QWidget *gutterArea; + + QTextEdit::ExtraSelection currentLine; + QList errorMarkers; + + std::set errorLines; + + void updateExtraSelections(); }; #endif // CODEEDITOR_H diff --git a/pglab/QueryTab.cpp b/pglab/QueryTab.cpp index 1e1c378..f489b79 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTab.cpp @@ -512,7 +512,9 @@ void QueryTab::query_ready(Expected> exp_res, qin // statusBar()->showMessage(tr("No tuples returned, possibly an error...")); // } ui->tabWidget->setCurrentWidget(ui->messageTab); - receiveNotice(dbres->diagDetails()); + auto details = dbres->diagDetails(); + markError(details); + receiveNotice(details); } } } @@ -526,6 +528,37 @@ void QueryTab::query_ready(Expected> exp_res, qin } } +void QueryTab::markError(const Pgsql::ErrorDetails &details) +{ + + if (details.statementPosition > 0) { + QTextCursor cursor = ui->queryEdit->textCursor(); + cursor.setPosition(details.statementPosition-1); + ui->queryEdit->setTextCursor(cursor); + + int length = 0; + if (details.state == "42703") { + int pos = details.messagePrimary.find('"'); + if (pos != std::string::npos) { + int pos2 = details.messagePrimary.find('"', pos+1); + if (pos2 != std::string::npos) { + length = pos2 - pos; + } + } + } + else if (details.state == "42P01") { + int pos = details.messagePrimary.find('"'); + if (pos != std::string::npos) { + int pos2 = details.messagePrimary.find('"', pos+1); + if (pos2 != std::string::npos) { + length = pos2 - pos; + } + } + } + ui->queryEdit->addErrorMarker(details.statementPosition-1, length); + } +} + void QueryTab::clearResult() { for (auto e : resultList) diff --git a/pglab/QueryTab.h b/pglab/QueryTab.h index 89bf7ff..5c3350e 100644 --- a/pglab/QueryTab.h +++ b/pglab/QueryTab.h @@ -15,6 +15,10 @@ namespace Ui { class QueryTab; } +namespace Pgsql { + class ErrorDetails ; +} + class QTableView; class QTabWidget; @@ -95,6 +99,7 @@ private: QTabWidget *getTabWidget(); void setTabCaption(const QString &caption, const QString &tooltip); void clearResult(); + void markError(const Pgsql::ErrorDetails &details); private slots: