Editor: improve trailing space highlight performance

This commit is contained in:
Le Tan 2018-07-29 13:20:57 +08:00
parent 8679ffa051
commit 24a20e60e9
3 changed files with 93 additions and 34 deletions

View File

@ -21,7 +21,9 @@ VEditor::VEditor(VFile *p_file, QWidget *p_editor)
m_file(p_file), m_file(p_file),
m_editOps(nullptr), m_editOps(nullptr),
m_document(nullptr), m_document(nullptr),
m_enableInputMethod(true) m_enableInputMethod(true),
m_timeStamp(0),
m_trailingSpaceSelectionTS(0)
{ {
} }
@ -33,6 +35,7 @@ void VEditor::init()
{ {
const int labelTimerInterval = 500; const int labelTimerInterval = 500;
const int extraSelectionHighlightTimer = 500; const int extraSelectionHighlightTimer = 500;
const int trailingSpaceUpdateTimer = 500;
const int labelSize = 64; const int labelSize = 64;
m_document = documentW(); m_document = documentW();
@ -67,6 +70,12 @@ void VEditor::init()
QObject::connect(m_highlightTimer, &QTimer::timeout, QObject::connect(m_highlightTimer, &QTimer::timeout,
m_object, &VEditorObject::doHighlightExtraSelections); m_object, &VEditorObject::doHighlightExtraSelections);
m_trailingSpaceTimer = new QTimer(m_editor);
m_trailingSpaceTimer->setSingleShot(true);
m_trailingSpaceTimer->setInterval(trailingSpaceUpdateTimer);
QObject::connect(m_trailingSpaceTimer, &QTimer::timeout,
m_object, &VEditorObject::doUpdateTrailingSpaceHighlights);
m_extraSelections.resize((int)SelectionId::MaxSelection); m_extraSelections.resize((int)SelectionId::MaxSelection);
updateFontAndPalette(); updateFontAndPalette();
@ -80,18 +89,56 @@ void VEditor::labelTimerTimeout()
m_wrapLabel->hide(); m_wrapLabel->hide();
} }
void VEditor::updateTrailingSpaceHighlights()
{
if (m_trailingSpaceSelectionTS != m_timeStamp) {
m_trailingSpaceTimer->start();
} else {
highlightExtraSelections(false);
}
}
void VEditor::doHighlightExtraSelections() void VEditor::doHighlightExtraSelections()
{ {
int nrExtra = m_extraSelections.size(); int nrExtra = m_extraSelections.size();
Q_ASSERT(nrExtra == (int)SelectionId::MaxSelection); Q_ASSERT(nrExtra == (int)SelectionId::MaxSelection);
QList<QTextEdit::ExtraSelection> extraSelects; QList<QTextEdit::ExtraSelection> extraSelects;
for (int i = 0; i < nrExtra; ++i) { for (int i = 0; i < nrExtra; ++i) {
if (i == (int)SelectionId::TrailingSapce) {
filterTrailingSpace(extraSelects, m_extraSelections[i]);
} else {
extraSelects.append(m_extraSelections[i]); extraSelects.append(m_extraSelections[i]);
} }
}
setExtraSelectionsW(extraSelects); setExtraSelectionsW(extraSelects);
} }
void VEditor::doUpdateTrailingSpaceHighlights()
{
if (!g_config->getEnableTrailingSpaceHighlight()) {
QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::TrailingSapce];
if (!selects.isEmpty()) {
selects.clear();
highlightExtraSelections(true);
}
m_trailingSpaceSelectionTS = m_timeStamp;
return;
}
QTextCharFormat format;
format.setBackground(m_trailingSpaceColor);
QString text("\\s+$");
highlightTextAll(text,
FindOption::RegularExpression,
SelectionId::TrailingSapce,
format);
m_trailingSpaceSelectionTS = m_timeStamp;
highlightExtraSelections(true);
}
void VEditor::updateEditConfig() void VEditor::updateEditConfig()
{ {
m_config.update(QFontMetrics(m_editor->font())); m_config.update(QFontMetrics(m_editor->font()));
@ -109,13 +156,13 @@ void VEditor::highlightOnCursorPositionChanged()
QTextCursor cursor = textCursorW(); QTextCursor cursor = textCursorW();
if (lastCursor.isNull() || cursor.blockNumber() != lastCursor.blockNumber()) { if (lastCursor.isNull() || cursor.blockNumber() != lastCursor.blockNumber()) {
updateTrailingSpaceHighlights();
highlightCurrentLine(); highlightCurrentLine();
highlightTrailingSpace();
} else { } else {
// Judge whether we have trailing space at current line. // Judge whether we have trailing space at current line.
QString text = cursor.block().text(); QString text = cursor.block().text();
if (text.rbegin()->isSpace()) { if (text.rbegin()->isSpace()) {
highlightTrailingSpace(); updateTrailingSpaceHighlights();
} }
// Handle word-wrap in one block. // Handle word-wrap in one block.
@ -129,6 +176,11 @@ void VEditor::highlightOnCursorPositionChanged()
lastCursor = cursor; lastCursor = cursor;
} }
void VEditor::updateTimeStamp()
{
++m_timeStamp;
}
void VEditor::highlightCurrentLine() void VEditor::highlightCurrentLine()
{ {
QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::CurrentLine]; QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::CurrentLine];
@ -172,46 +224,25 @@ void VEditor::highlightCurrentLine()
highlightExtraSelections(true); highlightExtraSelections(true);
} }
// Do not highlight trailing spaces with current cursor right behind. void VEditor::filterTrailingSpace(QList<QTextEdit::ExtraSelection> &p_selects,
static void trailingSpaceFilter(VEditor *p_editor, QList<QTextEdit::ExtraSelection> &p_result) const QList<QTextEdit::ExtraSelection> &p_src)
{ {
QTextCursor cursor = p_editor->textCursorW(); QTextCursor cursor = textCursorW();
if (!cursor.atBlockEnd()) { if (!cursor.atBlockEnd()) {
p_selects.append(p_src);
return; return;
} }
int cursorPos = cursor.position(); int cursorPos = cursor.position();
for (auto it = p_result.begin(); it != p_result.end(); ++it) { for (auto it = p_src.begin(); it != p_src.end(); ++it) {
if (it->cursor.selectionEnd() == cursorPos) { if (it->cursor.selectionEnd() == cursorPos) {
p_result.erase(it); continue;
} else {
// There will be only one. p_selects.append(*it);
return;
} }
} }
} }
void VEditor::highlightTrailingSpace()
{
if (!g_config->getEnableTrailingSpaceHighlight()) {
QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::TrailingSapce];
if (!selects.isEmpty()) {
selects.clear();
highlightExtraSelections(true);
}
return;
}
QTextCharFormat format;
format.setBackground(m_trailingSpaceColor);
QString text("\\s+$");
highlightTextAll(text,
FindOption::RegularExpression,
SelectionId::TrailingSapce,
format,
trailingSpaceFilter);
}
void VEditor::highlightExtraSelections(bool p_now) void VEditor::highlightExtraSelections(bool p_now)
{ {
m_highlightTimer->stop(); m_highlightTimer->stop();

View File

@ -212,6 +212,8 @@ protected:
// Do some highlight on cursor position changed. // Do some highlight on cursor position changed.
void highlightOnCursorPositionChanged(); void highlightOnCursorPositionChanged();
void updateTimeStamp();
// Highlight selected text. // Highlight selected text.
void highlightSelectedWord(); void highlightSelectedWord();
@ -246,7 +248,9 @@ protected:
private: private:
friend class VEditorObject; friend class VEditorObject;
void highlightTrailingSpace(); // Filter out the trailing space right before cursor.
void filterTrailingSpace(QList<QTextEdit::ExtraSelection> &p_selects,
const QList<QTextEdit::ExtraSelection> &p_src);
// Trigger the timer to request highlight. // Trigger the timer to request highlight.
// If @p_now is true, stop the timer and highlight immediately. // If @p_now is true, stop the timer and highlight immediately.
@ -310,6 +314,9 @@ private:
// Timer for extra selections highlight. // Timer for extra selections highlight.
QTimer *m_highlightTimer; QTimer *m_highlightTimer;
// Timer for update trailing space.
QTimer *m_trailingSpaceTimer;
bool m_readyToScroll; bool m_readyToScroll;
bool m_mouseMoveScrolled; bool m_mouseMoveScrolled;
int m_oriMouseX; int m_oriMouseX;
@ -318,12 +325,20 @@ private:
// Whether enable input method. // Whether enable input method.
bool m_enableInputMethod; bool m_enableInputMethod;
TimeStamp m_timeStamp;
TimeStamp m_trailingSpaceSelectionTS;
// Functions for private slots. // Functions for private slots.
private: private:
void labelTimerTimeout(); void labelTimerTimeout();
// Do the real work to highlight extra selections. // Do the real work to highlight extra selections.
void doHighlightExtraSelections(); void doHighlightExtraSelections();
void updateTrailingSpaceHighlights();
void doUpdateTrailingSpaceHighlights();
}; };
@ -387,6 +402,11 @@ private slots:
m_editor->doHighlightExtraSelections(); m_editor->doHighlightExtraSelections();
} }
void doUpdateTrailingSpaceHighlights()
{
m_editor->doUpdateTrailingSpaceHighlights();
}
private: private:
friend class VEditor; friend class VEditor;

View File

@ -52,6 +52,14 @@ VMdEditor::VMdEditor(VFile *p_file,
highlightOnCursorPositionChanged(); highlightOnCursorPositionChanged();
}); });
connect(document(), &QTextDocument::contentsChange,
this, [this](int p_position, int p_charsRemoved, int p_charsAdded) {
Q_UNUSED(p_position);
if (p_charsAdded > 0 || p_charsAdded > 0) {
updateTimeStamp();
}
});
connect(this, &VTextEdit::selectionChanged, connect(this, &VTextEdit::selectionChanged,
this, [this]() { this, [this]() {
highlightSelectedWord(); highlightSelectedWord();