qmlls: Fix TextSynchronization

The offset from a given range was incorrectly calculated in
findBlockByNumber because textblocks that are used to obtain that
position were mistakenly ignoring the newline character. This were
leading us to setting a different text than what we actually typed.
Add an extra text block if the text ends with \n.

Add a manual test but exclude it from tst_qmlformat as it is not a valid
qml document.

Fixes: QTBUG-113725
Change-Id: Ifb1b4121fd8af46df7627d986303ae67e170e50c
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Semih Yavuz 2023-05-23 15:02:50 +02:00
parent dc30e3859f
commit 7a4175ff60
3 changed files with 62 additions and 8 deletions

View File

@ -68,22 +68,30 @@ void TextDocument::setPlainText(const QString &text)
m_content = text;
m_blocks.clear();
int blockStart = 0;
int blockNumber = 0;
while (blockStart < text.size()) {
const auto appendToBlocks = [this](int blockNumber, int start, int length) {
Block block;
block.textBlock.setBlockNumber(blockNumber++);
block.textBlock.setPosition(blockStart);
block.textBlock.setBlockNumber(blockNumber);
block.textBlock.setPosition(start);
block.textBlock.setDocument(this);
block.textBlock.setLength(length);
m_blocks.append(block);
};
int blockStart = 0;
int blockNumber = -1;
while (blockStart < text.size()) {
int blockEnd = text.indexOf(u'\n', blockStart) + 1;
if (blockEnd == 0)
blockEnd = text.size();
block.textBlock.setLength(blockEnd - blockStart);
m_blocks.append(block);
appendToBlocks(++blockNumber, blockStart, blockEnd - blockStart);
blockStart = blockEnd;
}
// Add an empty block if the text ends with \n. This is required for retrieving
// the actual line of the text editor if requested, for example, in findBlockByNumber.
// Consider a case with text aa\nbb\n\n. You are on 4th line of the text editor and even
// if it is an empty line, we introduce a text block for it to maybe use later.
if (text.endsWith(u'\n'))
appendToBlocks(++blockNumber, blockStart, 0);
}
bool TextDocument::isModified() const

View File

@ -87,6 +87,7 @@ void TestQmlformat::initTestCase()
m_excludedDirs << "doc/src/snippets/qtquick1/qtbinding";
m_excludedDirs << "doc/src/snippets/qtquick1/imports";
m_excludedDirs << "tests/manual/v4";
m_excludedDirs << "tests/manual/qmllsformatter";
m_excludedDirs << "tests/auto/qml/ecmascripttests";
m_excludedDirs << "tests/auto/qml/qmllint";

View File

@ -0,0 +1,45 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
// Start Test
// Open that test.qml file in a text editor that has a client for qmlls
////////////////////////////////////////////////////////////
// Test Case - 1
// Type the following line manually
import QtQml
Window {
}
// Then, execute "Format Document" in the text editor
// Expected Result
import QtQml
Window {
}
////////////////////////////////////////////////////////////
// Test Case - 2
// Type the following line manually
import QtQml
Window {
aa a: {
}
}
// Then, execute "Format Document" in the text editor
// Expected Result
import QtQml
Window {
aa: {
}
}