diff options
author | David Schulz <david.schulz@qt.io> | 2021-04-16 12:30:47 +0200 |
---|---|---|
committer | David Schulz <david.schulz@qt.io> | 2021-05-03 11:12:34 +0000 |
commit | a2dadb3d0bf4f8850cc0dacc34ddc58fd9f2ef35 (patch) | |
tree | 9655572acc562676c4de170fd987d2bff9dfac9b /src/plugins/texteditor/snippets/snippetoverlay.cpp | |
parent | 4890902abfb9d0063593091972a77d754bb60efc (diff) | |
download | qt-creator-a2dadb3d0bf4f8850cc0dacc34ddc58fd9f2ef35.tar.gz |
TextEditor: Snippet ranges refactoring
Parsed snippets are now reported in chunks of texts and variables. A
variable has a index that can be used to identify matching variables and
maybe a mangler that can be used to modify the variable when applying
the snippet.
This effictively moves the variable matching logic from the overlay to
the parser of the snippet, which is needed to implement the LSP snippet
parser.
Task-number: QTCREATORBUG-22406
Change-Id: I6999554c6c6d0f1887c98bf732473f01aa1f230c
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/plugins/texteditor/snippets/snippetoverlay.cpp')
-rw-r--r-- | src/plugins/texteditor/snippets/snippetoverlay.cpp | 158 |
1 files changed, 105 insertions, 53 deletions
diff --git a/src/plugins/texteditor/snippets/snippetoverlay.cpp b/src/plugins/texteditor/snippets/snippetoverlay.cpp index e80cf8cb94..f35c8b6aa9 100644 --- a/src/plugins/texteditor/snippets/snippetoverlay.cpp +++ b/src/plugins/texteditor/snippets/snippetoverlay.cpp @@ -25,87 +25,139 @@ #include "snippetoverlay.h" -#include "snippet.h" +#include <utils/algorithm.h> +#include <utils/qtcassert.h> namespace TextEditor { namespace Internal { - void SnippetOverlay::clear() { TextEditorOverlay::clear(); - m_equivalentSelections.clear(); - m_manglers.clear(); + m_selections.clear(); + m_variables.clear(); } -void SnippetOverlay::mapEquivalentSelections() +void SnippetOverlay::addSnippetSelection(const QTextCursor &cursor, + const QColor &color, + NameMangler *mangler, + int variableIndex) { - m_equivalentSelections.clear(); - m_equivalentSelections.resize(selections().size()); - - QMultiMap<QString, int> all; - for (int i = 0; i < selections().size(); ++i) - all.insert(selectionText(i).toLower(), i); - - const QList<QString> &uniqueKeys = all.uniqueKeys(); - foreach (const QString &key, uniqueKeys) { - QList<int> indexes; - const auto cAll = all; - QMultiMap<QString, int>::const_iterator lbit = cAll.lowerBound(key); - QMultiMap<QString, int>::const_iterator ubit = cAll.upperBound(key); - while (lbit != ubit) { - indexes.append(lbit.value()); - ++lbit; - } - - foreach (int index, indexes) - m_equivalentSelections[index] = indexes; - } + m_variables[variableIndex] << selections().size(); + SnippetSelection selection; + selection.variableIndex = variableIndex; + selection.mangler = mangler; + m_selections << selection; + addOverlaySelection(cursor, color, color, TextEditorOverlay::ExpandBegin); } void SnippetOverlay::updateEquivalentSelections(const QTextCursor &cursor) { - int selectionIndex = selectionIndexForCursor(cursor); - if (selectionIndex == -1) + const int ¤tIndex = indexForCursor(cursor); + if (currentIndex < 0) return; - - const QString ¤tText = selectionText(selectionIndex); - const QList<int> &equivalents = m_equivalentSelections.at(selectionIndex); - foreach (int i, equivalents) { - if (i == selectionIndex) + const QString ¤tText = cursorForIndex(currentIndex).selectedText(); + const QList<int> &equivalents = m_variables.value(m_selections[currentIndex].variableIndex); + for (int i : equivalents) { + if (i == currentIndex) continue; - const QString &equivalentText = selectionText(i); + QTextCursor cursor = cursorForIndex(i); + const QString &equivalentText = cursor.selectedText(); if (currentText != equivalentText) { - QTextCursor selectionCursor = assembleCursorForSelection(i); - selectionCursor.joinPreviousEditBlock(); - selectionCursor.removeSelectedText(); - selectionCursor.insertText(currentText); - selectionCursor.endEditBlock(); + cursor.joinPreviousEditBlock(); + cursor.insertText(currentText); + cursor.endEditBlock(); } } } -void SnippetOverlay::setNameMangler(const QList<NameMangler *> &manglers) +void SnippetOverlay::mangle() { - m_manglers = manglers; + for (int i = 0; i < m_selections.size(); ++i) { + if (NameMangler *mangler = m_selections[i].mangler) { + QTextCursor cursor = cursorForIndex(i); + const QString current = cursor.selectedText(); + const QString result = mangler->mangle(current); + if (result != current) { + cursor.joinPreviousEditBlock(); + cursor.insertText(result); + cursor.endEditBlock(); + } + } + } } -void SnippetOverlay::mangle() +bool SnippetOverlay::hasCursorInSelection(const QTextCursor &cursor) const { - for (int i = 0; i < m_manglers.count(); ++i) { - if (!m_manglers.at(i)) - continue; + return indexForCursor(cursor) >= 0; +} + +QTextCursor SnippetOverlay::nextSelectionCursor(const QTextCursor &cursor) const +{ + const QList<OverlaySelection> selections = TextEditorOverlay::selections(); + if (selections.isEmpty()) + return {}; + const SnippetSelection ¤tSelection = selectionForCursor(cursor); + if (currentSelection.variableIndex >= 0) { + int nextVariableIndex = currentSelection.variableIndex + 1; + if (nextVariableIndex >= m_variables.size()) + nextVariableIndex = 0; - const QString current = selectionText(i); - const QString result = m_manglers.at(i)->mangle(current); - if (result != current) { - QTextCursor selectionCursor = assembleCursorForSelection(i); - selectionCursor.joinPreviousEditBlock(); - selectionCursor.removeSelectedText(); - selectionCursor.insertText(result); - selectionCursor.endEditBlock(); + for (int selectionIndex : m_variables[nextVariableIndex]) { + if (selections[selectionIndex].m_cursor_begin.position() > cursor.position()) + return cursorForIndex(selectionIndex); } + return cursorForIndex(m_variables[nextVariableIndex].first()); } + // currently not over a variable simply select the next available one + for (const OverlaySelection &candidate : selections) { + if (candidate.m_cursor_begin.position() > cursor.position()) + return cursorForSelection(candidate); + } + return cursorForSelection(selections.first()); +} + +QTextCursor SnippetOverlay::previousSelectionCursor(const QTextCursor &cursor) const +{ + const QList<OverlaySelection> selections = TextEditorOverlay::selections(); + if (selections.isEmpty()) + return {}; + const SnippetSelection ¤tSelection = selectionForCursor(cursor); + if (currentSelection.variableIndex >= 0) { + int previousVariableIndex = currentSelection.variableIndex - 1; + if (previousVariableIndex < 0) + previousVariableIndex = m_variables.size(); + + auto equivalents = m_variables[previousVariableIndex].toStdList(); + equivalents.reverse(); + for (int selectionIndex : equivalents) { + if (selections[selectionIndex].m_cursor_end.position() < cursor.position()) + return cursorForIndex(selectionIndex); + } + return cursorForIndex(m_variables[previousVariableIndex].last()); + } + // currently not over a variable simply select the previous available one + auto reverse = selections.toStdList(); + reverse.reverse(); + for (const OverlaySelection &candidate : reverse) { + if (candidate.m_cursor_end.position() < cursor.position()) + return cursorForSelection(candidate); + } + return cursorForSelection(selections.last()); +} + +int SnippetOverlay::indexForCursor(const QTextCursor &cursor) const +{ + return Utils::indexOf(selections(), + [pos = cursor.position()](const OverlaySelection &selection) { + return selection.m_cursor_begin.position() <= pos + && selection.m_cursor_end.position() >= pos; + }); +} + +SnippetOverlay::SnippetSelection SnippetOverlay::selectionForCursor(const QTextCursor &cursor) const +{ + return m_selections.value(indexForCursor(cursor)); } } // namespace Internal |