From 9ba2d2758a71592a716da42e233587a715a0b073 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 8 Nov 2021 16:33:57 +0200 Subject: [PATCH] QmlDesigner: Adjust ComponentTextModifier offsets for whitespace change Whitespace change can also occur inside the subcomponent code when new nodes are added into subcomponent and the document is saved. Changed the text change handling to adjust for whitespace changes both before and inside the subcomponent code. The new handling is simpler and doesn't require subcomponent to have id to work. The downside is that non-whitespace changes before subcomponent code are no longer adjusted for, but that was just a hacky workaround for a small part of a much larger issue that needs to be tackled properly anyway (i.e. supporting arbitrary undo/redo/manual edits), so losing it is not a big deal. Fixes: QDS-5362 Change-Id: I1ca1084baf78709727b1b4726b4c034558063401 Reviewed-by: Thomas Hartmann --- .../model/componenttextmodifier.cpp | 67 ++++++++++--------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp b/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp index f9255225058..6aca50c4334 100644 --- a/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp +++ b/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp @@ -111,7 +111,8 @@ void ComponentTextModifier::commitGroup() { m_originalModifier->commitGroup(); - int textLength = m_originalModifier->text().length(); + m_originalText = m_originalModifier->text(); + int textLength = m_originalText.length(); m_componentEndOffset += (textLength - m_startLength); m_startLength = textLength; } @@ -157,40 +158,42 @@ void ComponentTextModifier::handleOriginalTextChanged() { // Update offsets when original text changes, if necessary - // Detect and adjust for removal/addition of unrelated text before the subcomponent code, - // as that can happen even without user editing the text (e.g. whitespace removal at save time) - const QString currentText = m_originalModifier->text(); - if (m_originalText.left(m_componentStartOffset) != currentText.left(m_componentStartOffset)) { - // Subcomponent item id is the only reliable indicator for adjustment - const int idIndex = m_originalText.indexOf("id:", m_componentStartOffset); - if (idIndex != -1 && idIndex < m_componentEndOffset) { - int newLineIndex = m_originalText.indexOf('\n', idIndex); - if (newLineIndex != -1) { - const QString checkLine = m_originalText.mid(idIndex, newLineIndex - idIndex); - int lineIndex = currentText.indexOf(checkLine); - if (lineIndex != -1) { - // Paranoia check - This shouldn't happen except when modifying text manually, - // but it's possible something was inserted between id and start - // of the component, which would throw off the calculation, so check that - // the first line is still correct even with new offset. - const int diff = idIndex - lineIndex; - newLineIndex = m_originalText.indexOf('\n', m_componentStartOffset); - if (newLineIndex != -1) { - const QString firstLine = m_originalText.mid(m_componentStartOffset, - newLineIndex - m_componentStartOffset); - const int newStart = m_componentStartOffset - diff; - if (firstLine == currentText.mid(newStart, firstLine.size())) { - m_componentEndOffset -= diff; - m_componentStartOffset = newStart; - m_originalText = currentText; - } - } - } - } + // Adjust for removal/addition of whitespace in the document + // Check that non-whitespace portion of the text is the same and count the whitespace diff + const int oldLen = m_originalText.size(); + const int newLen = currentText.size(); + int newSpace = 0; + int oldSpace = 0; + int newIdx = 0; + for (int oldIdx = 0; oldIdx < oldLen; ++oldIdx) { + const QChar oldChar = m_originalText[oldIdx]; + if (oldIdx == m_componentStartOffset) + m_componentStartOffset += newSpace - oldSpace; + if (oldIdx == m_componentEndOffset) { + m_componentEndOffset += newSpace - oldSpace; + break; + } + + while (newIdx < newLen && currentText[newIdx].isSpace()) { + ++newSpace; + ++newIdx; + } + + if (oldChar.isSpace()) { + ++oldSpace; + continue; + } + + if (currentText[newIdx] != oldChar) { + // Non-whitespace difference, we can't determine a valid offset in this case + // TODO: Needs proper handling to deal with undo/redo/arbitrary edits somehow (QDS-5392) + break; + } else { + ++newIdx; } } - + m_originalText = currentText; emit textChanged(); }