Skip to content

Commit 7b7bf07

Browse files
committed
Merge branch 'language-server'
2 parents e5d668c + cc3d6a3 commit 7b7bf07

File tree

6 files changed

+186
-10
lines changed

6 files changed

+186
-10
lines changed

.github/workflows/build_test.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
name: "CI: Build Test"
22

3-
on: [push, pull_request]
3+
on:
4+
push:
5+
paths-ignore:
6+
- '*.md'
7+
- '*/*.md'
8+
- '*/*/*.md'
9+
pull_request:
10+
paths-ignore:
11+
- '*.md'
12+
- '*/*.md'
13+
- '*/*/*.md'
414

515
env:
616
CMAKE_VERSION: 3.17.1

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ set(CMAKE_CXX_STANDARD 11)
66
option(BUILD_EXAMPLE "Example building required" Off)
77

88
if (${BUILD_EXAMPLE})
9-
message(STATUS "QCodeEditor example will be built.")
10-
add_subdirectory(example)
9+
message(STATUS "QCodeEditor example will be built.")
10+
add_subdirectory(example)
1111
endif()
1212

1313
set(RESOURCES_FILE

example/src/MainWindow.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,13 @@ void MainWindow::setupWidgets()
192192
m_codeEditor->setPlainText (m_codeSamples[0].second);
193193
m_codeEditor->setSyntaxStyle(m_styles[0].second);
194194
m_codeEditor->setCompleter (m_completers[0].second);
195-
m_codeEditor->setHighlighter(m_highlighters[0].second);
195+
m_codeEditor->setHighlighter(new QCXXHighlighter);
196+
197+
// m_codeEditor->squiggle(QCodeEditor::SeverityLevel::Warning, {3,2}, {13,5}, "unused variable");
198+
m_codeEditor->squiggle(QCodeEditor::SeverityLevel::Error, {7,0}, {8,0}, "Big error");
199+
200+
201+
//m_codeEditor->clearSquiggle();
196202

197203
QStringList list;
198204
// Code samples

include/internal/QCodeEditor.hpp

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
// Qt
44
#include <QTextEdit> // Required for inheritance
55

6+
// Standard
7+
#include <set>
8+
69
class QCompleter;
710
class QLineNumberArea;
811
class QSyntaxStyle;
@@ -17,6 +20,17 @@ class QCodeEditor : public QTextEdit
1720
Q_OBJECT
1821

1922
public:
23+
/**
24+
* @brief The SeverityLevel enum
25+
*/
26+
enum class SeverityLevel
27+
{
28+
Error,
29+
Warning,
30+
Information,
31+
Hint
32+
};
33+
2034
/**
2135
* @brief Constructor.
2236
* @param widget Pointer to parent widget.
@@ -111,6 +125,20 @@ class QCodeEditor : public QTextEdit
111125
*/
112126
QCompleter *completer() const;
113127

128+
/**
129+
* @brief squiggle Puts a underline squiggle under text ranges in Editor
130+
* @param level defines the color of the underline depending upon the severity
131+
* @param tooltipMessage The tooltip hover message to show when over selection.
132+
* @note QPair<int, int>: first -> Line number in 1-based indexing
133+
* second -> Character number in 0-based indexing
134+
*/
135+
void squiggle(SeverityLevel level, QPair<int, int>, QPair<int, int>, QString tooltipMessage);
136+
137+
/**
138+
* @brief clearSquiggle, Clears complete squiggle from editor
139+
*/
140+
void clearSquiggle();
141+
114142
public Q_SLOTS:
115143

116144
/**
@@ -226,6 +254,11 @@ class QCodeEditor : public QTextEdit
226254
*/
227255
void focusInEvent(QFocusEvent *e) override;
228256

257+
/**
258+
* @brief Method for tooltip generation
259+
*/
260+
bool event(QEvent *e) override;
261+
229262
private:
230263
/**
231264
* @brief Method for initializing default
@@ -300,6 +333,21 @@ class QCodeEditor : public QTextEdit
300333
*/
301334
void addInEachLineOfSelection(const QRegularExpression &regex, const QString &str);
302335

336+
/**
337+
* @brief The SquiggleInformation struct, Line number will be index of vector+1;
338+
*/
339+
struct SquiggleInformation
340+
{
341+
SquiggleInformation(QPair<int, int> start, QPair<int, int> stop, QString text)
342+
: m_startPos(start), m_stopPos(stop), m_tooltipText(std::move(text))
343+
{
344+
}
345+
346+
QPair<int, int> m_startPos;
347+
QPair<int, int> m_stopPos;
348+
QString m_tooltipText;
349+
};
350+
303351
QStyleSyntaxHighlighter *m_highlighter;
304352
QSyntaxStyle *m_syntaxStyle;
305353
QLineNumberArea *m_lineNumberArea;
@@ -311,5 +359,7 @@ class QCodeEditor : public QTextEdit
311359
bool m_autoRemoveParentheses;
312360
QString m_tabReplace;
313361

314-
QList<QTextEdit::ExtraSelection> extra1, extra2;
362+
QList<QTextEdit::ExtraSelection> extra1, extra2, extra_squiggles;
363+
364+
std::vector<SquiggleInformation> m_squiggler;
315365
};

src/internal/QCodeEditor.cpp

Lines changed: 108 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <utility>
2+
13
// QCodeEditor
24
#include <QCXXHighlighter>
35
#include <QCodeEditor>
@@ -13,6 +15,7 @@
1315
#include <QAbstractTextDocumentLayout>
1416
#include <QCompleter>
1517
#include <QCursor>
18+
#include <QDebug>
1619
#include <QFontDatabase>
1720
#include <QMimeData>
1821
#include <QPaintEvent>
@@ -21,16 +24,18 @@
2124
#include <QTextBlock>
2225
#include <QTextCharFormat>
2326
#include <QTextStream>
27+
#include <QToolTip>
2428

2529
static QVector<QPair<QString, QString>> parentheses = {{"(", ")"}, {"{", "}"}, {"[", "]"}, {"\"", "\""}, {"'", "'"}};
2630

2731
QCodeEditor::QCodeEditor(QWidget *widget)
2832
: QTextEdit(widget), m_highlighter(nullptr), m_syntaxStyle(nullptr), m_lineNumberArea(new QLineNumberArea(this)),
2933
m_completer(nullptr), m_autoIndentation(true), m_autoParentheses(true), m_replaceTab(true),
30-
m_autoRemoveParentheses(true), m_tabReplace(QString(4, ' ')), extra1(), extra2()
34+
m_autoRemoveParentheses(true), m_tabReplace(QString(4, ' ')), extra1(), extra2(), extra_squiggles(), m_squiggler()
3135
{
3236
initFont();
3337
performConnections();
38+
setMouseTracking(true);
3439

3540
setSyntaxStyle(QSyntaxStyle::defaultStyle());
3641
}
@@ -147,7 +152,7 @@ void QCodeEditor::updateExtraSelection1()
147152
highlightCurrentLine();
148153
highlightParenthesis();
149154

150-
setExtraSelections(extra1 + extra2);
155+
setExtraSelections(extra1 + extra2 + extra_squiggles);
151156
}
152157

153158
void QCodeEditor::updateExtraSelection2()
@@ -156,7 +161,7 @@ void QCodeEditor::updateExtraSelection2()
156161

157162
highlightOccurrences();
158163

159-
setExtraSelections(extra1 + extra2);
164+
setExtraSelections(extra1 + extra2 + extra_squiggles);
160165
}
161166

162167
void QCodeEditor::indent()
@@ -421,7 +426,7 @@ void QCodeEditor::highlightParenthesis()
421426
selection.cursor = textCursor();
422427
selection.cursor.clearSelection();
423428
selection.cursor.movePosition(directionEnum, QTextCursor::MoveMode::MoveAnchor,
424-
std::abs(textCursor().position() - position));
429+
qAbs(textCursor().position() - position));
425430

426431
selection.cursor.movePosition(QTextCursor::MoveOperation::Right, QTextCursor::MoveMode::KeepAnchor, 1);
427432

@@ -473,7 +478,7 @@ void QCodeEditor::highlightOccurrences()
473478
{
474479
QTextEdit::ExtraSelection e;
475480
e.cursor = cursor;
476-
e.format.setFontUnderline(true);
481+
e.format.setBackground(m_syntaxStyle->getFormat("Selection").background());
477482
extra2.push_back(e);
478483
}
479484
cursor = doc->find(text, cursor, QTextDocument::FindWholeWords | QTextDocument::FindCaseSensitively);
@@ -820,6 +825,45 @@ void QCodeEditor::focusInEvent(QFocusEvent *e)
820825
QTextEdit::focusInEvent(e);
821826
}
822827

828+
bool QCodeEditor::event(QEvent *event)
829+
{
830+
if (event->type() == QEvent::ToolTip)
831+
{
832+
auto *helpEvent = dynamic_cast<QHelpEvent *>(event);
833+
auto point = helpEvent->pos();
834+
point.setX(point.x() - m_lineNumberArea->geometry().right());
835+
QTextCursor cursor = cursorForPosition(point);
836+
837+
auto lineNumber = cursor.blockNumber() + 1;
838+
839+
QTextCursor copyCursor(cursor);
840+
copyCursor.movePosition(QTextCursor::StartOfBlock);
841+
842+
auto blockPositionStart = cursor.positionInBlock() - copyCursor.positionInBlock();
843+
QPair<int, int> positionOfTooltip{lineNumber, blockPositionStart};
844+
845+
QString text;
846+
for (auto const &e : m_squiggler)
847+
{
848+
if (e.m_startPos <= positionOfTooltip && e.m_stopPos >= positionOfTooltip)
849+
{
850+
if (text.isEmpty())
851+
text = e.m_tooltipText;
852+
else
853+
text += "; " + e.m_tooltipText;
854+
}
855+
}
856+
857+
if (text.isEmpty())
858+
QToolTip::hideText();
859+
else
860+
QToolTip::showText(helpEvent->globalPos(), text);
861+
862+
return true;
863+
}
864+
return QTextEdit::event(event);
865+
}
866+
823867
void QCodeEditor::insertCompletion(QString s)
824868
{
825869
if (m_completer->widget() != this)
@@ -838,6 +882,65 @@ QCompleter *QCodeEditor::completer() const
838882
return m_completer;
839883
}
840884

885+
void QCodeEditor::squiggle(SeverityLevel level, QPair<int, int> start, QPair<int, int> stop, QString tooltipMessage)
886+
{
887+
if (stop < start)
888+
return;
889+
890+
SquiggleInformation info(start, stop, tooltipMessage);
891+
m_squiggler.push_back(info);
892+
893+
auto cursor = textCursor();
894+
895+
cursor.movePosition(QTextCursor::Start);
896+
cursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, start.first - 1);
897+
cursor.movePosition(QTextCursor::StartOfBlock);
898+
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, start.second);
899+
900+
if (stop.first > start.first)
901+
cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor, stop.first - start.first);
902+
903+
cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
904+
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, stop.second);
905+
906+
QTextCharFormat newcharfmt = currentCharFormat();
907+
newcharfmt.setFontUnderline(true);
908+
909+
switch (level)
910+
{
911+
case SeverityLevel::Error:
912+
newcharfmt.setUnderlineColor(m_syntaxStyle->getFormat("Error").underlineColor());
913+
newcharfmt.setUnderlineStyle(m_syntaxStyle->getFormat("Error").underlineStyle());
914+
break;
915+
case SeverityLevel::Warning:
916+
newcharfmt.setUnderlineColor(m_syntaxStyle->getFormat("Warning").underlineColor());
917+
newcharfmt.setUnderlineStyle(m_syntaxStyle->getFormat("Warning").underlineStyle());
918+
break;
919+
case SeverityLevel::Information:
920+
newcharfmt.setUnderlineColor(m_syntaxStyle->getFormat("Warning").underlineColor());
921+
newcharfmt.setUnderlineStyle(QTextCharFormat::DotLine);
922+
break;
923+
case SeverityLevel::Hint:
924+
newcharfmt.setUnderlineColor(m_syntaxStyle->getFormat("Text").foreground().color());
925+
newcharfmt.setUnderlineStyle(QTextCharFormat::DotLine);
926+
}
927+
928+
extra_squiggles.push_back({cursor, newcharfmt});
929+
930+
setExtraSelections(extra1 + extra2 + extra_squiggles);
931+
}
932+
933+
void QCodeEditor::clearSquiggle()
934+
{
935+
if (m_squiggler.empty())
936+
return;
937+
938+
m_squiggler.clear();
939+
extra_squiggles.clear();
940+
941+
setExtraSelections(extra1 + extra2);
942+
}
943+
841944
QChar QCodeEditor::charUnderCursor(int offset) const
842945
{
843946
auto block = textCursor().blockNumber();

src/internal/QSyntaxStyle.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ bool QSyntaxStyle::load(QString fl)
9797
format.setUnderlineStyle(s);
9898
}
9999

100+
if (attributes.hasAttribute("underlineColor"))
101+
{
102+
auto color = attributes.value("underlineColor");
103+
104+
format.setUnderlineColor(QColor(color.toString()));
105+
}
106+
100107
m_data[name.toString()] = format;
101108
}
102109
}

0 commit comments

Comments
 (0)