forked from qt-creator/qt-creator
QmlDesigner: Add function to locate import insertion point in QML text
This patch introduces `find_import_location`, which determines the appropriate location to insert a new `import` statement in a QML file. It scans the header section of the file, checks for existing imports, and avoids inserting duplicates when the target import already exists without an alias. The function returns an iterator pointing to the correct insertion point. Change-Id: If1c55da7e56066b5395cf47f589e1e3566c119c6 Reviewed-by: Henning Gründl <henning.gruendl@qt.io>
This commit is contained in:
@@ -18,6 +18,7 @@ add_qtc_library(QmlDesignerUtils STATIC
|
|||||||
version.cpp version.h
|
version.cpp version.h
|
||||||
maputils.h
|
maputils.h
|
||||||
stringutils.cpp stringutils.h
|
stringutils.cpp stringutils.h
|
||||||
|
importutils.cpp importutils.h
|
||||||
)
|
)
|
||||||
|
|
||||||
extend_qtc_library(QmlDesignerUtils
|
extend_qtc_library(QmlDesignerUtils
|
||||||
|
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (C) 2025 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "importutils.h"
|
||||||
|
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline constexpr bool std::ranges::enable_borrowed_range<QStringView> = true;
|
||||||
|
template<>
|
||||||
|
inline constexpr bool std::ranges::enable_view<QStringView> = true;
|
||||||
|
|
||||||
|
namespace QmlDesigner::ImportUtils {
|
||||||
|
|
||||||
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
|
std::optional<QStringView::iterator> find_import_location(QStringView text, QStringView directory)
|
||||||
|
{
|
||||||
|
const auto begin = text.begin();
|
||||||
|
const auto headerEnd = std::ranges::find(text, u'{');
|
||||||
|
QStringView header = {begin, headerEnd};
|
||||||
|
QStringView import{u"import"};
|
||||||
|
|
||||||
|
auto importRange = std::ranges::search(header.rbegin(),
|
||||||
|
header.rend(),
|
||||||
|
import.rbegin(),
|
||||||
|
import.rend());
|
||||||
|
|
||||||
|
if (importRange.empty())
|
||||||
|
return {begin};
|
||||||
|
|
||||||
|
auto endLine = std::ranges::find(importRange.begin().base(), headerEnd, u'\n');
|
||||||
|
|
||||||
|
QRegularExpression regex{uR"(^import\s+")"_s + directory + uR"("\s+(?!as))"_s};
|
||||||
|
|
||||||
|
if (regex.matchView({begin, endLine}).hasMatch())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (endLine == text.end())
|
||||||
|
return {text.end()};
|
||||||
|
|
||||||
|
return std::make_optional<QStringView::iterator>(std::ranges::next(endLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner::ImportUtils
|
16
src/plugins/qmldesigner/libs/qmldesignerutils/importutils.h
Normal file
16
src/plugins/qmldesigner/libs/qmldesignerutils/importutils.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (C) 2025 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qmldesignerutils_global.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <QStringView>
|
||||||
|
|
||||||
|
namespace QmlDesigner::ImportUtils {
|
||||||
|
|
||||||
|
QMLDESIGNERUTILS_EXPORT std::optional<QStringView::iterator> find_import_location(QStringView text,
|
||||||
|
QStringView directory);
|
||||||
|
|
||||||
|
} // namespace QmlDesigner::ImportUtils
|
@@ -4,4 +4,5 @@ extend_qtc_test(unittest
|
|||||||
SOURCES
|
SOURCES
|
||||||
version-test.cpp
|
version-test.cpp
|
||||||
stringutils-test.cpp
|
stringutils-test.cpp
|
||||||
|
importutils-test.cpp
|
||||||
)
|
)
|
||||||
|
@@ -0,0 +1,89 @@
|
|||||||
|
// Copyright (C) 2025 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include <googletest.h>
|
||||||
|
|
||||||
|
#include <qmldesignerutils/importutils.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace Qt::StringLiterals;
|
||||||
|
using QmlDesigner::ImportUtils::find_import_location;
|
||||||
|
|
||||||
|
TEST(ImportUtils, begin_for_no_imports)
|
||||||
|
{
|
||||||
|
auto content = QStringView{uR"("Item {})"};
|
||||||
|
QStringView directory = u"foo";
|
||||||
|
|
||||||
|
auto found = find_import_location(content, directory);
|
||||||
|
|
||||||
|
ASSERT_THAT(found, content.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImportUtils, begin_for_imports_after_last_import)
|
||||||
|
{
|
||||||
|
auto content = QStringView{u"import foo\n"
|
||||||
|
u"import bar\n"
|
||||||
|
u"\n"
|
||||||
|
u"Item {}\n"};
|
||||||
|
QStringView directory = u"foo";
|
||||||
|
|
||||||
|
auto found = find_import_location(content, directory);
|
||||||
|
|
||||||
|
QStringView rest{*found, content.end()};
|
||||||
|
ASSERT_THAT(rest, u"\nItem {}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImportUtils, skip_already_existing_directory_import)
|
||||||
|
{
|
||||||
|
auto content = QStringView{u"import \"foo\"\n"
|
||||||
|
u"import bar\n"
|
||||||
|
u"\n"
|
||||||
|
u"Item {}\n"};
|
||||||
|
QStringView directory = u"foo";
|
||||||
|
|
||||||
|
auto found = find_import_location(content, directory);
|
||||||
|
|
||||||
|
ASSERT_THAT(found, std::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImportUtils, dont_already_existing_directory_import_with_as)
|
||||||
|
{
|
||||||
|
auto content = QStringView{u"import \"foo\" as foo\n"
|
||||||
|
u"import bar\n"
|
||||||
|
u"\n"
|
||||||
|
u"Item {}\n"};
|
||||||
|
QStringView directory = u"foo";
|
||||||
|
|
||||||
|
auto found = find_import_location(content, directory);
|
||||||
|
|
||||||
|
QStringView rest{*found, content.end()};
|
||||||
|
ASSERT_THAT(rest, u"\nItem {}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImportUtils, ignore_import_properties)
|
||||||
|
{
|
||||||
|
auto content = QStringView{u"import foo\n"
|
||||||
|
u"import bar\n"
|
||||||
|
u"\n"
|
||||||
|
u"Item { import :}\n"};
|
||||||
|
QStringView directory = u"foo";
|
||||||
|
|
||||||
|
auto found = find_import_location(content, directory);
|
||||||
|
|
||||||
|
QStringView rest{*found, content.end()};
|
||||||
|
ASSERT_THAT(rest, u"\nItem { import :}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImportUtils, handle_nothing_after_import)
|
||||||
|
{
|
||||||
|
auto content = QStringView{u"import foo\n"
|
||||||
|
u"import bar"};
|
||||||
|
QStringView directory = u"foo";
|
||||||
|
|
||||||
|
auto found = find_import_location(content, directory);
|
||||||
|
|
||||||
|
ASSERT_THAT(found, content.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
Reference in New Issue
Block a user