diff options
Diffstat (limited to 'src')
315 files changed, 6149 insertions, 2207 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 799d8ef68c..70dfa9b5f6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,8 +51,9 @@ endif() include(CMakeFindDependencyMacro) find_dependency(Qt5 ${IDE_QT_VERSION_MIN} - COMPONENTS Concurrent Core Gui Widgets Core5Compat Network PrintSupport Qml Quick QuickWidgets Sql REQUIRED + COMPONENTS Concurrent Core Gui Widgets Core5Compat Network PrintSupport Qml Sql REQUIRED ) +find_dependency(Qt5 COMPONENTS Quick QuickWidgets QUIET) if (NOT IDE_VERSION) include(\${CMAKE_CURRENT_LIST_DIR}/QtCreatorIDEBranding.cmake) diff --git a/src/libs/3rdparty/syntax-highlighting/.git-blame-ignore-revs b/src/libs/3rdparty/syntax-highlighting/.git-blame-ignore-revs new file mode 100644 index 0000000000..8b2ba6d3d5 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/.git-blame-ignore-revs @@ -0,0 +1,4 @@ +# clang-format +56ed6f3f5f505eb0dbffc630729d67c3fb510546 +#clang-tidy +0960472cc3f57831a97697a4ae0cd139e2cc5551 diff --git a/src/libs/3rdparty/syntax-highlighting/.gitignore b/src/libs/3rdparty/syntax-highlighting/.gitignore index 4d50e82c2d..a29428fe5e 100644 --- a/src/libs/3rdparty/syntax-highlighting/.gitignore +++ b/src/libs/3rdparty/syntax-highlighting/.gitignore @@ -9,6 +9,11 @@ callgrind.* heaptrack.* /build*/ *.unc-backup* -.clang-format -.cmake/ -*.code-workspace
\ No newline at end of file +/.clang-format +/.cmake/ +/*.code-workspace +/compile_commands.json +.clangd +.idea +/cmake-build* +.cache diff --git a/src/libs/3rdparty/syntax-highlighting/.gitlab-ci.yml b/src/libs/3rdparty/syntax-highlighting/.gitlab-ci.yml new file mode 100644 index 0000000000..8950fb6d61 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/.gitlab-ci.yml @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org> +# SPDX-License-Identifier: CC0-1.0 + +include: + - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml diff --git a/src/libs/3rdparty/syntax-highlighting/.kde-ci.yml b/src/libs/3rdparty/syntax-highlighting/.kde-ci.yml new file mode 100644 index 0000000000..cf1d3363f9 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/.kde-ci.yml @@ -0,0 +1,7 @@ +Dependencies: +- 'on': ['@all'] + 'require': + 'frameworks/extra-cmake-modules': '@same' + +Options: + test-before-installing: True diff --git a/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt index 8dc268071a..25f1af3573 100644 --- a/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt @@ -10,11 +10,12 @@ add_qtc_library(KSyntaxHighlighting SHARED PUBLIC_INCLUDES src/lib autogenerated/src/lib - DEFINES KSYNTAXHIGHLIGHTING_LIBRARY + DEFINES KF5SyntaxHighlighting_EXPORTS DEPENDS Qt5::Network Qt5::Widgets SOURCES autogenerated/src/lib/ksyntaxhighlighting_logging.cpp autogenerated/src/lib/ksyntaxhighlighting_logging.h autogenerated/ksyntaxhighlighting_version.h + autogenerated/src/lib/ksyntaxhighlighting_export.h data/themes/theme-data.qrc @@ -29,7 +30,6 @@ add_qtc_library(KSyntaxHighlighting SHARED src/lib/format.cpp src/lib/format.h src/lib/format_p.h src/lib/htmlhighlighter.cpp src/lib/htmlhighlighter.h src/lib/keywordlist.cpp src/lib/keywordlist_p.h - src/lib/ksyntaxhighlighting_export.h src/lib/matchresult_p.h src/lib/repository.cpp src/lib/repository.h src/lib/repository_p.h src/lib/rule.cpp src/lib/rule_p.h diff --git a/src/libs/3rdparty/syntax-highlighting/README.md b/src/libs/3rdparty/syntax-highlighting/README.md index 2acff73b18..2e668dd3da 100644 --- a/src/libs/3rdparty/syntax-highlighting/README.md +++ b/src/libs/3rdparty/syntax-highlighting/README.md @@ -23,6 +23,8 @@ It's meant as a building block for text editors as well as for simple highlighte text rendering (e.g. as HTML), supporting both integration with a custom editor as well as a ready-to-use QSyntaxHighlighter sub-class. +Besides a C++ API, a [QML API](@ref qml_api) is also provided. + ## Out of scope To not turn this into yet another text editor, the following things are considered @@ -46,7 +48,7 @@ in **data/syntax/** and have the **.xml** extension. Additional ones are picked up from the file system if present, so you can easily extend this by application-specific syntax definitions for example. -To install or test a syntax definiton file locally, place it in +To install or test a syntax definition file locally, place it in **org.kde.syntax-highlighting/syntax/**, which is located in your user directory. Usually it is: @@ -56,47 +58,56 @@ Usually it is: <td>$HOME/.local/share/org.kde.syntax-highlighting/syntax/</td> </tr> <tr> - <td>For <a href="https://flathub.org/apps/details/org.kde.kate">Kate's Flatpak package</a></td> - <td>$HOME/.var/app/org.kde.kate/data/org.kde.syntax-highlighting/syntax/</td> + <td>For Flatpak packages</td> + <td>$HOME/.var/app/<em>package-name</em>/data/org.kde.syntax-highlighting/syntax/</td> </tr> <tr> - <td>For <a href="https://snapcraft.io/kate">Kate's Snap package</a></td> - <td>$HOME/snap/kate/current/.local/share/org.kde.syntax-highlighting/syntax/</td> + <td>For Snap packages</a></td> + <td>$HOME/snap/<em>package-name</em>/current/.local/share/org.kde.syntax-highlighting/syntax/</td> </tr> <tr> <td>On Windows®</td> <td>%USERPROFILE%\AppData\Local\org.kde.syntax-highlighting\syntax\</td> </tr> + <tr> + <td>On macOS®</td> + <td>$HOME/Library/Application Support/org.kde.syntax-highlighting/syntax/</td> + </tr> </table> For more details, see ["The Highlight Definition XML Format" (Working with Syntax Highlighting, KDE Documentation)](https://docs.kde.org/?application=katepart&branch=trunk5&path=highlight.html#katehighlight-xml-format). -Also, in **data/schema/** there is a script to validate the syntax definiton XML +Also, in **data/schema/** there is a script to validate the syntax definition XML files. Use the command `validatehl.sh mySyntax.xml`. ## Color theme files -This library includes the color themes, the theme files use the **JSON** -format and are located in **data/themes/** with the **.theme** extension. +This library includes the color themes, which are documented +[here](https://docs.kde.org/?application=katepart&branch=trunk5&path=color-themes.html). +The color theme files use the JSON format and are located in **data/themes/** +with the **.theme** extension. Additional ones are also picked up from the file system if present, in the **org.kde.syntax-highlighting/themes/** folder of your user directory, -allowing you to easily add custom color theme files. -The location of **org.kde.syntax-highlighting/themes/** is the same +allowing you to easily add custom color theme files. This location is the same as shown in the table of the [previous section](#syntax-definition-files), replacing the **syntax** folder with **themes**. +For more details, see ["The Color Themes JSON Format" (Working with Color Themes, KDE Documentation)](https://docs.kde.org/?application=katepart&branch=trunk5&path=color-themes.html#color-themes-json). The [KTextEditor](https://api.kde.org/frameworks/ktexteditor/html/) library -(used by Kate, Kile and KDevelop, for example) provides -a user interface for editing and creating KSyntaxHighlighting color themes, including +(used by Kate, Kile and KDevelop, for example) provides a +[user interface](https://docs.kde.org/?application=katepart&branch=trunk5&path=color-themes.html#color-themes-gui) +for editing and creating KSyntaxHighlighting color themes, including a tool for exporting and importing the JSON theme files. + +Note that in KDE text editors, the KSyntaxHighlighting color themes are used +[since KDE Frameworks 5.75](https://kate-editor.org/post/2020/2020-09-13-kate-color-themes-5.75/), +released on October 10, 2020. Previously, Kate's color schemes +(KConfig based schema config) were used and are now deprecated. The tool **utils/schema-converter/** and the script **utils/kateschema_to_theme_converter.py** convert the old Kate schemas to KSyntaxHighlighting themes. -For more information, see: - -* [Kate - Color Themes with Frameworks 5.75 (Kate Editor Website)](https://kate-editor.org/post/2020/2020-09-13-kate-color-themes-5.75/) -* [Submit a KSyntaxHighlighting Color Theme (Kate Editor Website)](https://kate-editor.org/post/2020/2020-09-18-submit-a-ksyntaxhighlighting-color-theme/) +Also see ["Submit a KSyntaxHighlighting Color Theme" (Kate Editor Website)](https://kate-editor.org/post/2020/2020-09-18-submit-a-ksyntaxhighlighting-color-theme/). ## Build it diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/autogenerated.pri b/src/libs/3rdparty/syntax-highlighting/autogenerated/autogenerated.pri index aee620add9..1c540d45be 100644 --- a/src/libs/3rdparty/syntax-highlighting/autogenerated/autogenerated.pri +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/autogenerated.pri @@ -6,4 +6,5 @@ SOURCES += \ HEADERS += \ $$PWD/ksyntaxhighlighting_version.h \ - $$PWD/src/lib/ksyntaxhighlighting_logging.h + $$PWD/src/lib/ksyntaxhighlighting_logging.h \ + $$PWD/src/lib/ksyntaxhighlighting_export.h diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h b/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h index 32e5aa62a7..a8c5d74235 100644 --- a/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h @@ -3,10 +3,10 @@ #ifndef SyntaxHighlighting_VERSION_H #define SyntaxHighlighting_VERSION_H -#define SyntaxHighlighting_VERSION_STRING "5.80.0" +#define SyntaxHighlighting_VERSION_STRING "5.87.0" #define SyntaxHighlighting_VERSION_MAJOR 5 -#define SyntaxHighlighting_VERSION_MINOR 80 +#define SyntaxHighlighting_VERSION_MINOR 87 #define SyntaxHighlighting_VERSION_PATCH 0 -#define SyntaxHighlighting_VERSION ((5<<16)|(80<<8)|(0)) +#define SyntaxHighlighting_VERSION ((5<<16)|(87<<8)|(0)) #endif diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/WildcardMatcher b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/WildcardMatcher new file mode 100644 index 0000000000..ecea1b09bd --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/WildcardMatcher @@ -0,0 +1 @@ +#include "wildcardmatcher.h" diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h new file mode 100644 index 0000000000..1213499635 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h @@ -0,0 +1,218 @@ + +#ifndef KSYNTAXHIGHLIGHTING_EXPORT_H +#define KSYNTAXHIGHLIGHTING_EXPORT_H + +#include <QtGlobal> + +#ifdef KSYNTAXHIGHLIGHTING_STATIC_DEFINE +# define KSYNTAXHIGHLIGHTING_EXPORT +# define KSYNTAXHIGHLIGHTING_NO_EXPORT +#else +# ifndef KSYNTAXHIGHLIGHTING_EXPORT +# ifdef KF5SyntaxHighlighting_EXPORTS + /* We are building this library */ +# define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_EXPORT +# else + /* We are using this library */ +# define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_IMPORT +# endif +# endif + +# ifndef KSYNTAXHIGHLIGHTING_NO_EXPORT +# define KSYNTAXHIGHLIGHTING_NO_EXPORT +# endif +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DECL_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DECL_DEPRECATED __declspec(deprecated) +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_EXPORT +# define KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_NO_EXPORT +# define KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_NO_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef KSYNTAXHIGHLIGHTING_NO_DEPRECATED +# define KSYNTAXHIGHLIGHTING_NO_DEPRECATED +# endif +#endif + +#define KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_TEXT(text) __declspec(deprecated(text)) + +#define ECM_GENERATEEXPORTHEADER_VERSION_VALUE(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) + +/* Take any defaults from group settings */ +#if !defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED) && !defined(KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) +# ifdef KF_NO_DEPRECATED +# define KSYNTAXHIGHLIGHTING_NO_DEPRECATED +# elif defined(KF_DISABLE_DEPRECATED_BEFORE_AND_AT) +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT KF_DISABLE_DEPRECATED_BEFORE_AND_AT +# endif +#endif +#if !defined(KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) && defined(KF_DISABLE_DEPRECATED_BEFORE_AND_AT) +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT KF_DISABLE_DEPRECATED_BEFORE_AND_AT +#endif + +#if !defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS) && !defined(KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE) +# ifdef KF_NO_DEPRECATED_WARNINGS +# define KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS +# elif defined(KF_DEPRECATED_WARNINGS_SINCE) +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KF_DEPRECATED_WARNINGS_SINCE +# endif +#endif +#if !defined(KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE) && defined(KF_DEPRECATED_WARNINGS_SINCE) +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KF_DEPRECATED_WARNINGS_SINCE +#endif + +#if defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED) +# undef KSYNTAXHIGHLIGHTING_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_EXPORT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_NO_EXPORT +#elif defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS) +# define KSYNTAXHIGHLIGHTING_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_EXPORT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_NO_EXPORT +#else +# define KSYNTAXHIGHLIGHTING_DEPRECATED KSYNTAXHIGHLIGHTING_DECL_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_EXPORT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_NO_EXPORT +#endif + +/* No deprecated API had been removed from build */ +#define KSYNTAXHIGHLIGHTING_EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 + +#define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1 + +#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55700 +#endif +#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0 +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE +# ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT +# else +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55700 +# endif +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0 +#endif + +#ifdef KSYNTAXHIGHLIGHTING_DEPRECATED +# define KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(major, minor) (ECM_GENERATEEXPORTHEADER_VERSION_VALUE(major, minor, 0) > KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) +#else +# define KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(major, minor) 0 +#endif + +#if KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE >= 0x55700 +# define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_87(text) KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_TEXT(text) +#else +# define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_87(text) +#endif +#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5(minor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_##minor(text) +#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION(major, minor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_##major(minor, "Since "#major"."#minor". " text) +#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_##major(minor, "Since "#textmajor"."#textminor". " text) +// Not yet implemented for MSVC +#define KSYNTAXHIGHLIGHTING_ENUMERATOR_DEPRECATED_VERSION(major, minor, text) +#define KSYNTAXHIGHLIGHTING_ENUMERATOR_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) + +#endif /* KSYNTAXHIGHLIGHTING_EXPORT_H */ + + +#ifndef ECM_GENERATEEXPORTHEADER_KSYNTAXHIGHLIGHTING_EXPORT_H +#define ECM_GENERATEEXPORTHEADER_KSYNTAXHIGHLIGHTING_EXPORT_H + + +#define KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_TEXT(text) __declspec(deprecated(text)) + +#define ECM_GENERATEEXPORTHEADER_VERSION_VALUE(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) + +/* Take any defaults from group settings */ +#if !defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED) && !defined(KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) +# ifdef KF_NO_DEPRECATED +# define KSYNTAXHIGHLIGHTING_NO_DEPRECATED +# elif defined(KF_DISABLE_DEPRECATED_BEFORE_AND_AT) +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT KF_DISABLE_DEPRECATED_BEFORE_AND_AT +# endif +#endif +#if !defined(KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) && defined(KF_DISABLE_DEPRECATED_BEFORE_AND_AT) +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT KF_DISABLE_DEPRECATED_BEFORE_AND_AT +#endif + +#if !defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS) && !defined(KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE) +# ifdef KF_NO_DEPRECATED_WARNINGS +# define KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS +# elif defined(KF_DEPRECATED_WARNINGS_SINCE) +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KF_DEPRECATED_WARNINGS_SINCE +# endif +#endif +#if !defined(KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE) && defined(KF_DEPRECATED_WARNINGS_SINCE) +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KF_DEPRECATED_WARNINGS_SINCE +#endif + +#if defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED) +# undef KSYNTAXHIGHLIGHTING_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_EXPORT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_NO_EXPORT +#elif defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS) +# define KSYNTAXHIGHLIGHTING_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_EXPORT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_NO_EXPORT +#else +# define KSYNTAXHIGHLIGHTING_DEPRECATED KSYNTAXHIGHLIGHTING_DECL_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_EXPORT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_NO_EXPORT +#endif + +/* No deprecated API had been removed from build */ +#define KSYNTAXHIGHLIGHTING_EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 + +#define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1 + +#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55700 +#endif +#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0 +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE +# ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT +# else +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55700 +# endif +#endif + +#ifndef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0 +#endif + +#ifdef KSYNTAXHIGHLIGHTING_DEPRECATED +# define KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(major, minor) (ECM_GENERATEEXPORTHEADER_VERSION_VALUE(major, minor, 0) > KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) +#else +# define KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(major, minor) 0 +#endif + +#if KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE >= 0x55700 +# define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_87(text) KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_TEXT(text) +#else +# define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_87(text) +#endif +#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5(minor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_##minor(text) +#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION(major, minor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_##major(minor, "Since "#major"."#minor". " text) +#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_##major(minor, "Since "#textmajor"."#textminor". " text) +// Not yet implemented for MSVC +#define KSYNTAXHIGHLIGHTING_ENUMERATOR_DEPRECATED_VERSION(major, minor, text) +#define KSYNTAXHIGHLIGHTING_ENUMERATOR_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) + + +#endif /* ECM_GENERATEEXPORTHEADER_KSYNTAXHIGHLIGHTING_EXPORT_H */ diff --git a/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt index 8b923c4795..acc2429ec8 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt @@ -38,8 +38,11 @@ generate_syntax_definition(generate-doxygenlua.pl doxygenlua.xml doxygen.xml) file(GLOB src_defs "${CMAKE_CURRENT_SOURCE_DIR}/syntax/*.xml") set(defs ${src_defs} ${gen_defs}) +# object library to make cross-folder dependencies work +add_library(SyntaxHighlightingData OBJECT) + # theme data resource -qt5_add_resources(themes_QRC ${CMAKE_CURRENT_SOURCE_DIR}/themes/theme-data.qrc) +target_sources(SyntaxHighlightingData PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/themes/theme-data.qrc) # do we want syntax files bundled in the library? if (QRC_SYNTAX) @@ -66,14 +69,10 @@ if (QRC_SYNTAX) ) set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" PROPERTIES SKIP_AUTOMOC ON) - # object library to make cross-folder dependencies work, themes + syntax files - add_library(SyntaxHighlightingData OBJECT ${themes_QRC} ${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp) + target_sources(SyntaxHighlightingData PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp) else() # install the syntax files as normal files into the prefix install (FILES ${defs} DESTINATION ${KDE_INSTALL_DATADIR}/org.kde.syntax-highlighting/syntax) - - # object library to make cross-folder dependencies work, only themes - add_library(SyntaxHighlightingData OBJECT ${themes_QRC}) endif() # set PIC to allow use in static and shared libs diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl index 8e8d37d266..1c1a3da4ba 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl @@ -22,7 +22,7 @@ <language name="CMake" - version="31" + version="<!--{version}-->" kateversion="5.0" section="Other" extensions="CMakeLists.txt;*.cmake;*.cmake.in" diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml index 7d4f113cba..ab26c2153b 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml @@ -1,3 +1,5 @@ +version: 34 + global-properties: - ALLOW_DUPLICATE_CUSTOM_TARGETS - AUTOGEN_SOURCE_GROUP @@ -56,6 +58,7 @@ directory-properties: - DEFINITIONS - EXCLUDE_FROM_ALL - IMPLICIT_DEPENDS_INCLUDE_TRANSFORM + - IMPORTED_TARGETS # Since 3.21 - INCLUDE_DIRECTORIES - INCLUDE_REGULAR_EXPRESSION - INTERPROCEDURAL_OPTIMIZATION_<CONFIG> @@ -172,6 +175,7 @@ target-properties: - EXCLUDE_FROM_ALL - EXCLUDE_FROM_DEFAULT_BUILD_<CONFIG> - EXCLUDE_FROM_DEFAULT_BUILD + - EXPORT_COMPILE_COMMANDS # Since 3.20 - EXPORT_NAME - EXPORT_PROPERTIES # Since 3.12 - FOLDER @@ -243,6 +247,7 @@ target-properties: - <LANG>_CPPCHECK # Since 3.10 - <LANG>_CPPLINT - <LANG>_INCLUDE_WHAT_YOU_USE + - <LANG>_LINKER_LAUNCHER # Sine 3.21 - <LANG>_VISIBILITY_PRESET - LIBRARY_OUTPUT_DIRECTORY_<CONFIG> - LIBRARY_OUTPUT_DIRECTORY @@ -284,7 +289,6 @@ target-properties: - OBJCXX_STANDARD # Since 3.16 - OBJCXX_STANDARD_REQUIRED # Since 3.16 - OPTIMIZE_DEPENDENCIES # Since 3.19 - - OBJC_STANDARD - OSX_ARCHITECTURES_<CONFIG> - OSX_ARCHITECTURES - OSX_CURRENT_VERSION # Since 3.17 @@ -329,6 +333,7 @@ target-properties: - UNITY_BUILD_CODE_AFTER_INCLUDE # Since 3.16 - UNITY_BUILD_CODE_BEFORE_INCLUDE # Since 3.16 - UNITY_BUILD_MODE # Since 3.18 + - UNITY_BUILD_UNIQUE_ID # Since 3.20 - VERSION - VISIBILITY_INLINES_HIDDEN - VS_CONFIGURATION_TYPE @@ -372,6 +377,10 @@ target-properties: - WIN32_EXECUTABLE - WINDOWS_EXPORT_ALL_SYMBOLS - XCODE_ATTRIBUTE_<an-attribute> + - XCODE_EMBED_<type>_CODE_SIGN_ON_COPY # Since 3.20 + - XCODE_EMBED_<type>_PATH # Since 3.20 + - XCODE_EMBED_<type>_REMOVE_HEADERS_ON_COPY # Since 3.20 + - XCODE_EMBED_<type> # Since 3.20 - XCODE_EXPLICIT_FILE_TYPE - XCODE_GENERATE_SCHEME # Since 3.15 - XCODE_LINK_BUILD_PHASE_MODE # Since 3.19 @@ -572,6 +581,7 @@ generator-expressions: - TARGET_BUNDLE_DIR - TARGET_BUNDLE_CONTENT_DIR - TARGET_PROPERTY + - TARGET_RUNTIME_DLLS # Since 3.21 - INSTALL_PREFIX # Output-Related Expressions - TARGET_NAME @@ -581,6 +591,8 @@ generator-expressions: - MAKE_C_IDENTIFIER - TARGET_OBJECTS - SHELL_PATH + - OUTPUT_CONFIG # Since 3.20 + - COMMAND_CONFIG # Since 3.20 variables: # Variables that Provide Information @@ -687,6 +699,7 @@ variables: - CMAKE_XCODE_PLATFORM_TOOLSET - <PROJECT-NAME>_BINARY_DIR - <PROJECT-NAME>_DESCRIPTION # Since 3.12 + - <PROJECT-NAME>_IS_TOP_LEVEL # Since 3.21 - <PROJECT-NAME>_HOMEPAGE_URL # Since 3.12 - <PROJECT-NAME>_SOURCE_DIR - <PROJECT-NAME>_VERSION @@ -696,6 +709,7 @@ variables: - <PROJECT-NAME>_VERSION_TWEAK - PROJECT_BINARY_DIR - PROJECT_DESCRIPTION # Since 3.9 + - PROJECT_IS_TOP_LEVEL # Since 3.21 - PROJECT_HOMEPAGE_URL # Since 3.12 - PROJECT_NAME - PROJECT_SOURCE_DIR @@ -819,6 +833,7 @@ variables: - ANDROID - APPLE - BORLAND + - CMAKE_ANDROID_NDK_VERSION # Since 3.20 - CMAKE_CL_64 - CMAKE_COMPILER_2005 - CMAKE_HOST_APPLE @@ -949,6 +964,9 @@ variables: - CMAKE_<LANG>_CPPCHECK # Since 3.10 - CMAKE_<LANG>_CPPLINT - CMAKE_<LANG>_INCLUDE_WHAT_YOU_USE + - CMAKE_<LANG>_LINKER_LAUNCHER # Sine 3.21 + - CMAKE_<LANG>_LINK_LIBRARY_FILE_FLAG # Sine 3.16 + - CMAKE_<LANG>_LINK_LIBRARY_FLAG # Sine 3.16 - CMAKE_<LANG>_VISIBILITY_PRESET - CMAKE_LIBRARY_OUTPUT_DIRECTORY - CMAKE_LIBRARY_OUTPUT_DIRECTORY_<CONFIG> @@ -1046,6 +1064,7 @@ variables: - CMAKE_<LANG>_ARCHIVE_APPEND - CMAKE_<LANG>_ARCHIVE_CREATE - CMAKE_<LANG>_ARCHIVE_FINISH + - CMAKE_<LANG>_BYTE_ORDER # Since 3.20 - CMAKE_<LANG>_COMPILER - CMAKE_<LANG>_COMPILER_EXTERNAL_TOOLCHAIN - CMAKE_<LANG>_COMPILER_ID @@ -1173,6 +1192,7 @@ variables: # Variables for CPack - CPACK_ABSOLUTE_DESTINATION_FILES - CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY + - CPACK_CUSTOM_INSTALL_VARIABLES # Since 3.21 - CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION - CPACK_INCLUDE_TOPLEVEL_DIRECTORY - CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS # Since 3.11 @@ -1182,32 +1202,57 @@ variables: - CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION # Variables for `find_package()` - PACKAGE_FIND_NAME - - PACKAGE_FIND_VERSION - - PACKAGE_FIND_VERSION_MAJOR - - PACKAGE_FIND_VERSION_MINOR - - PACKAGE_FIND_VERSION_PATCH - - PACKAGE_FIND_VERSION_TWEAK + # NOTE <SMTH>_VERSION and components already defined above, so skipped here - PACKAGE_FIND_VERSION_COUNT + - PACKAGE_FIND_VERSION_RANGE + - PACKAGE_FIND_VERSION_RANGE_MIN + - PACKAGE_FIND_VERSION_RANGE_MAX + - PACKAGE_FIND_VERSION_MIN + - PACKAGE_FIND_VERSION_MIN_MAJOR + - PACKAGE_FIND_VERSION_MIN_MINOR + - PACKAGE_FIND_VERSION_MIN_PATCH + - PACKAGE_FIND_VERSION_MIN_TWEAK + - PACKAGE_FIND_VERSION_MIN_COUNT + - PACKAGE_FIND_VERSION_MAX + - PACKAGE_FIND_VERSION_MAX_MAJOR + - PACKAGE_FIND_VERSION_MAX_MINOR + - PACKAGE_FIND_VERSION_MAX_PATCH + - PACKAGE_FIND_VERSION_MAX_TWEAK + - PACKAGE_FIND_VERSION_MAX_COUNT + - PACKAGE_FIND_VERSION_COMPLETE - PACKAGE_VERSION - PACKAGE_VERSION_EXACT - PACKAGE_VERSION_COMPATIBLE - PACKAGE_VERSION_UNSUITABLE - # NOTE <SMTH>_VERSION and components already defined above, so skipped here + # Package File Interface Variables - <package>_FOUND - - <package>_VERSION_COUNT - <package>_FIND_REQUIRED - <package>_FIND_QUIETLY - - <package>_FIND_VERSION - - <package>_FIND_VERSION_MAJOR - - <package>_FIND_VERSION_MINOR - - <package>_FIND_VERSION_PATCH - - <package>_FIND_VERSION_TWEAK - - <package>_FIND_VERSION_COUNT - - <package>_FIND_VERSION_EXACT - - <package>_FIND_COMPONENTS - - <package>_FIND_REQUIRED_<c> - - <package>_CONSIDERED_CONFIGS - - <package>_CONSIDERED_VERSIONS + - <package>_VERSION_COUNT + # NOTE <SMTH>_VERSION and components already defined above, so skipped here + - <PackageName>_FIND_VERSION_COUNT + - <PackageName>_FIND_VERSION_EXACT + - <PackageName>_FIND_COMPONENTS + - <PackageName>_FIND_REQUIRED_<c> + - <PackageName>_FIND_VERSION_RANGE + - <PackageName>_FIND_VERSION_RANGE_MIN + - <PackageName>_FIND_VERSION_RANGE_MAX + - <PackageName>_FIND_VERSION_MIN + - <PackageName>_FIND_VERSION_MIN_MAJOR + - <PackageName>_FIND_VERSION_MIN_MINOR + - <PackageName>_FIND_VERSION_MIN_PATCH + - <PackageName>_FIND_VERSION_MIN_TWEAK + - <PackageName>_FIND_VERSION_MIN_COUNT + - <PackageName>_FIND_VERSION_MAX + - <PackageName>_FIND_VERSION_MAX_MAJOR + - <PackageName>_FIND_VERSION_MAX_MINOR + - <PackageName>_FIND_VERSION_MAX_PATCH + - <PackageName>_FIND_VERSION_MAX_TWEAK + - <PackageName>_FIND_VERSION_MAX_COUNT + - <PackageName>_FIND_VERSION_COMPLETE + - <PackageName>_CONFIG + - <PackageName>_CONSIDERED_CONFIGS + - <PackageName>_CONSIDERED_VERSIONS - <PackageName>_ROOT # Since 3.12 # Other standard variables/patterns # - `try_run` @@ -1220,6 +1265,10 @@ variables: # - `cmake_parse_arguments` - <pfx>_UNPARSED_ARGUMENTS - <pfx>_KEYWORDS_MISSING_VALUES + # Variables that control `file(GET_RUNTIME_DEPENDENCIES)` behavior + - CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM + - CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL + - CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND # Well known CMake's official module's variables # - CheckCompilerFlag # - CheckCCompilerFlag @@ -1327,6 +1376,7 @@ variables: - CPACK_DEBIAN_PACKAGE_HOMEPAGE - CPACK_DEBIAN_PACKAGE_SHLIBDEPS - CPACK_DEBIAN_<COMPONENT>_PACKAGE_SHLIBDEPS + - CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS # Since 3.20 - CPACK_DEBIAN_PACKAGE_DEBUG - CPACK_DEBIAN_PACKAGE_PREDEPENDS - CPACK_DEBIAN_<COMPONENT>_PACKAGE_PREDEPENDS @@ -1364,6 +1414,7 @@ variables: - CPACK_DMG_SLA_DIR - CPACK_DMG_SLA_LANGUAGES - CPACK_DMG_<component>_FILE_NAME # Since 3.17 + - CPACK_DMG_FILESYSTEM # Since 3.21 - CPACK_COMMAND_HDIUTIL - CPACK_COMMAND_SETFILE - CPACK_COMMAND_REZ @@ -1389,6 +1440,7 @@ variables: - CPACK_IFW_PACKAGE_STYLE_SHEET # Since 3.15 - CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH - CPACK_IFW_PACKAGE_WIZARD_DEFAULT_HEIGHT + - CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST # Since 3.20 - CPACK_IFW_PACKAGE_TITLE_COLOR - CPACK_IFW_PACKAGE_START_MENU_DIRECTORY - CPACK_IFW_TARGET_DIRECTORY @@ -1443,6 +1495,9 @@ variables: - CPACK_NSIS_FINISH_TITLE_3LINES # Since 3.17 - CPACK_NSIS_MUI_HEADERIMAGE # Since 3.17 - CPACK_NSIS_MANIFEST_DPI_AWARE # Since 3.18 + - CPACK_NSIS_BRANDING_TEXT # Since 3.20 + - CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION # Since 3.20 + - CPACK_NSIS_EXECUTABLE # Since 3.21 # - CPackNuGet (since 3.12) - CPACK_NUGET_COMPONENT_INSTALL - CPACK_NUGET_PACKAGE_NAME @@ -1461,14 +1516,22 @@ variables: - CPACK_NUGET_<compName>_PACKAGE_HOMEPAGE_URL - CPACK_NUGET_PACKAGE_LICENSEURL - CPACK_NUGET_<compName>_PACKAGE_LICENSEURL + - CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION # Since 3.20 + - CPACK_NUGET_<compName>_PACKAGE_LICENSE_EXPRESSION # Since 3.20 + - CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME # Since 3.20 + - CPACK_NUGET_<compName>_PACKAGE_LICENSE_FILE_NAME # Since 3.20 - CPACK_NUGET_PACKAGE_ICONURL - CPACK_NUGET_<compName>_PACKAGE_ICONURL + - CPACK_NUGET_PACKAGE_ICON # Since 3.20 + - CPACK_NUGET_<compName>_PACKAGE_ICON # Since 3.20 - CPACK_NUGET_PACKAGE_DESCRIPTION_SUMMARY - CPACK_NUGET_<compName>_PACKAGE_DESCRIPTION_SUMMARY - CPACK_NUGET_PACKAGE_RELEASE_NOTES - CPACK_NUGET_<compName>_PACKAGE_RELEASE_NOTES - CPACK_NUGET_PACKAGE_COPYRIGHT - CPACK_NUGET_<compName>_PACKAGE_COPYRIGHT + - CPACK_NUGET_PACKAGE_LANGUAGE # Since 3.20 + - CPACK_NUGET_<compName>_PACKAGE_LANGUAGE # Since 3.20 - CPACK_NUGET_PACKAGE_TAGS - CPACK_NUGET_<compName>_PACKAGE_TAGS - CPACK_NUGET_PACKAGE_DEPENDENCIES @@ -1617,6 +1680,7 @@ variables: - CPACK_PACKAGE_EXECUTABLES - CPACK_STRIP_FILES - CPACK_VERBATIM_VARIABLES + - CPACK_THREADS # Since 3.20 - CPACK_SOURCE_PACKAGE_FILE_NAME - CPACK_SOURCE_STRIP_FILES - CPACK_SOURCE_GENERATOR @@ -1754,12 +1818,19 @@ variables: - CMAKE_NO_ANSI_STRING_STREAM # - TestForSTDNamespace - CMAKE_NO_STD_NAMESPACE + # - UseJava + - CMAKE_JAVA_COMPILE_FLAGS + - CMAKE_JAVA_INCLUDE_PATH + - CMAKE_JNI_TARGET + - CMAKE_JAR_CLASSES_PREFIX # - UseSWIG + - UseSWIG_MODULE_VERSION # Since 3.12 - CMAKE_SWIG_FLAGS - CMAKE_SWIG_OUTDIR - SWIG_OUTFILE_DIR - SWIG_MODULE_<name>_EXTRA_DEPS - SWIG_SOURCE_FILE_EXTENSIONS # Since 3.14 + - SWIG_USE_SWIG_DEPENDENCIES # Since 3.20 deprecated-or-internal-variables: - CMAKE_HOME_DIRECTORY @@ -1784,6 +1855,10 @@ deprecated-or-internal-variables: - CPACK_TEMPORARY_DIRECTORY - CPACK_TOPLEVEL_DIRECTORY - CPACK_INSTALL_PREFIX + # Mentioned in `file(GET_RUNTIME_DEPENDENCIES)` docs + - CMAKE_OBJDUMP + # Mentioned in "Deprecated and Removed Features" of release notes 3.21 + - CMAKE_SYSTEM_ARCH # https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html # NOTE Added to syntax file version 14 at 3.15.0 version of CMake @@ -1801,6 +1876,7 @@ environment-variables: - CMAKE_MSVCIDE_RUN_PATH - CMAKE_NO_VERBOSE - CMAKE_OSX_ARCHITECTURES + - CMAKE_TOOLCHAIN_FILE # Since 3.21 - DESTDIR - LDFLAGS - MACOSX_DEPLOYMENT_TARGET @@ -1812,6 +1888,7 @@ environment-variables: - CC - CFLAGS - CSFLAGS + - CUDAARCHS # Since 3.20 - CUDACXX - CUDAFLAGS - CUDAHOSTCXX @@ -1897,6 +1974,55 @@ scripting-commands: name: cmake_parse_arguments named-args: [PARSE_ARGV] - + name: cmake_path # Since 3.20 + named-args: [ + # Decomposition + GET + , ROOT_NAME + , ROOT_DIRECTORY + , ROOT_PATH + , FILENAME + , EXTENSION + , LAST_ONLY + , STEM + , RELATIVE_PART + , PARENT_PATH + # Query + , HAS_ROOT_NAME + , HAS_ROOT_DIRECTORY + , HAS_ROOT_PATH + , HAS_FILENAME + , HAS_EXTENSION + , HAS_STEM + , HAS_RELATIVE_PART + , HAS_PARENT_PATH + , IS_ABSOLUTE + , IS_RELATIVE + , IS_PREFIX + , NORMALIZE + # Modification + , SET + , APPEND + , OUTPUT_VARIABLE + , APPEND_STRING + , REMOVE_FILENAME + , REPLACE_FILENAME + , REMOVE_EXTENSION + , REPLACE_EXTENSION + # Generation + , NORMAL_PATH + , RELATIVE_PATH + , BASE_DIRECTORY + , ABSOLUTE_PATH + # Native Conversion + , NATIVE_PATH + , CONVERT + , TO_CMAKE_PATH_LIST + , TO_NATIVE_PATH_LIST + # Hashing + , HASH + ] + - name: cmake_policy named-args: [GET, SET, PUSH, POP, VERSION] special-args: [OLD, NEW] @@ -1908,6 +2034,8 @@ scripting-commands: , NO_SOURCE_PERMISSIONS # Since 3.19 , "@ONLY" , NEWLINE_STYLE + , USE_SOURCE_PERMISSIONS # Since 3.20 + , FILE_PERMISSIONS # Since 3.20 ] special-args: [UNIX, DOS, WIN32, LF, CRLF] - @@ -2098,6 +2226,19 @@ scripting-commands: , SIZE # New sub-options since 3.16 , GET_RUNTIME_DEPENDENCIES + , RESOLVED_DEPENDENCIES_VAR + , UNRESOLVED_DEPENDENCIES_VAR + , EXECUTABLES + , LIBRARIES + , MODULES + , DIRECTORIES + , BUNDLE_EXECUTABLE + , PRE_INCLUDE_REGEXES + , PRE_EXCLUDE_REGEXES + , POST_INCLUDE_REGEXES + , POST_EXCLUDE_REGEXES + , POST_INCLUDE_FILES # Since 3.21 + , POST_EXCLUDE_FILES # Since 3.21 # New sub-options since 3.18 , ARCHIVE_CREATE , FILES @@ -2112,10 +2253,17 @@ scripting-commands: , ESCAPE_QUOTES , "@ONLY" , NEWLINE_STYLE - , CHMOD # Since 3.19 - , CHMOD_RECURSE # Since 3.19 - , REAL_PATH # Since 3.19 - , BASE_DIRECTORY # Since 3.19 + # New sub-options since 3.19 + , CHMOD + , CHMOD_RECURSE + , REAL_PATH + , BASE_DIRECTORY + # New sub-options since 3.21 + , COPY_FILE + , RESULT + , ONLY_IF_DIFFERENT + , EXPAND_TILDE + , NO_REPLACE ] special-args: [ UTF-8 @@ -2169,6 +2317,7 @@ scripting-commands: , PATHS , PATH_SUFFIXES , DOC + , NO_CACHE # Since 3.21 , REQUIRED # Since 3.18 , NO_DEFAULT_PATH , NO_PACKAGE_ROOT_PATH @@ -2189,6 +2338,7 @@ scripting-commands: , PATHS , PATH_SUFFIXES , DOC + , NO_CACHE # Since 3.21 , REQUIRED # Since 3.18 , NO_DEFAULT_PATH , NO_PACKAGE_ROOT_PATH @@ -2595,7 +2745,11 @@ project-commands: name: aux_source_directory - name: build_command - named-args: [CONFIGURATION, TARGET] + named-args: [ + CONFIGURATION + , PARALLEL_LEVEL # Since 3.21 + , TARGET + ] - name: create_test_sourcelist named-args: [EXTRA_INCLUDE, FUNCTION] @@ -2615,6 +2769,7 @@ project-commands: , CSharp , CXX , CUDA + , HIP # Since 3.21 , ISPC # Since 3.19 , Java , OBJC # Since 3.16 @@ -2664,6 +2819,7 @@ project-commands: , EXCLUDE_FROM_ALL , RENAME , OPTIONAL + , TYPE # Since 3.20 # Installing Targets , TARGETS , EXPORT @@ -2679,6 +2835,7 @@ project-commands: , INCLUDES , NAMELINK_ONLY , NAMELINK_SKIP + , RUNTIME_DEPENDENCIES # Since 3.21 # Installing Files , FILES , PROGRAMS @@ -2700,6 +2857,17 @@ project-commands: , FILE , EXPORT_ANDROID_MK , EXPORT_LINK_INTERFACE_LIBRARIES + # Installing Imported Runtime Artifacts (since 3.21) + , IMPORTED_RUNTIME_ARTIFACTS + , RUNTIME_DEPENDENCY_SET + # Installing Runtime Dependencies (since 3.21) + , PRE_INCLUDE_REGEXES + , PRE_EXCLUDE_REGEXES + , POST_INCLUDE_REGEXES + , POST_EXCLUDE_REGEXES + , POST_INCLUDE_FILES + , POST_EXCLUDE_FILES + , DIRECTORIES ] special-args: &valid_permissions [ OWNER_READ @@ -2740,6 +2908,7 @@ project-commands: , CSharp , CXX , CUDA + , HIP # Since 3.21 , ISPC # Since 3.19 , Java , OBJC # Since 3.16 @@ -2787,6 +2956,7 @@ project-commands: , cxx_std_14 , cxx_std_17 , cxx_std_20 # Since 3.12 + , cxx_std_23 # Since 3.20 , cxx_aggregate_default_initializers , cxx_alias_templates , cxx_alignas @@ -2848,6 +3018,8 @@ project-commands: , c_std_90 , c_std_99 , c_std_11 + , c_std_17 # Since 3.21 + , c_std_23 # Since 3.21 , c_function_prototypes , c_restrict , c_static_assert @@ -2858,13 +3030,21 @@ project-commands: , cuda_std_14 , cuda_std_17 , cuda_std_20 + , cuda_std_23 # Since 3.21 ] - name: target_compile_options named-args: &target_compile_options [BEFORE, INTERFACE, PUBLIC, PRIVATE] - name: target_include_directories - named-args: [BEFORE, SYSTEM, INTERFACE, PUBLIC, PRIVATE] + named-args: [ + AFTER # Since 3.20 + , BEFORE + , SYSTEM + , INTERFACE + , PUBLIC + , PRIVATE + ] - # Since 3.13 name: target_link_directories @@ -2910,6 +3090,7 @@ project-commands: , COMPILE_OUTPUT_VARIABLE , RUN_OUTPUT_VARIABLE , OUTPUT_VARIABLE + , WORKING_DIRECTORY # Since 3.20 , ARGS ] diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-doxygenlua.pl b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-doxygenlua.pl new file mode 100644 index 0000000000..ffc38ea17e --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-doxygenlua.pl @@ -0,0 +1,42 @@ +#!/usr/bin/env perl +# SPDX-FileCopyrightText: 2020 Jonathan Poelen <jonathan.poelen@gmail.com> +# SPDX-License-Identifier: MIT + +my $file = ""; + +open(my $input, '<:encoding(UTF-8)', $ARGV[0]) + or die "Could not open file '$ARGV[0]': $!"; + +open(my $output, '>:encoding(UTF-8)', $ARGV[1]) + or die "Could not open file '$ARGV[1]': $!"; + +while (<$input>) +{ + $file .= $_; +} + +$warning = "\n\n<!-- ***** THIS FILE WAS GENERATED BY A SCRIPT - DO NOT EDIT ***** -->\n"; +$first_context = " <context attribute=\"Normal Text\" lineEndContext=\"#stay\" name=\"Normal\"> + <RegExpr attribute=\"Comment\" context=\"LineComment\" String=\"--(?:!|(?:-(?=[^-]|\$)))\"/> + <RegExpr attribute=\"Region\" context=\"#stay\" String=\"--\\s*\@\\{\\s*\$\" beginRegion=\"MemberGroup\" /> + <RegExpr attribute=\"Region\" context=\"#stay\" String=\"--\\s*\@\\}\\s*\$\" endRegion=\"MemberGroup\" /> + </context>"; + +$file =~ s/\n\s*<context [^\n]*?(?:name="ML_|name="BlockComment").*?<\/context>//gs; +$file =~ s/\n\s*<context [^\n]*?name="Normal".*?<\/context>/\n$first_context/s; +$file =~ s/\n[^\n]*?(?: ml_word|LineContinue)[^\n]+//gs; +$file =~ s/\/\/\//---/gs; +$file =~ s/\/\/!/--!/gs; + +$language = $file =~ s/.*?(<language[^>]+?>).*/$1/sr; +$language =~ s/ name="[^"]+/ name="DoxygenLua/s; +$language =~ s/ extensions="[^"]+/ extensions="/s; +$language =~ s/ mimetype="[^"]+/ mimetype="/s; +$language =~ s/ priority="[^"]+"//s; +$version = $language =~ s/.*? version="([^"]+).*/$1/sr; +$version = $version+2; +$language =~ s/ version="[^"]+/ version="$version/s; +$file =~ s/<language[^>]+?>/$warning\n$language/s; + +print $output $file; +print $output $warning; diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-php.pl b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-php.pl index a3b20fb554..a516332ef2 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-php.pl +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-php.pl @@ -45,6 +45,7 @@ if ($root == 1) $file =~ s/<language([^>]+)section="[^"]*"/<language$1section="Scripts"/s; $file =~ s/<language([^>]+)extensions="[^"]*"/<language$1extensions="*.php;*.php3;*.wml;*.phtml;*.phtm;*.inc;*.ctp"/s; $file =~ s/<language([^>]+)mimetype="[^"]*"/<language$1mimetype="text\/x-php4-src;text\/x-php3-src;text\/vnd.wap.wml;application\/x-php"/s; + $file =~ s/<language([^>]+)*/<language$1 indenter="cstyle"/s; } else { diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-spdx-syntax.py b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-spdx-syntax.py new file mode 100644 index 0000000000..73ff29092c --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-spdx-syntax.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Generate SPDX-Comments syntax file +# +# SPDX-FileCopyrightText: 2020 Alex Turbov <i.zaufi@gmail.com> +# SPDX-License-Identifier: MIT +# +# To install prerequisites: +# +# $ pip install --user click jinja2 +# +# To use: +# +# $ ./generate-spdx-syntax.py > ../syntax/spdx-comments.xml +# + +import json +import pathlib +import urllib.request + +import click +import jinja2 + + +def get_json(url): + with urllib.request.urlopen(url=url) as body: + return json.load(body) + + +@click.command() +@click.argument('template', type=click.File('r'), default='./spdx-comments.xml.tpl') +def cli(template): + + data = { + 'licenses': [ + *filter( + lambda l: not l['licenseId'].endswith('+') + , get_json(url='https://spdx.org/licenses/licenses.json')['licenses'] + ) + ] + , 'exceptions': [ + *filter( + lambda l: not l['licenseExceptionId'].endswith('+') + , get_json(url='https://spdx.org/licenses/exceptions.json')['exceptions'] + ) + ] + } + + env = jinja2.Environment( + keep_trailing_newline=True + ) + env.block_start_string = '<!--[' + env.block_end_string = ']-->' + env.variable_start_string = '<!--{' + env.variable_end_string = '}-->' + env.comment_start_string = '<!--#' + env.comment_end_string = '#-->' + + tpl = env.from_string(template.read()) + result = tpl.render(data) + print(result.strip(), end=None) + + +if __name__ == '__main__': + cli() + # TODO Handle execptions and show errors diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl b/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl new file mode 100644 index 0000000000..58cc80f960 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE language SYSTEM "language.dtd"> +<language + version="4" + kateversion="3.1" + name="SPDX-Comments" + section="Other" + extensions="" + mimetype="" + author="Alex Turbov (i.zaufi@gmail.com)" + license="MIT" + hidden="true" + > + <highlighting> + <list name="tags"> + <item>SPDX-License-Identifier:</item> + <item>SPDX-FileContributor:</item> + <item>SPDX-FileCopyrightText:</item> + <item>SPDX-LicenseInfoInFile:</item> + </list> + + <list name="operators"> + <item>AND</item> + <item>OR</item> + <item>WITH</item> + </list> + + <list name="licenses"> + <!--[- for license in licenses if not license.isDeprecatedLicenseId ]--> + <item><!--{ license.licenseId }--></item> + <!--[- endfor ]--> + </list> + + <list name="deprecated-licenses"> + <!--[- for license in licenses if license.isDeprecatedLicenseId ]--> + <item><!--{ license.licenseId }--></item> + <!--[- endfor ]--> + </list> + + <list name="exceptions"> + <!--[- for exception in exceptions if not exception.isDeprecatedLicenseId ]--> + <item><!--{ exception.licenseExceptionId }--></item> + <!--[- endfor ]--> + </list> + + <list name="deprecated-exceptions"> + <!--[- for exception in exceptions if exception.isDeprecatedLicenseId ]--> + <item><!--{ exception.licenseExceptionId }--></item> + <!--[- endfor ]--> + </list> + + <contexts> + + <context name="Normal" attribute="SPDX Tag" lineEndContext="#pop"> + <WordDetect String="SPDX-License-Identifier:" attribute="SPDX Tag" context="license-expression" /> + <keyword String="tags" attribute="SPDX Tag" /> + </context> + + <context name="license-expression" attribute="SPDX Value" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop"> + <DetectSpaces/> + <DetectChar char="(" context="#stay" attribute="SPDX License Expression Operator" /> + <DetectChar char=")" context="#stay" attribute="SPDX License Expression Operator" /> + <DetectChar char="+" context="#stay" attribute="SPDX License Expression Operator" /> + <keyword String="licenses" context="#stay" attribute="SPDX License" /> + <keyword String="deprecated-licenses" context="#stay" attribute="SPDX Deprecated License" /> + <keyword String="exceptions" context="#stay" attribute="SPDX License Exception" /> + <keyword String="deprecated-exceptions" context="#stay" attribute="SPDX Deprecated License Exception" /> + <keyword String="operators" context="#stay" attribute="SPDX License Expression Operator" /> + <RegExpr attribute="SPDX License" context="#stay" String="\bLicenseRef-[^\s]+" /> + </context> + + </contexts> + + <itemDatas> + <itemData name="SPDX Tag" defStyleNum="dsAnnotation" italic="true" spellChecking="false" /> + <itemData name="SPDX Value" defStyleNum="dsAnnotation" italic="true" spellChecking="false" /> + <itemData name="SPDX License" defStyleNum="dsAnnotation" italic="true" spellChecking="false" /> + <itemData name="SPDX License Exception" defStyleNum="dsAnnotation" italic="true" spellChecking="false" /> + <itemData name="SPDX Deprecated License" defStyleNum="dsAnnotation" italic="true" spellChecking="false" /> + <itemData name="SPDX Deprecated License Exception" defStyleNum="dsAnnotation" italic="true" spellChecking="false" /> + <itemData name="SPDX License Expression Operator" defStyleNum="dsOperator" italic="true" spellChecking="false" /> + </itemDatas> + + </highlighting> + + <general> + <keywords casesensitive="1" weakDeliminator=":-." /> + </general> + +</language> +<!-- kate: indent-width 2; --> diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml index d7e4ed3d70..c7b21cb2a0 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml @@ -5,7 +5,7 @@ <!ENTITY funcname "([^&_fragpathseps;}=#$]|[+!@](?!\())([^&_fragpathseps;}=$]*+([+!@](?!\())?+)*+"> <!ENTITY varname "[A-Za-z_][A-Za-z0-9_]*"> <!ENTITY eos "(?=$|[ &tab;])"> <!-- eol or space following --> - <!ENTITY eoexpr "(?=$|[ &tab;<>|&;])"> + <!ENTITY eoexpr "(?=$|[ &tab;<>|&;)])"> <!ENTITY substseps "${'"`\\"> <!ENTITY symbolseps "<>|&;()"> <!-- see man bash --> @@ -18,6 +18,13 @@ <!ENTITY opt "(?:[^&_fragpathseps;=/]*+&_fragpathnosep;)*+"> <!ENTITY pathpart "(?:~|\.\.?|&fragpath;)(?:/&path;|(?=[*?]|[+!@]\(|&fragpath;(?:[/*?]|[+!@]\()))|(?:~|\.\.?)(?=[&wordseps;]|$)"> + <!ENTITY _fragpathseps_alt "*?+!@&substseps;}"> + <!ENTITY _fragpathnosep_alt "(?:[+!@](?!\()|\\.)?+"> + <!ENTITY path_alt "(?:[^&_fragpathseps_alt;]*+&_fragpathnosep_alt;)*+"> + <!ENTITY fragpath_alt "(?:[^&_fragpathseps_alt;/]*+&_fragpathnosep_alt;)*+"> + <!ENTITY opt_alt "(?:[^&_fragpathseps_alt;=/]*+&_fragpathnosep_alt;)*+"> + <!ENTITY pathpart_alt "(?:~|\.\.?|&fragpath_alt;)(?:/&path_alt;|(?=[*?]|[+!@]\(|&fragpath_alt;(?:[/*?]|[+!@]\()))|(?:~|\.\.?)(?=\}|$)"> + <!ENTITY _braceexpansion_spe " &tab;<>|&;{}\\`'"$"> <!ENTITY _brace_noexpansion "\{[^&_braceexpansion_spe;,]*+\}"> <!ENTITY _braceexpansion_var "\$(?:\{[^\[\]&_braceexpansion_spe;]*+(?:\[[*@a-zA-Z0-9]\])\})?"> @@ -28,9 +35,11 @@ <!ENTITY braceexpansion "{&_braceexpansion;"> <!ENTITY heredocq "(?|"([^"]+)"|'([^']+)'|\\(.[^&wordseps;&substseps;]*))"> + + <!ENTITY arithmetic_as_subshell "\(((?:[^`'"()$]++|\$\{[^`'"(){}$]+\}|\$(?=[^{`'"()])|`[^`]*+`|\((?1)(?:[)]|(?=['"])))++)(?:[)](?=$|[^)])|["'])"> ]> -<language name="Bash" version="27" kateversion="5.79" section="Scripts" extensions="*.sh;*.bash;*.ebuild;*.eclass;*.nix;.bashrc;.bash_profile;.bash_login;.profile;PKGBUILD;APKBUILD" mimetype="application/x-shellscript" casesensitive="1" author="Wilbert Berendsen (wilbert@kde.nl)" license="LGPL"> +<language name="Bash" version="30" kateversion="5.79" section="Scripts" extensions="*.sh;*.bash;*.ebuild;*.eclass;*.nix;.bashrc;.bash_profile;.bash_login;.profile;PKGBUILD;APKBUILD" mimetype="application/x-shellscript" casesensitive="1" author="Wilbert Berendsen (wilbert@kde.nl)" license="LGPL"> <!-- (c) 2004 by Wilbert Berendsen (wilbert@kde.nl) Changes by Matthew Woehlke (mw_triad@users.sourceforge.net) @@ -40,6 +49,7 @@ <highlighting> <list name="keywords"> + <item>break</item> <item>case</item> <item>continue</item> <item>do</item> @@ -66,7 +76,6 @@ <item>alias</item> <item>bg</item> <item>bind</item> - <item>break</item> <item>builtin</item> <item>cd</item> <item>caller</item> @@ -458,7 +467,7 @@ <DetectSpaces attribute="Normal Text" context="#stay"/> <DetectChar attribute="Comment" context="Comment" char="#"/> <!-- start expression in double parentheses --> - <Detect2Chars attribute="Keyword" context="ExprDblParen" char="(" char1="(" beginRegion="expression"/> + <Detect2Chars context="ExprDblParenOrSubShell" char="(" char1="(" lookAhead="1"/> <!-- start a subshell --> <DetectChar attribute="Keyword" context="SubShell" char="(" beginRegion="subshell"/> <!-- start expression in single/double brackets --> @@ -554,8 +563,8 @@ </context> <context attribute="Command" lineEndContext="#pop#pop" name="DispatchSubstVariables"> <Detect2Chars attribute="Parameter Expansion" context="#pop!VarBraceStart" char="$" char1="{"/> - <StringDetect attribute="Parameter Expansion" context="#pop!ExprDblParenSubst" String="$((" beginRegion="expression"/> - <Detect2Chars attribute="Parameter Expansion" context="#pop!SubstCommand" char="$" char1="("/> + <StringDetect context="#pop!ExprDblParenSubstOrSubstCommand" String="$((" lookAhead="1"/> + <Detect2Chars attribute="Parameter Expansion" context="#pop!SubstCommand" char="$" char1="(" beginRegion="subshell"/> </context> <context attribute="Command" lineEndContext="#pop#pop" name="DispatchStringVariables"> <Detect2Chars attribute="String SingleQ" context="#pop!StringEsc" char="$" char1="'"/> @@ -695,27 +704,30 @@ </context> <context attribute="Path" lineEndContext="#stay" name="ExtGlobAndPop"> <DetectChar attribute="Glob" context="#pop!PathThenPop" char=")"/> + <IncludeRules context="FindWord"/> <IncludeRules context="IncExtGlob"/> </context> - <context attribute="Path" lineEndContext="#stay" name="RecursiveExtGlob"> - <DetectChar attribute="Glob" context="#pop" char=")"/> - <IncludeRules context="IncExtGlob"/> - </context> - <context attribute="Path" lineEndContext="#stay" name="IncExtGlob"> + <context attribute="Path" lineEndContext="#stay" name="FindExtGlob"> <Detect2Chars attribute="Glob" context="RecursiveExtGlob" char="?" char1="("/> <Detect2Chars attribute="Glob" context="RecursiveExtGlob" char="*" char1="("/> <Detect2Chars attribute="Glob" context="RecursiveExtGlob" char="+" char1="("/> <Detect2Chars attribute="Glob" context="RecursiveExtGlob" char="@" char1="("/> <Detect2Chars attribute="Glob" context="RecursiveExtGlob" char="!" char1="("/> <AnyChar attribute="Glob" context="#stay" String="|?*"/> + </context> + <context attribute="Path" lineEndContext="#stay" name="RecursiveExtGlob"> + <DetectChar attribute="Glob" context="#pop" char=")"/> <IncludeRules context="FindWord"/> + <IncludeRules context="IncExtGlob"/> + </context> + <context attribute="Path" lineEndContext="#stay" name="IncExtGlob"> + <IncludeRules context="FindExtGlob"/> <DetectChar context="PathMaybeBraceExpansion" char="{" lookAhead="1"/> </context> <context attribute="Path" lineEndContext="#pop#pop" name="PathThenPop"> <AnyChar context="#pop#pop" String="&wordseps;`" lookAhead="1"/> <IncludeRules context="FindWord"/> - <IncludeRules context="FindExtGlobAndPop"/> - <AnyChar attribute="Glob" context="#stay" String="?*"/> + <IncludeRules context="FindExtGlob"/> <DetectChar context="PathMaybeBraceExpansion" char="{" lookAhead="1"/> <RegExpr attribute="Path" context="#stay" String="&path;"/> </context> @@ -724,6 +736,47 @@ <DetectChar attribute="Path" context="#pop" char="{"/> </context> + <!-- FindPathThenPopInAlternateValue consumes path in ${xx:here}--> + <context attribute="Normal Text" lineEndContext="#pop" name="FindPathThenPopInAlternateValue"> + <IncludeRules context="FindExtGlobAndPopInAlternateValue"/> + <AnyChar attribute="Glob" context="PathThenPopInAlternateValue" String="?*"/> + <RegExpr attribute="Path" context="PathThenPopInAlternateValue" String="&pathpart_alt;"/> + </context> + <context attribute="Path" lineEndContext="#stay" name="FindExtGlobAndPopInAlternateValue"> + <Detect2Chars attribute="Glob" context="ExtGlobAndPopInAlternateValue" char="?" char1="("/> + <Detect2Chars attribute="Glob" context="ExtGlobAndPopInAlternateValue" char="*" char1="("/> + <Detect2Chars attribute="Glob" context="ExtGlobAndPopInAlternateValue" char="+" char1="("/> + <Detect2Chars attribute="Glob" context="ExtGlobAndPopInAlternateValue" char="@" char1="("/> + <Detect2Chars attribute="Glob" context="ExtGlobAndPopInAlternateValue" char="!" char1="("/> + </context> + <context attribute="Path" lineEndContext="#stay" name="FindExtGlobInAlternateValue"> + <Detect2Chars attribute="Glob" context="RecursiveExtGlobInAlternateValue" char="?" char1="("/> + <Detect2Chars attribute="Glob" context="RecursiveExtGlobInAlternateValue" char="*" char1="("/> + <Detect2Chars attribute="Glob" context="RecursiveExtGlobInAlternateValue" char="+" char1="("/> + <Detect2Chars attribute="Glob" context="RecursiveExtGlobInAlternateValue" char="@" char1="("/> + <Detect2Chars attribute="Glob" context="RecursiveExtGlobInAlternateValue" char="!" char1="("/> + <AnyChar attribute="Glob" context="#stay" String="|?*"/> + </context> + <context attribute="Path" lineEndContext="#stay" name="RecursiveExtGlobInAlternateValue"> + <DetectChar attribute="Glob" context="#pop" char=")"/> + <DetectChar context="#pop" char="}" lookAhead="1"/> + <IncludeRules context="FindWord"/> + <IncludeRules context="FindExtGlobInAlternateValue"/> + </context> + <context attribute="Path" lineEndContext="#stay" name="ExtGlobAndPopInAlternateValue"> + <DetectChar attribute="Glob" context="#pop!PathThenPopInAlternateValue" char=")"/> + <DetectChar attribute="Error" context="#pop#pop" char="}"/> + <IncludeRules context="FindWord"/> + <IncludeRules context="FindExtGlobInAlternateValue"/> + </context> + <context attribute="Path" lineEndContext="#pop#pop" name="PathThenPopInAlternateValue"> + <DetectChar attribute="Parameter Expansion" context="#pop#pop" char="}"/> + <IncludeRules context="FindWord"/> + <IncludeRules context="FindExtGlobAndPopInAlternateValue"/> + <AnyChar attribute="Glob" context="#stay" String="?*"/> + <RegExpr attribute="Path" context="#stay" String="&path_alt;"/> + </context> + <context attribute="Pattern" lineEndContext="#stay" name="FindPattern"> <Detect2Chars attribute="Glob" context="ExtPattern" char="?" char1="("/> <Detect2Chars attribute="Glob" context="ExtPattern" char="*" char1="("/> @@ -1038,7 +1091,7 @@ <!-- SubstCommand is called after a $( is encountered --> <context attribute="Normal Text" lineEndContext="#stay" name="SubstCommand" fallthroughContext="Command"> - <DetectChar attribute="Parameter Expansion" context="#pop" char=")"/> + <DetectChar attribute="Parameter Expansion" context="#pop" char=")" endRegion="subshell"/> <IncludeRules context="Start"/> </context> @@ -1084,7 +1137,7 @@ <Detect2Chars attribute="Parameter Expansion Operator" context="#pop!AlternatePatternValue" char="," char1=","/> <DetectChar attribute="Parameter Expansion Operator" context="#pop!VarSub" char=":"/> <DetectChar attribute="Parameter Expansion Operator" context="#pop!VarSubst" char="/"/> - <AnyChar attribute="Parameter Expansion Operator" context="#pop!AlternateValue" String="%#"/> + <AnyChar attribute="Parameter Expansion Operator" context="#pop!AlternateValue" String="-+=?#%"/> <AnyChar attribute="Parameter Expansion Operator" context="#pop!AlternatePatternValue" String="^,"/> <DetectChar attribute="Parameter Expansion Operator" context="#pop!VarTransformation" char="@"/> </context> @@ -1109,7 +1162,7 @@ <context attribute="Normal Text" lineEndContext="#stay" name="AlternateValue"> <DetectChar attribute="Parameter Expansion" context="#pop" char="}"/> <IncludeRules context="FindWord"/> - <IncludeRules context="FindPattern"/> + <IncludeRules context="FindPathThenPopInAlternateValue"/> </context> <!-- called as soon as ${xxx^ are ${xxx, are encoutered --> @@ -1125,7 +1178,7 @@ </context> <context attribute="Pattern" lineEndContext="#stay" name="VarSubstPat"> <DetectChar attribute="Parameter Expansion Operator" context="#pop!AlternateValue" char="/"/> - <IncludeRules context="AlternateValue"/> + <IncludeRules context="AlternatePatternValue"/> </context> <!-- called as soon as ${xxx@ is encoutered --> @@ -1164,19 +1217,26 @@ <!-- ====== These are the contexts that can be branched to ======= --> + <context attribute="Normal Text" lineEndContext="#stay" name="ExprDblParenOrSubShell"> + <RegExpr attribute="Keyword" context="#pop!SubShell" String="\((?=&arithmetic_as_subshell;)|" beginRegion="subshell"/> + <Detect2Chars attribute="Keyword" context="#pop!ExprDblParen" char="(" char1="(" beginRegion="expression"/> + </context> <!-- ExprDblParen consumes an expression started in command mode till )) --> <context attribute="Normal Text" lineEndContext="#stay" name="ExprDblParen"> <DetectSpaces attribute="Normal Text" context="#stay"/> <Detect2Chars attribute="Keyword" context="#pop" char=")" char1=")" endRegion="expression"/> <IncludeRules context="FindExprDblParen"/> + <!-- ((cmd + ) # jump to SubShell context --> + <DetectChar attribute="Keyword" context="#pop!SubShell" char=")" endRegion="expression" beginRegion="subshell"/> </context> <context attribute="Normal Text" lineEndContext="#stay" name="FindExprDblParen"> <Detect2Chars attribute="Control" context="#stay" char="&" char1="&"/> <Detect2Chars attribute="Control" context="#stay" char="|" char1="|"/> <AnyChar attribute="Operator" context="#stay" String="+-!~*/%<>=&^|?:"/> + <AnyChar context="Number" String="0123456789" lookAhead="1"/> <DetectChar attribute="Control" context="#stay" char=","/> <DetectChar attribute="Normal Text" context="ExprSubDblParen" char="("/> - <AnyChar context="Number" String="0123456789" lookAhead="1"/> <DetectChar attribute="Parameter Expansion Operator" context="Subscript" char="["/> <IncludeRules context="FindWord"/> <DetectChar attribute="Error" context="#stay" char="#"/> @@ -1184,8 +1244,9 @@ <DetectIdentifier attribute="Variable" context="#stay"/> </context> <context attribute="Normal Text" lineEndContext="#stay" name="ExprSubDblParen"> + <DetectSpaces attribute="Normal Text" context="#stay"/> <DetectChar attribute="Normal Text" context="#pop" char=")"/> - <IncludeRules context="ExprDblParen"/> + <IncludeRules context="FindExprDblParen"/> </context> <context attribute="Normal Text" lineEndContext="#pop" name="MaybeArithmeticBrace"> <IncludeRules context="DispatchBraceExpansion"/> @@ -1216,11 +1277,18 @@ <AnyChar attribute="Error" context="#stay" String="8901234567"/> </context> + <context attribute="Normal Text" lineEndContext="#stay" name="ExprDblParenSubstOrSubstCommand"> + <RegExpr attribute="Parameter Expansion" context="#pop!SubstCommand" String="\$\((?=&arithmetic_as_subshell;)|" beginRegion="subshell"/> + <StringDetect attribute="Parameter Expansion" context="#pop!ExprDblParenSubst" String="$((" beginRegion="expression"/> + </context> <!-- ExprDblParenSubst like ExprDblParen but matches )) as Variable --> <context attribute="Normal Text" lineEndContext="#stay" name="ExprDblParenSubst"> <DetectSpaces attribute="Normal Text" context="#stay"/> <Detect2Chars attribute="Variable" context="#pop" char=")" char1=")" endRegion="expression"/> <IncludeRules context="FindExprDblParen"/> + <!-- $((cmd + ) # jump to SubstCommand context --> + <DetectChar attribute="Parameter Expansion" context="#pop!SubstCommand" char=")" endRegion="expression" beginRegion="subshell"/> </context> <!-- ExprBracket consumes an expression till ] --> @@ -1305,7 +1373,7 @@ </context> <context attribute="Normal Text" lineEndContext="#pop" name="ExprDblBracketValue"> - <Detect2Chars attribute="Keyword" context="ExprDblParen" char="(" char1="(" beginRegion="expression"/> + <Detect2Chars context="ExprDblBracketDblParentOrSubValue" char="(" char1="(" lookAhead="1"/> <DetectChar context="ExprDblBracketSubValue" char="(" lookAhead="1"/> <DetectChar attribute="Operator" context="#pop#pop" char=")"/> <Detect2Chars attribute="Control" context="#pop#pop!ExprDblBracket" char="&" char1="&"/> @@ -1321,6 +1389,18 @@ <DetectChar attribute="Operator" context="ExprDblBracketNot" char="("/> <Detect2Chars context="#pop#pop" char="]" char1="]" lookAhead="1"/> </context> + <context attribute="Normal Text" lineEndContext="#pop" name="ExprDblBracketDblParentOrSubValue"> + <RegExpr context="#pop!ExprDblBracketSubValue" String="\((?=&arithmetic_as_subshell;)|" lookAhead="1"/> + <Detect2Chars attribute="Keyword" context="#pop!ExprDblBracketExprDblParen" char="(" char1="(" beginRegion="expression"/> + </context> + <context attribute="Normal Text" lineEndContext="#stay" name="ExprDblBracketExprDblParen"> + <DetectSpaces attribute="Normal Text" context="#stay"/> + <Detect2Chars attribute="Keyword" context="#pop" char=")" char1=")" endRegion="expression"/> + <IncludeRules context="FindExprDblParen"/> + <!-- ((cmd + ) # jump to ExprDblBracketValue context --> + <DetectChar attribute="Operator" context="ExprDblBracketValue" char=")" endRegion="expression" beginRegion="subshell"/> + </context> <context attribute="Normal Text" lineEndContext="#stay" name="ExprDblBracketParam2" fallthroughContext="ExprDblBracketValue"> <DetectSpaces attribute="Normal Text" context="#pop!ExprDblBracketParam3"/> diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml index 7f3920bfb6..d8676a250d 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml @@ -22,7 +22,7 @@ <language name="CMake" - version="31" + version="34" kateversion="5.0" section="Other" extensions="CMakeLists.txt;*.cmake;*.cmake.in" @@ -39,6 +39,7 @@ <item>cmake_language</item> <item>cmake_minimum_required</item> <item>cmake_parse_arguments</item> + <item>cmake_path</item> <item>cmake_policy</item> <item>configure_file</item> <item>continue</item> @@ -196,6 +197,47 @@ <list name="cmake_parse_arguments_nargs"> <item>PARSE_ARGV</item> </list> + <list name="cmake_path_nargs"> + <item>ABSOLUTE_PATH</item> + <item>APPEND</item> + <item>APPEND_STRING</item> + <item>BASE_DIRECTORY</item> + <item>CONVERT</item> + <item>EXTENSION</item> + <item>FILENAME</item> + <item>GET</item> + <item>HASH</item> + <item>HAS_EXTENSION</item> + <item>HAS_FILENAME</item> + <item>HAS_PARENT_PATH</item> + <item>HAS_RELATIVE_PART</item> + <item>HAS_ROOT_DIRECTORY</item> + <item>HAS_ROOT_NAME</item> + <item>HAS_ROOT_PATH</item> + <item>HAS_STEM</item> + <item>IS_ABSOLUTE</item> + <item>IS_PREFIX</item> + <item>IS_RELATIVE</item> + <item>LAST_ONLY</item> + <item>NATIVE_PATH</item> + <item>NORMALIZE</item> + <item>NORMAL_PATH</item> + <item>OUTPUT_VARIABLE</item> + <item>PARENT_PATH</item> + <item>RELATIVE_PART</item> + <item>RELATIVE_PATH</item> + <item>REMOVE_EXTENSION</item> + <item>REMOVE_FILENAME</item> + <item>REPLACE_EXTENSION</item> + <item>REPLACE_FILENAME</item> + <item>ROOT_DIRECTORY</item> + <item>ROOT_NAME</item> + <item>ROOT_PATH</item> + <item>SET</item> + <item>STEM</item> + <item>TO_CMAKE_PATH_LIST</item> + <item>TO_NATIVE_PATH_LIST</item> + </list> <list name="cmake_policy_nargs"> <item>GET</item> <item>POP</item> @@ -211,8 +253,10 @@ <item>@ONLY</item> <item>COPYONLY</item> <item>ESCAPE_QUOTES</item> + <item>FILE_PERMISSIONS</item> <item>NEWLINE_STYLE</item> <item>NO_SOURCE_PERMISSIONS</item> + <item>USE_SOURCE_PERMISSIONS</item> </list> <list name="configure_file_sargs"> <item>CRLF</item> @@ -291,6 +335,7 @@ <item>ARCHIVE_CREATE</item> <item>ARCHIVE_EXTRACT</item> <item>BASE_DIRECTORY</item> + <item>BUNDLE_EXECUTABLE</item> <item>CHMOD</item> <item>CHMOD_RECURSE</item> <item>COMPRESSION</item> @@ -300,13 +345,17 @@ <item>CONFIGURE_DEPENDS</item> <item>CONTENT</item> <item>COPY</item> + <item>COPY_FILE</item> <item>DESTINATION</item> + <item>DIRECTORIES</item> <item>DIRECTORY</item> <item>DIRECTORY_PERMISSIONS</item> <item>DOWNLOAD</item> <item>ENCODING</item> <item>ESCAPE_QUOTES</item> <item>EXCLUDE</item> + <item>EXECUTABLES</item> + <item>EXPAND_TILDE</item> <item>EXPECTED_HASH</item> <item>EXPECTED_MD5</item> <item>FILES</item> @@ -327,6 +376,7 @@ <item>INSTALL</item> <item>LENGTH_MAXIMUM</item> <item>LENGTH_MINIMUM</item> + <item>LIBRARIES</item> <item>LIMIT</item> <item>LIMIT_COUNT</item> <item>LIMIT_INPUT</item> @@ -337,17 +387,26 @@ <item>LOG</item> <item>MAKE_DIRECTORY</item> <item>MD5</item> + <item>MODULES</item> <item>MTIME</item> <item>NETRC</item> <item>NETRC_FILE</item> <item>NEWLINE_CONSUME</item> <item>NEWLINE_STYLE</item> <item>NO_HEX_CONVERSION</item> + <item>NO_REPLACE</item> <item>NO_SOURCE_PERMISSIONS</item> <item>OFFSET</item> + <item>ONLY_IF_DIFFERENT</item> <item>OUTPUT</item> <item>PATTERN</item> <item>PERMISSIONS</item> + <item>POST_EXCLUDE_FILES</item> + <item>POST_EXCLUDE_REGEXES</item> + <item>POST_INCLUDE_FILES</item> + <item>POST_INCLUDE_REGEXES</item> + <item>PRE_EXCLUDE_REGEXES</item> + <item>PRE_INCLUDE_REGEXES</item> <item>READ</item> <item>READ_SYMLINK</item> <item>REAL_PATH</item> @@ -358,6 +417,8 @@ <item>REMOVE</item> <item>REMOVE_RECURSE</item> <item>RENAME</item> + <item>RESOLVED_DEPENDENCIES_VAR</item> + <item>RESULT</item> <item>RESULT_VARIABLE</item> <item>SHA1</item> <item>SHA224</item> @@ -381,6 +442,7 @@ <item>TOUCH_NOCREATE</item> <item>TO_CMAKE_PATH</item> <item>TO_NATIVE_PATH</item> + <item>UNRESOLVED_DEPENDENCIES_VAR</item> <item>UPLOAD</item> <item>USERPWD</item> <item>USE_SOURCE_PERMISSIONS</item> @@ -433,6 +495,7 @@ <item>DOC</item> <item>HINTS</item> <item>NAMES</item> + <item>NO_CACHE</item> <item>NO_CMAKE_ENVIRONMENT_PATH</item> <item>NO_CMAKE_FIND_ROOT_PATH</item> <item>NO_CMAKE_PATH</item> @@ -451,6 +514,7 @@ <item>HINTS</item> <item>NAMES</item> <item>NAMES_PER_DIR</item> + <item>NO_CACHE</item> <item>NO_CMAKE_ENVIRONMENT_PATH</item> <item>NO_CMAKE_FIND_ROOT_PATH</item> <item>NO_CMAKE_PATH</item> @@ -495,6 +559,7 @@ <item>DOC</item> <item>HINTS</item> <item>NAMES</item> + <item>NO_CACHE</item> <item>NO_CMAKE_ENVIRONMENT_PATH</item> <item>NO_CMAKE_FIND_ROOT_PATH</item> <item>NO_CMAKE_PATH</item> @@ -513,6 +578,7 @@ <item>HINTS</item> <item>NAMES</item> <item>NAMES_PER_DIR</item> + <item>NO_CACHE</item> <item>NO_CMAKE_ENVIRONMENT_PATH</item> <item>NO_CMAKE_FIND_ROOT_PATH</item> <item>NO_CMAKE_PATH</item> @@ -883,6 +949,7 @@ </list> <list name="build_command_nargs"> <item>CONFIGURATION</item> + <item>PARALLEL_LEVEL</item> <item>TARGET</item> </list> <list name="create_test_sourcelist_nargs"> @@ -914,6 +981,7 @@ <item>CUDA</item> <item>CXX</item> <item>Fortran</item> + <item>HIP</item> <item>ISPC</item> <item>Java</item> <item>OBJC</item> @@ -951,6 +1019,7 @@ <item>COMPONENT</item> <item>CONFIGURATIONS</item> <item>DESTINATION</item> + <item>DIRECTORIES</item> <item>DIRECTORY</item> <item>DIRECTORY_PERMISSIONS</item> <item>EXCLUDE</item> @@ -963,6 +1032,7 @@ <item>FILES_MATCHING</item> <item>FILE_PERMISSIONS</item> <item>FRAMEWORK</item> + <item>IMPORTED_RUNTIME_ARTIFACTS</item> <item>INCLUDES</item> <item>LIBRARY</item> <item>MESSAGE_NEVER</item> @@ -974,6 +1044,12 @@ <item>OPTIONAL</item> <item>PATTERN</item> <item>PERMISSIONS</item> + <item>POST_EXCLUDE_FILES</item> + <item>POST_EXCLUDE_REGEXES</item> + <item>POST_INCLUDE_FILES</item> + <item>POST_INCLUDE_REGEXES</item> + <item>PRE_EXCLUDE_REGEXES</item> + <item>PRE_INCLUDE_REGEXES</item> <item>PRIVATE_HEADER</item> <item>PROGRAMS</item> <item>PUBLIC_HEADER</item> @@ -981,8 +1057,11 @@ <item>RENAME</item> <item>RESOURCE</item> <item>RUNTIME</item> + <item>RUNTIME_DEPENDENCIES</item> + <item>RUNTIME_DEPENDENCY_SET</item> <item>SCRIPT</item> <item>TARGETS</item> + <item>TYPE</item> <item>USE_SOURCE_PERMISSIONS</item> </list> <list name="install_sargs"> @@ -1028,6 +1107,7 @@ <item>CUDA</item> <item>CXX</item> <item>Fortran</item> + <item>HIP</item> <item>ISPC</item> <item>Java</item> <item>NONE</item> @@ -1068,6 +1148,8 @@ <item>c_restrict</item> <item>c_static_assert</item> <item>c_std_11</item> + <item>c_std_17</item> + <item>c_std_23</item> <item>c_std_90</item> <item>c_std_99</item> <item>c_variadic_macros</item> @@ -1076,6 +1158,7 @@ <item>cuda_std_14</item> <item>cuda_std_17</item> <item>cuda_std_20</item> + <item>cuda_std_23</item> <item>cxx_aggregate_default_initializers</item> <item>cxx_alias_templates</item> <item>cxx_alignas</item> @@ -1126,6 +1209,7 @@ <item>cxx_std_14</item> <item>cxx_std_17</item> <item>cxx_std_20</item> + <item>cxx_std_23</item> <item>cxx_std_98</item> <item>cxx_strong_enums</item> <item>cxx_template_template_parameters</item> @@ -1146,6 +1230,7 @@ <item>PUBLIC</item> </list> <list name="target_include_directories_nargs"> + <item>AFTER</item> <item>BEFORE</item> <item>INTERFACE</item> <item>PRIVATE</item> @@ -1201,6 +1286,7 @@ <item>OUTPUT_VARIABLE</item> <item>RUN_OUTPUT_VARIABLE</item> <item>RUN_RESULT_VAR</item> + <item>WORKING_DIRECTORY</item> </list> <list name="ctest_build_nargs"> <item>APPEND</item> @@ -1342,6 +1428,7 @@ <item>CMAKE_ANDROID_NDK_DEPRECATED_HEADERS</item> <item>CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG</item> <item>CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION</item> + <item>CMAKE_ANDROID_NDK_VERSION</item> <item>CMAKE_ANDROID_PROCESS_MAX</item> <item>CMAKE_ANDROID_PROGUARD</item> <item>CMAKE_ANDROID_PROGUARD_CONFIG_PATH</item> @@ -1497,6 +1584,9 @@ <item>CMAKE_GENERATOR_NO_COMPILER_ENV</item> <item>CMAKE_GENERATOR_PLATFORM</item> <item>CMAKE_GENERATOR_TOOLSET</item> + <item>CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND</item> + <item>CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM</item> + <item>CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL</item> <item>CMAKE_GLOBAL_AUTOGEN_TARGET</item> <item>CMAKE_GLOBAL_AUTOGEN_TARGET_NAME</item> <item>CMAKE_GLOBAL_AUTORCC_TARGET</item> @@ -1576,6 +1666,10 @@ <item>CMAKE_ISPC_HEADER_DIRECTORY</item> <item>CMAKE_ISPC_HEADER_SUFFIX</item> <item>CMAKE_ISPC_INSTRUCTION_SETS</item> + <item>CMAKE_JAR_CLASSES_PREFIX</item> + <item>CMAKE_JAVA_COMPILE_FLAGS</item> + <item>CMAKE_JAVA_INCLUDE_PATH</item> + <item>CMAKE_JNI_TARGET</item> <item>CMAKE_JOB_POOLS</item> <item>CMAKE_JOB_POOL_COMPILE</item> <item>CMAKE_JOB_POOL_LINK</item> @@ -1787,6 +1881,7 @@ <item>CPACK_COMPONENTS_GROUPING</item> <item>CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY</item> <item>CPACK_CREATE_DESKTOP_LINKS</item> + <item>CPACK_CUSTOM_INSTALL_VARIABLES</item> <item>CPACK_CYGWIN_BUILD_SCRIPT</item> <item>CPACK_CYGWIN_PATCH_FILE</item> <item>CPACK_CYGWIN_PATCH_NUMBER</item> @@ -1818,6 +1913,7 @@ <item>CPACK_DEBIAN_PACKAGE_REPLACES</item> <item>CPACK_DEBIAN_PACKAGE_SECTION</item> <item>CPACK_DEBIAN_PACKAGE_SHLIBDEPS</item> + <item>CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS</item> <item>CPACK_DEBIAN_PACKAGE_SOURCE</item> <item>CPACK_DEBIAN_PACKAGE_SUGGESTS</item> <item>CPACK_DEBIAN_PACKAGE_VERSION</item> @@ -1826,6 +1922,7 @@ <item>CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK</item> <item>CPACK_DMG_DS_STORE</item> <item>CPACK_DMG_DS_STORE_SETUP_SCRIPT</item> + <item>CPACK_DMG_FILESYSTEM</item> <item>CPACK_DMG_FORMAT</item> <item>CPACK_DMG_SLA_DIR</item> <item>CPACK_DMG_SLA_LANGUAGES</item> @@ -1865,6 +1962,7 @@ <item>CPACK_IFW_PACKAGE_WINDOW_ICON</item> <item>CPACK_IFW_PACKAGE_WIZARD_DEFAULT_HEIGHT</item> <item>CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH</item> + <item>CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST</item> <item>CPACK_IFW_PACKAGE_WIZARD_STYLE</item> <item>CPACK_IFW_PRODUCT_URL</item> <item>CPACK_IFW_REPOGEN_EXECUTABLE</item> @@ -1880,12 +1978,15 @@ <item>CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS</item> <item>CPACK_INSTALL_SCRIPTS</item> <item>CPACK_MONOLITHIC_INSTALL</item> + <item>CPACK_NSIS_BRANDING_TEXT</item> + <item>CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION</item> <item>CPACK_NSIS_COMPRESSOR</item> <item>CPACK_NSIS_CONTACT</item> <item>CPACK_NSIS_CREATE_ICONS_EXTRA</item> <item>CPACK_NSIS_DELETE_ICONS_EXTRA</item> <item>CPACK_NSIS_DISPLAY_NAME</item> <item>CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL</item> + <item>CPACK_NSIS_EXECUTABLE</item> <item>CPACK_NSIS_EXECUTABLES_DIRECTORY</item> <item>CPACK_NSIS_EXTRA_INSTALL_COMMANDS</item> <item>CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS</item> @@ -1918,8 +2019,12 @@ <item>CPACK_NUGET_PACKAGE_DESCRIPTION</item> <item>CPACK_NUGET_PACKAGE_DESCRIPTION_SUMMARY</item> <item>CPACK_NUGET_PACKAGE_HOMEPAGE_URL</item> + <item>CPACK_NUGET_PACKAGE_ICON</item> <item>CPACK_NUGET_PACKAGE_ICONURL</item> + <item>CPACK_NUGET_PACKAGE_LANGUAGE</item> <item>CPACK_NUGET_PACKAGE_LICENSEURL</item> + <item>CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION</item> + <item>CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME</item> <item>CPACK_NUGET_PACKAGE_NAME</item> <item>CPACK_NUGET_PACKAGE_OWNERS</item> <item>CPACK_NUGET_PACKAGE_RELEASE_NOTES</item> @@ -2037,6 +2142,7 @@ <item>CPACK_SOURCE_STRIP_FILES</item> <item>CPACK_STRIP_FILES</item> <item>CPACK_SYSTEM_NAME</item> + <item>CPACK_THREADS</item> <item>CPACK_TOPLEVEL_TAG</item> <item>CPACK_VERBATIM_VARIABLES</item> <item>CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION</item> @@ -2180,12 +2286,23 @@ <item>MSVC_TOOLSET_VERSION</item> <item>MSVC_VERSION</item> <item>PACKAGE_FIND_NAME</item> - <item>PACKAGE_FIND_VERSION</item> + <item>PACKAGE_FIND_VERSION_COMPLETE</item> <item>PACKAGE_FIND_VERSION_COUNT</item> - <item>PACKAGE_FIND_VERSION_MAJOR</item> - <item>PACKAGE_FIND_VERSION_MINOR</item> - <item>PACKAGE_FIND_VERSION_PATCH</item> - <item>PACKAGE_FIND_VERSION_TWEAK</item> + <item>PACKAGE_FIND_VERSION_MAX</item> + <item>PACKAGE_FIND_VERSION_MAX_COUNT</item> + <item>PACKAGE_FIND_VERSION_MAX_MAJOR</item> + <item>PACKAGE_FIND_VERSION_MAX_MINOR</item> + <item>PACKAGE_FIND_VERSION_MAX_PATCH</item> + <item>PACKAGE_FIND_VERSION_MAX_TWEAK</item> + <item>PACKAGE_FIND_VERSION_MIN</item> + <item>PACKAGE_FIND_VERSION_MIN_COUNT</item> + <item>PACKAGE_FIND_VERSION_MIN_MAJOR</item> + <item>PACKAGE_FIND_VERSION_MIN_MINOR</item> + <item>PACKAGE_FIND_VERSION_MIN_PATCH</item> + <item>PACKAGE_FIND_VERSION_MIN_TWEAK</item> + <item>PACKAGE_FIND_VERSION_RANGE</item> + <item>PACKAGE_FIND_VERSION_RANGE_MAX</item> + <item>PACKAGE_FIND_VERSION_RANGE_MIN</item> <item>PACKAGE_VERSION</item> <item>PACKAGE_VERSION_COMPATIBLE</item> <item>PACKAGE_VERSION_EXACT</item> @@ -2196,6 +2313,7 @@ <item>PROJECT_BINARY_DIR</item> <item>PROJECT_DESCRIPTION</item> <item>PROJECT_HOMEPAGE_URL</item> + <item>PROJECT_IS_TOP_LEVEL</item> <item>PROJECT_NAME</item> <item>PROJECT_SOURCE_DIR</item> <item>PROJECT_VERSION</item> @@ -2206,8 +2324,10 @@ <item>QTIFWDIR</item> <item>SWIG_OUTFILE_DIR</item> <item>SWIG_SOURCE_FILE_EXTENSIONS</item> + <item>SWIG_USE_SWIG_DEPENDENCIES</item> <item>THREADS_PREFER_PTHREAD_FLAG</item> <item>UNIX</item> + <item>UseSWIG_MODULE_VERSION</item> <item>WIN32</item> <item>WINCE</item> <item>WINDOWS_PHONE</item> @@ -2220,8 +2340,10 @@ <item>CMAKE_HOME_DIRECTORY</item> <item>CMAKE_INTERNAL_PLATFORM_ABI</item> <item>CMAKE_NOT_USING_CONFIG_FLAGS</item> + <item>CMAKE_OBJDUMP</item> <item>CMAKE_SUPPRESS_DEVELOPER_ERRORS</item> <item>CMAKE_SUPPRESS_DEVELOPER_WARNINGS</item> + <item>CMAKE_SYSTEM_ARCH</item> <item>CMAKE_VS_INTEL_Fortran_PROJECT_VERSION</item> <item>CPACK_INSTALL_PREFIX</item> <item>CPACK_INSTALL_SCRIPT</item> @@ -2248,12 +2370,14 @@ <item>CMAKE_NO_VERBOSE</item> <item>CMAKE_OSX_ARCHITECTURES</item> <item>CMAKE_PREFIX_PATH</item> + <item>CMAKE_TOOLCHAIN_FILE</item> <item>CSFLAGS</item> <item>CTEST_INTERACTIVE_DEBUG_MODE</item> <item>CTEST_OUTPUT_ON_FAILURE</item> <item>CTEST_PARALLEL_LEVEL</item> <item>CTEST_PROGRESS_OUTPUT</item> <item>CTEST_USE_LAUNCHERS_DEFAULT</item> + <item>CUDAARCHS</item> <item>CUDACXX</item> <item>CUDAFLAGS</item> <item>CUDAHOSTCXX</item> @@ -2326,6 +2450,7 @@ <item>DEFINITIONS</item> <item>EXCLUDE_FROM_ALL</item> <item>IMPLICIT_DEPENDS_INCLUDE_TRANSFORM</item> + <item>IMPORTED_TARGETS</item> <item>INCLUDE_DIRECTORIES</item> <item>INCLUDE_REGULAR_EXPRESSION</item> <item>INTERPROCEDURAL_OPTIMIZATION</item> @@ -2429,6 +2554,7 @@ <item>ENABLE_EXPORTS</item> <item>EXCLUDE_FROM_ALL</item> <item>EXCLUDE_FROM_DEFAULT_BUILD</item> + <item>EXPORT_COMPILE_COMMANDS</item> <item>EXPORT_NAME</item> <item>EXPORT_PROPERTIES</item> <item>EchoString</item> @@ -2554,6 +2680,7 @@ <item>UNITY_BUILD_CODE_AFTER_INCLUDE</item> <item>UNITY_BUILD_CODE_BEFORE_INCLUDE</item> <item>UNITY_BUILD_MODE</item> + <item>UNITY_BUILD_UNIQUE_ID</item> <item>VERSION</item> <item>VISIBILITY_INLINES_HIDDEN</item> <item>VS_CONFIGURATION_TYPE</item> @@ -2782,6 +2909,7 @@ <item>TARGET_BUNDLE_DIR</item> <item>TARGET_BUNDLE_CONTENT_DIR</item> <item>TARGET_PROPERTY</item> + <item>TARGET_RUNTIME_DLLS</item> <item>INSTALL_PREFIX</item> <item>TARGET_NAME</item> <item>LINK_ONLY</item> @@ -2790,6 +2918,8 @@ <item>MAKE_C_IDENTIFIER</item> <item>TARGET_OBJECTS</item> <item>SHELL_PATH</item> + <item>OUTPUT_CONFIG</item> + <item>COMMAND_CONFIG</item> </list> <contexts> @@ -2801,6 +2931,7 @@ <WordDetect String="cmake_language" insensitive="true" attribute="Command" context="cmake_language_ctx" /> <WordDetect String="cmake_minimum_required" insensitive="true" attribute="Command" context="cmake_minimum_required_ctx" /> <WordDetect String="cmake_parse_arguments" insensitive="true" attribute="Command" context="cmake_parse_arguments_ctx" /> + <WordDetect String="cmake_path" insensitive="true" attribute="Command" context="cmake_path_ctx" /> <WordDetect String="cmake_policy" insensitive="true" attribute="Command" context="cmake_policy_ctx" /> <WordDetect String="configure_file" insensitive="true" attribute="Command" context="configure_file_ctx" /> <WordDetect String="continue" insensitive="true" attribute="Command" context="continue_ctx" /> @@ -2950,6 +3081,14 @@ <keyword attribute="Named Args" context="#stay" String="cmake_parse_arguments_nargs" /> <IncludeRules context="User Function Args" /> </context> + <context attribute="Normal Text" lineEndContext="#stay" name="cmake_path_ctx"> + <DetectChar attribute="Normal Text" context="cmake_path_ctx_op" char="(" /> + </context> + <context attribute="Normal Text" lineEndContext="#stay" name="cmake_path_ctx_op"> + <IncludeRules context="EndCmdPop2" /> + <keyword attribute="Named Args" context="#stay" String="cmake_path_nargs" /> + <IncludeRules context="User Function Args" /> + </context> <context attribute="Normal Text" lineEndContext="#stay" name="cmake_policy_ctx"> <DetectChar attribute="Normal Text" context="cmake_policy_ctx_op" char="(" /> </context> @@ -3860,7 +3999,7 @@ </context> <context attribute="Normal Text" lineEndContext="#stay" name="Detect More target-properties"> - <RegExpr attribute="Property" context="#stay" String="\b(?:XCODE_ATTRIBUTE_&id_re;|VS_SOURCE_SETTINGS_&id_re;|VS_GLOBAL_&id_re;|VS_DOTNET_REFERENCE_&id_re;|VS_DOTNET_REFERENCEPROP_&id_re;_TAG_&id_re;|STATIC_LIBRARY_FLAGS_&id_re;|RUNTIME_OUTPUT_NAME_&id_re;|RUNTIME_OUTPUT_DIRECTORY_&id_re;|PDB_OUTPUT_DIRECTORY_&id_re;|PDB_NAME_&id_re;|OUTPUT_NAME_&id_re;|OSX_ARCHITECTURES_&id_re;|MAP_IMPORTED_CONFIG_&id_re;|LOCATION_&id_re;|LINK_INTERFACE_MULTIPLICITY_&id_re;|LINK_INTERFACE_LIBRARIES_&id_re;|LINK_FLAGS_&id_re;|LIBRARY_OUTPUT_NAME_&id_re;|LIBRARY_OUTPUT_DIRECTORY_&id_re;|INTERPROCEDURAL_OPTIMIZATION_&id_re;|IMPORTED_SONAME_&id_re;|IMPORTED_OBJECTS_&id_re;|IMPORTED_NO_SONAME_&id_re;|IMPORTED_LOCATION_&id_re;|IMPORTED_LINK_INTERFACE_MULTIPLICITY_&id_re;|IMPORTED_LINK_INTERFACE_LIBRARIES_&id_re;|IMPORTED_LINK_INTERFACE_LANGUAGES_&id_re;|IMPORTED_LINK_DEPENDENT_LIBRARIES_&id_re;|IMPORTED_LIBNAME_&id_re;|IMPORTED_IMPLIB_&id_re;|FRAMEWORK_MULTI_CONFIG_POSTFIX_&id_re;|EXCLUDE_FROM_DEFAULT_BUILD_&id_re;|COMPILE_PDB_OUTPUT_DIRECTORY_&id_re;|COMPILE_PDB_NAME_&id_re;|ARCHIVE_OUTPUT_NAME_&id_re;|ARCHIVE_OUTPUT_DIRECTORY_&id_re;|&id_re;_VISIBILITY_PRESET|&id_re;_POSTFIX|&id_re;_OUTPUT_NAME|&id_re;_INCLUDE_WHAT_YOU_USE|&id_re;_CPPLINT|&id_re;_CPPCHECK|&id_re;_COMPILER_LAUNCHER|&id_re;_CLANG_TIDY)\b" /> + <RegExpr attribute="Property" context="#stay" String="\b(?:XCODE_EMBED_&id_re;_REMOVE_HEADERS_ON_COPY|XCODE_EMBED_&id_re;_PATH|XCODE_EMBED_&id_re;_CODE_SIGN_ON_COPY|XCODE_EMBED_&id_re;|XCODE_ATTRIBUTE_&id_re;|VS_SOURCE_SETTINGS_&id_re;|VS_GLOBAL_&id_re;|VS_DOTNET_REFERENCE_&id_re;|VS_DOTNET_REFERENCEPROP_&id_re;_TAG_&id_re;|STATIC_LIBRARY_FLAGS_&id_re;|RUNTIME_OUTPUT_NAME_&id_re;|RUNTIME_OUTPUT_DIRECTORY_&id_re;|PDB_OUTPUT_DIRECTORY_&id_re;|PDB_NAME_&id_re;|OUTPUT_NAME_&id_re;|OSX_ARCHITECTURES_&id_re;|MAP_IMPORTED_CONFIG_&id_re;|LOCATION_&id_re;|LINK_INTERFACE_MULTIPLICITY_&id_re;|LINK_INTERFACE_LIBRARIES_&id_re;|LINK_FLAGS_&id_re;|LIBRARY_OUTPUT_NAME_&id_re;|LIBRARY_OUTPUT_DIRECTORY_&id_re;|INTERPROCEDURAL_OPTIMIZATION_&id_re;|IMPORTED_SONAME_&id_re;|IMPORTED_OBJECTS_&id_re;|IMPORTED_NO_SONAME_&id_re;|IMPORTED_LOCATION_&id_re;|IMPORTED_LINK_INTERFACE_MULTIPLICITY_&id_re;|IMPORTED_LINK_INTERFACE_LIBRARIES_&id_re;|IMPORTED_LINK_INTERFACE_LANGUAGES_&id_re;|IMPORTED_LINK_DEPENDENT_LIBRARIES_&id_re;|IMPORTED_LIBNAME_&id_re;|IMPORTED_IMPLIB_&id_re;|FRAMEWORK_MULTI_CONFIG_POSTFIX_&id_re;|EXCLUDE_FROM_DEFAULT_BUILD_&id_re;|COMPILE_PDB_OUTPUT_DIRECTORY_&id_re;|COMPILE_PDB_NAME_&id_re;|ARCHIVE_OUTPUT_NAME_&id_re;|ARCHIVE_OUTPUT_DIRECTORY_&id_re;|&id_re;_VISIBILITY_PRESET|&id_re;_POSTFIX|&id_re;_OUTPUT_NAME|&id_re;_LINKER_LAUNCHER|&id_re;_INCLUDE_WHAT_YOU_USE|&id_re;_CPPLINT|&id_re;_CPPCHECK|&id_re;_COMPILER_LAUNCHER|&id_re;_CLANG_TIDY)\b" /> </context> <context attribute="Normal Text" lineEndContext="#stay" name="Detect More source-properties"> @@ -3894,7 +4033,7 @@ <context attribute="Normal Text" lineEndContext="#stay" name="Detect More Builtin Variables"> <RegExpr attribute="CMake Internal Variable" context="#stay" String="\b(?:CMAKE_&id_re;_PLATFORM_ID|CMAKE_&id_re;_COMPILER_VERSION_INTERNAL|CMAKE_&id_re;_COMPILER_ARCHITECTURE_ID|CMAKE_&id_re;_COMPILER_ABI)\b" /> - <RegExpr attribute="Builtin Variable" context="#stay" String="\b(?:SWIG_MODULE_&id_re;_EXTRA_DEPS|ExternalData_URL_ALGO_&id_re;_&id_re;|ExternalData_CUSTOM_SCRIPT_&id_re;|DOXYGEN_&id_re;|CPACK_WIX_PROPERTY_&id_re;|CPACK_WIX_&id_re;_EXTRA_FLAGS|CPACK_WIX_&id_re;_EXTENSIONS|CPACK_RPM_NO_&id_re;_INSTALL_PREFIX_RELOCATION|CPACK_RPM_&id_re;_USER_FILELIST|CPACK_RPM_&id_re;_USER_BINARY_SPECFILE|CPACK_RPM_&id_re;_PACKAGE_URL|CPACK_RPM_&id_re;_PACKAGE_SUMMARY|CPACK_RPM_&id_re;_PACKAGE_SUGGESTS|CPACK_RPM_&id_re;_PACKAGE_REQUIRES_PREUN|CPACK_RPM_&id_re;_PACKAGE_REQUIRES_PRE|CPACK_RPM_&id_re;_PACKAGE_REQUIRES_POSTUN|CPACK_RPM_&id_re;_PACKAGE_REQUIRES_POST|CPACK_RPM_&id_re;_PACKAGE_REQUIRES|CPACK_RPM_&id_re;_PACKAGE_PROVIDES|CPACK_RPM_&id_re;_PACKAGE_PREFIX|CPACK_RPM_&id_re;_PACKAGE_OBSOLETES|CPACK_RPM_&id_re;_PACKAGE_NAME|CPACK_RPM_&id_re;_PACKAGE_GROUP|CPACK_RPM_&id_re;_PACKAGE_DESCRIPTION|CPACK_RPM_&id_re;_PACKAGE_CONFLICTS|CPACK_RPM_&id_re;_PACKAGE_AUTOREQPROV|CPACK_RPM_&id_re;_PACKAGE_AUTOREQ|CPACK_RPM_&id_re;_PACKAGE_AUTOPROV|CPACK_RPM_&id_re;_PACKAGE_ARCHITECTURE|CPACK_RPM_&id_re;_FILE_NAME|CPACK_RPM_&id_re;_DEFAULT_USER|CPACK_RPM_&id_re;_DEFAULT_GROUP|CPACK_RPM_&id_re;_DEFAULT_FILE_PERMISSIONS|CPACK_RPM_&id_re;_DEFAULT_DIR_PERMISSIONS|CPACK_RPM_&id_re;_DEBUGINFO_PACKAGE|CPACK_RPM_&id_re;_DEBUGINFO_FILE_NAME|CPACK_RPM_&id_re;_BUILD_SOURCE_DIRS_PREFIX|CPACK_PREFLIGHT_&id_re;_SCRIPT|CPACK_POSTFLIGHT_&id_re;_SCRIPT|CPACK_NUGET_PACKAGE_DEPENDENCIES_&id_re;_VERSION|CPACK_NUGET_&id_re;_PACKAGE_VERSION|CPACK_NUGET_&id_re;_PACKAGE_TITLE|CPACK_NUGET_&id_re;_PACKAGE_TAGS|CPACK_NUGET_&id_re;_PACKAGE_RELEASE_NOTES|CPACK_NUGET_&id_re;_PACKAGE_OWNERS|CPACK_NUGET_&id_re;_PACKAGE_NAME|CPACK_NUGET_&id_re;_PACKAGE_LICENSEURL|CPACK_NUGET_&id_re;_PACKAGE_ICONURL|CPACK_NUGET_&id_re;_PACKAGE_HOMEPAGE_URL|CPACK_NUGET_&id_re;_PACKAGE_DESCRIPTION_SUMMARY|CPACK_NUGET_&id_re;_PACKAGE_DESCRIPTION|CPACK_NUGET_&id_re;_PACKAGE_DEPENDENCIES_&id_re;_VERSION|CPACK_NUGET_&id_re;_PACKAGE_DEPENDENCIES|CPACK_NUGET_&id_re;_PACKAGE_COPYRIGHT|CPACK_NUGET_&id_re;_PACKAGE_AUTHORS|CPACK_NSIS_&id_re;_INSTALL_DIRECTORY|CPACK_DMG_&id_re;_FILE_NAME|CPACK_DEBIAN_&id_re;_PACKAGE_SUGGESTS|CPACK_DEBIAN_&id_re;_PACKAGE_SOURCE|CPACK_DEBIAN_&id_re;_PACKAGE_SHLIBDEPS|CPACK_DEBIAN_&id_re;_PACKAGE_SECTION|CPACK_DEBIAN_&id_re;_PACKAGE_REPLACES|CPACK_DEBIAN_&id_re;_PACKAGE_RECOMMENDS|CPACK_DEBIAN_&id_re;_PACKAGE_PROVIDES|CPACK_DEBIAN_&id_re;_PACKAGE_PRIORITY|CPACK_DEBIAN_&id_re;_PACKAGE_PREDEPENDS|CPACK_DEBIAN_&id_re;_PACKAGE_NAME|CPACK_DEBIAN_&id_re;_PACKAGE_ENHANCES|CPACK_DEBIAN_&id_re;_PACKAGE_DEPENDS|CPACK_DEBIAN_&id_re;_PACKAGE_CONTROL_STRICT_PERMISSION|CPACK_DEBIAN_&id_re;_PACKAGE_CONTROL_EXTRA|CPACK_DEBIAN_&id_re;_PACKAGE_CONFLICTS|CPACK_DEBIAN_&id_re;_PACKAGE_BREAKS|CPACK_DEBIAN_&id_re;_PACKAGE_ARCHITECTURE|CPACK_DEBIAN_&id_re;_FILE_NAME|CPACK_DEBIAN_&id_re;_DESCRIPTION|CPACK_DEBIAN_&id_re;_DEBUGINFO_PACKAGE|CPACK_COMPONENT_&id_re;_REQUIRED|CPACK_COMPONENT_&id_re;_HIDDEN|CPACK_COMPONENT_&id_re;_GROUP|CPACK_COMPONENT_&id_re;_DISPLAY_NAME|CPACK_COMPONENT_&id_re;_DISABLED|CPACK_COMPONENT_&id_re;_DESCRIPTION|CPACK_COMPONENT_&id_re;_DEPENDS|CPACK_BINARY_&id_re;|CPACK_ARCHIVE_&id_re;_FILE_NAME|CPACK_&id_re;_COMPONENT_INSTALL|CMAKE_XCODE_ATTRIBUTE_&id_re;|CMAKE_USER_MAKE_RULES_OVERRIDE_&id_re;|CMAKE_STATIC_LINKER_FLAGS_&id_re;_INIT|CMAKE_STATIC_LINKER_FLAGS_&id_re;|CMAKE_SHARED_LINKER_FLAGS_&id_re;_INIT|CMAKE_SHARED_LINKER_FLAGS_&id_re;|CMAKE_RUNTIME_OUTPUT_DIRECTORY_&id_re;|CMAKE_PROJECT_&id_re;_INCLUDE|CMAKE_POLICY_WARNING_CMP[0-9]{4}|CMAKE_POLICY_DEFAULT_CMP[0-9]{4}|CMAKE_PDB_OUTPUT_DIRECTORY_&id_re;|CMAKE_MODULE_LINKER_FLAGS_&id_re;_INIT|CMAKE_MODULE_LINKER_FLAGS_&id_re;|CMAKE_MATCH_[0-9]+|CMAKE_MAP_IMPORTED_CONFIG_&id_re;|CMAKE_LIBRARY_OUTPUT_DIRECTORY_&id_re;|CMAKE_INTERPROCEDURAL_OPTIMIZATION_&id_re;|CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_&id_re;|CMAKE_EXE_LINKER_FLAGS_&id_re;_INIT|CMAKE_EXE_LINKER_FLAGS_&id_re;|CMAKE_DISABLE_FIND_PACKAGE_&id_re;|CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_&id_re;|CMAKE_ARGV[0-9]+|CMAKE_ARCHIVE_OUTPUT_DIRECTORY_&id_re;|CMAKE_&id_re;_VISIBILITY_PRESET|CMAKE_&id_re;_STANDARD_LIBRARIES|CMAKE_&id_re;_STANDARD_INCLUDE_DIRECTORIES|CMAKE_&id_re;_SOURCE_FILE_EXTENSIONS|CMAKE_&id_re;_SIZEOF_DATA_PTR|CMAKE_&id_re;_SIMULATE_VERSION|CMAKE_&id_re;_SIMULATE_ID|CMAKE_&id_re;_POSTFIX|CMAKE_&id_re;_OUTPUT_EXTENSION|CMAKE_&id_re;_LINK_EXECUTABLE|CMAKE_&id_re;_LINKER_WRAPPER_FLAG_SEP|CMAKE_&id_re;_LINKER_WRAPPER_FLAG|CMAKE_&id_re;_LINKER_PREFERENCE_PROPAGATES|CMAKE_&id_re;_LINKER_PREFERENCE|CMAKE_&id_re;_LIBRARY_ARCHITECTURE|CMAKE_&id_re;_INCLUDE_WHAT_YOU_USE|CMAKE_&id_re;_IMPLICIT_LINK_LIBRARIES|CMAKE_&id_re;_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES|CMAKE_&id_re;_IMPLICIT_LINK_DIRECTORIES|CMAKE_&id_re;_IMPLICIT_INCLUDE_DIRECTORIES|CMAKE_&id_re;_IGNORE_EXTENSIONS|CMAKE_&id_re;_GHS_KERNEL_FLAGS_RELWITHDEBINFO|CMAKE_&id_re;_GHS_KERNEL_FLAGS_RELEASE|CMAKE_&id_re;_GHS_KERNEL_FLAGS_MINSIZEREL|CMAKE_&id_re;_GHS_KERNEL_FLAGS_DEBUG|CMAKE_&id_re;_FLAGS_RELWITHDEBINFO_INIT|CMAKE_&id_re;_FLAGS_RELWITHDEBINFO|CMAKE_&id_re;_FLAGS_RELEASE_INIT|CMAKE_&id_re;_FLAGS_RELEASE|CMAKE_&id_re;_FLAGS_MINSIZEREL_INIT|CMAKE_&id_re;_FLAGS_MINSIZEREL|CMAKE_&id_re;_FLAGS_INIT|CMAKE_&id_re;_FLAGS_DEBUG_INIT|CMAKE_&id_re;_FLAGS_DEBUG|CMAKE_&id_re;_FLAGS|CMAKE_&id_re;_CREATE_STATIC_LIBRARY|CMAKE_&id_re;_CREATE_SHARED_MODULE|CMAKE_&id_re;_CREATE_SHARED_LIBRARY|CMAKE_&id_re;_CPPLINT|CMAKE_&id_re;_CPPCHECK|CMAKE_&id_re;_COMPILE_OBJECT|CMAKE_&id_re;_COMPILER_VERSION|CMAKE_&id_re;_COMPILER_TARGET|CMAKE_&id_re;_COMPILER_RANLIB|CMAKE_&id_re;_COMPILER_LOADED|CMAKE_&id_re;_COMPILER_LAUNCHER|CMAKE_&id_re;_COMPILER_ID|CMAKE_&id_re;_COMPILER_EXTERNAL_TOOLCHAIN|CMAKE_&id_re;_COMPILER_AR|CMAKE_&id_re;_COMPILER|CMAKE_&id_re;_CLANG_TIDY|CMAKE_&id_re;_ARCHIVE_FINISH|CMAKE_&id_re;_ARCHIVE_CREATE|CMAKE_&id_re;_ARCHIVE_APPEND|CMAKE_&id_re;_ANDROID_TOOLCHAIN_SUFFIX|CMAKE_&id_re;_ANDROID_TOOLCHAIN_PREFIX|CMAKE_&id_re;_ANDROID_TOOLCHAIN_MACHINE|ARGV[0-9]+|&id_re;__TRYRUN_OUTPUT|&id_re;_VERSION_TWEAK|&id_re;_VERSION_STRING|&id_re;_VERSION_PATCH|&id_re;_VERSION_MINOR|&id_re;_VERSION_MAJOR|&id_re;_VERSION_COUNT|&id_re;_VERSION|&id_re;_UNPARSED_ARGUMENTS|&id_re;_SOURCE_DIR|&id_re;_ROOT|&id_re;_MODULE_NAME|&id_re;_LIBRARY_DIRS|&id_re;_LIBRARIES|&id_re;_KEYWORDS_MISSING_VALUES|&id_re;_INCLUDE_DIRS|&id_re;_HOMEPAGE_URL|&id_re;_FOUND|&id_re;_FIND_VERSION_TWEAK|&id_re;_FIND_VERSION_PATCH|&id_re;_FIND_VERSION_MINOR|&id_re;_FIND_VERSION_MAJOR|&id_re;_FIND_VERSION_EXACT|&id_re;_FIND_VERSION_COUNT|&id_re;_FIND_VERSION|&id_re;_FIND_REQUIRED_&id_re;|&id_re;_FIND_REQUIRED|&id_re;_FIND_QUIETLY|&id_re;_FIND_COMPONENTS|&id_re;_DESCRIPTION|&id_re;_CONSIDERED_VERSIONS|&id_re;_CONSIDERED_CONFIGS|&id_re;_BINARY_DIR)\b" /> + <RegExpr attribute="Builtin Variable" context="#stay" String="\b(?:SWIG_MODULE_&id_re;_EXTRA_DEPS|ExternalData_URL_ALGO_&id_re;_&id_re;|ExternalData_CUSTOM_SCRIPT_&id_re;|DOXYGEN_&id_re;|CPACK_WIX_PROPERTY_&id_re;|CPACK_WIX_&id_re;_EXTRA_FLAGS|CPACK_WIX_&id_re;_EXTENSIONS|CPACK_RPM_NO_&id_re;_INSTALL_PREFIX_RELOCATION|CPACK_RPM_&id_re;_USER_FILELIST|CPACK_RPM_&id_re;_USER_BINARY_SPECFILE|CPACK_RPM_&id_re;_PACKAGE_URL|CPACK_RPM_&id_re;_PACKAGE_SUMMARY|CPACK_RPM_&id_re;_PACKAGE_SUGGESTS|CPACK_RPM_&id_re;_PACKAGE_REQUIRES_PREUN|CPACK_RPM_&id_re;_PACKAGE_REQUIRES_PRE|CPACK_RPM_&id_re;_PACKAGE_REQUIRES_POSTUN|CPACK_RPM_&id_re;_PACKAGE_REQUIRES_POST|CPACK_RPM_&id_re;_PACKAGE_REQUIRES|CPACK_RPM_&id_re;_PACKAGE_PROVIDES|CPACK_RPM_&id_re;_PACKAGE_PREFIX|CPACK_RPM_&id_re;_PACKAGE_OBSOLETES|CPACK_RPM_&id_re;_PACKAGE_NAME|CPACK_RPM_&id_re;_PACKAGE_GROUP|CPACK_RPM_&id_re;_PACKAGE_DESCRIPTION|CPACK_RPM_&id_re;_PACKAGE_CONFLICTS|CPACK_RPM_&id_re;_PACKAGE_AUTOREQPROV|CPACK_RPM_&id_re;_PACKAGE_AUTOREQ|CPACK_RPM_&id_re;_PACKAGE_AUTOPROV|CPACK_RPM_&id_re;_PACKAGE_ARCHITECTURE|CPACK_RPM_&id_re;_FILE_NAME|CPACK_RPM_&id_re;_DEFAULT_USER|CPACK_RPM_&id_re;_DEFAULT_GROUP|CPACK_RPM_&id_re;_DEFAULT_FILE_PERMISSIONS|CPACK_RPM_&id_re;_DEFAULT_DIR_PERMISSIONS|CPACK_RPM_&id_re;_DEBUGINFO_PACKAGE|CPACK_RPM_&id_re;_DEBUGINFO_FILE_NAME|CPACK_RPM_&id_re;_BUILD_SOURCE_DIRS_PREFIX|CPACK_PREFLIGHT_&id_re;_SCRIPT|CPACK_POSTFLIGHT_&id_re;_SCRIPT|CPACK_NUGET_PACKAGE_DEPENDENCIES_&id_re;_VERSION|CPACK_NUGET_&id_re;_PACKAGE_VERSION|CPACK_NUGET_&id_re;_PACKAGE_TITLE|CPACK_NUGET_&id_re;_PACKAGE_TAGS|CPACK_NUGET_&id_re;_PACKAGE_RELEASE_NOTES|CPACK_NUGET_&id_re;_PACKAGE_OWNERS|CPACK_NUGET_&id_re;_PACKAGE_NAME|CPACK_NUGET_&id_re;_PACKAGE_LICENSE_FILE_NAME|CPACK_NUGET_&id_re;_PACKAGE_LICENSE_EXPRESSION|CPACK_NUGET_&id_re;_PACKAGE_LICENSEURL|CPACK_NUGET_&id_re;_PACKAGE_LANGUAGE|CPACK_NUGET_&id_re;_PACKAGE_ICONURL|CPACK_NUGET_&id_re;_PACKAGE_ICON|CPACK_NUGET_&id_re;_PACKAGE_HOMEPAGE_URL|CPACK_NUGET_&id_re;_PACKAGE_DESCRIPTION_SUMMARY|CPACK_NUGET_&id_re;_PACKAGE_DESCRIPTION|CPACK_NUGET_&id_re;_PACKAGE_DEPENDENCIES_&id_re;_VERSION|CPACK_NUGET_&id_re;_PACKAGE_DEPENDENCIES|CPACK_NUGET_&id_re;_PACKAGE_COPYRIGHT|CPACK_NUGET_&id_re;_PACKAGE_AUTHORS|CPACK_NSIS_&id_re;_INSTALL_DIRECTORY|CPACK_DMG_&id_re;_FILE_NAME|CPACK_DEBIAN_&id_re;_PACKAGE_SUGGESTS|CPACK_DEBIAN_&id_re;_PACKAGE_SOURCE|CPACK_DEBIAN_&id_re;_PACKAGE_SHLIBDEPS|CPACK_DEBIAN_&id_re;_PACKAGE_SECTION|CPACK_DEBIAN_&id_re;_PACKAGE_REPLACES|CPACK_DEBIAN_&id_re;_PACKAGE_RECOMMENDS|CPACK_DEBIAN_&id_re;_PACKAGE_PROVIDES|CPACK_DEBIAN_&id_re;_PACKAGE_PRIORITY|CPACK_DEBIAN_&id_re;_PACKAGE_PREDEPENDS|CPACK_DEBIAN_&id_re;_PACKAGE_NAME|CPACK_DEBIAN_&id_re;_PACKAGE_ENHANCES|CPACK_DEBIAN_&id_re;_PACKAGE_DEPENDS|CPACK_DEBIAN_&id_re;_PACKAGE_CONTROL_STRICT_PERMISSION|CPACK_DEBIAN_&id_re;_PACKAGE_CONTROL_EXTRA|CPACK_DEBIAN_&id_re;_PACKAGE_CONFLICTS|CPACK_DEBIAN_&id_re;_PACKAGE_BREAKS|CPACK_DEBIAN_&id_re;_PACKAGE_ARCHITECTURE|CPACK_DEBIAN_&id_re;_FILE_NAME|CPACK_DEBIAN_&id_re;_DESCRIPTION|CPACK_DEBIAN_&id_re;_DEBUGINFO_PACKAGE|CPACK_COMPONENT_&id_re;_REQUIRED|CPACK_COMPONENT_&id_re;_HIDDEN|CPACK_COMPONENT_&id_re;_GROUP|CPACK_COMPONENT_&id_re;_DISPLAY_NAME|CPACK_COMPONENT_&id_re;_DISABLED|CPACK_COMPONENT_&id_re;_DESCRIPTION|CPACK_COMPONENT_&id_re;_DEPENDS|CPACK_BINARY_&id_re;|CPACK_ARCHIVE_&id_re;_FILE_NAME|CPACK_&id_re;_COMPONENT_INSTALL|CMAKE_XCODE_ATTRIBUTE_&id_re;|CMAKE_USER_MAKE_RULES_OVERRIDE_&id_re;|CMAKE_STATIC_LINKER_FLAGS_&id_re;_INIT|CMAKE_STATIC_LINKER_FLAGS_&id_re;|CMAKE_SHARED_LINKER_FLAGS_&id_re;_INIT|CMAKE_SHARED_LINKER_FLAGS_&id_re;|CMAKE_RUNTIME_OUTPUT_DIRECTORY_&id_re;|CMAKE_PROJECT_&id_re;_INCLUDE|CMAKE_POLICY_WARNING_CMP[0-9]{4}|CMAKE_POLICY_DEFAULT_CMP[0-9]{4}|CMAKE_PDB_OUTPUT_DIRECTORY_&id_re;|CMAKE_MODULE_LINKER_FLAGS_&id_re;_INIT|CMAKE_MODULE_LINKER_FLAGS_&id_re;|CMAKE_MATCH_[0-9]+|CMAKE_MAP_IMPORTED_CONFIG_&id_re;|CMAKE_LIBRARY_OUTPUT_DIRECTORY_&id_re;|CMAKE_INTERPROCEDURAL_OPTIMIZATION_&id_re;|CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_&id_re;|CMAKE_EXE_LINKER_FLAGS_&id_re;_INIT|CMAKE_EXE_LINKER_FLAGS_&id_re;|CMAKE_DISABLE_FIND_PACKAGE_&id_re;|CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_&id_re;|CMAKE_ARGV[0-9]+|CMAKE_ARCHIVE_OUTPUT_DIRECTORY_&id_re;|CMAKE_&id_re;_VISIBILITY_PRESET|CMAKE_&id_re;_STANDARD_LIBRARIES|CMAKE_&id_re;_STANDARD_INCLUDE_DIRECTORIES|CMAKE_&id_re;_SOURCE_FILE_EXTENSIONS|CMAKE_&id_re;_SIZEOF_DATA_PTR|CMAKE_&id_re;_SIMULATE_VERSION|CMAKE_&id_re;_SIMULATE_ID|CMAKE_&id_re;_POSTFIX|CMAKE_&id_re;_OUTPUT_EXTENSION|CMAKE_&id_re;_LINK_LIBRARY_FLAG|CMAKE_&id_re;_LINK_LIBRARY_FILE_FLAG|CMAKE_&id_re;_LINK_EXECUTABLE|CMAKE_&id_re;_LINKER_WRAPPER_FLAG_SEP|CMAKE_&id_re;_LINKER_WRAPPER_FLAG|CMAKE_&id_re;_LINKER_PREFERENCE_PROPAGATES|CMAKE_&id_re;_LINKER_PREFERENCE|CMAKE_&id_re;_LINKER_LAUNCHER|CMAKE_&id_re;_LIBRARY_ARCHITECTURE|CMAKE_&id_re;_INCLUDE_WHAT_YOU_USE|CMAKE_&id_re;_IMPLICIT_LINK_LIBRARIES|CMAKE_&id_re;_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES|CMAKE_&id_re;_IMPLICIT_LINK_DIRECTORIES|CMAKE_&id_re;_IMPLICIT_INCLUDE_DIRECTORIES|CMAKE_&id_re;_IGNORE_EXTENSIONS|CMAKE_&id_re;_GHS_KERNEL_FLAGS_RELWITHDEBINFO|CMAKE_&id_re;_GHS_KERNEL_FLAGS_RELEASE|CMAKE_&id_re;_GHS_KERNEL_FLAGS_MINSIZEREL|CMAKE_&id_re;_GHS_KERNEL_FLAGS_DEBUG|CMAKE_&id_re;_FLAGS_RELWITHDEBINFO_INIT|CMAKE_&id_re;_FLAGS_RELWITHDEBINFO|CMAKE_&id_re;_FLAGS_RELEASE_INIT|CMAKE_&id_re;_FLAGS_RELEASE|CMAKE_&id_re;_FLAGS_MINSIZEREL_INIT|CMAKE_&id_re;_FLAGS_MINSIZEREL|CMAKE_&id_re;_FLAGS_INIT|CMAKE_&id_re;_FLAGS_DEBUG_INIT|CMAKE_&id_re;_FLAGS_DEBUG|CMAKE_&id_re;_FLAGS|CMAKE_&id_re;_CREATE_STATIC_LIBRARY|CMAKE_&id_re;_CREATE_SHARED_MODULE|CMAKE_&id_re;_CREATE_SHARED_LIBRARY|CMAKE_&id_re;_CPPLINT|CMAKE_&id_re;_CPPCHECK|CMAKE_&id_re;_COMPILE_OBJECT|CMAKE_&id_re;_COMPILER_VERSION|CMAKE_&id_re;_COMPILER_TARGET|CMAKE_&id_re;_COMPILER_RANLIB|CMAKE_&id_re;_COMPILER_LOADED|CMAKE_&id_re;_COMPILER_LAUNCHER|CMAKE_&id_re;_COMPILER_ID|CMAKE_&id_re;_COMPILER_EXTERNAL_TOOLCHAIN|CMAKE_&id_re;_COMPILER_AR|CMAKE_&id_re;_COMPILER|CMAKE_&id_re;_CLANG_TIDY|CMAKE_&id_re;_BYTE_ORDER|CMAKE_&id_re;_ARCHIVE_FINISH|CMAKE_&id_re;_ARCHIVE_CREATE|CMAKE_&id_re;_ARCHIVE_APPEND|CMAKE_&id_re;_ANDROID_TOOLCHAIN_SUFFIX|CMAKE_&id_re;_ANDROID_TOOLCHAIN_PREFIX|CMAKE_&id_re;_ANDROID_TOOLCHAIN_MACHINE|ARGV[0-9]+|&id_re;__TRYRUN_OUTPUT|&id_re;_VERSION_TWEAK|&id_re;_VERSION_STRING|&id_re;_VERSION_PATCH|&id_re;_VERSION_MINOR|&id_re;_VERSION_MAJOR|&id_re;_VERSION_COUNT|&id_re;_VERSION|&id_re;_UNPARSED_ARGUMENTS|&id_re;_SOURCE_DIR|&id_re;_ROOT|&id_re;_MODULE_NAME|&id_re;_LIBRARY_DIRS|&id_re;_LIBRARIES|&id_re;_KEYWORDS_MISSING_VALUES|&id_re;_IS_TOP_LEVEL|&id_re;_INCLUDE_DIRS|&id_re;_HOMEPAGE_URL|&id_re;_FOUND|&id_re;_FIND_VERSION_RANGE_MIN|&id_re;_FIND_VERSION_RANGE_MAX|&id_re;_FIND_VERSION_RANGE|&id_re;_FIND_VERSION_MIN_TWEAK|&id_re;_FIND_VERSION_MIN_PATCH|&id_re;_FIND_VERSION_MIN_MINOR|&id_re;_FIND_VERSION_MIN_MAJOR|&id_re;_FIND_VERSION_MIN_COUNT|&id_re;_FIND_VERSION_MIN|&id_re;_FIND_VERSION_MAX_TWEAK|&id_re;_FIND_VERSION_MAX_PATCH|&id_re;_FIND_VERSION_MAX_MINOR|&id_re;_FIND_VERSION_MAX_MAJOR|&id_re;_FIND_VERSION_MAX_COUNT|&id_re;_FIND_VERSION_MAX|&id_re;_FIND_VERSION_EXACT|&id_re;_FIND_VERSION_COUNT|&id_re;_FIND_VERSION_COMPLETE|&id_re;_FIND_REQUIRED_&id_re;|&id_re;_FIND_REQUIRED|&id_re;_FIND_QUIETLY|&id_re;_FIND_COMPONENTS|&id_re;_DESCRIPTION|&id_re;_CONSIDERED_VERSIONS|&id_re;_CONSIDERED_CONFIGS|&id_re;_CONFIG|&id_re;_BINARY_DIR)\b" /> </context> <context attribute="Normal Text" lineEndContext="#stay" name="Detect Variable Substitutions"> diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/doxygen.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/doxygen.xml index d7a53a167c..5516c1454b 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/doxygen.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/doxygen.xml @@ -1,12 +1,12 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE language SYSTEM "language.dtd" [ - <!ENTITY wordsep "(?:[][,?;()]|\.$|\.?\s)"> <!-- things that end a TagWord --> + <!ENTITY wordsep "(?:[][,?;()]|\.$|\.?\s|$)"> <!-- things that end a TagWord --> <!ENTITY sl_word ".*?(?=&wordsep;)"> <!ENTITY ml_word ".*?(?=&wordsep;|\*/)"> ]> <language name="Doxygen" - version="13" + version="14" kateversion="5.0" section="Markup" extensions="*.dox;*.doxygen" diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/ini.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/ini.xml index 8b36a56290..476522961b 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/ini.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/ini.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE language SYSTEM "language.dtd"> -<language name="INI Files" section="Configuration" extensions="*.ini;*.pls;*.kcfgc" mimetype="" version="8" kateversion="5.0" author="Jan Janssen (medhefgo@web.de)" license="LGPL"> +<language name="INI Files" section="Configuration" extensions="*.ini;*.pls;*.kcfgc" mimetype="" version="10" kateversion="5.0" author="Jan Janssen (medhefgo@web.de)" license="LGPL"> <highlighting> <list name="keywords"> @@ -34,15 +34,26 @@ <contexts> <context name="ini" attribute="Normal Text" lineEndContext="#stay"> - <RangeDetect attribute="Section" context="#stay" char="[" char1="]" beginRegion="Section" endRegion="Section" /> + <RangeDetect attribute="Section" context="#stay" char="[" char1="]" beginRegion="Section" endRegion="Section" /> <DetectChar attribute="Assignment" context="Value" char="=" /> <AnyChar String=";#" attribute="Comment" context="Comment" firstNonSpace="true" /> + <DetectIdentifier /> + <DetectSpaces /> + </context> + + <context name="Value" attribute="Value" lineEndContext="#pop" fallthrough="1" fallthroughContext="#pop!NormalValue"> + <RegExpr context="#pop!SpecialValue" String="\s*((-?(\d+(\.\d*)?|\.d+)(e\d+)?|On|Off|Defaults?|Localhost|Null|True|False|Yes|No|Normal)\s*$|~?(E_ALL|E_ERROR|E_WARNING|E_PARSE|E_NOTICE|E_STRICT|E_CORE_ERROR|E_CORE_WARNING|E_COMPILE_ERROR|E_COMPILE_WARNING|E_USER_ERROR|E_USER_WARNING|E_USER_NOTICE)\b)" lookAhead="1" insensitive="1"/> </context> - <context name="Value" attribute="Value" lineEndContext="#pop" > + <context name="SpecialValue" attribute="Value" lineEndContext="#pop"> <Float attribute="Float" /> <Int attribute="Int" /> - <keyword attribute="Keyword" String="keywords" /> + <keyword attribute="Keyword" String="keywords"/> + <DetectChar attribute="Int" char="-" /> + <DetectSpaces /> + </context> + + <context name="NormalValue" attribute="Value" lineEndContext="#pop"> </context> <context name="Comment" attribute="Comment" lineEndContext="#pop"> diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/java.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/java.xml index 6091cd4ee2..e71b1618a0 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/java.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/java.xml @@ -7,7 +7,7 @@ <!ENTITY float "(\b∫(\.((∫&exp;?+|&exp;)[fFdD]?\b|[fFdD]\b)?|&exp;[fFdD]?\b|[fFdD]\b)|\.∫&exp;?[fFdD]?\b)"> <!ENTITY hexfloat "\b0[xX](&hex;\.?+&hex;?+|\.&hex;?)[pP][-+]?∫[fFdD]?\b"> ]> -<language name="Java" version="9" kateversion="5.62" section="Sources" extensions="*.java" mimetype="text/x-java" license="LGPL" author="Alfredo Luiz Foltran Fialho (alfoltran@ig.com.br)"> +<language name="Java" version="10" kateversion="5.62" section="Sources" extensions="*.java" mimetype="text/x-java" license="LGPL" author="Alfredo Luiz Foltran Fialho (alfoltran@ig.com.br)"> <highlighting> <list name="java15"> <item>ACTIVE</item> @@ -3732,6 +3732,7 @@ <item>volatile</item> </list> <list name="control flow"> + <item>assert</item> <item>break</item> <item>case</item> <item>catch</item> @@ -3760,6 +3761,7 @@ <item>long</item> <item>short</item> <item>static</item> + <item>var</item> <item>void</item> </list> <contexts> diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml index b35397af9c..f03587977a 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml @@ -90,7 +90,7 @@ <!ENTITY checkbox "\[[ x]\](?=\s)"> ]> -<language name="Markdown" version="17" kateversion="5.79" section="Markup" extensions="*.md;*.mmd;*.markdown" priority="15" author="Darrin Yeager, Claes Holmerson" license="GPL,BSD"> +<language name="Markdown" version="19" kateversion="5.79" section="Markup" extensions="*.md;*.mmd;*.markdown" priority="15" author="Darrin Yeager, Claes Holmerson" license="GPL,BSD"> <highlighting> <contexts> <!-- Start of the Markdown document: find metadata or code block --> @@ -149,14 +149,33 @@ </context> <context name="find-header" attribute="Normal Text" lineEndContext="#pop"> - <RegExpr attribute="Header H1" context="#pop" String="^#\s.*[#]?$" column="0"/> - <RegExpr attribute="Header H2" context="#pop" String="^##\s.*[#]?$" column="0"/> - <RegExpr attribute="Header H3" context="#pop" String="^###\s.*[#]?$" column="0"/> - <RegExpr attribute="Header H4" context="#pop" String="^####\s.*[#]?$" column="0"/> - <RegExpr attribute="Header H5" context="#pop" String="^#####\s.*[#]?$" column="0"/> - <RegExpr attribute="Header H6" context="#pop" String="^######\s.*[#]?$" column="0"/> + <!-- TODO: Replace "(?=.$)" in the regexes with just "$" when close-H#-region are removed --> + <RegExpr attribute="Header H1" context="#pop!close-H2-region" String="^#\s.*[#]?(?=.$)" column="0" endRegion="H1" beginRegion="H1"/> + <RegExpr attribute="Header H2" context="#pop!close-H3-region" String="^##\s.*[#]?(?=.$)" column="0" endRegion="H2" beginRegion="H2"/> + <RegExpr attribute="Header H3" context="#pop!close-H4-region" String="^###\s.*[#]?(?=.$)" column="0" endRegion="H3" beginRegion="H3"/> + <RegExpr attribute="Header H4" context="#pop!close-H5-region" String="^####\s.*[#]?(?=.$)" column="0" endRegion="H4" beginRegion="H4"/> + <RegExpr attribute="Header H5" context="#pop!close-H6-region" String="^#####\s.*[#]?(?=.$)" column="0" endRegion="H5" beginRegion="H5"/> + <RegExpr attribute="Header H6" context="#pop" String="^######\s.*[#]?$" column="0" endRegion="H6" beginRegion="H6"/> <DetectChar attribute="Normal Text" context="#pop" char="#"/> </context> + <!-- BUG: 441278 sub-headers should be closed when their parent header is closed (e.g. in h1 h2 h3 h1, h1-h3 should all be closed at the 2nd h1) --> + <!-- TODO: Port to a less hacky version (maybe a new attribute for declaring multiple endRegions) --> + <context name="close-H2-region" attribute="Header H2" lineEndContext="#pop!close-H3-region" fallthroughContext="#pop!close-H3-region"> + <RegExpr attribute="Header H2" context="#pop!close-H3-region" String="." lookAhead="true" endRegion="H2"/> + </context> + <context name="close-H3-region" attribute="Header H3" lineEndContext="#pop!close-H4-region" fallthroughContext="#pop!close-H4-region"> + <RegExpr attribute="Header H3" context="#pop!close-H4-region" String="." lookAhead="true" endRegion="H3"/> + </context> + <context name="close-H4-region" attribute="Header H4" lineEndContext="#pop!close-H5-region" fallthroughContext="#pop!close-H5-region"> + <RegExpr attribute="Header H4" context="#pop!close-H5-region" String="." lookAhead="true" endRegion="H4"/> + </context> + <context name="close-H5-region" attribute="Header H5" lineEndContext="#pop!close-H6-region" fallthroughContext="#pop!close-H6-region"> + <RegExpr attribute="Header H5" context="#pop!close-H6-region" String="." lookAhead="true" endRegion="H5"/> + </context> + <context name="close-H6-region" attribute="Header H6" lineEndContext="#pop" fallthroughContext="#pop"> + <RegExpr attribute="Header H6" context="#pop" String="." endRegion="H6"/> + </context> + <context name="find-strong-normal" attribute="Normal Text" lineEndContext="#pop"> <RegExpr attribute="Strong-Emphasis Text" context="#pop" minimal="true" String="&strongemphasisregex_ast_und;|&strongemphasisregex_ast_und2;"/> <RegExpr attribute="Strong Text" context="#pop" minimal="true" String="&strongregex_ast;"/> diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml index fdf2266558..c9a60d64db 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml @@ -39,7 +39,7 @@ Enhance tr/// and y/// support. --> -<language name="Perl" version="17" kateversion="5.0" section="Scripts" extensions="*.pl;*.PL;*.pm" mimetype="application/x-perl;text/x-perl" priority="5" author="Anders Lund (anders@alweb.dk)" license="LGPLv2"> +<language name="Perl" version="18" kateversion="5.0" section="Scripts" extensions="*.pl;*.PL;*.pm" mimetype="application/x-perl;text/x-perl" priority="5" author="Anders Lund (anders@alweb.dk)" license="LGPLv2"> <highlighting> <list name="keywords"> <item>if</item> @@ -92,7 +92,7 @@ <item>+</item> <item>-</item> <item>*</item> - <!-- <item>/</item>//--> + <!-- <item>/</item>//--> <item>%</item> <item>||</item> <item>//</item> @@ -420,7 +420,8 @@ <DetectChar attribute="Operator" context="quote_word_paren" char="(" beginRegion="Wordlist" /> <DetectChar attribute="Operator" context="quote_word_brace" char="{" beginRegion="Wordlist" /> <DetectChar attribute="Operator" context="quote_word_bracket" char="[" beginRegion="Wordlist" /> - <RegExpr attribute="Operator" context="quote_word" String="([^a-zA-Z0-9_\s[\]{}()])" beginRegion="Wordlist" /> + <DetectChar attribute="Operator" context="quote_word_angular" char="<" beginRegion="Wordlist" /> + <RegExpr attribute="Operator" context="quote_word" String="([^a-zA-Z0-9_\s[\]{}()\<>])" beginRegion="Wordlist" /> <RegExpr attribute="Comment" context="#stay" String="\s+#.*" /><!-- q[qwx] # == comment, look for the delim on the next line --> </context> @@ -756,6 +757,12 @@ <Detect2Chars attribute="Normal Text" context="#stay" char="\" char1="]" /> <DetectChar attribute="Operator" context="#pop#pop#pop" char="]" endRegion="Wordlist" /> </context> + <context name="quote_word_angular" attribute="Normal Text" lineEndContext="#stay"> + <DetectSpaces /> + <DetectIdentifier /> + <Detect2Chars attribute="Normal Text" context="#stay" char="\" char1=">" /> + <DetectChar attribute="Operator" context="#pop#pop#pop" char=">" endRegion="Wordlist" /> + </context> <!-- ====== Here Documents ====== --> <context name="find_here_document" attribute="Normal Text" lineEndContext="#pop" > diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/python.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/python.xml index f1c89a54e4..676872f03f 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/python.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/python.xml @@ -33,6 +33,10 @@ type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" --> <!ENTITY strsubstitution_py3 "\{(?:(?:[a-zA-Z0-9_]+|[0-9]+)(?:\.[a-zA-Z0-9_]+|\[[^ \]]+\])*)?(?:![rs])?(?::(?:[^}]?[<>=^])?[ +-]?#?0?[0-9]*(?:\.[0-9]+)?[bcdeEfFgGnosxX%]?)?\}"> + + <!ENTITY rawString "(?:ru|u?r|)(?:'(?:[^']++|\\')*+'|"(?:[^"]++|\\")*+")"> + <!ENTITY formatString "(?:r?f|fr?)(?:'(?:[^'{]++|\\'|\{\{|\{[^}]++\})*+'|"(?:[^"]++|\\"|\{\{|\{[^}]*+\})*+")"> + <!ENTITY string "&rawString;|&formatString;"> ]> <!-- Python syntax highlightning v0.9 by Per Wigren --> <!-- Python syntax highlighting v1.9 by Michael Bueker (improved keyword differentiation) --> @@ -48,7 +52,7 @@ <!-- v2.07 add support for %prog and co, see bug 142832 --> <!-- v2.08 add missing overloaders, new Python 3 statements, builtins, and keywords --> <!-- v2.29 recognize escape sequenzes correctly --> -<language name="Python" version="14" style="python" indenter="python" kateversion="5.0" section="Scripts" extensions="*.py;*.pyw;SConstruct;SConscript;*.FCMacro" mimetype="application/x-python;text/x-python;text/x-python3" casesensitive="1" author="Michael Bueker" license=""> +<language name="Python" version="22" style="python" indenter="python" kateversion="5.0" section="Scripts" extensions="*.py;*.pyw;SConstruct;SConscript;*.FCMacro" mimetype="application/x-python;text/x-python;text/x-python3" casesensitive="1" author="Michael Bueker" license=""> <highlighting> <list name="import"> <item>import</item> @@ -86,10 +90,21 @@ <item>try</item> <item>while</item> <item>with</item> - <item>yield</item> <item>async</item> <item>await</item> </list> + <list name="flow_yield"> + <item>yield</item> + <!-- + "yield from" added here as a keyword for autocompletion. The actual handling + is in context="yield" so that we won't need to add space as a weakDeliminator. + --> + <item>yield from</item> + </list> + <list name="patternmatching"> + <item>match</item> + <item>case</item> + </list> <list name="builtinfuncs"> <item>__import__</item> <item>abs</item> @@ -366,89 +381,137 @@ </list> <contexts> <context name="Normal" attribute="Normal Text" lineEndContext="#stay"> + <DetectSpaces attribute="Normal Text"/> + <keyword attribute="Import" String="import" context="#stay"/> <keyword attribute="Definition Keyword" String="defs" context="#stay"/> <keyword attribute="Operator Keyword" String="operators" context="#stay"/> <keyword attribute="Flow Control Keyword" String="flow" context="#stay"/> + <keyword attribute="Flow Control Keyword" String="flow_yield" context="yield"/> + <keyword attribute="Flow Control Keyword" String="patternmatching" context="Pattern Matching" lookAhead="1" firstNonSpace="1"/> <keyword attribute="Builtin Function" String="builtinfuncs" context="#stay"/> <keyword attribute="Special Variable" String="specialvars" context="#stay"/> <keyword attribute="Extensions" String="bindings" context="#stay"/> <keyword attribute="Exceptions" String="exceptions" context="#stay"/> <keyword attribute="Overloaders" String="overloaders" context="#stay"/> - <RegExpr attribute="Normal Text" String="[a-zA-Z_][a-zA-Z_0-9]{2,}" context="#stay"/> - - <!-- Complex: 1j ; 1.1j ; 1.j ; .1j ; 1e3j ; 1.1e3j ; 1.e3j ; .1e3j --> - <RegExpr attribute="Complex" String="(?:&beforeDigit;&digitPart;(?:\.(?:&digitPart;)?)?|&beforePointFloat;\.&digitPart;)(?:[eE][\+\-]?&digitPart;)?[jJ]\b" context="#stay"/> - <!-- Hexadecimal: 0xA1, Binary: 0b01, Octal: 0o71 --> - <RegExpr attribute="Hex" String="&beforeDigit;0[xX](?:_?[\da-fA-F])+\b" context="#stay"/> - <RegExpr attribute="Binary" String="&beforeDigit;0[bB](?:_?[01])+\b" context="#stay"/> - <RegExpr attribute="Octal" String="&beforeDigit;0[oO](?:_?[0-7])+\b" context="#stay"/> - <!-- Float: 1.1 ; 1. ; .1 ; 1e3 ; 1.1e3 ; 1.e3 ; .1e3 --> - <RegExpr attribute="Float" String="(?:&beforeDigit;&digitPart;(?:\.(?:&digitPart;)?)?|&beforePointFloat;\.&digitPart;)[eE][\+\-]?&digitPart;\b|(?:&beforeDigit;&digitPart;\.(?:&digitPart;\b)?|&beforePointFloat;\.&digitPart;\b)" context="#stay"/> - <!-- Decimal: 123 ; 000 --> - <RegExpr attribute="Int" String="&beforeDigit;(?:[1-9](?:_?\d)*|0(?:_?0)*)[lL]?\b" context="#stay"/> <DetectChar attribute="Normal Text" char="{" context="Dictionary" beginRegion="Dictionary"/> <DetectChar attribute="Normal Text" char="[" context="List" beginRegion="List"/> <DetectChar attribute="Normal Text" char="(" context="Tuple" beginRegion="Tuple"/> - <IncludeRules context="CommentVariants" /> - <DetectChar attribute="Comment" char="#" context="Hash comment"/> + <IncludeRules context="Number" /> + <IncludeRules context="CommentVariants" /> <IncludeRules context="StringVariants" /> + <DetectIdentifier attribute="Normal Text"/> + <RegExpr attribute="Decorator" String="@[_a-zA-Z[:^ascii:]][\._a-zA-Z0-9[:^ascii:]]*" firstNonSpace="true"/> - <AnyChar attribute="Operator" String="+*/%\|=;\!<>!^&~-@" context="#stay"/> + <AnyChar attribute="Operator" String="+*/%\|=;<>!^&~-@" context="#stay"/> + + <Int attribute="Error"/> + </context> + + <!-- https://docs.python.org/2/reference/lexical_analysis.html#integer-and-long-integer-literals --> + <!-- https://docs.python.org/3/reference/lexical_analysis.html#integer-literals --> + <context name="Number" attribute="Normal Text" lineEndContext="#pop"> + <!-- fast path --> + <RegExpr String="&beforeDigit;[0-9]|&beforePointFloat;\.[0-9]" context="AssumeNumber" lookAhead="1"/> + </context> + <context name="AssumeNumber" attribute="Normal Text" lineEndContext="#pop"> + <!-- Complex: 1j ; 1.1j ; 1.j ; .1j ; 1e3j ; 1.1e3j ; 1.e3j ; .1e3j --> + <RegExpr attribute="Complex" String="(?:&digitPart;(?:\.(?:&digitPart;)?)?|&beforePointFloat;\.&digitPart;)(?:[eE][\+\-]?&digitPart;)?[jJ]" context="CheckSuffixError"/> + <!-- Hexadecimal: 0xA1, Binary: 0b01, Octal: 0o71 --> + <RegExpr attribute="Hex" String="0[xX](?:_?[0-9a-fA-F])+" context="CheckSuffixError"/> + <RegExpr attribute="Binary" String="0[bB](?:_?[01])+" context="CheckSuffixError"/> + <RegExpr attribute="Octal" String="0[oO](?:_?[0-7])+" context="CheckSuffixError"/> + <!-- Float: 1.1 ; 1. ; .1 ; 1e3 ; 1.1e3 ; 1.e3 ; .1e3 --> + <RegExpr attribute="Float" String="(?:&digitPart;(?:\.(?:&digitPart;)?)?|\.&digitPart;)[eE][\+\-]?&digitPart;|&digitPart;\.(?:&digitPart;)?|\.&digitPart;" context="CheckSuffixError"/> + <!-- Decimal: 123 ; 000 --> + <!-- l and L are python2 suffixes --> + <RegExpr attribute="Int" String="(?:[1-9](?:_?\d)*|0(?:_?0)*)[lL]?" context="CheckSuffixError"/> + </context> + <context name="CheckSuffixError" attribute="Normal Text" lineEndContext="#pop#pop" fallthrough="1" fallthroughContext="#pop#pop"> + <RegExpr attribute="Error" String="[\w\d]+" context="#pop#pop"/> + </context> + + <context name="yield" attribute="Flow Control Keyword" lineEndContext="#pop" fallthrough="1" fallthroughContext="#pop"> + <DetectSpaces attribute="Normal Text" context="#stay"/> + <WordDetect attribute="Flow Control Keyword" context="#pop" String="from"/> + </context> + + <context name="Pattern Matching" attribute="Flow Control Keyword" lineEndContext="#pop"> + <!-- + Python 3.10: https://docs.python.org/3.10/reference/compound_stmts.html#the-match-statement + ( 'match' | 'case' ) expression ':' + exclude: + ( 'match' | 'case' ) ( 'if' | 'for' | '.' | ':' | '=' | ',' | ']' | ')' ) ... + --> + <RegExpr attribute="Flow Control Keyword" String="\w++(?=\s+(?!(?:if|for)\b)[\w'"~]|\s*+(?![.:=\]),]|(?:if|for)\b)((?:&string;|[^#;(){}]|\(\)|\((?1)\)|\{\}|\{(\s*+(?:(?:&string;|[a-zA-Z0-9.]++)\s*+:\s*+(?:&string;|[^#;(){},]|\(\)|\((?1)\)|\{\}|\{(?2)\})++,?)*+)\})+?):)|" context="#pop"/> + <DetectIdentifier attribute="Normal Text" context="#pop"/> </context> <context name="#CheckForString" attribute="Normal Text" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop"> <DetectSpaces/> - <LineContinue attribute="Normal Text" context="CheckForStringNext"/> + <LineContinue attribute="Normal Text" context="#pop!CheckForStringNext"/> </context> - <context name="CheckForStringNext" attribute="Normal Text" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop"> + <context name="CheckForStringNext" attribute="Normal Text" lineEndContext="#pop#pop" fallthrough="true" fallthroughContext="#pop#pop"> <DetectSpaces/> - <LineContinue attribute="Normal Text" context="CheckForStringNext"/> + <LineContinue attribute="Normal Text" context="#stay"/> <IncludeRules context="StringVariants"/> </context> + <!-- https://docs.python.org/2/reference/lexical_analysis.html#string-literals --> + <!-- https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals --> <context name="StringVariants" attribute="Normal Text" lineEndContext="#stay"> - <DetectSpaces/> - - <RegExpr attribute="String" String="u?'''" insensitive="true" context="Triple A-string" beginRegion="Triple A-region"/> - <RegExpr attribute="String" String="u?"""" insensitive="true" context="Triple Q-string" beginRegion="Triple Q-region"/> - <RegExpr attribute="String" String="u?'" insensitive="true" context="Single A-string"/> - <RegExpr attribute="String" String="u?"" insensitive="true" context="Single Q-string"/> - - <RegExpr attribute="Raw String" String="(?:u?r|ru)'''" insensitive="true" context="Raw Triple A-string" beginRegion="Triple A-region"/> - <RegExpr attribute="Raw String" String="(?:u?r|ru)"""" insensitive="true" context="Raw Triple Q-string" beginRegion="Triple Q-region"/> - <RegExpr attribute="Raw String" String="(?:u?r|ru)'" insensitive="true" context="Raw A-string"/> - <RegExpr attribute="Raw String" String="(?:u?r|ru)"" insensitive="true" context="Raw Q-string"/> - - <StringDetect attribute="F-String" String="f'''" insensitive="true" context="Triple A-F-String" beginRegion="Triple A-region"/> - <StringDetect attribute="F-String" String="f"""" insensitive="true" context="Triple Q-F-String" beginRegion="Triple Q-region"/> - <StringDetect attribute="F-String" String="f'" insensitive="true" context="Single A-F-String"/> - <StringDetect attribute="F-String" String="f"" insensitive="true" context="Single Q-F-String"/> - - <RegExpr attribute="Raw F-String" String="(?:fr|rf)'''" insensitive="true" context="Raw Triple A-F-String" beginRegion="Triple A-region"/> - <RegExpr attribute="Raw F-String" String="(?:fr|rf)"""" insensitive="true" context="Raw Triple Q-F-String" beginRegion="Triple Q-region"/> - <RegExpr attribute="Raw F-String" String="(?:fr|rf)'" insensitive="true" context="Raw A-F-String"/> - <RegExpr attribute="Raw F-String" String="(?:fr|rf)"" insensitive="true" context="Raw Q-F-String"/> - </context> - + <!-- fast path --> + <RegExpr String="(?:u|r|b|f|ur|fr|rf|br|rb)?['"]" insensitive="true" context="AssumeStringVariants" lookAhead="1"/> + </context> + <context name="AssumeStringVariants" attribute="Normal Text" lineEndContext="#stay"> + <RegExpr attribute="String" String="u?'''" insensitive="true" context="#pop!Triple A-string" beginRegion="Triple A-region"/> + <RegExpr attribute="String" String="u?"""" insensitive="true" context="#pop!Triple Q-string" beginRegion="Triple Q-region"/> + <RegExpr attribute="String" String="u?'" insensitive="true" context="#pop!Single A-string"/> + <RegExpr attribute="String" String="u?"" insensitive="true" context="#pop!Single Q-string"/> + + <RegExpr attribute="Raw String" String="u?r'''" insensitive="true" context="#pop!Raw Triple A-string" beginRegion="Triple A-region"/> + <RegExpr attribute="Raw String" String="u?r"""" insensitive="true" context="#pop!Raw Triple Q-string" beginRegion="Triple Q-region"/> + <RegExpr attribute="Raw String" String="u?r'" insensitive="true" context="#pop!Raw A-string"/> + <RegExpr attribute="Raw String" String="u?r"" insensitive="true" context="#pop!Raw Q-string"/> + + <StringDetect attribute="F-String" String="f'''" insensitive="true" context="#pop!Triple A-F-String" beginRegion="Triple A-region"/> + <StringDetect attribute="F-String" String="f"""" insensitive="true" context="#pop!Triple Q-F-String" beginRegion="Triple Q-region"/> + <StringDetect attribute="F-String" String="f'" insensitive="true" context="#pop!Single A-F-String"/> + <StringDetect attribute="F-String" String="f"" insensitive="true" context="#pop!Single Q-F-String"/> + + <RegExpr attribute="Raw F-String" String="(?:fr|rf)'''" insensitive="true" context="#pop!Raw Triple A-F-String" beginRegion="Triple A-region"/> + <RegExpr attribute="Raw F-String" String="(?:fr|rf)"""" insensitive="true" context="#pop!Raw Triple Q-F-String" beginRegion="Triple Q-region"/> + <RegExpr attribute="Raw F-String" String="(?:fr|rf)'" insensitive="true" context="#pop!Raw A-F-String"/> + <RegExpr attribute="Raw F-String" String="(?:fr|rf)"" insensitive="true" context="#pop!Raw Q-F-String"/> + + <StringDetect attribute="B-String" String="b'''" insensitive="true" context="#pop!Triple A-B-String" beginRegion="Triple A-region"/> + <StringDetect attribute="B-String" String="b"""" insensitive="true" context="#pop!Triple Q-B-String" beginRegion="Triple Q-region"/> + <StringDetect attribute="B-String" String="b'" insensitive="true" context="#pop!Single A-B-String"/> + <StringDetect attribute="B-String" String="b"" insensitive="true" context="#pop!Single Q-B-String"/> + + <RegExpr attribute="Raw B-String" String="(?:br|rb)'''" insensitive="true" context="#pop!Raw Triple A-B-String" beginRegion="Triple A-region"/> + <RegExpr attribute="Raw B-String" String="(?:br|rb)"""" insensitive="true" context="#pop!Raw Triple Q-B-String" beginRegion="Triple Q-region"/> + <RegExpr attribute="Raw B-String" String="(?:br|rb)'" insensitive="true" context="#pop!Raw A-B-String"/> + <RegExpr attribute="Raw B-String" String="(?:br|rb)"" insensitive="true" context="#pop!Raw Q-B-String"/> + </context> + + <!-- https://docs.python.org/2/reference/lexical_analysis.html#string-literals --> + <!-- https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals --> <context name="CommentVariants" attribute="Normal Text" lineEndContext="#stay"> - <DetectSpaces/> - - <RegExpr attribute="Comment" String="u?'''" insensitive="true" firstNonSpace="true" context="Triple A-comment" beginRegion="Triple A-region"/> - <RegExpr attribute="Comment" String="u?"""" insensitive="true" firstNonSpace="true" context="Triple Q-comment" beginRegion="Triple Q-region"/> - <RegExpr attribute="Comment" String="u?'" insensitive="true" firstNonSpace="true" context="Single A-comment"/> - <RegExpr attribute="Comment" String="u?"" insensitive="true" firstNonSpace="true" context="Single Q-comment"/> - - <RegExpr attribute="Comment" String="(?:u?r|ru)'''" insensitive="true" firstNonSpace="true" context="Triple A-comment" beginRegion="Triple A-region"/> - <RegExpr attribute="Comment" String="(?:u?r|ru)"""" insensitive="true" firstNonSpace="true" context="Triple Q-comment" beginRegion="Triple Q-region"/> - <RegExpr attribute="Comment" String="(?:u?r|ru)'" insensitive="true" firstNonSpace="true" context="Single A-comment"/> - <RegExpr attribute="Comment" String="(?:u?r|ru)"" insensitive="true" firstNonSpace="true" context="Single Q-comment"/> + <!-- fast path --> + <RegExpr String="(?:u|r|ur)?['"]" insensitive="true" firstNonSpace="true" context="AssumeCommentVariants" lookAhead="1"/> + </context> + <context name="AssumeCommentVariants" attribute="Normal Text" lineEndContext="#stay"> + <RegExpr attribute="Comment" String="(?:u?r?)'''" insensitive="true" context="#pop!Triple A-comment" beginRegion="Triple A-region"/> + <RegExpr attribute="Comment" String="(?:u?r?)"""" insensitive="true" context="#pop!Triple Q-comment" beginRegion="Triple Q-region"/> + <RegExpr attribute="Comment" String="(?:u?r?)'" insensitive="true" context="#pop!Single A-comment"/> + <RegExpr attribute="Comment" String="(?:u?r?)"" insensitive="true" context="#pop!Single Q-comment"/> </context> <context name="Dictionary" attribute="Normal Text" lineEndContext="#stay" noIndentationBasedFolding="true"> @@ -472,35 +535,53 @@ <IncludeRules context="Normal" /> </context> + <context name="UnfinishedStringError" attribute="Error" lineEndContext="#stay" noIndentationBasedFolding="true"> + <!-- A single string/comment reached the end of the line without a \ line escape --> + <!-- We set ALL succeeding lines to the "Error" attribute so that this error is easier to spot --> + </context> + <!-- Comments --> <context name="Hash comment" attribute="Comment" lineEndContext="#pop"> <DetectSpaces /> <IncludeRules context="##Comments" /> + <DetectIdentifier/> </context> <context name="Triple A-comment" attribute="Comment" lineEndContext="#stay" noIndentationBasedFolding="true"> - <IncludeRules context="stringescape"/> + <DetectSpaces/> <StringDetect attribute="Comment" String="'''" context="#pop" endRegion="Triple A-region"/> <IncludeRules context="##Comments" /> + <DetectIdentifier/> + <IncludeRules context="stringescape"/> + <LineContinue attribute="String Char" context="#stay"/> </context> <context name="Triple Q-comment" attribute="Comment" lineEndContext="#stay" noIndentationBasedFolding="true"> - <IncludeRules context="stringescape"/> + <DetectSpaces/> <StringDetect attribute="Comment" String=""""" context="#pop" endRegion="Triple Q-region"/> <IncludeRules context="##Comments" /> + <DetectIdentifier/> + <IncludeRules context="stringescape"/> + <LineContinue attribute="String Char" context="#stay"/> </context> - <context name="Single A-comment" attribute="Comment" lineEndContext="#stay"> - <IncludeRules context="stringescape"/> + <context name="Single A-comment" attribute="Comment" lineEndContext="#pop!UnfinishedStringError"> + <DetectSpaces/> <DetectChar attribute="Comment" char="'" context="#pop"/> <IncludeRules context="##Comments" /> + <DetectIdentifier/> + <IncludeRules context="stringescape"/> + <LineContinue attribute="String Char" context="#stay"/> </context> - <context name="Single Q-comment" attribute="Comment" lineEndContext="#stay"> - <IncludeRules context="stringescape"/> + <context name="Single Q-comment" attribute="Comment" lineEndContext="#pop!UnfinishedStringError"> + <DetectSpaces/> <DetectChar attribute="Comment" char=""" context="#pop"/> <IncludeRules context="##Comments" /> + <DetectIdentifier/> + <IncludeRules context="stringescape"/> + <LineContinue attribute="String Char" context="#stay"/> </context> <!-- Strings --> @@ -520,14 +601,25 @@ <RegExpr attribute="String Char" String="\\[\\'"abfnrtv]|\\[0-7]{1,3}|\\x[0-9A-Fa-f]{2}|\\u[0-9A-Fa-f]{4}|\\U[0-9A-Fa-f]{8}|\\N\{[a-zA-Z0-9\- ]+\}" context="#stay"/> </context> + <!-- escape characters --> + <context name="bytesescape" attribute="String Char" lineEndContext="#stay"> + <!-- As this highlighting style is for both, Python 2 and 3, + we do not know if a normal string is “unicode” or not. So we + --> + <RegExpr attribute="String Char" String="\\[\\'"abfnrtv]|\\[0-7]{1,3}|\\x[0-9A-Fa-f]{2}" context="#stay"/> + </context> + <!-- f-literals --> <context name="stringinterpolation" attribute="F-String" lineEndContext="#stay"> <Detect2Chars attribute="String Char" char="{" char1="{" context="#stay"/> <DetectChar attribute="String Substitution" char="{" context="String Interpolation"/> + <Detect2Chars attribute="String Char" char="}" char1="}" context="#stay"/> + <DetectChar attribute="Error" char="}" context="#stay"/> </context> <context name="String Interpolation" attribute="String Substitution" lineEndContext="#stay"> <DetectChar attribute="Error" char="\" context="#pop"/> - <RegExpr attribute="String Substitution" String="(?:![rs])?(?::(?:[^}]?[<>=^])?[ +-]?#?0?[0-9]*(?:\.[0-9]+)?[bcdeEfFgGnosxX%]?)?\}" context="#pop"/> + <!-- format specifiers: [[fill]align][sign][#][0][minimumwidth][.precision][type] --> + <RegExpr attribute="String Substitution" String="(?:![rsa])?(?::(?:[^}]?[<>=^])?[ +-]?#?0?[0-9]*(?:\.[0-9]+)?[bcdeEfFgGnosxX%]?)?\}" context="#pop"/> <IncludeRules context="Normal"/> <!-- TODO: create expression context instead --> </context> @@ -542,107 +634,218 @@ Adding byte literals wouldn’t make the current 2⁴ into 2⁵ contexts, as there are no byte f-literals --> - <!-- Triple-quoted A-strings --> <context name="Triple A-string" attribute="String" lineEndContext="#stay" noIndentationBasedFolding="true"> + <DetectSpaces attribute="String"/> + <DetectIdentifier attribute="String"/> <IncludeRules context="stringescape"/> <IncludeRules context="stringformat"/> <StringDetect attribute="String" String="'''" context="#pop!#CheckForString" endRegion="Triple A-region"/> + <LineContinue attribute="String Char" context="#stay"/> </context> <context name="Raw Triple A-string" attribute="Raw String" lineEndContext="#stay" noIndentationBasedFolding="true"> - <HlCStringChar attribute="Raw String" context="#stay"/> + <DetectSpaces attribute="Raw String"/> + <DetectIdentifier attribute="Raw String"/> + <Detect2Chars attribute="Raw String" char="\" char1="'"/> + <Detect2Chars attribute="Raw String" char="\" char1="\"/> <IncludeRules context="stringformat"/> <StringDetect attribute="Raw String" String="'''" context="#pop!#CheckForString" endRegion="Triple A-region"/> </context> <context name="Triple A-F-String" attribute="F-String" lineEndContext="#stay" noIndentationBasedFolding="true"> + <DetectSpaces attribute="F-String"/> + <DetectIdentifier attribute="F-String"/> <IncludeRules context="stringescape"/> <IncludeRules context="stringinterpolation"/> <StringDetect attribute="F-String" String="'''" context="#pop!#CheckForString" endRegion="Triple A-region"/> + <LineContinue attribute="String Char" context="#stay"/> </context> <context name="Raw Triple A-F-String" attribute="Raw F-String" lineEndContext="#stay" noIndentationBasedFolding="true"> - <HlCStringChar attribute="Raw F-String" context="#stay"/> + <DetectSpaces attribute="Raw F-String"/> + <DetectIdentifier attribute="Raw F-String"/> + <Detect2Chars attribute="Raw F-String" char="\" char1="'"/> + <Detect2Chars attribute="Raw F-String" char="\" char1="\"/> <IncludeRules context="stringinterpolation"/> <StringDetect attribute="Raw F-String" String="'''" context="#pop!#CheckForString" endRegion="Triple A-region"/> </context> + <context name="Triple A-B-String" attribute="B-String" lineEndContext="#stay" noIndentationBasedFolding="true"> + <RegExpr attribute="B-String" String="([\x20-\x26\x28-\x5B\x5D-\x7E]++|\\(?=[^\\'"abfnrtvx0-7])|\\x(?![0-9a-fA-F]{2})|'(?!''))++"/> + <IncludeRules context="bytesescape"/> + <StringDetect attribute="B-String" String="'''" context="#pop!#CheckForString" endRegion="Triple A-region"/> + <LineContinue attribute="String Char" context="#stay"/> + <RegExpr attribute="Error" String="."/> + </context> + + <context name="Raw Triple A-B-String" attribute="Raw B-String" lineEndContext="#stay" noIndentationBasedFolding="true"> + <RegExpr attribute="Raw B-String" String="([\x20-\x26\x28-\x5B\x5D-\x7E]++|\\.?|'(?!''))++"/> + <StringDetect attribute="Raw B-String" String="'''" context="#pop!#CheckForString" endRegion="Triple A-region"/> + <RegExpr attribute="Error" String="."/> + </context> + <!-- Triple-quoted Q-strings --> <context name="Triple Q-string" attribute="String" lineEndContext="#stay" noIndentationBasedFolding="true"> + <DetectSpaces attribute="String"/> + <DetectIdentifier attribute="String"/> <IncludeRules context="stringescape"/> <IncludeRules context="stringformat"/> <StringDetect attribute="String" String=""""" context="#pop!#CheckForString" endRegion="Triple Q-region"/> + <LineContinue attribute="String Char" context="#stay"/> </context> <context name="Raw Triple Q-string" attribute="Raw String" lineEndContext="#stay" noIndentationBasedFolding="true"> - <HlCStringChar attribute="Raw String" context="#stay"/> + <DetectSpaces attribute="Raw String"/> + <DetectIdentifier attribute="Raw String"/> + <Detect2Chars attribute="Raw String" char="\" char1="""/> + <Detect2Chars attribute="Raw String" char="\" char1="\"/> <IncludeRules context="stringformat"/> <StringDetect attribute="Raw String" String=""""" context="#pop!#CheckForString" endRegion="Triple Q-region"/> </context> <context name="Triple Q-F-String" attribute="F-String" lineEndContext="#stay" noIndentationBasedFolding="true"> + <DetectSpaces attribute="F-String"/> + <DetectIdentifier attribute="F-String"/> <IncludeRules context="stringescape"/> <IncludeRules context="stringinterpolation"/> <StringDetect attribute="F-String" String=""""" context="#pop!#CheckForString" endRegion="Triple Q-region"/> + <LineContinue attribute="String Char" context="#stay"/> </context> <context name="Raw Triple Q-F-String" attribute="Raw F-String" lineEndContext="#stay" noIndentationBasedFolding="true"> - <HlCStringChar attribute="Raw F-String" context="#stay"/> + <DetectSpaces attribute="Raw F-String"/> + <DetectIdentifier attribute="Raw F-String"/> + <Detect2Chars attribute="Raw F-String" char="\" char1="""/> + <Detect2Chars attribute="Raw F-String" char="\" char1="\"/> <IncludeRules context="stringinterpolation"/> <StringDetect attribute="Raw F-String" String=""""" context="#pop!#CheckForString" endRegion="Triple Q-region"/> </context> + <context name="Triple Q-B-String" attribute="B-String" lineEndContext="#stay" noIndentationBasedFolding="true"> + <RegExpr attribute="B-String" String="([\x20\x21\x23-\x5B\x5D-\x7E]++|\\(?=[^\\'"abfnrtvx0-7])|\\x(?![0-9a-fA-F]{2})|"(?!""))++"/> + <IncludeRules context="bytesescape"/> + <StringDetect attribute="B-String" String=""""" context="#pop!#CheckForString" endRegion="Triple Q-region"/> + <LineContinue attribute="String Char" context="#stay"/> + <RegExpr attribute="Error" String="."/> + </context> + + <context name="Raw Triple Q-B-String" attribute="Raw B-String" lineEndContext="#stay" noIndentationBasedFolding="true"> + <RegExpr attribute="Raw B-String" String="([\x20\x21\x23-\x5B\x5D-\x7E]++|\\.?|"(?!""))++"/> + <StringDetect attribute="Raw B-String" String=""""" context="#pop!#CheckForString" endRegion="Triple Q-region"/> + <RegExpr attribute="Error" String="."/> + </context> + <!-- Single-quoted A-strings --> - <context name="Single A-string" attribute="String" lineEndContext="#stay"> + <context name="Single A-string" attribute="String" lineEndContext="#pop!UnfinishedStringError"> + <DetectSpaces attribute="String"/> + <DetectIdentifier attribute="String"/> <IncludeRules context="stringescape"/> <IncludeRules context="stringformat"/> <DetectChar attribute="String" char="'" context="#pop!#CheckForString"/> + <LineContinue attribute="String Char" context="#stay"/> </context> - <context name="Raw A-string" attribute="Raw String" lineEndContext="#stay"> - <HlCStringChar attribute="Raw String" context="#stay"/> + <context name="Raw A-string" attribute="Raw String" lineEndContext="#pop!UnfinishedStringError"> + <DetectSpaces attribute="Raw String"/> + <DetectIdentifier attribute="Raw String"/> + <Detect2Chars attribute="Raw String" char="\" char1="'"/> + <Detect2Chars attribute="Raw String" char="\" char1="\"/> <IncludeRules context="stringformat"/> <DetectChar attribute="Raw String" char="'" context="#pop!#CheckForString"/> + <LineContinue attribute="Raw String" context="#stay"/> </context> - <context name="Single A-F-String" attribute="F-String" lineEndContext="#stay"> + <context name="Single A-F-String" attribute="F-String" lineEndContext="#pop!UnfinishedStringError"> + <DetectSpaces attribute="F-String"/> + <DetectIdentifier attribute="F-String"/> <IncludeRules context="stringescape"/> <IncludeRules context="stringinterpolation"/> <DetectChar attribute="F-String" char="'" context="#pop!#CheckForString"/> + <LineContinue attribute="String Char" context="#stay"/> </context> - <context name="Raw A-F-String" attribute="Raw F-String" lineEndContext="#stay"> - <HlCStringChar attribute="Raw F-String" context="#stay"/> + <context name="Raw A-F-String" attribute="Raw F-String" lineEndContext="#pop!UnfinishedStringError"> + <DetectSpaces attribute="Raw F-String"/> + <DetectIdentifier attribute="Raw F-String"/> + <Detect2Chars attribute="Raw F-String" char="\" char1="'"/> + <Detect2Chars attribute="Raw F-String" char="\" char1="\"/> <IncludeRules context="stringinterpolation"/> <DetectChar attribute="Raw F-String" char="'" context="#pop!#CheckForString"/> + <LineContinue attribute="Raw F-String" context="#stay"/> + </context> + + <context name="Single A-B-String" attribute="B-String" lineEndContext="#pop!UnfinishedStringError"> + <RegExpr attribute="B-String" String="([\x20-\x26\x28-\x5B\x5D-\x7E]++|\\(?=[^\\'"abfnrtvx0-7])|\\x(?![0-9a-fA-F]{2}))++"/> + <IncludeRules context="bytesescape"/> + <DetectChar attribute="B-String" char="'" context="#pop!#CheckForString"/> + <LineContinue attribute="String Char" context="#stay"/> + <RegExpr attribute="Error" String="."/> + </context> + + <context name="Raw A-B-String" attribute="Raw B-String" lineEndContext="#pop!UnfinishedStringError"> + <RegExpr attribute="Raw B-String" String="([\x20-\x26\x28-\x5B\x5D-\x7E]++|\\.)++"/> + <DetectChar attribute="Raw B-String" char="'" context="#pop!#CheckForString"/> + <LineContinue attribute="Raw B-String" context="#stay"/> + <RegExpr attribute="Error" String="."/> </context> <!-- Single-quoted Q-strings --> - <context name="Single Q-string" attribute="String" lineEndContext="#stay"> + <context name="Single Q-string" attribute="String" lineEndContext="#pop!UnfinishedStringError"> + <DetectSpaces attribute="String"/> + <DetectIdentifier attribute="String"/> <IncludeRules context="stringescape"/> <IncludeRules context="stringformat"/> <DetectChar attribute="String" char=""" context="#pop!#CheckForString"/> + <LineContinue attribute="String Char" context="#stay"/> </context> - <context name="Raw Q-string" attribute="Raw String" lineEndContext="#stay"> - <HlCStringChar attribute="Raw String" context="#stay"/> + <context name="Raw Q-string" attribute="Raw String" lineEndContext="#pop!UnfinishedStringError"> + <DetectSpaces attribute="Raw String"/> + <DetectIdentifier attribute="Raw String"/> + <Detect2Chars attribute="Raw String" char="\" char1="""/> + <Detect2Chars attribute="Raw String" char="\" char1="\"/> <IncludeRules context="stringformat"/> <DetectChar attribute="Raw String" char=""" context="#pop!#CheckForString"/> + <LineContinue attribute="Raw String" context="#stay"/> </context> - <context name="Single Q-F-String" attribute="F-String" lineEndContext="#stay"> + <context name="Single Q-F-String" attribute="F-String" lineEndContext="#pop!UnfinishedStringError"> + <DetectSpaces attribute="F-String"/> + <DetectIdentifier attribute="F-String"/> <IncludeRules context="stringescape"/> <IncludeRules context="stringinterpolation"/> <DetectChar attribute="F-String" char=""" context="#pop!#CheckForString"/> + <LineContinue attribute="String Char" context="#stay"/> </context> - <context name="Raw Q-F-String" attribute="Raw F-String" lineEndContext="#stay"> - <HlCStringChar attribute="Raw F-String" context="#stay"/> + <context name="Raw Q-F-String" attribute="Raw F-String" lineEndContext="#pop!UnfinishedStringError"> + <DetectSpaces attribute="Raw F-String"/> + <DetectIdentifier attribute="Raw F-String"/> + <Detect2Chars attribute="Raw F-String" char="\" char1="""/> + <Detect2Chars attribute="Raw F-String" char="\" char1="\"/> <IncludeRules context="stringinterpolation"/> <DetectChar attribute="Raw F-String" char=""" context="#pop!#CheckForString"/> + <LineContinue attribute="Raw F-String" context="#stay"/> </context> + + <context name="Single Q-B-String" attribute="B-String" lineEndContext="#pop!UnfinishedStringError"> + <RegExpr attribute="B-String" String="([\x20\x21\x23-\x5B\x5D-\x7E]++|\\(?=[^\\'"abfnrtvx0-7])|\\x(?![0-9a-fA-F]{2}))++"/> + <IncludeRules context="bytesescape"/> + <DetectChar attribute="B-String" char=""" context="#pop!#CheckForString"/> + <LineContinue attribute="String Char" context="#stay"/> + <RegExpr attribute="Error" String="."/> + </context> + + <context name="Raw Q-B-String" attribute="Raw B-String" lineEndContext="#pop!UnfinishedStringError"> + <RegExpr attribute="Raw B-String" String="([\x20\x21\x23-\x5B\x5D-\x7E]++|\\.)++"/> + <DetectChar attribute="Raw B-String" char=""" context="#pop!#CheckForString"/> + <Detect2Chars attribute="Raw B-String" char="\" char1="\"/> + <LineContinue attribute="Raw B-String" context="#stay"/> + <RegExpr attribute="Error" String="."/> + </context> + </contexts> <itemDatas> @@ -668,6 +871,8 @@ <itemData name="Raw String" defStyleNum="dsVerbatimString"/> <itemData name="F-String" defStyleNum="dsSpecialString"/> <itemData name="Raw F-String" defStyleNum="dsVerbatimString"/> + <itemData name="B-String" defStyleNum="dsString" spellChecking="false"/> + <itemData name="Raw B-String" defStyleNum="dsVerbatimString" spellChecking="false"/> <itemData name="String Char" defStyleNum="dsChar" spellChecking="false"/> <itemData name="String Substitution" defStyleNum="dsSpecialChar" spellChecking="false"/> <itemData name="Decorator" defStyleNum="dsAttribute" spellChecking="false"/> diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml index fbefcb6dad..839e8f9162 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml @@ -6,7 +6,7 @@ <!ENTITY name "(?![0-9])[\w_:][\w.:_-]*"> <!ENTITY entref "&(?:#[0-9]+|#[xX][0-9A-Fa-f]+|&name;);"> ]> -<language name="XML" version="12" kateversion="5.0" section="Markup" extensions="*.docbook;*.xml;*.rc;*.daml;*.rdf;*.rss;*.xspf;*.xsd;*.svg;*.ui;*.kcfg;*.qrc;*.wsdl;*.scxml;*.xbel;*.dae;*.sch;*.brd" mimetype="text/xml;text/book;text/daml;text/rdf;application/rss+xml;application/xspf+xml;image/svg+xml;application/x-designer;application/x-xbel;application/xml;application/scxml+xml" casesensitive="1" indenter="xml" author="Wilbert Berendsen (wilbert@kde.nl)" license="LGPL"> +<language name="XML" version="14" kateversion="5.0" section="Markup" extensions="*.docbook;*.xml;*.rc;*.daml;*.rdf;*.rss;*.xspf;*.xsd;*.svg;*.ui;*.kcfg;*.qrc;*.wsdl;*.scxml;*.xbel;*.dae;*.sch;*.brd" mimetype="text/xml;text/book;text/daml;text/rdf;application/rss+xml;application/xspf+xml;image/svg+xml;application/x-designer;application/x-xbel;application/xml;application/scxml+xml" casesensitive="1" indenter="xml" author="Wilbert Berendsen (wilbert@kde.nl)" license="LGPL"> <highlighting> <contexts> @@ -16,13 +16,13 @@ <context name="FindXML" attribute="Normal Text" lineEndContext="#stay"> <DetectSpaces /> + <DetectIdentifier /> + <RegExpr attribute="Element Symbols" context="ElementTagName" String="<(?=(&name;))" beginRegion="element" /> <StringDetect attribute="Comment" context="Comment" String="<!--" beginRegion="comment" /> <StringDetect attribute="CDATA" context="CDATAStart" String="<![CDATA[" lookAhead="true" /> - <RegExpr attribute="Doctype Symbols" context="DoctypeTagName" String="<!(?=DOCTYPE\s+)" beginRegion="doctype" /> + <RegExpr attribute="Doctype Symbols" context="DoctypeTagName" String="<!(?=DOCTYPE(\s|$))" beginRegion="doctype" /> <IncludeRules context="FindProcessingInstruction" /> - <RegExpr attribute="Element Symbols" context="ElementTagName" String="<(?=(&name;))" beginRegion="element" /> <IncludeRules context="FindEntityRefs" /> - <DetectIdentifier /> </context> <context name="FindEntityRefs" attribute="Other Text" lineEndContext="#stay"> @@ -70,13 +70,13 @@ <context name="PI-XML" attribute="Other Text" lineEndContext="#stay"> <IncludeRules context="PI" /> <RegExpr attribute="Attribute" context="#stay" String="(?:^|\s+)&name;" /> - <DetectChar attribute="Attribute" context="Value" char="=" /> + <DetectChar attribute="Attribute Separator" context="Value" char="=" /> </context> <context name="DoctypeTagName" attribute="Other Text" lineEndContext="#pop"> <StringDetect attribute="Doctype" context="#pop!DoctypeVariableName" String="DOCTYPE" /> </context> - <context name="DoctypeVariableName" attribute="Other Text" lineEndContext="#pop!Doctype" fallthrough="true" fallthroughContext="#pop!Doctype"> + <context name="DoctypeVariableName" attribute="Other Text" lineEndContext="#stay" fallthrough="true" fallthroughContext="#pop!Doctype"> <DetectSpaces /> <RegExpr attribute="Doctype Name" context="#pop!Doctype" String="&name;" /> </context> @@ -116,7 +116,7 @@ <IncludeRules context="FindPEntityRefs" /> </context> - <context name="ElementTagName" attribute="Other Text" lineEndContext="#pop!Element" fallthrough="true" fallthroughContext="#pop!Element"> + <context name="ElementTagName" attribute="Other Text" lineEndContext="#pop!Element"> <StringDetect attribute="Element" context="#pop!Element" String="%1" dynamic="true" /> </context> <context name="Element" attribute="Other Text" lineEndContext="#stay"> @@ -131,7 +131,7 @@ <IncludeRules context="FindXML" /> </context> - <context name="El End TagName" attribute="Other Text" lineEndContext="#pop!El End" fallthrough="true" fallthroughContext="#pop!El End"> + <context name="El End TagName" attribute="Other Text" lineEndContext="#pop!El End"> <StringDetect attribute="Element" context="#pop!El End" String="%1" dynamic="true" /> </context> <context name="El End" attribute="Other Text" lineEndContext="#stay"> @@ -140,7 +140,7 @@ </context> <context name="Attribute" attribute="Other Text" lineEndContext="#stay"> - <DetectChar attribute="Attribute" context="#pop!Value" char="=" /> + <DetectChar attribute="Attribute Separator" context="#pop!Value" char="=" /> <RegExpr attribute="Error" context="#stay" String="\S" /> </context> @@ -175,6 +175,7 @@ <itemData name="Element" defStyleNum="dsKeyword" spellChecking="false" /> <itemData name="Element Symbols" defStyleNum="dsNormal" spellChecking="false" /> <itemData name="Attribute" defStyleNum="dsOthers" spellChecking="false" /> + <itemData name="Attribute Separator" defStyleNum="dsOthers" spellChecking="false" /> <itemData name="Value" defStyleNum="dsString" spellChecking="false" /> <itemData name="EntityRef" defStyleNum="dsDecVal" spellChecking="false" /> <itemData name="PEntityRef" defStyleNum="dsDecVal" spellChecking="false" /> diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-dark.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-dark.theme index ebfde02797..fea8def01f 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-dark.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-dark.theme @@ -1,6 +1,6 @@ { "_comments": [ - "Last update: Feb 22, 2021 (revision 3)", + "Last update: Jul 28, 2021 (revision 4)", "This file has been converted from: https://github.com/dempfi/ayu", "Also see: https://github.com/ayu-theme" ], @@ -11,7 +11,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "ayu Dark", - "revision": 3 + "revision": 4 }, "editor-colors": { "BackgroundColor": "#0a0e14", @@ -169,8 +169,8 @@ "text-color": "#39bae6" }, "VerbatimString": { - "selected-text-color": "#c2d94c", - "text-color": "#c2d94c" + "selected-text-color": "#99ca44", + "text-color": "#99ca44" }, "Warning": { "selected-text-color": "#f07178", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-light.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-light.theme index c93e414457..30e119ed1b 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-light.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-light.theme @@ -1,6 +1,6 @@ { "_comments": [ - "Last update: Sep 21, 2020 (revision 2)", + "Last update: Jul 28, 2021 (revision 3)", "This file has been converted from: https://github.com/dempfi/ayu", "Also see: https://github.com/ayu-theme" ], @@ -11,7 +11,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "ayu Light", - "revision": 2 + "revision": 3 }, "editor-colors": { "BackgroundColor": "#fafafa", @@ -169,8 +169,8 @@ "text-color": "#55b4d4" }, "VerbatimString": { - "selected-text-color": "#86b300", - "text-color": "#86b300" + "selected-text-color": "#729800", + "text-color": "#729800" }, "Warning": { "selected-text-color": "#f07171", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-mirage.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-mirage.theme index e389ecf298..005d6a0ad2 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-mirage.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/ayu-mirage.theme @@ -1,6 +1,6 @@ { "_comments": [ - "Last update: Feb 22, 2021 (revision 3)", + "Last update: Jul 28, 2021 (revision 4)", "This file has been converted from: https://github.com/dempfi/ayu", "Also see: https://github.com/ayu-theme" ], @@ -11,7 +11,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "ayu Mirage", - "revision": 3 + "revision": 4 }, "editor-colors": { "BackgroundColor": "#1f2430", @@ -169,8 +169,8 @@ "text-color": "#5ccfe6" }, "VerbatimString": { - "selected-text-color": "#bae67e", - "text-color": "#bae67e" + "selected-text-color": "#82e26a", + "text-color": "#82e26a" }, "Warning": { "selected-text-color": "#f28779", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-dark.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-dark.theme index 712da4acc4..1ad7fffee3 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-dark.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-dark.theme @@ -5,7 +5,7 @@ "SPDX-FileCopyrightText: 2016 Dominik Haumann <dhaumann@kde.org>" ], "license": "SPDX-License-Identifier: MIT", - "revision" : 6, + "revision" : 7, "name" : "Breeze Dark" }, "text-styles": { @@ -149,7 +149,7 @@ "editor-colors": { "BackgroundColor" : "#232629", "CodeFolding" : "#224e65", - "BracketMatching" : "#323030", + "BracketMatching" : "#8e44ad", "CurrentLine" : "#2A2E32", "IconBorder" : "#31363b", "IndentationLine" : "#3a3f44", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-light.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-light.theme index 7d0116bea9..6dee8dd777 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-light.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/breeze-light.theme @@ -5,7 +5,7 @@ "SPDX-FileCopyrightText: 2016 Dominik Haumann <dhaumann@kde.org>" ], "license": "SPDX-License-Identifier: MIT", - "revision" : 8, + "revision" : 9, "name" : "Breeze Light" }, "text-styles": { @@ -70,7 +70,7 @@ "selected-text-color" : "#9c0e0e" }, "VerbatimString" : { - "text-color" : "#bf0303", + "text-color" : "#e31616", "selected-text-color" : "#9c0e0e" }, "SpecialString" : { diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/dracula.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/dracula.theme index 93b1833334..b388396050 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/dracula.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/dracula.theme @@ -570,7 +570,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "Dracula", - "revision": 7 + "revision": 8 }, "text-styles": { "Alert": { @@ -694,8 +694,8 @@ "text-color": "#8be9fd" }, "VerbatimString": { - "selected-text-color": "#f1fa8c", - "text-color": "#f1fa8c" + "selected-text-color": "#d7e60a", + "text-color": "#d7e60a" }, "Warning": { "selected-text-color": "#ff5555", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/falcon.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/falcon.theme new file mode 100644 index 0000000000..1ebf8c6946 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/falcon.theme @@ -0,0 +1,184 @@ +{ + "_comments": [ + "A theme focused on ergonomics, using the 3 digit Tango color palette" + ], + "metadata": { + "name": "Falcon", + "revision": 4, + "license": "SPDX-License-Identifier: MIT", + "copyright": [ "SPDX-FileCopyrightText: 2021 Alberto Salvia Novella <https://es20490446e.wordpress.com>" ] + }, + "custom-styles": { + "Bash": { + "Normal Text": { + "text-color": "#bbbbbb" + } + } + }, + "editor-colors": { + "BackgroundColor": "#223333", + "BracketMatching": "#555555", + "CodeFolding": "#224488", + "CurrentLine": "#555555", + "CurrentLineNumber": "#bbbbbb", + "IconBorder": "#223333", + "IndentationLine": "#888888", + "LineNumbers": "#888888", + "MarkBookmark": "#7799cc", + "MarkBreakpointActive": "#ffaa33", + "MarkBreakpointDisabled": "#aa77aa", + "MarkBreakpointReached": "#449900", + "MarkError": "#ef2929", + "MarkExecution": "#888888", + "MarkWarning": "#aa77aa", + "ModifiedLines": "#aa0000", + "ReplaceHighlight": "#224488", + "SavedLines": "#449900", + "SearchHighlight": "#224488", + "Separator": "#555753", + "SpellChecking": "#ef2929", + "TabMarker": "#555555", + "TemplateBackground": "#223333", + "TemplateFocusedPlaceholder": "#23321a", + "TemplatePlaceholder": "#23321a", + "TemplateReadOnlyPlaceholder": "#451e1a", + "TextSelection": "#3366aa", + "WordWrapMarker": "#555753" + }, + "text-styles": { + "Alert": { + "background-color": "#320000", + "bold": true, + "selected-text-color": "#ffaa33", + "text-color": "#ee2222" + }, + "Annotation": { + "selected-text-color": "#ddddcc", + "text-color": "#aa77aa" + }, + "Attribute": { + "selected-text-color": "#ddddcc", + "text-color": "#aa77aa" + }, + "BaseN": { + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + }, + "BuiltIn": { + "selected-text-color": "#ddddcc", + "text-color": "#7799cc" + }, + "Char": { + "selected-text-color": "#ffaa33", + "text-color": "#ffaa33" + }, + "Comment": { + "selected-text-color": "#eeeeec", + "text-color": "#888888" + }, + "CommentVar": { + "selected-text-color": "#ddddcc", + "text-color": "#aa77aa" + }, + "Constant": { + "bold": true, + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + }, + "ControlFlow": { + "bold": true, + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + }, + "DataType": { + "selected-text-color": "#ddddcc", + "text-color": "#7799cc" + }, + "DecVal": { + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + }, + "Documentation": { + "selected-text-color": "#eeeeee", + "text-color": "#d3d7cf" + }, + "Error": { + "selected-text-color": "#ffaa33", + "text-color": "#ee2222", + "underline": true + }, + "Extension": { + "bold": true, + "selected-text-color": "#ddddcc", + "text-color": "#7799cc" + }, + "Float": { + "selected-text-color": "#ffaa33", + "text-color": "#ffaa33" + }, + "Function": { + "bold": true, + "selected-text-color": "#ddddcc", + "text-color": "#7799cc" + }, + "Import": { + "selected-text-color": "#88ee33", + "text-color": "#88ee33" + }, + "Information": { + "selected-text-color": "#eeeeee", + "text-color": "#ddddcc" + }, + "Keyword": { + "bold": true, + "selected-text-color": "#ddddcc", + "text-color": "#aa77aa" + }, + "Normal": { + "selected-text-color": "#eeeeee", + "text-color": "#ddddcc" + }, + "Operator": { + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + }, + "Others": { + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + }, + "Preprocessor": { + "selected-text-color": "#ddddcc", + "text-color": "#aa77aa" + }, + "RegionMarker": { + "background-color": "#0d1932", + "selected-text-color": "#ddddcc", + "text-color": "#7799cc" + }, + "SpecialChar": { + "selected-text-color": "#ffaa33", + "text-color": "#ffaa33" + }, + "SpecialString": { + "selected-text-color": "#eeeeee", + "text-color": "#ddddcc" + }, + "String": { + "selected-text-color": "#eeeeee", + "text-color": "#ddddcc" + }, + "Variable": { + "bold": true, + "selected-text-color": "#ffaa33", + "text-color": "#ffaa33" + }, + "VerbatimString": { + "selected-text-color": "#ffaa33", + "text-color": "#ffaa33" + }, + "Warning": { + "selected-text-color": "#ffee44", + "text-color": "#eedd00" + } + } +} diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/github-dark.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/github-dark.theme index 313e99f052..a699638532 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/github-dark.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/github-dark.theme @@ -82,7 +82,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "GitHub Dark", - "revision": 2 + "revision": 3 }, "text-styles": { "Alert": { @@ -205,8 +205,8 @@ "text-color": "#ffab70" }, "VerbatimString": { - "selected-text-color": "#9ecbff", - "text-color": "#9ecbff" + "selected-text-color": "#41a0ff", + "text-color": "#41a0ff" }, "Warning": { "selected-text-color": "#ff5555", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/github-light.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/github-light.theme index 5f465c653c..ed56418fde 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/github-light.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/github-light.theme @@ -82,7 +82,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "GitHub Light", - "revision": 2 + "revision": 3 }, "text-styles": { "Alert": { @@ -205,8 +205,8 @@ "text-color": "#e36209" }, "VerbatimString": { - "selected-text-color": "#032f62", - "text-color": "#032f62" + "selected-text-color": "#034c95", + "text-color": "#034c95" }, "Warning": { "selected-text-color": "#ff5555", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-dark.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-dark.theme index 66c6c9afb7..0e006ab46e 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-dark.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-dark.theme @@ -1,6 +1,6 @@ { "_comments": [ - "Last update: Sep 17, 2020 (revision 2)", + "Last update: Jul 28, 2021 (revision 3)", "This file has been converted from: https://github.com/morhetz/gruvbox" ], "metadata" : { @@ -10,7 +10,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name" : "gruvbox Dark", - "revision" : 2 + "revision" : 3 }, "text-styles": { "Normal" : { @@ -73,7 +73,7 @@ "selected-text-color" : "#b8bb26" }, "VerbatimString" : { - "text-color" : "#98971a", + "text-color" : "#848216", "selected-text-color" : "#b8bb26" }, "SpecialString" : { diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-light.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-light.theme index 6038c70e94..937a43d084 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-light.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/gruvbox-light.theme @@ -1,6 +1,6 @@ { "_comments": [ - "Last update: Sep 17, 2020 (revision 2)", + "Last update: Jul 28, 2021 (revision 3)", "This file has been converted from: https://github.com/morhetz/gruvbox" ], "metadata" : { @@ -10,7 +10,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name" : "gruvbox Light", - "revision" : 2 + "revision" : 3 }, "text-styles": { "Normal" : { @@ -73,7 +73,7 @@ "selected-text-color" : "#79740e" }, "VerbatimString" : { - "text-color" : "#98971a", + "text-color" : "#848216", "selected-text-color" : "#79740e" }, "SpecialString" : { diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/monokai.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/monokai.theme index 3df8e66c00..e0026ca3b3 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/monokai.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/monokai.theme @@ -259,7 +259,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "Monokai", - "revision": 5 + "revision": 6 }, "text-styles": { "Alert": { @@ -383,8 +383,8 @@ "text-color": "#f8f8f2" }, "VerbatimString": { - "selected-text-color": "#e6db74", - "text-color": "#e6db74" + "selected-text-color": "#d8c72c", + "text-color": "#d8c72c" }, "Warning": { "selected-text-color": "#ff5555", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/nord.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/nord.theme index 6ad4d82e43..dbe44d9b09 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/nord.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/nord.theme @@ -1,6 +1,6 @@ { "_comments": [ - "Last update: Sep 21, 2020 (revision 2)", + "Last update: Jul 28, 2020 (revision 3)", "This theme has been adapted from: https://www.nordtheme.com" ], "metadata": { @@ -11,7 +11,7 @@ ], "license": "SPDX-License-Identifier: MIT", "name": "Nord", - "revision": 2 + "revision": 3 }, "editor-colors": { "BackgroundColor": "#2e3440", @@ -170,8 +170,8 @@ "text-color": "#5e81ac" }, "VerbatimString": { - "selected-text-color": "#a3be8c", - "text-color": "#a3be8c" + "selected-text-color": "#8dae70", + "text-color": "#8dae70" }, "Warning": { "selected-text-color": "#bf616a", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/printing.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/printing.theme index 26d779582d..49bbe6419f 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/printing.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/printing.theme @@ -5,7 +5,7 @@ "SPDX-FileCopyrightText: 2016 Dominik Haumann <dhaumann@kde.org>" ], "license": "SPDX-License-Identifier: MIT", - "revision" : 4, + "revision" : 5, "name" : "Printing" }, "text-styles": { @@ -69,7 +69,7 @@ "selected-text-color" : "#9c0e0e" }, "VerbatimString" : { - "text-color" : "#bf0303", + "text-color" : "#ea0404", "selected-text-color" : "#9c0e0e" }, "SpecialString" : { diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-dark.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-dark.theme index b8d13b31d3..1fe48bacd0 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-dark.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-dark.theme @@ -9,7 +9,7 @@ "SPDX-FileCopyrightText: 2018 Andrew Crouthamel <andrew.crouthamel@kdemail.net>" ], "license": "SPDX-License-Identifier: MIT", - "revision" : 5, + "revision" : 6, "name" : "Solarized Dark" }, "text-styles": { @@ -70,8 +70,8 @@ "selected-text-color" : "#2aa198" }, "VerbatimString" : { - "text-color" : "#2aa198", - "selected-text-color" : "#2aa198" + "text-color" : "#23877e", + "selected-text-color" : "#23877e" }, "SpecialString" : { "text-color" : "#dc322f", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-light.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-light.theme index a532b128f8..51c76faaec 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-light.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/solarized-light.theme @@ -9,7 +9,7 @@ "SPDX-FileCopyrightText: 2018 Andrew Crouthamel <andrew.crouthamel@kdemail.net>" ], "license": "SPDX-License-Identifier: MIT", - "revision" : 4, + "revision" : 5, "name" : "Solarized Light" }, "text-styles": { @@ -73,8 +73,8 @@ "selected-text-color" : "#2aa198" }, "VerbatimString" : { - "text-color" : "#2aa198", - "selected-text-color" : "#2aa198" + "text-color" : "#23837a", + "selected-text-color" : "#23837a" }, "SpecialString" : { "text-color" : "#dc322f", diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/theme-data.qrc b/src/libs/3rdparty/syntax-highlighting/data/themes/theme-data.qrc index fe0a1627be..cf9d658c82 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/theme-data.qrc +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/theme-data.qrc @@ -9,6 +9,7 @@ <file>ayu-light.theme</file> <file>ayu-mirage.theme</file> <file>dracula.theme</file> + <file>falcon.theme</file> <file>github-dark.theme</file> <file>github-light.theme</file> <file>gruvbox-dark.theme</file> diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/vim-dark.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/vim-dark.theme index 1a2c7785ac..d039822cae 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/vim-dark.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/vim-dark.theme @@ -5,7 +5,7 @@ "SPDX-FileCopyrightText: 2020 Nibaldo González <nibgonz@gmail.com>" ], "license": "SPDX-License-Identifier: MIT", - "revision" : 3, + "revision" : 4, "name" : "Vim Dark" }, "text-styles": { @@ -70,8 +70,8 @@ "selected-text-color" : "#ff54ff" }, "VerbatimString" : { - "text-color" : "#ff54ff", - "selected-text-color" : "#ff54ff" + "text-color" : "#f000f0", + "selected-text-color" : "#f000f0" }, "SpecialString" : { "text-color" : "#ff5500", diff --git a/src/libs/3rdparty/syntax-highlighting/metainfo.yaml b/src/libs/3rdparty/syntax-highlighting/metainfo.yaml index 7a3220a31e..a82f7a986d 100644 --- a/src/libs/3rdparty/syntax-highlighting/metainfo.yaml +++ b/src/libs/3rdparty/syntax-highlighting/metainfo.yaml @@ -6,7 +6,7 @@ platforms: - name: Linux - name: FreeBSD - name: Windows - - name: MacOSX + - name: macOS - name: Android portingAid: false deprecated: false diff --git a/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp index a009c4f259..749123aa54 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp @@ -30,10 +30,11 @@ static void applyHighlighter(Highlighter &highlighter, const QCommandLineOption &outputName, const Ts &...highlightParams) { - if (parser.isSet(outputName)) + if (parser.isSet(outputName)) { highlighter.setOutputFile(parser.value(outputName)); - else + } else { highlighter.setOutputFile(stdout); + } if (fromFileName) { highlighter.highlightFile(inFileName, highlightParams...); @@ -126,8 +127,9 @@ int main(int argc, char **argv) } if (parser.isSet(listThemes)) { - for (const auto &theme : repo.themes()) + for (const auto &theme : repo.themes()) { std::cout << qPrintable(theme.name()) << std::endl; + } return 0; } @@ -158,9 +160,10 @@ int main(int argc, char **argv) if (!def.isValid()) { /* see if it's a extension instead */ def = repo.definitionForFileName(QLatin1String("f.") + syntax); - if (!def.isValid()) + if (!def.isValid()) { /* see if it's a filename instead */ def = repo.definitionForFileName(syntax); + } } } } else if (fromFileName) { @@ -177,8 +180,9 @@ int main(int argc, char **argv) QString outputFormat = parser.value(outputFormatOption); if (0 == outputFormat.compare(QLatin1String("html"), Qt::CaseInsensitive)) { QString title; - if (parser.isSet(titleOption)) + if (parser.isSet(titleOption)) { title = parser.value(titleOption); + } HtmlHighlighter highlighter; highlighter.setDefinition(def); diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt index 508cd276cc..4a84696ad9 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt @@ -28,7 +28,8 @@ elseif(CMAKE_CROSSCOMPILING) else() # host build add_executable(katehighlightingindexer katehighlightingindexer.cpp ../lib/worddelimiters.cpp) - if(Qt5XmlPatterns_FOUND) + ecm_mark_nongui_executable(katehighlightingindexer) + if(Qt5XmlPatterns_FOUND AND NOT ECM_ENABLE_SANITIZERS) target_link_libraries(katehighlightingindexer Qt5::XmlPatterns) else() target_link_libraries(katehighlightingindexer Qt5::Core) diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp index 86b3a38b12..4de51ba7c8 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp @@ -31,7 +31,8 @@ using KSyntaxHighlighting::Xml::attrToBool; class HlFilesChecker { public: - void setDefinition(const QStringRef &verStr, const QString &filename, const QString &name) + template<typename T> + void setDefinition(const T &verStr, const QString &filename, const QString &name) { m_currentDefinition = &*m_definitions.insert(name, Definition{}); m_currentDefinition->languageName = name; @@ -93,6 +94,12 @@ public: continue; } + auto markAsUsedContext = [](ContextName &ContextName) { + if (!ContextName.stay && ContextName.context) { + ContextName.context->isOnlyIncluded = false; + } + }; + QMutableMapIterator<QString, Context> contextIt(contexts); while (contextIt.hasNext()) { contextIt.next(); @@ -100,12 +107,21 @@ public: resolveContextName(definition, context, context.lineEndContext, context.line); resolveContextName(definition, context, context.lineEmptyContext, context.line); resolveContextName(definition, context, context.fallthroughContext, context.line); + markAsUsedContext(context.lineEndContext); + markAsUsedContext(context.lineEmptyContext); + markAsUsedContext(context.fallthroughContext); for (auto &rule : context.rules) { + rule.parentContext = &context; resolveContextName(definition, context, rule.context, rule.line); + if (rule.type != Context::Rule::Type::IncludeRules) { + markAsUsedContext(rule.context); + } } } - definition.firstContext = &*definition.contexts.find(definition.firstContextName); + auto *firstContext = &*definition.contexts.find(definition.firstContextName); + firstContext->isOnlyIncluded = false; + definition.firstContext = firstContext; } resolveIncludeRules(); @@ -118,6 +134,7 @@ public: const auto usedContexts = extractUsedContexts(); QMap<const Definition *, const Definition *> maxVersionByDefinitions; + QMap<const Context::Rule *, IncludedRuleUnreachableBy> unreachableIncludedRules; QMapIterator<QString, Definition> def(m_definitions); while (def.hasNext()) { @@ -135,14 +152,7 @@ public: QSet<const Keywords *> referencedKeywords; QSet<ItemDatas::Style> usedAttributeNames; success = checkKeywordsList(definition, referencedKeywords) && success; - success = checkContexts(definition, referencedKeywords, usedAttributeNames, usedContexts) && success; - - // search for non-existing or unreferenced keyword lists. - for (const auto &keywords : definition.keywordsList) { - if (!referencedKeywords.contains(&keywords)) { - qWarning() << filename << "line" << keywords.line << "unused keyword:" << keywords.name; - } - } + success = checkContexts(definition, referencedKeywords, usedAttributeNames, usedContexts, unreachableIncludedRules) && success; // search for non-existing itemDatas. const auto invalidNames = usedAttributeNames - definition.itemDatas.styleNames; @@ -159,6 +169,56 @@ public: } } + QMutableMapIterator<const Context::Rule *, IncludedRuleUnreachableBy> unreachableIncludedRuleIt(unreachableIncludedRules); + while (unreachableIncludedRuleIt.hasNext()) { + unreachableIncludedRuleIt.next(); + IncludedRuleUnreachableBy &unreachableRulesBy = unreachableIncludedRuleIt.value(); + if (unreachableRulesBy.alwaysUnreachable) { + auto *rule = unreachableIncludedRuleIt.key(); + + if (!rule->parentContext->isOnlyIncluded) { + continue; + } + + // remove duplicates rules + QSet<const Context::Rule *> rules; + auto &unreachableBy = unreachableRulesBy.unreachableBy; + unreachableBy.erase(std::remove_if(unreachableBy.begin(), + unreachableBy.end(), + [&](const RuleAndInclude &ruleAndInclude) { + if (rules.contains(ruleAndInclude.rule)) { + return true; + } + rules.insert(ruleAndInclude.rule); + return false; + }), + unreachableBy.end()); + + QString message; + message.reserve(128); + for (auto &ruleAndInclude : std::as_const(unreachableBy)) { + message += QStringLiteral("line "); + message += QString::number(ruleAndInclude.rule->line); + message += QStringLiteral(" ["); + message += ruleAndInclude.rule->parentContext->name; + if (rule->filename != ruleAndInclude.rule->filename) { + message += QStringLiteral(" ("); + message += ruleAndInclude.rule->filename; + message += QLatin1Char(')'); + } + if (ruleAndInclude.includeRules) { + message += QStringLiteral(" via line "); + message += QString::number(ruleAndInclude.includeRules->line); + } + message += QStringLiteral("], "); + } + message.chop(2); + + qWarning() << rule->filename << "line" << rule->line << "no IncludeRule can reach this rule, hidden by" << message; + success = false; + } + } + return success; } @@ -176,7 +236,7 @@ private: int popCount = 0; bool stay = false; - const Context *context = nullptr; + Context *context = nullptr; }; struct Parser { @@ -185,12 +245,13 @@ private: QXmlStreamAttribute &attr; bool success; - //! Read a string type attribute, \c sucess = \c false when \p str is not empty + //! Read a string type attribute, \c success = \c false when \p str is not empty //! \return \c true when attr.name() == attrName, otherwise false bool extractString(QString &str, const QString &attrName) { - if (attr.name() != attrName) + if (attr.name() != attrName) { return false; + } str = attr.value().toString(); if (str.isEmpty()) { @@ -201,24 +262,26 @@ private: return true; } - //! Read a bool type attribute, \c sucess = \c false when \p xmlBool is not \c XmlBool::Unspecified. + //! Read a bool type attribute, \c success = \c false when \p xmlBool is not \c XmlBool::Unspecified. //! \return \c true when attr.name() == attrName, otherwise false bool extractXmlBool(XmlBool &xmlBool, const QString &attrName) { - if (attr.name() != attrName) + if (attr.name() != attrName) { return false; + } xmlBool = attr.value().isNull() ? XmlBool::Unspecified : attrToBool(attr.value()) ? XmlBool::True : XmlBool::False; return true; } - //! Read a positive integer type attribute, \c sucess = \c false when \p positive is already greater than or equal to 0 + //! Read a positive integer type attribute, \c success = \c false when \p positive is already greater than or equal to 0 //! \return \c true when attr.name() == attrName, otherwise false bool extractPositive(int &positive, const QString &attrName) { - if (attr.name() != attrName) + if (attr.name() != attrName) { return false; + } bool ok = true; positive = attr.value().toInt(&ok); @@ -231,12 +294,13 @@ private: return true; } - //! Read a color, \c sucess = \c false when \p color is already greater than or equal to 0 + //! Read a color, \c success = \c false when \p color is already greater than or equal to 0 //! \return \c true when attr.name() == attrName, otherwise false bool checkColor(const QString &attrName) { - if (attr.name() != attrName) + if (attr.name() != attrName) { return false; + } const auto value = attr.value().toString(); if (value.isEmpty() /*|| QColor(value).isValid()*/) { @@ -247,16 +311,17 @@ private: return true; } - //! Read a QChar, \c sucess = \c false when \p c is not \c '\0' or does not have one char + //! Read a QChar, \c success = \c false when \p c is not \c '\0' or does not have one char //! \return \c true when attr.name() == attrName, otherwise false bool extractChar(QChar &c, const QString &attrName) { - if (attr.name() != attrName) + if (attr.name() != attrName) { return false; + } - if (attr.value().size() == 1) + if (attr.value().size() == 1) { c = attr.value()[0]; - else { + } else { c = QLatin1Char('_'); qWarning() << filename << "line" << xml.lineNumber() << attrName << "must contain exactly one char:" << attr.value(); success = false; @@ -268,8 +333,9 @@ private: //! \return parsing status when \p isExtracted is \c true, otherwise \c false bool checkIfExtracted(bool isExtracted) { - if (isExtracted) + if (isExtracted) { return success; + } qWarning() << filename << "line" << xml.lineNumber() << "unknown attribute:" << attr.name(); return false; @@ -284,7 +350,7 @@ private: friend uint qHash(const Item &item, uint seed = 0) { - return qHash(item.content, seed); + return uint(qHash(item.content, seed)); } friend bool operator==(const Item &item0, const Item &item1) @@ -400,18 +466,19 @@ private: QString additionalDeliminator; QString weakDeliminator; - // rules included by IncludeRules + // rules included by IncludeRules (without IncludeRule) QVector<const Rule *> includedRules; // IncludeRules included by IncludeRules QSet<const Rule *> includedIncludeRules; + Context const *parentContext = nullptr; + QString filename; bool parseElement(const QString &filename, QXmlStreamReader &xml) { this->filename = filename; - line = xml.lineNumber(); using Pair = QPair<QString, Type>; @@ -579,6 +646,8 @@ private: }; int line; + // becomes false when a context refers to it + bool isOnlyIncluded = true; QString name; QString attribute; ContextName lineEndContext; @@ -650,7 +719,7 @@ private: friend uint qHash(const Style &style, uint seed = 0) { - return qHash(style.name, seed); + return uint(qHash(style.name, seed)); } friend bool operator==(const Style &style0, const Style &style1) @@ -723,8 +792,9 @@ private: { Context context; m_success = context.parseElement(m_currentDefinition->filename, xml) && m_success; - if (m_currentDefinition->firstContextName.isEmpty()) + if (m_currentDefinition->firstContextName.isEmpty()) { m_currentDefinition->firstContextName = context.name; + } if (m_currentDefinition->contexts.contains(context.name)) { qWarning() << m_currentDefinition->filename << "line" << xml.lineNumber() << "duplicate context:" << context.name; m_success = false; @@ -784,6 +854,7 @@ private: m_success = false; continue; } + if (rule.context.popCount) { qWarning() << definition.filename << "line" << rule.line << "IncludeRules with #pop prefix"; m_success = false; @@ -794,6 +865,8 @@ private: continue; } + // resolve includedRules and includedIncludeRules + usedContexts.clear(); usedContexts.insert(rule.context.context); contexts.clear(); @@ -866,11 +939,27 @@ private: return usedContexts; } + struct RuleAndInclude { + const Context::Rule *rule; + const Context::Rule *includeRules; + + explicit operator bool() const + { + return rule; + } + }; + + struct IncludedRuleUnreachableBy { + QVector<RuleAndInclude> unreachableBy; + bool alwaysUnreachable = true; + }; + //! Check contexts and rules bool checkContexts(const Definition &definition, QSet<const Keywords *> &referencedKeywords, QSet<ItemDatas::Style> &usedAttributeNames, - const QSet<const Context *> &usedContexts) const + const QSet<const Context *> &usedContexts, + QMap<const Context::Rule *, IncludedRuleUnreachableBy> &unreachableIncludedRules) const { bool success = true; @@ -892,16 +981,18 @@ private: success = false; } - if (!context.attribute.isEmpty()) + if (!context.attribute.isEmpty()) { usedAttributeNames.insert({context.attribute, context.line}); + } success = checkfallthrough(definition, context) && success; - success = checkUreachableRules(definition.filename, context) && success; + success = checkUreachableRules(definition.filename, context, unreachableIncludedRules) && success; success = suggestRuleMerger(definition.filename, context) && success; for (const auto &rule : context.rules) { - if (!rule.attribute.isEmpty()) + if (!rule.attribute.isEmpty()) { usedAttributeNames.insert({rule.attribute, rule.line}); + } success = checkLookAhead(rule) && success; success = checkStringDetect(rule) && success; success = checkAnyChar(rule) && success; @@ -954,9 +1045,14 @@ private: return false; } +#define REG_ESCAPE_CHAR R"(\\(?:[^0BDPSWbdpswoux]|x[0-9a-fA-F]{2}|x\{[0-9a-fA-F]+\}|0\d\d|o\{[0-7]+\}|u[0-9a-fA-F]{4}))" +#define REG_CHAR "(?:" REG_ESCAPE_CHAR "|\\[(?:" REG_ESCAPE_CHAR "|.)\\]|[^[.^])" + // is RangeDetect - static const QRegularExpression isRange(QStringLiteral( - R"(^(\\(?:[^0BDPSWbdpswoux]|x[0-9a-fA-F]{2}|x\{[0-9a-fA-F]+\}|0\d\d|o\{[0-7]+\}|u[0-9a-fA-F]{4})|[^[.]|\[[^].\\]\])(?:\.|\[^\1\])\*[?*]?\1$)")); + static const QRegularExpression isRange(QStringLiteral("^\\^?" REG_CHAR "(?:" + "\\.\\*[?*]?" REG_CHAR "|" + "\\[\\^(" REG_ESCAPE_CHAR "|.)\\]\\*[?*]?\\1" + ")$")); if (( rule.lookAhead == XmlBool::True || rule.minimal == XmlBool::True || rule.string.contains(QStringLiteral(".*?")) @@ -967,11 +1063,21 @@ private: return false; } + // is LineContinue + static const QRegularExpression isLineContinue(QStringLiteral("^\\^?" REG_CHAR "\\$$")); + if (reg.contains(isLineContinue)) { + auto extra = (reg[0] == QLatin1Char('^')) ? "with column=\"0\"" : ""; + qWarning() << filename << "line" << rule.line << "RegExpr should be replaced by LineContinue:" << rule.string << extra; + return false; + } + // replace \c, \xhhh, \x{hhh...}, \0dd, \o{ddd}, \uhhhh, with _ - static const QRegularExpression sanitize1( - QStringLiteral(R"(\\(?:[^0BDPSWbdpswoux]|x[0-9a-fA-F]{2}|x\{[0-9a-fA-F]+\}|0\d\d|o\{[0-7]+\}|u[0-9a-fA-F]{4}))")); + static const QRegularExpression sanitize1(QStringLiteral(REG_ESCAPE_CHAR)); reg.replace(sanitize1, QStringLiteral("_")); +#undef REG_CHAR +#undef REG_ESCAPE_CHAR + // use minimal or lazy operator static const QRegularExpression isMinimal(QStringLiteral( R"([.][*+][^][?+*()|$]*$)")); @@ -1008,8 +1114,9 @@ private: char const *extraMsg = rule.string.contains(QLatin1Char('^')) ? "+ column=\"0\" or firstNonSpace=\"1\"" : ""; qWarning() << rule.filename << "line" << rule.line << "RegExpr should be replaced by StringDetect / Detect2Chars / DetectChar" << extraMsg << ":" << rule.string; - if (len != reg.size()) + if (len != reg.size()) { qWarning() << rule.filename << "line" << rule.line << "insensitive=\"1\" missing:" << rule.string; + } return false; } @@ -1019,8 +1126,8 @@ private: // (^sas*) -> ok // (^sa|s*) -> ko // (^(sa|s*)) -> ok - auto first = qAsConst(reg).begin(); - auto last = qAsConst(reg).end(); + auto first = std::as_const(reg).begin(); + auto last = std::as_const(reg).end(); int depth = 0; while (QLatin1Char('(') == *first) { @@ -1066,8 +1173,8 @@ private: // add ^ with column=0 if (rule.column == 0 && !rule.isDotRegex) { bool hasStartOfLine = false; - auto first = qAsConst(reg).begin(); - auto last = qAsConst(reg).end(); + auto first = std::as_const(reg).begin(); + auto last = std::as_const(reg).end(); for (; first != last; ++first) { if (*first == QLatin1Char('^')) { hasStartOfLine = true; @@ -1306,8 +1413,9 @@ private: //! Search for additionalDeliminator/weakDeliminator which has no effect. bool checkDelimiters(const Definition &definition, const Context::Rule &rule) const { - if (rule.additionalDeliminator.isEmpty() && rule.weakDeliminator.isEmpty()) + if (rule.additionalDeliminator.isEmpty() && rule.weakDeliminator.isEmpty()) { return true; + } bool success = true; @@ -1472,16 +1580,39 @@ private: //! - StringDetect, WordDetect, RegExpr with as prefix Detect2Chars or other strings //! - duplicate rule (Int, Float, keyword with same String, etc) //! - Rule hidden by a dot regex - bool checkUreachableRules(const QString &filename, const Context &context) const + bool checkUreachableRules(const QString &filename, + const Context &context, + QMap<const Context::Rule *, IncludedRuleUnreachableBy> &unreachableIncludedRules) const { - struct RuleAndInclude { - const Context::Rule *rule; - const Context::Rule *includeRules; + if (context.isOnlyIncluded) { + return true; + } - explicit operator bool() const + struct Rule4 { + RuleAndInclude setRule(const Context::Rule &rule, const Context::Rule *includeRules = nullptr) { - return rule; + auto set = [&](RuleAndInclude &ruleAndInclude) { + auto old = ruleAndInclude; + ruleAndInclude = {&rule, includeRules}; + return old; + }; + + if (rule.firstNonSpace == XmlBool::True) { + return set(firstNonSpace); + } else if (rule.column == 0) { + return set(column0); + } else if (rule.column > 0) { + return set(columnGreaterThan0[rule.column]); + } else { + return set(normal); + } } + + private: + RuleAndInclude normal; + RuleAndInclude column0; + QMap<int, RuleAndInclude> columnGreaterThan0; + RuleAndInclude firstNonSpace; }; // Associate QChar with RuleAndInclude @@ -1489,8 +1620,9 @@ private: /// Search RuleAndInclude associated with @p c. RuleAndInclude find(QChar c) const { - if (c.unicode() < 128) + if (c.unicode() < 128) { return m_asciiMap[c.unicode()]; + } auto it = m_utf8Map.find(c); return it == m_utf8Map.end() ? RuleAndInclude{nullptr, nullptr} : it.value(); } @@ -1517,10 +1649,11 @@ private: /// Associates @p c with a rule. void append(QChar c, const Context::Rule &rule, const Context::Rule *includeRule = nullptr) { - if (c.unicode() < 128) + if (c.unicode() < 128) { m_asciiMap[c.unicode()] = {&rule, includeRule}; - else + } else { m_utf8Map[c] = {&rule, includeRule}; + } } /// Associates each character of @p s with a rule. @@ -1549,13 +1682,15 @@ private: // Char4Tables::char is always added. CharTableArray(Char4Tables &tables, const Context::Rule &rule) { - if (rule.firstNonSpace == XmlBool::True) + if (rule.firstNonSpace == XmlBool::True) { appendTable(tables.charsFirstNonSpace); + } - if (rule.column == 0) + if (rule.column == 0) { appendTable(tables.charsColumn0); - else if (rule.column > 0) + } else if (rule.column > 0) { appendTable(tables.charsColumnGreaterThan0[rule.column]); + } appendTable(tables.chars); } @@ -1572,8 +1707,9 @@ private: RuleAndInclude find(QChar c) const { for (int i = 0; i < m_size; ++i) { - if (auto ruleAndInclude = m_charTables[i]->find(c)) + if (auto ruleAndInclude = m_charTables[i]->find(c)) { return ruleAndInclude; + } } return RuleAndInclude{nullptr, nullptr}; } @@ -1621,9 +1757,19 @@ private: int m_size = 0; }; + struct ObservableRule { + const Context::Rule *rule; + const Context::Rule *includeRules; + + bool hasResolvedIncludeRules() const + { + return rule == includeRules; + } + }; + // Iterates over all the rules, including those in includedRules struct RuleIterator { - RuleIterator(const QVector<Context::Rule> &rules, const Context::Rule &endRule) + RuleIterator(const QVector<ObservableRule> &rules, const ObservableRule &endRule) : m_end(&endRule - rules.data()) , m_rules(rules) { @@ -1635,7 +1781,7 @@ private: // if in includedRules if (m_includedRules) { ++m_i2; - if (m_i2 != m_rules[m_i].includedRules.size()) { + if (m_i2 != m_includedRules->size()) { return (*m_includedRules)[m_i2]; } ++m_i; @@ -1643,10 +1789,10 @@ private: } // if is a includedRules - while (m_i < m_end && m_rules[m_i].type == Context::Rule::Type::IncludeRules) { - if (m_rules[m_i].includedRules.size()) { + while (m_i < m_end && m_rules[m_i].rule->type == Context::Rule::Type::IncludeRules) { + if (!m_rules[m_i].includeRules && m_rules[m_i].rule->includedRules.size()) { m_i2 = 0; - m_includedRules = &m_rules[m_i].includedRules; + m_includedRules = &m_rules[m_i].rule->includedRules; return (*m_includedRules)[m_i2]; } ++m_i; @@ -1654,7 +1800,7 @@ private: if (m_i < m_end) { ++m_i; - return &m_rules[m_i - 1]; + return m_rules[m_i - 1].rule; } return nullptr; @@ -1663,14 +1809,14 @@ private: /// \return current IncludeRules or nullptr const Context::Rule *currentIncludeRules() const { - return m_includedRules ? &m_rules[m_i] : nullptr; + return m_includedRules ? m_rules[m_i].rule : m_rules[m_i].includeRules; } private: int m_i = 0; int m_i2; int m_end; - const QVector<Context::Rule> &m_rules; + const QVector<ObservableRule> &m_rules; const QVector<const Context::Rule *> *m_includedRules = nullptr; }; @@ -1680,20 +1826,24 @@ private: void append(const Context::Rule &rule, const Context::Rule *includedRule) { auto array = extractDotRegexes(rule); - if (array[0]) + if (array[0]) { *array[0] = {&rule, includedRule}; - if (array[1]) + } + if (array[1]) { *array[1] = {&rule, includedRule}; + } } /// Search dot regex which hides @p rule RuleAndInclude find(const Context::Rule &rule) { auto array = extractDotRegexes(rule); - if (array[0]) + if (array[0]) { return *array[0]; - if (array[1]) + } + if (array[1]) { return *array[1]; + } return RuleAndInclude{}; } @@ -1707,13 +1857,15 @@ private: if (rule.firstNonSpace != XmlBool::True && rule.column == -1) { ret[0] = &dotRegex; } else { - if (rule.firstNonSpace == XmlBool::True) + if (rule.firstNonSpace == XmlBool::True) { ret[0] = &dotRegexFirstNonSpace; + } - if (rule.column == 0) + if (rule.column == 0) { ret[1] = &dotRegexColumn0; - else if (rule.column > 0) + } else if (rule.column > 0) { ret[1] = &dotRegexColumnGreaterThan0[rule.column]; + } } return ret; @@ -1734,23 +1886,44 @@ private: // characters of LineContinue Char4Tables lineContinueChars; - RuleAndInclude intRule{}; - RuleAndInclude floatRule{}; - RuleAndInclude hlCCharRule{}; - RuleAndInclude hlCOctRule{}; - RuleAndInclude hlCHexRule{}; - RuleAndInclude hlCStringCharRule{}; + Rule4 intRule{}; + Rule4 floatRule{}; + Rule4 hlCCharRule{}; + Rule4 hlCOctRule{}; + Rule4 hlCHexRule{}; + Rule4 hlCStringCharRule{}; + Rule4 detectIdentifierRule{}; // Contains includedRules and included includedRules QMap<Context const*, RuleAndInclude> includeContexts; DotRegex dotRegex; + QVector<ObservableRule> observedRules; + observedRules.reserve(context.rules.size()); for (const Context::Rule &rule : context.rules) { + const Context::Rule *includeRule = nullptr; + if (rule.type == Context::Rule::Type::IncludeRules) { + auto *context = rule.context.context; + if (context && context->isOnlyIncluded) { + includeRule = &rule; + } + } + + observedRules.push_back({&rule, includeRule}); + if (includeRule) { + for (const Context::Rule *rule2 : rule.includedRules) { + observedRules.push_back({rule2, includeRule}); + } + } + } + + for (auto &observedRule : observedRules) { + const Context::Rule &rule = *observedRule.rule; bool isUnreachable = false; QVector<RuleAndInclude> unreachableBy; - // declare rule as unreacheable if ruleAndInclude is not empty + // declare rule as unreachable if ruleAndInclude is not empty auto updateUnreachable1 = [&](RuleAndInclude ruleAndInclude) { if (ruleAndInclude) { isUnreachable = true; @@ -1758,7 +1931,7 @@ private: } }; - // declare rule as unreacheable if ruleAndIncludes is not empty + // declare rule as unreachable if ruleAndIncludes is not empty auto updateUnreachable2 = [&](const QVector<RuleAndInclude> &ruleAndIncludes) { if (!ruleAndIncludes.isEmpty()) { isUnreachable = true; @@ -1810,43 +1983,42 @@ private: // check if hidden by DetectChar/AnyChar case Context::Rule::Type::HlCChar: updateUnreachable1(CharTableArray(detectChars, rule).find(QLatin1Char('\''))); - updateUnreachable1(hlCCharRule); - hlCCharRule = {&rule, nullptr}; + updateUnreachable1(hlCCharRule.setRule(rule)); break; // check if hidden by DetectChar/AnyChar case Context::Rule::Type::HlCHex: updateUnreachable1(CharTableArray(detectChars, rule).find(QLatin1Char('0'))); - updateUnreachable1(hlCHexRule); - hlCHexRule = {&rule, nullptr}; + updateUnreachable1(hlCHexRule.setRule(rule)); break; // check if hidden by DetectChar/AnyChar case Context::Rule::Type::HlCOct: updateUnreachable1(CharTableArray(detectChars, rule).find(QLatin1Char('0'))); - updateUnreachable1(hlCOctRule); - hlCOctRule = {&rule, nullptr}; + updateUnreachable1(hlCOctRule.setRule(rule)); break; // check if hidden by DetectChar/AnyChar case Context::Rule::Type::HlCStringChar: updateUnreachable1(CharTableArray(detectChars, rule).find(QLatin1Char('\\'))); - updateUnreachable1(hlCStringCharRule); - hlCStringCharRule = {&rule, nullptr}; + updateUnreachable1(hlCStringCharRule.setRule(rule)); break; // check if hidden by DetectChar/AnyChar case Context::Rule::Type::Int: updateUnreachable2(CharTableArray(detectChars, rule).find(QStringLiteral("0123456789"))); - updateUnreachable1(intRule); - intRule = {&rule, nullptr}; + updateUnreachable1(intRule.setRule(rule)); break; // check if hidden by DetectChar/AnyChar case Context::Rule::Type::Float: updateUnreachable2(CharTableArray(detectChars, rule).find(QStringLiteral("0123456789."))); - updateUnreachable1(floatRule); - floatRule = {&rule, nullptr}; + updateUnreachable1(floatRule.setRule(rule)); + break; + + // check if hidden by another DetectIdentifier rule + case Context::Rule::Type::DetectIdentifier: + updateUnreachable1(detectIdentifierRule.setRule(rule)); break; // check if hidden by DetectChar/AnyChar or another LineContinue @@ -1865,10 +2037,11 @@ private: case Context::Rule::Type::RangeDetect: updateUnreachable1(CharTableArray(detectChars, rule).find(rule.char0)); if (!isUnreachable) { - RuleIterator ruleIterator(context.rules, rule); + RuleIterator ruleIterator(observedRules, observedRule); while (const auto *rulePtr = ruleIterator.next()) { - if (isUnreachable) + if (isUnreachable) { break; + } const auto &rule2 = *rulePtr; if (rule2.type == rule.type && isCompatible(rule2) && rule.char0 == rule2.char0 && rule.char1 == rule2.char1) { updateUnreachable1({&rule2, ruleIterator.currentIncludeRules()}); @@ -1884,10 +2057,11 @@ private: } // check that `rule` does not have another RegExpr as a prefix - RuleIterator ruleIterator(context.rules, rule); + RuleIterator ruleIterator(observedRules, observedRule); while (const auto *rulePtr = ruleIterator.next()) { - if (isUnreachable) + if (isUnreachable) { break; + } const auto &rule2 = *rulePtr; if (rule2.type == Context::Rule::Type::RegExpr && isCompatible(rule2) && rule.insensitive == rule2.insensitive && rule.dynamic == rule2.dynamic && rule.string.startsWith(rule2.string)) { @@ -1902,10 +2076,11 @@ private: case Context::Rule::Type::StringDetect: { // check that dynamic `rule` does not have another dynamic StringDetect as a prefix if (rule.type == Context::Rule::Type::StringDetect && rule.dynamic == XmlBool::True) { - RuleIterator ruleIterator(context.rules, rule); + RuleIterator ruleIterator(observedRules, observedRule); while (const auto *rulePtr = ruleIterator.next()) { - if (isUnreachable) + if (isUnreachable) { break; + } const auto &rule2 = *rulePtr; if (rule2.type != Context::Rule::Type::StringDetect || rule2.dynamic != XmlBool::True || !isCompatible(rule2)) { @@ -1963,10 +2138,11 @@ private: // combination of uppercase and lowercase RuleAndInclude detect2CharsInsensitives[]{{}, {}, {}, {}}; - RuleIterator ruleIterator(context.rules, rule); + RuleIterator ruleIterator(observedRules, observedRule); while (const auto *rulePtr = ruleIterator.next()) { - if (isUnreachable) + if (isUnreachable) { break; + } const auto &rule2 = *rulePtr; const bool isSensitive = (rule2.insensitive == XmlBool::True); const auto caseSensitivity = isSensitive ? Qt::CaseInsensitive : Qt::CaseSensitive; @@ -2030,10 +2206,11 @@ private: // check if hidden by another keyword rule case Context::Rule::Type::keyword: { - RuleIterator ruleIterator(context.rules, rule); + RuleIterator ruleIterator(observedRules, observedRule); while (const auto *rulePtr = ruleIterator.next()) { - if (isUnreachable) + if (isUnreachable) { break; + } const auto &rule2 = *rulePtr; if (rule2.type == Context::Rule::Type::keyword && isCompatible(rule2) && rule.string == rule2.string) { updateUnreachable1({&rule2, ruleIterator.currentIncludeRules()}); @@ -2049,6 +2226,10 @@ private: // <includedRules .../> <- reference a <DetectChar char="{" /> who will be added // <DetectChar char="{" /> <- hidden by previous rule case Context::Rule::Type::IncludeRules: + if (observedRule.includeRules && !observedRule.hasResolvedIncludeRules()) { + break; + } + if (auto &ruleAndInclude = includeContexts[rule.context.context]) { updateUnreachable1(ruleAndInclude); } @@ -2060,6 +2241,10 @@ private: includeContexts.insert(rulePtr->context.context, RuleAndInclude{rulePtr, &rule}); } + if (observedRule.includeRules) { + break; + } + for (const auto *rulePtr : rule.includedRules) { const auto &rule2 = *rulePtr; switch (rule2.type) { @@ -2087,27 +2272,27 @@ private: } case Context::Rule::Type::HlCChar: - hlCCharRule = {&rule2, &rule}; + hlCCharRule.setRule(rule2, &rule); break; case Context::Rule::Type::HlCHex: - hlCHexRule = {&rule2, &rule}; + hlCHexRule.setRule(rule2, &rule); break; case Context::Rule::Type::HlCOct: - hlCOctRule = {&rule2, &rule}; + hlCOctRule.setRule(rule2, &rule); break; case Context::Rule::Type::HlCStringChar: - hlCStringCharRule = {&rule2, &rule}; + hlCStringCharRule.setRule(rule2, &rule); break; case Context::Rule::Type::Int: - intRule = {&rule2, &rule}; + intRule.setRule(rule2, &rule); break; case Context::Rule::Type::Float: - floatRule = {&rule2, &rule}; + floatRule.setRule(rule2, &rule); break; case Context::Rule::Type::LineContinue: { @@ -2136,12 +2321,18 @@ private: } break; - case Context::Rule::Type::DetectIdentifier: case Context::Rule::Type::Unknown: break; } - if (isUnreachable) { + if (observedRule.includeRules && !observedRule.hasResolvedIncludeRules()) { + auto &unreachableIncludedRule = unreachableIncludedRules[&rule]; + if (isUnreachable && unreachableIncludedRule.alwaysUnreachable) { + unreachableIncludedRule.unreachableBy.append(unreachableBy); + } else { + unreachableIncludedRule.alwaysUnreachable = false; + } + } else if (isUnreachable) { success = false; QString message; message.reserve(128); @@ -2165,7 +2356,7 @@ private: message += QStringLiteral(", "); } message.chop(2); - qWarning() << filename << "line" << rule.line << "unreachable element by" << message; + qWarning() << filename << "line" << rule.line << "unreachable rule by" << message; } } @@ -2179,8 +2370,9 @@ private: { bool success = true; - if (context.rules.isEmpty()) + if (context.rules.isEmpty()) { return success; + } auto it = context.rules.begin(); const auto end = context.rules.end() - 1; @@ -2249,7 +2441,7 @@ private: //! - "#pop!Comment" -> "Comment" //! - "##ISO C++" -> "" //! - "Comment##ISO C++"-> "Comment" in ISO C++ - void resolveContextName(Definition &definition, const Context &context, ContextName &contextName, int line) + void resolveContextName(Definition &definition, Context &context, ContextName &contextName, int line) { QString name = contextName.name; if (name.isEmpty()) { @@ -2281,8 +2473,9 @@ private: const int idx = name.indexOf(QStringLiteral("##")); if (idx == -1) { auto it = definition.contexts.find(name); - if (it != definition.contexts.end()) + if (it != definition.contexts.end()) { contextName.context = &*it; + } } else { auto defName = name.mid(idx + 2); auto listName = name.left(idx); @@ -2392,14 +2585,16 @@ int main(int argc, char *argv[]) QCoreApplication app(argc, argv); // ensure enough arguments are passed - if (app.arguments().size() < 3) + if (app.arguments().size() < 3) { return 1; + } #ifdef QT_XMLPATTERNS_LIB // open schema QXmlSchema schema; - if (!schema.load(QUrl::fromLocalFile(app.arguments().at(2)))) + if (!schema.load(QUrl::fromLocalFile(app.arguments().at(2)))) { return 2; + } #endif const QString hlFilenamesListing = app.arguments().value(3); @@ -2422,7 +2617,7 @@ int main(int argc, char *argv[]) HlFilesChecker filesChecker; QVariantMap hls; int anyError = 0; - for (const QString &hlFilename : qAsConst(hlFilenames)) { + for (const QString &hlFilename : std::as_const(hlFilenames)) { QFile hlFile(hlFilename); if (!hlFile.open(QIODevice::ReadOnly)) { qWarning("Failed to open %s", qPrintable(hlFilename)); @@ -2456,7 +2651,7 @@ int main(int argc, char *argv[]) QVariantMap hl; // transfer text attributes - for (const QString &attribute : qAsConst(textAttributes)) { + for (const QString &attribute : std::as_const(textAttributes)) { hl[attribute] = xml.attributes().value(attribute).toString(); } @@ -2489,17 +2684,20 @@ int main(int argc, char *argv[]) filesChecker.resolveContexts(); - if (!filesChecker.check()) + if (!filesChecker.check()) { anyError = 7; + } // bail out if any problem was seen - if (anyError) + if (anyError) { return anyError; + } // create outfile, after all has worked! QFile outFile(app.arguments().at(1)); - if (!outFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) + if (!outFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { return 9; + } // write out json outFile.write(QCborValue::fromVariant(QVariant(hls)).toCbor()); diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt index 722f92742b..43a60cc19b 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt @@ -1,6 +1,8 @@ +add_library(KF5SyntaxHighlighting) + ecm_create_qm_loader(syntax_highlighting_QM_LOADER syntaxhighlighting5_qt) -set(syntax_highlighting_srcs +target_sources(KF5SyntaxHighlighting PRIVATE abstracthighlighter.cpp context.cpp contextswitch.cpp @@ -20,8 +22,9 @@ set(syntax_highlighting_srcs themedata.cpp worddelimiters.cpp ${syntax_highlighting_QM_LOADER} + $<TARGET_OBJECTS:SyntaxHighlightingData> ) -ecm_qt_declare_logging_category(syntax_highlighting_srcs +ecm_qt_declare_logging_category(KF5SyntaxHighlighting HEADER ksyntaxhighlighting_logging.h IDENTIFIER KSyntaxHighlighting::Log CATEGORY_NAME kf.syntaxhighlighting @@ -30,16 +33,27 @@ ecm_qt_declare_logging_category(syntax_highlighting_srcs EXPORT KSYNTAXHIGHLIGHTING ) -add_library(KF5SyntaxHighlighting ${syntax_highlighting_srcs} $<TARGET_OBJECTS:SyntaxHighlightingData>) -generate_export_header(KF5SyntaxHighlighting BASE_NAME KSyntaxHighlighting) +ecm_generate_export_header(KF5SyntaxHighlighting + BASE_NAME KSyntaxHighlighting + GROUP_BASE_NAME KF + VERSION ${KF_VERSION} + DEPRECATED_BASE_VERSION 0 + DEPRECATION_VERSIONS 5.87 + EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} +) set_target_properties(KF5SyntaxHighlighting PROPERTIES - VERSION ${SyntaxHighlighting_VERSION_STRING} + VERSION ${SyntaxHighlighting_VERSION} SOVERSION ${SyntaxHighlighting_SOVERSION} EXPORT_NAME SyntaxHighlighting ) target_include_directories(KF5SyntaxHighlighting INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF5}/KSyntaxHighlighting;${KDE_INSTALL_INCLUDEDIR_KF5}>") target_include_directories(KF5SyntaxHighlighting PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR};>") -target_link_libraries(KF5SyntaxHighlighting LINK_PUBLIC Qt5::Gui LINK_PRIVATE Qt5::Network) +target_link_libraries(KF5SyntaxHighlighting + PUBLIC + Qt5::Gui + PRIVATE + Qt5::Network +) ecm_generate_headers(SyntaxHighlighting_HEADERS HEADER_NAMES @@ -52,6 +66,7 @@ ecm_generate_headers(SyntaxHighlighting_HEADERS State SyntaxHighlighter Theme + WildcardMatcher REQUIRED_HEADERS SyntaxHighlighting_HEADERS ) diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp index 2ad9d371f9..d6f8cad0c7 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp @@ -36,11 +36,13 @@ void AbstractHighlighterPrivate::ensureDefinitionLoaded() defData = DefinitionData::get(m_definition); } - if (Q_UNLIKELY(!defData->repo && !defData->fileName.isEmpty())) + if (Q_UNLIKELY(!defData->repo && !defData->fileName.isEmpty())) { qCCritical(Log) << "Repository got deleted while a highlighter is still active!"; + } - if (m_definition.isValid()) + if (m_definition.isValid()) { defData->load(); + } } AbstractHighlighter::AbstractHighlighter() @@ -85,7 +87,7 @@ void AbstractHighlighter::setTheme(const Theme &theme) * Returns the index of the first non-space character. If the line is empty, * or only contains white spaces, text.size() is returned. */ -static inline int firstNonSpaceChar(const QString &text) +static inline int firstNonSpaceChar(QStringView text) { for (int i = 0; i < text.length(); ++i) { if (!text[i].isSpace()) { @@ -95,8 +97,15 @@ static inline int firstNonSpaceChar(const QString &text) return text.size(); } +#if KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(5, 87) State AbstractHighlighter::highlightLine(const QString &text, const State &state) { + return highlightLine(QStringView(text), state); +} +#endif + +State AbstractHighlighter::highlightLine(QStringView text, const State &state) +{ Q_D(AbstractHighlighter); // verify definition, deal with no highlighting being enabled @@ -145,8 +154,9 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state * skipping empty lines after a line continuation character (see bug 405903) */ } else if (!stateData->topContext()->lineEndContext().isStay() - && !d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) + && !d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) { break; + } // guard against endless loops ++endlessLoopingCounter; @@ -160,7 +170,8 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state return newState; } - int offset = 0, beginOffset = 0; + int offset = 0; + int beginOffset = 0; bool lineContinuation = false; /** @@ -247,8 +258,9 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state skipOffsets.clear(); } const auto currentSkipOffset = skipOffsets.value(rule.get()); - if (currentSkipOffset < 0 || currentSkipOffset > offset) + if (currentSkipOffset < 0 || currentSkipOffset > offset) { continue; + } const auto newResult = rule->doMatch(text, offset, stateData->topCaptures()); newOffset = newResult.offset(); @@ -265,8 +277,9 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state } } - if (newOffset <= offset) + if (newOffset <= offset) { continue; + } /** * apply folding. @@ -274,12 +287,14 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state * - rule with endRegion + beginRegion: in endRegion, the length is 0 * - rule with lookAhead: length is 0 */ - if (rule->endRegion().isValid() && rule->beginRegion().isValid()) + if (rule->endRegion().isValid() && rule->beginRegion().isValid()) { applyFolding(offset, 0, rule->endRegion()); - else if (rule->endRegion().isValid()) + } else if (rule->endRegion().isValid()) { applyFolding(offset, rule->isLookAhead() ? 0 : newOffset - offset, rule->endRegion()); - if (rule->beginRegion().isValid()) + } + if (rule->beginRegion().isValid()) { applyFolding(offset, rule->isLookAhead() ? 0 : newOffset - offset, rule->beginRegion()); + } if (rule->isLookAhead()) { Q_ASSERT(!rule->context().isStay()); @@ -290,12 +305,14 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state d->switchContext(stateData, rule->context(), newResult.captures()); newFormat = rule->attributeFormat().isValid() ? &rule->attributeFormat() : &stateData->topContext()->attributeFormat(); - if (newOffset == text.size() && std::dynamic_pointer_cast<LineContinue>(rule)) + if (newOffset == text.size() && std::dynamic_pointer_cast<LineContinue>(rule)) { lineContinuation = true; + } break; } - if (isLookAhead) + if (isLookAhead) { continue; + } if (newOffset <= offset) { // no matching rule if (stateData->topContext()->fallthrough()) { @@ -316,8 +333,9 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state * on format change, apply the last one and switch to new one */ if (newFormat != currentFormat && newFormat->id() != currentFormat->id()) { - if (offset > 0) + if (offset > 0) { applyFormat(beginOffset, offset - beginOffset, *currentFormat); + } beginOffset = offset; currentFormat = newFormat; } @@ -333,8 +351,9 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state /** * apply format for remaining text, if any */ - if (beginOffset < offset) + if (beginOffset < offset) { applyFormat(beginOffset, text.size() - beginOffset, *currentFormat); + } /** * handle line end context switches @@ -344,8 +363,9 @@ State AbstractHighlighter::highlightLine(const QString &text, const State &state { int endlessLoopingCounter = 0; while (!stateData->topContext()->lineEndContext().isStay() && !lineContinuation) { - if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) + if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) { break; + } // guard against endless loops ++endlessLoopingCounter; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h index 5e85873ce0..49cfbf2530 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h @@ -108,6 +108,15 @@ protected: AbstractHighlighter(); AbstractHighlighter(AbstractHighlighterPrivate *dd); +#if KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(5, 87) + /** + * @copydoc highlightLine(QStringView,const State&) + * @deprecated since 5.87, use highlightLine(QStringView, const State&) instead. + */ + // no deprecation warning, as removal of this will automatically "port" the using code + State highlightLine(const QString &text, const State &state); +#endif + // TODO KF6: add an optional void* context argument that is passed through // to the applyX() calls, so highlighters dealing with some form of line object // (such as QSyntaxHighlighter or KTextEditor) can avoid some ugly hacks to have @@ -120,14 +129,14 @@ protected: * @param state The highlighting state handle returned by the call * to highlightLine() for the previous line. For the very first line, * just pass a default constructed State(). - * @returns The state of the highlighing engine after processing the + * @returns The state of the highlighting engine after processing the * given line. This needs to passed into highlightLine() for the * next line. You can store the state for efficient partial * re-highlighting for example during editing. * * @see applyFormat(), applyFolding() */ - State highlightLine(const QString &text, const State &state); + State highlightLine(QStringView text, const State &state); /** * Reimplement this to apply formats to your output. The provided @p format diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp index 9ff012e1d7..8ae47d80eb 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp @@ -33,10 +33,6 @@ struct CieLab { double b; }; -#ifndef M_PI -constexpr double M_PI = 3.14159265358979323846; -#endif - // clang-format off // xterm color reference // constexpr Rgb888 xterm256Colors[] { @@ -388,10 +384,11 @@ CieLab rgbToLab(QRgb rgb) // Perform the inverse gamma companding for a sRGB color // http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html auto inverseGammaCompanding = [](int c) { - if (c <= 10) + if (c <= 10) { return c / (255.0 * 12.92); - else + } else { return std::pow((c / 255.0 + 0.055) / 1.055, 2.4); + } }; const double r = inverseGammaCompanding(qRed(rgb)); @@ -404,10 +401,11 @@ CieLab rgbToLab(QRgb rgb) // http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html auto f = [](double t) { - if (t > 216.0 / 24389.0) + if (t > 216.0 / 24389.0) { return std::cbrt(t); - else + } else { return t * (24389.0 / (27.0 * 116.0)) + 4.0 / 29.0; + } }; const double f_x = f(x / illuminant_D65[0]); @@ -440,8 +438,9 @@ inline double pow2(double x) inline double computeHPrime(double a_prime, double b) { - if (std::abs(a_prime) < epsilon && std::abs(b) < epsilon) + if (std::abs(a_prime) < epsilon && std::abs(b) < epsilon) { return 0.0; + } const double value = std::atan2(b, a_prime) * 180.0 / M_PI; return (value < 0.0) ? value + 360.0 : value; @@ -449,34 +448,38 @@ inline double computeHPrime(double a_prime, double b) inline double computeDeltaHPrime(double C1_prime, double C2_prime, double h1_prime, double h2_prime) { - if (C1_prime * C2_prime < epsilon) + if (C1_prime * C2_prime < epsilon) { return 0.0; + } const double diff = h2_prime - h1_prime; - if (std::abs(diff) <= 180.0) + if (std::abs(diff) <= 180.0) { return diff; - else if (diff > 180.0) + } else if (diff > 180.0) { return diff - 360.0; - else + } else { return diff + 360.0; + } } inline double computeHPrimeBar(double C1_prime, double C2_prime, double h1_prime, double h2_prime) { const double sum = h1_prime + h2_prime; - if (C1_prime * C2_prime < epsilon) + if (C1_prime * C2_prime < epsilon) { return sum; + } const double dist = std::abs(h1_prime - h2_prime); - if (dist <= 180.0) + if (dist <= 180.0) { return 0.5 * sum; - else if (sum < 360.0) + } else if (sum < 360.0) { return 0.5 * (sum + 360.0); - else + } else { return 0.5 * (sum - 360.0); + } } /// Calculate the perceptual color difference based on CIEDE2000. @@ -702,7 +705,7 @@ struct GraphLine { const int n2 = offset - labelLineLength; labelLineLength += n2 + 1; fillLine(labelLine, n2); - labelLine += graphLine.rightRef(graphLine.size() - ps1); + labelLine += QStringView(graphLine).right(graphLine.size() - ps1); } } @@ -781,8 +784,9 @@ public: state = highlightLine(currentLine, state); if (hasSeparator) { - if (!firstLine) + if (!firstLine) { out << QStringLiteral("\x1b[0m────────────────────────────────────────────────────\x1b[K\n"); + } firstLine = false; } @@ -793,14 +797,15 @@ public: for (const auto &fragment : m_highlightedFragments) { auto const &ansiStyle = ansiStyles[fragment.formatId]; - out << ansiStyle.first << currentLine.midRef(fragment.offset, fragment.length) << ansiStyle.second; + out << ansiStyle.first << QStringView(currentLine).mid(fragment.offset, fragment.length) << ansiStyle.second; } out << QStringLiteral("\x1b[K\n"); if (hasFormatOrContextTrace && !m_highlightedFragments.empty()) { - if (m_hasContextTrace || m_hasStackSizeTrace) + if (m_hasContextTrace || m_hasStackSizeTrace) { appendContextNames(oldState, currentLine); + } printFormats(out, infoStyle, ansiStyles); out << resetBgColor; @@ -817,8 +822,9 @@ public: void applyFolding(int offset, int /*length*/, FoldingRegion region) override { - if (!m_hasRegionTrace) + if (!m_hasRegionTrace) { return; + } const auto id = region.id(); @@ -829,8 +835,9 @@ public: auto &previousRegion = m_regions[m_regions.size() - 2]; if (previousRegion.state == Region::State::Close && previousRegion.offset == offset) { std::swap(previousRegion, m_regions.back()); - if (previousRegion.bindIndex != -1) + if (previousRegion.bindIndex != -1) { m_regions[previousRegion.bindIndex].bindIndex = m_regions.size() - 1; + } } } ++m_regionDepth; @@ -840,10 +847,11 @@ public: auto eit = m_regions.rend(); for (int depth = 0; it != eit; ++it) { if (it->regionId == id && it->bindIndex < 0) { - if (it->state == Region::State::Close) + if (it->state == Region::State::Close) { ++depth; - else if (--depth < 0) + } else if (--depth < 0) { break; + } } } @@ -868,8 +876,9 @@ private: void initRegionStyles(const std::vector<QPair<QString, QString>> &ansiStyles) { m_regionStyles.resize(ansiStyles.size()); - for (std::size_t i = 0; i < m_regionStyles.size(); ++i) + for (std::size_t i = 0; i < m_regionStyles.size(); ++i) { m_regionStyles[i] = ansiStyles[i].first; + } std::sort(m_regionStyles.begin(), m_regionStyles.end()); m_regionStyles.erase(std::unique(m_regionStyles.begin(), m_regionStyles.end()), m_regionStyles.end()); @@ -1216,7 +1225,7 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE } // initialize ansiStyles - for (auto &&definition : qAsConst(definitions)) { + for (auto &&definition : std::as_const(definitions)) { const auto formats = definition.formats(); for (auto &&format : formats) { const auto id = format.id(); @@ -1236,20 +1245,26 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE const bool hasUnderline = format.isUnderline(theme); const bool hasStrikeThrough = format.isStrikeThrough(theme); - if (hasFg) + if (hasFg) { buffer.appendForeground(format.textColor(theme).rgb(), is256Colors, colorCache); - else + } else { buffer.append(foregroundDefaultColor); - if (hasBg) + } + if (hasBg) { buffer.appendBackground(format.backgroundColor(theme).rgb(), is256Colors, colorCache); - if (hasBold) + } + if (hasBold) { buffer.append(QLatin1String("1;")); - if (hasItalic) + } + if (hasItalic) { buffer.append(QLatin1String("3;")); - if (hasUnderline) + } + if (hasUnderline) { buffer.append(QLatin1String("4;")); - if (hasStrikeThrough) + } + if (hasStrikeThrough) { buffer.append(QLatin1String("9;")); + } // if there is ANSI style if (buffer.latin1().size() > 2) { @@ -1266,14 +1281,18 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE d->ansiStyles[id].second = buffer.latin1(); } else if (hasEffect) { buffer.append(QLatin1String("\x1b[")); - if (hasBold) + if (hasBold) { buffer.append(QLatin1String("21;")); - if (hasItalic) + } + if (hasItalic) { buffer.append(QLatin1String("23;")); - if (hasUnderline) + } + if (hasUnderline) { buffer.append(QLatin1String("24;")); - if (hasStrikeThrough) + } + if (hasStrikeThrough) { buffer.append(QLatin1String("29;")); + } buffer.setFinalStyle(); d->ansiStyles[id].second = buffer.latin1(); } @@ -1301,10 +1320,11 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE d->currentLine = in.readLine(); state = highlightLine(d->currentLine, state); - if (useEditorBackground) + if (useEditorBackground) { d->out << QStringLiteral("\x1b[K\n"); - else + } else { d->out << QLatin1Char('\n'); + } } } else { AnsiBuffer buffer; @@ -1328,5 +1348,5 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE void AnsiHighlighter::applyFormat(int offset, int length, const Format &format) { auto const &ansiStyle = d->ansiStyles[format.id()]; - d->out << ansiStyle.first << d->currentLine.midRef(offset, length) << ansiStyle.second; + d->out << ansiStyle.first << QStringView(d->currentLine).mid(offset, length) << ansiStyle.second; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp index f980ea5be8..724f37a03f 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp @@ -30,8 +30,9 @@ void Context::setDefinition(const DefinitionRef &def) bool Context::indentationBasedFoldingEnabled() const { - if (m_noIndentationBasedFolding) + if (m_noIndentationBasedFolding) { return false; + } return m_def.definition().indentationBasedFoldingEnabled(); } @@ -56,8 +57,9 @@ void Context::load(QXmlStreamReader &reader) auto rule = Rule::create(reader.name()); if (rule) { rule->setDefinition(m_def.definition()); - if (rule->load(reader)) + if (rule->load(reader)) { m_rules.push_back(std::move(rule)); + } } else { reader.skipCurrentElement(); } @@ -79,8 +81,9 @@ void Context::resolveContexts() m_lineEndContext.resolve(def); m_lineEmptyContext.resolve(def); m_fallthroughContext.resolve(def); - for (const auto &rule : m_rules) + for (const auto &rule : m_rules) { rule->resolveContext(); + } } Context::ResolveState Context::resolveState() @@ -100,8 +103,9 @@ Context::ResolveState Context::resolveState() void Context::resolveIncludes() { - if (resolveState() == Resolved) + if (resolveState() == Resolved) { return; + } if (resolveState() == Resolving) { qCWarning(Log) << "Cyclic dependency!"; return; @@ -129,10 +133,11 @@ void Context::resolveIncludes() } auto defData = DefinitionData::get(def); defData->load(); - if (inc->contextName().isEmpty()) + if (inc->contextName().isEmpty()) { context = defData->initialContext(); - else + } else { context = defData->contextByName(inc->contextName()); + } } if (!context) { qCWarning(Log) << "Unable to resolve include rule for definition" << inc->contextName() << "##" << inc->definitionName() << "in" diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp index 7ccd73ee9b..e829af463a 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp @@ -29,8 +29,9 @@ Context *ContextSwitch::context() const void ContextSwitch::parse(QStringView contextInstr) { - if (contextInstr.isEmpty() || contextInstr == QLatin1String("#stay")) + if (contextInstr.isEmpty() || contextInstr == QLatin1String("#stay")) { return; + } if (contextInstr.startsWith(QLatin1String("#pop!"))) { ++m_popCount; @@ -60,13 +61,15 @@ void ContextSwitch::resolve(const Definition &def) d = DefinitionData::get(def)->repo->definitionForName(m_defName); auto data = DefinitionData::get(d); data->load(); - if (m_contextName.isEmpty()) + if (m_contextName.isEmpty()) { m_context = data->initialContext(); + } } if (!m_contextName.isEmpty()) { m_context = DefinitionData::get(d)->contextByName(m_contextName); - if (!m_context) + if (!m_context) { qCWarning(Log) << "cannot find context" << m_contextName << "in" << def.name(); + } } } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp index 7434e745b2..068907a4e2 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp @@ -52,29 +52,20 @@ DefinitionData *DefinitionData::get(const Definition &def) Definition::Definition() : d(new DefinitionData) { -} - -Definition::Definition(const Definition &other) - : d(other.d) -{ d->q = *this; } +Definition::Definition(Definition &&other) noexcept = default; +Definition::Definition(const Definition &) = default; +Definition::~Definition() = default; +Definition &Definition::operator=(Definition &&other) noexcept = default; +Definition &Definition::operator=(const Definition &) = default; + Definition::Definition(std::shared_ptr<DefinitionData> &&dd) : d(std::move(dd)) { } -Definition::~Definition() -{ -} - -Definition &Definition::operator=(const Definition &rhs) -{ - d = rhs.d; - return *this; -} - bool Definition::operator==(const Definition &other) const { return d->fileName == other.d->fileName; @@ -223,8 +214,9 @@ bool Definition::setKeywordList(const QString &name, const QStringList &content) if (list) { list->setKeywordList(content); return true; - } else + } else { return false; + } } QVector<Format> Definition::formats() const @@ -251,7 +243,7 @@ QVector<Definition> Definition::includedDefinitions() const // Iterate all context rules to find associated Definitions. This will // automatically catch other Definitions referenced with IncludeRuldes or ContextSwitch. const auto definition = queue.takeLast(); - for (const auto &context : qAsConst(definition.d->contexts)) { + for (const auto &context : std::as_const(definition.d->contexts)) { // handle context switch attributes of this context itself for (const auto switchContext : {context->lineEndContext().context(), context->lineEmptyContext().context(), context->fallthroughContext().context()}) { @@ -321,8 +313,9 @@ Context *DefinitionData::initialContext() const Context *DefinitionData::contextByName(const QString &wantedName) const { for (const auto context : contexts) { - if (context->name() == wantedName) + if (context->name() == wantedName) { return context; + } } return nullptr; } @@ -336,8 +329,9 @@ KeywordList *DefinitionData::keywordList(const QString &wantedName) Format DefinitionData::formatByName(const QString &wantedName) const { const auto it = formats.constFind(wantedName); - if (it != formats.constEnd()) + if (it != formats.constEnd()) { return it.value(); + } return Format(); } @@ -349,24 +343,29 @@ bool DefinitionData::isLoaded() const bool DefinitionData::load(OnlyKeywords onlyKeywords) { - if (fileName.isEmpty()) + if (fileName.isEmpty()) { return false; + } - if (isLoaded()) + if (isLoaded()) { return true; + } - if (bool(onlyKeywords) && keywordIsLoaded) + if (bool(onlyKeywords) && keywordIsLoaded) { return true; + } QFile file(fileName); - if (!file.open(QFile::ReadOnly)) + if (!file.open(QFile::ReadOnly)) { return false; + } QXmlStreamReader reader(&file); while (!reader.atEnd()) { const auto token = reader.readNext(); - if (token != QXmlStreamReader::StartElement) + if (token != QXmlStreamReader::StartElement) { continue; + } if (reader.name() == QLatin1String("highlighting")) { loadHighlighting(reader, onlyKeywords); @@ -375,21 +374,22 @@ bool DefinitionData::load(OnlyKeywords onlyKeywords) } } - else if (reader.name() == QLatin1String("general")) + else if (reader.name() == QLatin1String("general")) { loadGeneral(reader); + } } for (auto it = keywordLists.begin(); it != keywordLists.end(); ++it) { it->setCaseSensitivity(caseSensitive); } - for (const auto context : qAsConst(contexts)) { + for (const auto context : std::as_const(contexts)) { context->resolveContexts(); context->resolveIncludes(); context->resolveAttributeFormat(); } - for (const auto context : qAsConst(contexts)) { + for (const auto context : std::as_const(contexts)) { for (const auto &rule : context->rules()) { rule->resolvePostProcessing(); } @@ -427,14 +427,16 @@ bool DefinitionData::loadMetaData(const QString &definitionFileName) fileName = definitionFileName; QFile file(definitionFileName); - if (!file.open(QFile::ReadOnly)) + if (!file.open(QFile::ReadOnly)) { return false; + } QXmlStreamReader reader(&file); while (!reader.atEnd()) { const auto token = reader.readNext(); - if (token != QXmlStreamReader::StartElement) + if (token != QXmlStreamReader::StartElement) { continue; + } if (reader.name() == QLatin1String("language")) { return loadLanguage(reader); } @@ -457,11 +459,13 @@ bool DefinitionData::loadMetaData(const QString &file, const QCborMap &obj) fileName = file; const auto exts = obj.value(QLatin1String("extensions")).toString(); - for (const auto &ext : exts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) + for (const auto &ext : exts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) { extensions.push_back(ext); + } const auto mts = obj.value(QLatin1String("mimetype")).toString(); - for (const auto &mt : mts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) + for (const auto &mt : mts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) { mimetypes.push_back(mt); + } return true; } @@ -471,8 +475,9 @@ bool DefinitionData::loadLanguage(QXmlStreamReader &reader) Q_ASSERT(reader.name() == QLatin1String("language")); Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement); - if (!checkKateVersion(reader.attributes().value(QLatin1String("kateversion")))) + if (!checkKateVersion(reader.attributes().value(QLatin1String("kateversion")))) { return false; + } name = reader.attributes().value(QLatin1String("name")).toString(); section = reader.attributes().value(QLatin1String("section")).toString(); @@ -485,13 +490,16 @@ bool DefinitionData::loadLanguage(QXmlStreamReader &reader) author = reader.attributes().value(QLatin1String("author")).toString(); license = reader.attributes().value(QLatin1String("license")).toString(); const auto exts = reader.attributes().value(QLatin1String("extensions")).toString(); - for (const auto &ext : exts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) + for (const auto &ext : exts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) { extensions.push_back(ext); + } const auto mts = reader.attributes().value(QLatin1String("mimetype")).toString(); - for (const auto &mt : mts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) + for (const auto &mt : mts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) { mimetypes.push_back(mt); - if (reader.attributes().hasAttribute(QLatin1String("casesensitive"))) + } + if (reader.attributes().hasAttribute(QLatin1String("casesensitive"))) { caseSensitive = Xml::attrToBool(reader.attributes().value(QLatin1String("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive; + } return true; } @@ -618,8 +626,9 @@ void DefinitionData::loadGeneral(QXmlStreamReader &reader) ++elementRefCounter; if (reader.name() == QLatin1String("keywords")) { - if (reader.attributes().hasAttribute(QLatin1String("casesensitive"))) + if (reader.attributes().hasAttribute(QLatin1String("casesensitive"))) { caseSensitive = Xml::attrToBool(reader.attributes().value(QLatin1String("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive; + } // adapt wordDelimiters wordDelimiters.append(reader.attributes().value(QLatin1String("additionalDeliminator"))); @@ -628,14 +637,15 @@ void DefinitionData::loadGeneral(QXmlStreamReader &reader) // adapt WordWrapDelimiters auto wordWrapDeliminatorAttr = reader.attributes().value( QLatin1String("wordWrapDeliminator")); - if (wordWrapDeliminatorAttr.isEmpty()) + if (wordWrapDeliminatorAttr.isEmpty()) { wordWrapDelimiters = wordDelimiters; - else { + } else { wordWrapDelimiters.append(wordWrapDeliminatorAttr); } } else if (reader.name() == QLatin1String("folding")) { - if (reader.attributes().hasAttribute(QLatin1String("indentationsensitive"))) + if (reader.attributes().hasAttribute(QLatin1String("indentationsensitive"))) { indentationBasedFolding = Xml::attrToBool(reader.attributes().value(QLatin1String("indentationsensitive"))); + } } else if (reader.name() == QLatin1String("emptyLines")) { loadFoldingIgnoreList(reader); } else if (reader.name() == QLatin1String("comments")) { @@ -649,8 +659,9 @@ void DefinitionData::loadGeneral(QXmlStreamReader &reader) break; case QXmlStreamReader::EndElement: --elementRefCounter; - if (elementRefCounter == 0) + if (elementRefCounter == 0) { return; + } reader.readNext(); break; default: @@ -688,8 +699,9 @@ void DefinitionData::loadComments(QXmlStreamReader &reader) break; case QXmlStreamReader::EndElement: --elementRefCounter; - if (elementRefCounter == 0) + if (elementRefCounter == 0) { return; + } reader.readNext(); break; default: @@ -719,8 +731,9 @@ void DefinitionData::loadFoldingIgnoreList(QXmlStreamReader &reader) break; case QXmlStreamReader::EndElement: --elementRefCounter; - if (elementRefCounter == 0) + if (elementRefCounter == 0) { return; + } reader.readNext(); break; default: @@ -754,8 +767,9 @@ void DefinitionData::loadSpellchecking(QXmlStreamReader &reader) break; case QXmlStreamReader::EndElement: --elementRefCounter; - if (elementRefCounter == 0) + if (elementRefCounter == 0) { return; + } reader.readNext(); break; default: @@ -798,10 +812,6 @@ DefinitionRef::DefinitionRef(const Definition &def) { } -DefinitionRef::~DefinitionRef() -{ -} - DefinitionRef &DefinitionRef::operator=(const Definition &def) { d = def.d; @@ -810,8 +820,9 @@ DefinitionRef &DefinitionRef::operator=(const Definition &def) Definition DefinitionRef::definition() const { - if (!d.expired()) + if (!d.expired()) { return Definition(d.lock()); + } return Definition(); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h index 8226fbdd24..05757ea52a 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h @@ -13,6 +13,7 @@ #include <QPair> #include <QVector> #include <memory> +#include <qobjectdefs.h> QT_BEGIN_NAMESPACE class QChar; @@ -74,7 +75,7 @@ enum class CommentPosition { * singleLineCommentMarker() and multiLineCommentMarker() provide comment * markers that can be used for commenting/uncommenting code. Similarly, * formats() returns a list of Format items defined by this Definition (which - * equal the itemDatas of a highlighing definition file). includedDefinitions() + * equal the itemDatas of a highlighting definition file). includedDefinitions() * returns a list of all included Definition%s referenced by this Definition via * the rule IncludeRules, which is useful for displaying all Format items for * color configuration in the user interface. @@ -84,6 +85,13 @@ enum class CommentPosition { */ class KSYNTAXHIGHLIGHTING_EXPORT Definition { + Q_GADGET + Q_PROPERTY(QString name READ name) + Q_PROPERTY(QString translatedName READ translatedName) + Q_PROPERTY(QString section READ section) + Q_PROPERTY(QString translatedSection READ translatedSection) + Q_PROPERTY(QString author READ author) + Q_PROPERTY(QString license READ license) public: /** * Default constructor, creating an empty (invalid) Definition instance. @@ -94,6 +102,14 @@ public: Definition(); /** + * Move constructor. + * This definition takes the Definition data from @p other. + * @note @p other may only be assigned to or destroyed afterwards. + * @since 5.86 + */ + Definition(Definition &&other) noexcept; + + /** * Copy constructor. * Both this definition as well as @p other share the Definition data. */ @@ -105,7 +121,15 @@ public: ~Definition(); /** - * Assignment operator. + * Move assignment operator. + * This definition takes the Definition data from @p other. + * @note @p other may only be assigned to or destroyed afterwards. + * @since 5.86 + */ + Definition &operator=(Definition &&other) noexcept; + + /** + * Copy assignment operator. * Both this definition as well as @p rhs share the Definition data. */ Definition &operator=(const Definition &rhs); diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp index 3dff1dd436..b16139b731 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp @@ -51,24 +51,27 @@ void DefinitionDownloaderPrivate::definitionListDownloadFinished(QNetworkReply * while (!parser.atEnd()) { switch (parser.readNext()) { case QXmlStreamReader::StartElement: - if (parser.name() == QLatin1String("Definition")) + if (parser.name() == QLatin1String("Definition")) { updateDefinition(parser); + } break; default: break; } } - if (pendingDownloads == 0) + if (pendingDownloads == 0) { Q_EMIT q->informationMessage(QObject::tr("All syntax definitions are up-to-date.")); + } checkDone(); } void DefinitionDownloaderPrivate::updateDefinition(QXmlStreamReader &parser) { const auto name = parser.attributes().value(QLatin1String("name")); - if (name.isEmpty()) + if (name.isEmpty()) { return; + } auto localDef = repo->definitionForName(name.toString()); if (!localDef.isValid()) { @@ -86,11 +89,13 @@ void DefinitionDownloaderPrivate::updateDefinition(QXmlStreamReader &parser) void DefinitionDownloaderPrivate::downloadDefinition(const QUrl &downloadUrl) { - if (!downloadUrl.isValid()) + if (!downloadUrl.isValid()) { return; + } auto url = downloadUrl; - if (url.scheme() == QLatin1String("http")) + if (url.scheme() == QLatin1String("http")) { url.setScheme(QStringLiteral("https")); + } QNetworkRequest req(url); auto reply = nam->get(req); @@ -133,8 +138,9 @@ void DefinitionDownloaderPrivate::downloadDefinitionFinished(QNetworkReply *repl void DefinitionDownloaderPrivate::checkDone() { if (pendingDownloads == 0) { - if (needsReload) + if (needsReload) { repo->reload(); + } Q_EMIT QTimer::singleShot(0, q, &DefinitionDownloader::done); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h index 25a1a749e4..285fec3e20 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h @@ -13,7 +13,6 @@ namespace KSyntaxHighlighting { class Definition; class DefinitionData; -class DefinitionPrivate; /** Weak reference for Definition instances. * @@ -21,6 +20,8 @@ class DefinitionPrivate; * in objects hold directly or indirectly by Definition * to avoid reference count loops and thus memory leaks. * + * This class follows the rule of zero. It is implicitly movable and copyable. + * * @internal */ class DefinitionRef @@ -28,7 +29,6 @@ class DefinitionRef public: DefinitionRef(); explicit DefinitionRef(const Definition &def); - ~DefinitionRef(); DefinitionRef &operator=(const Definition &def); Definition definition() const; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp index d459ee36d8..bcc64c3c2b 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp @@ -21,8 +21,9 @@ using namespace KSyntaxHighlighting; static Theme::TextStyle stringToDefaultFormat(QStringView str) { - if (!str.startsWith(QLatin1String("ds"))) + if (!str.startsWith(QLatin1String("ds"))) { return Theme::Normal; + } static const auto idx = Theme::staticMetaObject.indexOfEnumerator("TextStyle"); Q_ASSERT(idx >= 0); @@ -30,8 +31,9 @@ static Theme::TextStyle stringToDefaultFormat(QStringView str) bool ok = false; const auto value = metaEnum.keyToValue(str.mid(2).toLatin1().constData(), &ok); - if (!ok || value < 0) + if (!ok || value < 0) { return Theme::Normal; + } return static_cast<Theme::TextStyle>(value); } @@ -44,8 +46,9 @@ FormatPrivate *FormatPrivate::detachAndGet(Format &format) TextStyleData FormatPrivate::styleOverride(const Theme &theme) const { const auto themeData = ThemeData::get(theme); - if (themeData) + if (themeData) { return themeData->textStyleOverride(definition.definition().name(), name); + } return TextStyleData(); } @@ -113,16 +116,18 @@ bool Format::hasTextColor(const Theme &theme) const QColor Format::textColor(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.textColor) + if (overrideStyle.textColor) { return overrideStyle.textColor; + } return d->style.textColor ? QColor::fromRgba(d->style.textColor) : QColor::fromRgba(theme.textColor(d->defaultStyle)); } QColor Format::selectedTextColor(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.selectedTextColor) + if (overrideStyle.selectedTextColor) { return overrideStyle.selectedTextColor; + } return d->style.selectedTextColor ? QColor::fromRgba(d->style.selectedTextColor) : QColor::fromRgba(theme.selectedTextColor(d->defaultStyle)); } @@ -136,8 +141,9 @@ bool Format::hasBackgroundColor(const Theme &theme) const QColor Format::backgroundColor(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.backgroundColor) + if (overrideStyle.backgroundColor) { return overrideStyle.backgroundColor; + } // use QColor::fromRgba for background QRgb => QColor conversion to avoid unset colors == black! return d->style.backgroundColor ? QColor::fromRgba(d->style.backgroundColor) : QColor::fromRgba(theme.backgroundColor(d->defaultStyle)); @@ -146,8 +152,9 @@ QColor Format::backgroundColor(const Theme &theme) const QColor Format::selectedBackgroundColor(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.selectedBackgroundColor) + if (overrideStyle.selectedBackgroundColor) { return overrideStyle.selectedBackgroundColor; + } // use QColor::fromRgba for background QRgb => QColor conversion to avoid unset colors == black! return d->style.selectedBackgroundColor ? QColor::fromRgba(d->style.selectedBackgroundColor) @@ -157,32 +164,36 @@ QColor Format::selectedBackgroundColor(const Theme &theme) const bool Format::isBold(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.hasBold) + if (overrideStyle.hasBold) { return overrideStyle.bold; + } return d->style.hasBold ? d->style.bold : theme.isBold(d->defaultStyle); } bool Format::isItalic(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.hasItalic) + if (overrideStyle.hasItalic) { return overrideStyle.italic; + } return d->style.hasItalic ? d->style.italic : theme.isItalic(d->defaultStyle); } bool Format::isUnderline(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.hasUnderline) + if (overrideStyle.hasUnderline) { return overrideStyle.underline; + } return d->style.hasUnderline ? d->style.underline : theme.isUnderline(d->defaultStyle); } bool Format::isStrikeThrough(const Theme &theme) const { const auto overrideStyle = d->styleOverride(theme); - if (overrideStyle.hasStrikeThrough) + if (overrideStyle.hasStrikeThrough) { return overrideStyle.strikeThrough; + } return d->style.hasStrikeThrough ? d->style.strikeThrough : theme.isStrikeThrough(d->defaultStyle); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp index 5ba421d0e1..688a42d45c 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp @@ -70,10 +70,11 @@ void HtmlHighlighter::highlightFile(const QString &fileName, const QString &titl return; } - if (title.isEmpty()) + if (title.isEmpty()) { highlightData(&f, fi.fileName()); - else + } else { highlightData(&f, title); + } } /** @@ -87,8 +88,9 @@ void HtmlHighlighter::highlightFile(const QString &fileName, const QString &titl */ static QString toHtmlRgbaString(const QColor &color) { - if (color.alpha() == 0xFF) + if (color.alpha() == 0xFF) { return color.name(); + } QString rgba = QStringLiteral("rgba("); rgba.append(QString::number(color.red())); @@ -111,10 +113,11 @@ void HtmlHighlighter::highlightData(QIODevice *dev, const QString &title) } QString htmlTitle; - if (title.isEmpty()) + if (title.isEmpty()) { htmlTitle = QStringLiteral("Kate Syntax Highlighter"); - else + } else { htmlTitle = title.toHtmlEscaped(); + } State state; *d->out << "<!DOCTYPE html>\n"; @@ -125,8 +128,9 @@ void HtmlHighlighter::highlightData(QIODevice *dev, const QString &title) << ")\"/>\n"; *d->out << "</head><body"; *d->out << " style=\"background-color:" << toHtmlRgbaString(QColor::fromRgba(theme().editorColor(Theme::BackgroundColor))); - if (theme().textColor(Theme::Normal)) + if (theme().textColor(Theme::Normal)) { *d->out << ";color:" << toHtmlRgbaString(QColor::fromRgba(theme().textColor(Theme::Normal))); + } *d->out << "\"><pre>\n"; QTextStream in(dev); @@ -148,27 +152,34 @@ void HtmlHighlighter::highlightData(QIODevice *dev, const QString &title) void HtmlHighlighter::applyFormat(int offset, int length, const Format &format) { - if (length == 0) + if (length == 0) { return; + } // collect potential output, cheaper than thinking about "is there any?" QVarLengthArray<QString, 16> formatOutput; - if (format.hasTextColor(theme())) + if (format.hasTextColor(theme())) { formatOutput << QStringLiteral("color:") << toHtmlRgbaString(format.textColor(theme())) << QStringLiteral(";"); - if (format.hasBackgroundColor(theme())) + } + if (format.hasBackgroundColor(theme())) { formatOutput << QStringLiteral("background-color:") << toHtmlRgbaString(format.backgroundColor(theme())) << QStringLiteral(";"); - if (format.isBold(theme())) + } + if (format.isBold(theme())) { formatOutput << QStringLiteral("font-weight:bold;"); - if (format.isItalic(theme())) + } + if (format.isItalic(theme())) { formatOutput << QStringLiteral("font-style:italic;"); - if (format.isUnderline(theme())) + } + if (format.isUnderline(theme())) { formatOutput << QStringLiteral("text-decoration:underline;"); - if (format.isStrikeThrough(theme())) + } + if (format.isStrikeThrough(theme())) { formatOutput << QStringLiteral("text-decoration:line-through;"); + } if (!formatOutput.isEmpty()) { *d->out << "<span style=\""; - for (const auto &out : qAsConst(formatOutput)) { + for (const auto &out : std::as_const(formatOutput)) { *d->out << out; } *d->out << "\">"; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp index b13e30607b..3a7514897a 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp @@ -16,6 +16,27 @@ using namespace KSyntaxHighlighting; +namespace +{ +struct KeywordComparator { + Qt::CaseSensitivity caseSensitive; + + bool operator()(QStringView a, QStringView b) const + { + if (a.size() < b.size()) { + return true; + } + + if (a.size() > b.size()) { + return false; + } + + return a.compare(b, caseSensitive) < 0; + } +}; + +} + bool KeywordList::contains(QStringView str, Qt::CaseSensitivity caseSensitive) const { /** @@ -26,9 +47,7 @@ bool KeywordList::contains(QStringView str, Qt::CaseSensitivity caseSensitive) c /** * search with right predicate */ - return std::binary_search(vectorToSearch.begin(), vectorToSearch.end(), QStringView(str), [caseSensitive](QStringView a, QStringView b) { - return a.compare(b, caseSensitive) < 0; - }); + return std::binary_search(vectorToSearch.begin(), vectorToSearch.end(), QStringView(str), KeywordComparator{caseSensitive}); } void KeywordList::load(QXmlStreamReader &reader) @@ -85,16 +104,14 @@ void KeywordList::initLookupForCaseSensitivity(Qt::CaseSensitivity caseSensitive * fill vector with refs to keywords */ vectorToSort.reserve(m_keywords.size()); - for (const auto &keyword : qAsConst(m_keywords)) { + for (const auto &keyword : std::as_const(m_keywords)) { vectorToSort.push_back(keyword); } /** * sort with right predicate */ - std::sort(vectorToSort.begin(), vectorToSort.end(), [caseSensitive](QStringView a, QStringView b) { - return a.compare(b, caseSensitive) < 0; - }); + std::sort(vectorToSort.begin(), vectorToSort.end(), KeywordComparator{caseSensitive}); } void KeywordList::resolveIncludeKeywords(DefinitionData &def) diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp index 1e3191a7bc..f3b36df459 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp @@ -11,7 +11,7 @@ #include "repository_p.h" #include "theme.h" #include "themedata_p.h" -#include "wildcardmatcher_p.h" +#include "wildcardmatcher.h" #include <QCborMap> #include <QCborValue> @@ -19,15 +19,75 @@ #include <QFile> #include <QFileInfo> #include <QPalette> +#include <QString> +#include <QStringView> #ifndef NO_STANDARD_PATHS #include <QStandardPaths> #endif +#include <algorithm> +#include <iterator> #include <limits> using namespace KSyntaxHighlighting; +namespace +{ +QString fileNameFromFilePath(const QString &filePath) +{ + return QFileInfo{filePath}.fileName(); +} + +auto anyWildcardMatches(QStringView str) +{ + return [str](const Definition &def) { + const auto strings = def.extensions(); + return std::any_of(strings.cbegin(), strings.cend(), [str](QStringView wildcard) { + return WildcardMatcher::exactMatch(str, wildcard); + }); + }; +} + +auto anyMimeTypeEquals(QStringView mimeTypeName) +{ + return [mimeTypeName](const Definition &def) { + const auto strings = def.mimeTypes(); + return std::any_of(strings.cbegin(), strings.cend(), [mimeTypeName](QStringView name) { + return mimeTypeName == name; + }); + }; +} + +// The two function templates below take defs - a map sorted by highlighting name - to be deterministic and independent of translations. + +template<typename UnaryPredicate> +Definition findHighestPriorityDefinitionIf(const QMap<QString, Definition> &defs, UnaryPredicate predicate) +{ + const Definition *match = nullptr; + auto matchPriority = std::numeric_limits<int>::lowest(); + for (const Definition &def : defs) { + const auto defPriority = def.priority(); + if (defPriority > matchPriority && predicate(def)) { + match = &def; + matchPriority = defPriority; + } + } + return match == nullptr ? Definition{} : *match; +} + +template<typename UnaryPredicate> +QVector<Definition> findDefinitionsIf(const QMap<QString, Definition> &defs, UnaryPredicate predicate) +{ + QVector<Definition> matches; + std::copy_if(defs.cbegin(), defs.cend(), std::back_inserter(matches), predicate); + std::stable_sort(matches.begin(), matches.end(), [](const Definition &lhs, const Definition &rhs) { + return lhs.priority() > rhs.priority(); + }); + return matches; +} +} // unnamed namespace + static void initResource() { #ifdef HAS_SYNTAX_RESOURCE @@ -52,8 +112,9 @@ Repository::~Repository() { // reset repo so we can detect in still alive definition instances // that the repo was deleted - for (const auto &def : qAsConst(d->m_sortedDefs)) + for (const auto &def : std::as_const(d->m_sortedDefs)) { DefinitionData::get(def)->repo = nullptr; + } } Definition Repository::definitionForName(const QString &defName) const @@ -61,58 +122,24 @@ Definition Repository::definitionForName(const QString &defName) const return d->m_defs.value(defName); } -static void sortDefinitions(QVector<Definition> &definitions) -{ - std::stable_sort(definitions.begin(), definitions.end(), [](const Definition &lhs, const Definition &rhs) { - return lhs.priority() > rhs.priority(); - }); -} - Definition Repository::definitionForFileName(const QString &fileName) const { - return definitionsForFileName(fileName).value(0); + return findHighestPriorityDefinitionIf(d->m_defs, anyWildcardMatches(fileNameFromFilePath(fileName))); } QVector<Definition> Repository::definitionsForFileName(const QString &fileName) const { - QFileInfo fi(fileName); - const auto name = fi.fileName(); - - // use d->m_defs, sorted map by highlighting name, to be deterministic and independent of translations - QVector<Definition> candidates; - for (const Definition &def : qAsConst(d->m_defs)) { - for (const auto &pattern : def.extensions()) { - if (WildcardMatcher::exactMatch(name, pattern)) { - candidates.push_back(def); - break; - } - } - } - - sortDefinitions(candidates); - return candidates; + return findDefinitionsIf(d->m_defs, anyWildcardMatches(fileNameFromFilePath(fileName))); } Definition Repository::definitionForMimeType(const QString &mimeType) const { - return definitionsForMimeType(mimeType).value(0); + return findHighestPriorityDefinitionIf(d->m_defs, anyMimeTypeEquals(mimeType)); } QVector<Definition> Repository::definitionsForMimeType(const QString &mimeType) const { - // use d->m_defs, sorted map by highlighting name, to be deterministic and independent of translations - QVector<Definition> candidates; - for (const Definition &def : qAsConst(d->m_defs)) { - for (const auto &matchType : def.mimeTypes()) { - if (mimeType == matchType) { - candidates.push_back(def); - break; - } - } - } - - sortDefinitions(candidates); - return candidates; + return findDefinitionsIf(d->m_defs, anyMimeTypeEquals(mimeType)); } QVector<Definition> Repository::definitions() const @@ -127,7 +154,7 @@ QVector<Theme> Repository::themes() const Theme Repository::theme(const QString &themeName) const { - for (const auto &theme : qAsConst(d->m_themes)) { + for (const auto &theme : std::as_const(d->m_themes)) { if (theme.name() == themeName) { return theme; } @@ -138,14 +165,15 @@ Theme Repository::theme(const QString &themeName) const Theme Repository::defaultTheme(Repository::DefaultTheme t) const { - if (t == DarkTheme) + if (t == DarkTheme) { return theme(QLatin1String("Breeze Dark")); + } return theme(QLatin1String("Breeze Light")); } Theme Repository::defaultTheme(Repository::DefaultTheme t) { - return qAsConst(*this).defaultTheme(t); + return std::as_const(*this).defaultTheme(t); } Theme Repository::themeForPalette(const QPalette &palette) const @@ -164,7 +192,7 @@ Theme Repository::themeForPalette(const QPalette &palette) const if (!matchingThemes.empty()) { // if there's multiple, search for one with a matching highlight color const auto highlight = palette.color(QPalette::Highlight); - for (const auto &theme : qAsConst(matchingThemes)) { + for (const auto &theme : std::as_const(matchingThemes)) { auto selection = theme.editorColor(KSyntaxHighlighting::Theme::EditorColorRole::TextSelection); if (selection == highlight.rgb()) { return theme; @@ -179,7 +207,7 @@ Theme Repository::themeForPalette(const QPalette &palette) const Theme Repository::themeForPalette(const QPalette &palette) { - return qAsConst(*this).themeForPalette(palette); + return std::as_const(*this).themeForPalette(palette); } void RepositoryPrivate::load(Repository *repo) @@ -189,29 +217,39 @@ void RepositoryPrivate::load(Repository *repo) // do lookup in standard paths, if not disabled #ifndef NO_STANDARD_PATHS - for (const auto &dir : - QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("org.kde.syntax-highlighting/syntax"), QStandardPaths::LocateDirectory)) + for (const auto &dir : QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, + QStringLiteral("org.kde.syntax-highlighting/syntax"), + QStandardPaths::LocateDirectory)) { loadSyntaxFolder(repo, dir); + } // backward compatibility with Kate - for (const auto &dir : QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("katepart5/syntax"), QStandardPaths::LocateDirectory)) + for (const auto &dir : + QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("katepart5/syntax"), QStandardPaths::LocateDirectory)) { loadSyntaxFolder(repo, dir); + } #endif - // default resources are always used - loadSyntaxFolder(repo, QStringLiteral(":/org.kde.syntax-highlighting/syntax")); + // default resources are always used, this is the one location that has a index cbor file + loadSyntaxFolderFromIndex(repo, QStringLiteral(":/org.kde.syntax-highlighting/syntax")); + + // extra resources provided by 3rdparty libraries/applications + loadSyntaxFolder(repo, QStringLiteral(":/org.kde.syntax-highlighting/syntax-addons")); // user given extra paths - for (const auto &path : qAsConst(m_customSearchPaths)) + for (const auto &path : std::as_const(m_customSearchPaths)) { loadSyntaxFolder(repo, path + QStringLiteral("/syntax")); + } m_sortedDefs.reserve(m_defs.size()); - for (auto it = m_defs.constBegin(); it != m_defs.constEnd(); ++it) + for (auto it = m_defs.constBegin(); it != m_defs.constEnd(); ++it) { m_sortedDefs.push_back(it.value()); + } std::sort(m_sortedDefs.begin(), m_sortedDefs.end(), [](const Definition &left, const Definition &right) { auto comparison = left.translatedSection().compare(right.translatedSection(), Qt::CaseInsensitive); - if (comparison == 0) + if (comparison == 0) { comparison = left.translatedName().compare(right.translatedName(), Qt::CaseInsensitive); + } return comparison < 0; }); @@ -219,54 +257,60 @@ void RepositoryPrivate::load(Repository *repo) // do lookup in standard paths, if not disabled #ifndef NO_STANDARD_PATHS - for (const auto &dir : - QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("org.kde.syntax-highlighting/themes"), QStandardPaths::LocateDirectory)) + for (const auto &dir : QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, + QStringLiteral("org.kde.syntax-highlighting/themes"), + QStandardPaths::LocateDirectory)) { loadThemeFolder(dir); + } #endif // default resources are always used loadThemeFolder(QStringLiteral(":/org.kde.syntax-highlighting/themes")); + // extra resources provided by 3rdparty libraries/applications + loadThemeFolder(QStringLiteral(":/org.kde.syntax-highlighting/themes-addons")); + // user given extra paths - for (const auto &path : qAsConst(m_customSearchPaths)) + for (const auto &path : std::as_const(m_customSearchPaths)) { loadThemeFolder(path + QStringLiteral("/themes")); + } } void RepositoryPrivate::loadSyntaxFolder(Repository *repo, const QString &path) { - if (loadSyntaxFolderFromIndex(repo, path)) - return; - QDirIterator it(path, QStringList() << QLatin1String("*.xml"), QDir::Files); while (it.hasNext()) { Definition def; auto defData = DefinitionData::get(def); defData->repo = repo; - if (defData->loadMetaData(it.next())) + if (defData->loadMetaData(it.next())) { addDefinition(def); + } } } -bool RepositoryPrivate::loadSyntaxFolderFromIndex(Repository *repo, const QString &path) +void RepositoryPrivate::loadSyntaxFolderFromIndex(Repository *repo, const QString &path) { QFile indexFile(path + QLatin1String("/index.katesyntax")); - if (!indexFile.open(QFile::ReadOnly)) - return false; + if (!indexFile.open(QFile::ReadOnly)) { + return; + } const auto indexDoc(QCborValue::fromCbor(indexFile.readAll())); const auto index = indexDoc.toMap(); for (auto it = index.begin(); it != index.end(); ++it) { - if (!it.value().isMap()) + if (!it.value().isMap()) { continue; + } const auto fileName = QString(path + QLatin1Char('/') + it.key().toString()); const auto defMap = it.value().toMap(); Definition def; auto defData = DefinitionData::get(def); defData->repo = repo; - if (defData->loadMetaData(fileName, defMap)) + if (defData->loadMetaData(fileName, defMap)) { addDefinition(def); + } } - return true; } void RepositoryPrivate::addDefinition(const Definition &def) @@ -277,8 +321,9 @@ void RepositoryPrivate::addDefinition(const Definition &def) return; } - if (it.value().version() >= def.version()) + if (it.value().version() >= def.version()) { return; + } m_defs.insert(def.name(), def); } @@ -287,8 +332,9 @@ void RepositoryPrivate::loadThemeFolder(const QString &path) QDirIterator it(path, QStringList() << QLatin1String("*.theme"), QDir::Files); while (it.hasNext()) { auto themeData = std::unique_ptr<ThemeData>(new ThemeData); - if (themeData->load(it.next())) + if (themeData->load(it.next())) { addTheme(Theme(themeData.release())); + } } } @@ -307,15 +353,17 @@ void RepositoryPrivate::addTheme(const Theme &theme) m_themes.insert(it, theme); return; } - if (themeRevision(*it) < themeRevision(theme)) + if (themeRevision(*it) < themeRevision(theme)) { *it = theme; + } } quint16 RepositoryPrivate::foldingRegionId(const QString &defName, const QString &foldName) { const auto it = m_foldingRegionIds.constFind(qMakePair(defName, foldName)); - if (it != m_foldingRegionIds.constEnd()) + if (it != m_foldingRegionIds.constEnd()) { return it.value(); + } m_foldingRegionIds.insert(qMakePair(defName, foldName), ++m_foldingRegionId); return m_foldingRegionId; } @@ -329,8 +377,9 @@ quint16 RepositoryPrivate::nextFormatId() void Repository::reload() { qCDebug(Log) << "Reloading syntax definitions!"; - for (const auto &def : qAsConst(d->m_sortedDefs)) + for (const auto &def : std::as_const(d->m_sortedDefs)) { DefinitionData::get(def)->clear(); + } d->m_defs.clear(); d->m_sortedDefs.clear(); diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h index 323407f008..9e19ecda56 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h @@ -86,6 +86,11 @@ class Theme; * The internal resource path is ":/org.kde.syntax-highlighting/syntax". * This path should never be touched by other applications. * + * -# Then, all custom files compiled into resources are loaded. + * The resource path is ":/org.kde.syntax-highlighting/syntax-addons". + * This path can be used by other libraries/applications to bundle specialized definitions. + * Per default this path isn't used by the framework itself. + * * -# Finally, the search path can be extended by calling addCustomSearchPath(). * A custom search path can either be a path on disk or again a path to * a Qt resource. @@ -102,6 +107,11 @@ class Theme; * The internal resource path is ":/org.kde.syntax-highlighting/themes". * This path should never be touched by other applications. * + * -# Then, all custom files compiled into resources are loaded. + * The resource path is ":/org.kde.syntax-highlighting/themes-addons". + * This path can be used by other libraries/applications to bundle specialized themes. + * Per default this path isn't used by the framework itself. + * * -# Finally, all Theme%s located in the paths added addCustomSearchPath() * are loaded. * diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h index 447cfae699..abc992358d 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h @@ -29,7 +29,7 @@ public: void load(Repository *repo); void loadSyntaxFolder(Repository *repo, const QString &path); - bool loadSyntaxFolderFromIndex(Repository *repo, const QString &path); + void loadSyntaxFolderFromIndex(Repository *repo, const QString &path); void addDefinition(const Definition &def); diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp index c8d3fa0e63..f4e88b719a 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp @@ -34,10 +34,11 @@ static bool isHexChar(QChar c) return isDigit(c) || (c <= QLatin1Char('f') && QLatin1Char('a') <= c) || (c <= QLatin1Char('F') && QLatin1Char('A') <= c); } -static int matchEscapedChar(const QString &text, int offset) +static int matchEscapedChar(QStringView text, int offset) { - if (text.at(offset) != QLatin1Char('\\') || text.size() < offset + 2) + if (text.at(offset) != QLatin1Char('\\') || text.size() < offset + 2) { return offset; + } const auto c = text.at(offset + 1); switch (c.unicode()) { @@ -59,8 +60,9 @@ static int matchEscapedChar(const QString &text, int offset) // hex encoded character case 'x': if (offset + 2 < text.size() && isHexChar(text.at(offset + 2))) { - if (offset + 3 < text.size() && isHexChar(text.at(offset + 3))) + if (offset + 3 < text.size() && isHexChar(text.at(offset + 3))) { return offset + 4; + } return offset + 3; } return offset; @@ -75,8 +77,9 @@ static int matchEscapedChar(const QString &text, int offset) case '6': case '7': if (offset + 2 < text.size() && isOctalChar(text.at(offset + 2))) { - if (offset + 3 < text.size() && isOctalChar(text.at(offset + 3))) + if (offset + 3 < text.size() && isOctalChar(text.at(offset + 3))) { return offset + 4; + } return offset + 3; } return offset + 2; @@ -116,26 +119,31 @@ bool Rule::load(QXmlStreamReader &reader) Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement); m_attribute = reader.attributes().value(QLatin1String("attribute")).toString(); - if (reader.name() != QLatin1String("IncludeRules")) // IncludeRules uses this with a different semantic + if (reader.name() != QLatin1String("IncludeRules")) { // IncludeRules uses this with a different semantic m_context.parse(reader.attributes().value(QLatin1String("context"))); + } m_firstNonSpace = Xml::attrToBool(reader.attributes().value(QLatin1String("firstNonSpace"))); m_lookAhead = Xml::attrToBool(reader.attributes().value(QLatin1String("lookAhead"))); bool colOk = false; m_column = reader.attributes().value(QLatin1String("column")).toInt(&colOk); - if (!colOk) + if (!colOk) { m_column = -1; + } auto regionName = reader.attributes().value(QLatin1String("beginRegion")); - if (!regionName.isEmpty()) + if (!regionName.isEmpty()) { m_beginRegion = FoldingRegion(FoldingRegion::Begin, DefinitionData::get(m_def.definition())->foldingRegionId(regionName.toString())); + } regionName = reader.attributes().value(QLatin1String("endRegion")); - if (!regionName.isEmpty()) + if (!regionName.isEmpty()) { m_endRegion = FoldingRegion(FoldingRegion::End, DefinitionData::get(m_def.definition())->foldingRegionId(regionName.toString())); + } auto result = doLoad(reader); - if (m_lookAhead && m_context.isStay()) + if (m_lookAhead && m_context.isStay()) { result = false; + } // be done with this rule, skip all subelements, e.g. no longer supported sub-rules reader.skipCurrentElement(); @@ -184,42 +192,60 @@ void Rule::loadAdditionalWordDelimiters(QXmlStreamReader &reader) Rule::Ptr Rule::create(QStringView name) { - if (name == QLatin1String("AnyChar")) + if (name == QLatin1String("AnyChar")) { return std::make_shared<AnyChar>(); - if (name == QLatin1String("DetectChar")) + } + if (name == QLatin1String("DetectChar")) { return std::make_shared<DetectChar>(); - if (name == QLatin1String("Detect2Chars")) + } + if (name == QLatin1String("Detect2Chars")) { return std::make_shared<Detect2Char>(); - if (name == QLatin1String("DetectIdentifier")) + } + if (name == QLatin1String("DetectIdentifier")) { return std::make_shared<DetectIdentifier>(); - if (name == QLatin1String("DetectSpaces")) + } + if (name == QLatin1String("DetectSpaces")) { return std::make_shared<DetectSpaces>(); - if (name == QLatin1String("Float")) + } + if (name == QLatin1String("Float")) { return std::make_shared<Float>(); - if (name == QLatin1String("Int")) + } + if (name == QLatin1String("Int")) { return std::make_shared<Int>(); - if (name == QLatin1String("HlCChar")) + } + if (name == QLatin1String("HlCChar")) { return std::make_shared<HlCChar>(); - if (name == QLatin1String("HlCHex")) + } + if (name == QLatin1String("HlCHex")) { return std::make_shared<HlCHex>(); - if (name == QLatin1String("HlCOct")) + } + if (name == QLatin1String("HlCOct")) { return std::make_shared<HlCOct>(); - if (name == QLatin1String("HlCStringChar")) + } + if (name == QLatin1String("HlCStringChar")) { return std::make_shared<HlCStringChar>(); - if (name == QLatin1String("IncludeRules")) + } + if (name == QLatin1String("IncludeRules")) { return std::make_shared<IncludeRules>(); - if (name == QLatin1String("keyword")) + } + if (name == QLatin1String("keyword")) { return std::make_shared<KeywordListRule>(); - if (name == QLatin1String("LineContinue")) + } + if (name == QLatin1String("LineContinue")) { return std::make_shared<LineContinue>(); - if (name == QLatin1String("RangeDetect")) + } + if (name == QLatin1String("RangeDetect")) { return std::make_shared<RangeDetect>(); - if (name == QLatin1String("RegExpr")) + } + if (name == QLatin1String("RegExpr")) { return std::make_shared<RegExpr>(); - if (name == QLatin1String("StringDetect")) + } + if (name == QLatin1String("StringDetect")) { return std::make_shared<StringDetect>(); - if (name == QLatin1String("WordDetect")) + } + if (name == QLatin1String("WordDetect")) { return std::make_shared<WordDetect>(); + } qCWarning(Log) << "Unknown rule type:" << name; return Ptr(nullptr); @@ -233,23 +259,26 @@ bool Rule::isWordDelimiter(QChar c) const bool AnyChar::doLoad(QXmlStreamReader &reader) { m_chars = reader.attributes().value(QLatin1String("String")).toString(); - if (m_chars.size() == 1) + if (m_chars.size() == 1) { qCDebug(Log) << "AnyChar rule with just one char: use DetectChar instead."; + } return !m_chars.isEmpty(); } -MatchResult AnyChar::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &) const { - if (m_chars.contains(text.at(offset))) + if (m_chars.contains(text.at(offset))) { return offset + 1; + } return offset; } bool DetectChar::doLoad(QXmlStreamReader &reader) { const auto s = reader.attributes().value(QLatin1String("char")); - if (s.isEmpty()) + if (s.isEmpty()) { return false; + } m_char = s.at(0); m_dynamic = Xml::attrToBool(reader.attributes().value(QLatin1String("dynamic"))); if (m_dynamic) { @@ -258,18 +287,21 @@ bool DetectChar::doLoad(QXmlStreamReader &reader) return true; } -MatchResult DetectChar::doMatch(const QString &text, int offset, const QStringList &captures) const +MatchResult DetectChar::doMatch(QStringView text, int offset, const QStringList &captures) const { if (m_dynamic) { - if (m_captureIndex == 0 || captures.size() <= m_captureIndex || captures.at(m_captureIndex).isEmpty()) + if (m_captureIndex == 0 || captures.size() <= m_captureIndex || captures.at(m_captureIndex).isEmpty()) { return offset; - if (text.at(offset) == captures.at(m_captureIndex).at(0)) + } + if (text.at(offset) == captures.at(m_captureIndex).at(0)) { return offset + 1; + } return offset; } - if (text.at(offset) == m_char) + if (text.at(offset) == m_char) { return offset + 1; + } return offset; } @@ -277,40 +309,46 @@ bool Detect2Char::doLoad(QXmlStreamReader &reader) { const auto s1 = reader.attributes().value(QLatin1String("char")); const auto s2 = reader.attributes().value(QLatin1String("char1")); - if (s1.isEmpty() || s2.isEmpty()) + if (s1.isEmpty() || s2.isEmpty()) { return false; + } m_char1 = s1.at(0); m_char2 = s2.at(0); return true; } -MatchResult Detect2Char::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult Detect2Char::doMatch(QStringView text, int offset, const QStringList &) const { - if (text.size() - offset < 2) + if (text.size() - offset < 2) { return offset; - if (text.at(offset) == m_char1 && text.at(offset + 1) == m_char2) + } + if (text.at(offset) == m_char1 && text.at(offset + 1) == m_char2) { return offset + 2; + } return offset; } -MatchResult DetectIdentifier::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult DetectIdentifier::doMatch(QStringView text, int offset, const QStringList &) const { - if (!text.at(offset).isLetter() && text.at(offset) != QLatin1Char('_')) + if (!text.at(offset).isLetter() && text.at(offset) != QLatin1Char('_')) { return offset; + } for (int i = offset + 1; i < text.size(); ++i) { const auto c = text.at(i); - if (!c.isLetterOrNumber() && c != QLatin1Char('_')) + if (!c.isLetterOrNumber() && c != QLatin1Char('_')) { return i; + } } return text.size(); } -MatchResult DetectSpaces::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult DetectSpaces::doMatch(QStringView text, int offset, const QStringList &) const { - while (offset < text.size() && text.at(offset).isSpace()) + while (offset < text.size() && text.at(offset).isSpace()) { ++offset; + } return offset; } @@ -320,63 +358,76 @@ bool Float::doLoad(QXmlStreamReader &reader) return true; } -MatchResult Float::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult Float::doMatch(QStringView text, int offset, const QStringList &) const { - if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) + if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) { return offset; + } auto newOffset = offset; - while (newOffset < text.size() && isDigit(text.at(newOffset))) + while (newOffset < text.size() && isDigit(text.at(newOffset))) { ++newOffset; + } - if (newOffset >= text.size() || text.at(newOffset) != QLatin1Char('.')) + if (newOffset >= text.size() || text.at(newOffset) != QLatin1Char('.')) { return offset; + } ++newOffset; - while (newOffset < text.size() && isDigit(text.at(newOffset))) + while (newOffset < text.size() && isDigit(text.at(newOffset))) { ++newOffset; + } - if (newOffset == offset + 1) // we only found a decimal point + if (newOffset == offset + 1) { // we only found a decimal point return offset; + } auto expOffset = newOffset; - if (expOffset >= text.size() || (text.at(expOffset) != QLatin1Char('e') && text.at(expOffset) != QLatin1Char('E'))) + if (expOffset >= text.size() || (text.at(expOffset) != QLatin1Char('e') && text.at(expOffset) != QLatin1Char('E'))) { return newOffset; + } ++expOffset; - if (expOffset < text.size() && (text.at(expOffset) == QLatin1Char('+') || text.at(expOffset) == QLatin1Char('-'))) + if (expOffset < text.size() && (text.at(expOffset) == QLatin1Char('+') || text.at(expOffset) == QLatin1Char('-'))) { ++expOffset; + } bool foundExpDigit = false; while (expOffset < text.size() && isDigit(text.at(expOffset))) { ++expOffset; foundExpDigit = true; } - if (!foundExpDigit) + if (!foundExpDigit) { return newOffset; + } return expOffset; } -MatchResult HlCChar::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult HlCChar::doMatch(QStringView text, int offset, const QStringList &) const { - if (text.size() < offset + 3) + if (text.size() < offset + 3) { return offset; + } - if (text.at(offset) != QLatin1Char('\'') || text.at(offset + 1) == QLatin1Char('\'')) + if (text.at(offset) != QLatin1Char('\'') || text.at(offset + 1) == QLatin1Char('\'')) { return offset; + } auto newOffset = matchEscapedChar(text, offset + 1); if (newOffset == offset + 1) { - if (text.at(newOffset) == QLatin1Char('\\')) + if (text.at(newOffset) == QLatin1Char('\\')) { return offset; - else + } else { ++newOffset; + } } - if (newOffset >= text.size()) + if (newOffset >= text.size()) { return offset; + } - if (text.at(newOffset) == QLatin1Char('\'')) + if (text.at(newOffset) == QLatin1Char('\'')) { return newOffset + 1; + } return offset; } @@ -387,23 +438,28 @@ bool HlCHex::doLoad(QXmlStreamReader &reader) return true; } -MatchResult HlCHex::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult HlCHex::doMatch(QStringView text, int offset, const QStringList &) const { - if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) + if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) { return offset; + } - if (text.size() < offset + 3) + if (text.size() < offset + 3) { return offset; + } - if (text.at(offset) != QLatin1Char('0') || (text.at(offset + 1) != QLatin1Char('x') && text.at(offset + 1) != QLatin1Char('X'))) + if (text.at(offset) != QLatin1Char('0') || (text.at(offset + 1) != QLatin1Char('x') && text.at(offset + 1) != QLatin1Char('X'))) { return offset; + } - if (!isHexChar(text.at(offset + 2))) + if (!isHexChar(text.at(offset + 2))) { return offset; + } offset += 3; - while (offset < text.size() && isHexChar(text.at(offset))) + while (offset < text.size() && isHexChar(text.at(offset))) { ++offset; + } // TODO Kate matches U/L suffix, QtC does not? @@ -416,28 +472,33 @@ bool HlCOct::doLoad(QXmlStreamReader &reader) return true; } -MatchResult HlCOct::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult HlCOct::doMatch(QStringView text, int offset, const QStringList &) const { - if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) + if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) { return offset; + } - if (text.size() < offset + 2) + if (text.size() < offset + 2) { return offset; + } - if (text.at(offset) != QLatin1Char('0')) + if (text.at(offset) != QLatin1Char('0')) { return offset; + } - if (!isOctalChar(text.at(offset + 1))) + if (!isOctalChar(text.at(offset + 1))) { return offset; + } offset += 2; - while (offset < text.size() && isOctalChar(text.at(offset))) + while (offset < text.size() && isOctalChar(text.at(offset))) { ++offset; + } return offset; } -MatchResult HlCStringChar::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult HlCStringChar::doMatch(QStringView text, int offset, const QStringList &) const { return matchEscapedChar(text, offset); } @@ -461,17 +522,19 @@ bool IncludeRules::doLoad(QXmlStreamReader &reader) { const auto s = reader.attributes().value(QLatin1String("context")); const auto split = s.split(QString::fromLatin1("##"), Qt::KeepEmptyParts); - if (split.isEmpty()) + if (split.isEmpty()) { return false; + } m_contextName = split.at(0).toString(); - if (split.size() > 1) + if (split.size() > 1) { m_defName = split.at(1).toString(); + } m_includeAttribute = Xml::attrToBool(reader.attributes().value(QLatin1String("includeAttrib"))); return !m_contextName.isEmpty() || !m_defName.isEmpty(); } -MatchResult IncludeRules::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult IncludeRules::doMatch(QStringView text, int offset, const QStringList &) const { Q_UNUSED(text); qCWarning(Log) << "Unresolved include rule for" << m_contextName << "##" << m_defName; @@ -484,13 +547,15 @@ bool Int::doLoad(QXmlStreamReader &reader) return true; } -MatchResult Int::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult Int::doMatch(QStringView text, int offset, const QStringList &) const { - if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) + if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) { return offset; + } - while (offset < text.size() && isDigit(text.at(offset))) + while (offset < text.size() && isDigit(text.at(offset))) { ++offset; + } return offset; } @@ -522,21 +587,24 @@ bool KeywordListRule::doLoad(QXmlStreamReader &reader) return !m_keywordList->isEmpty(); } -MatchResult KeywordListRule::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult KeywordListRule::doMatch(QStringView text, int offset, const QStringList &) const { auto newOffset = offset; - while (text.size() > newOffset && !isWordDelimiter(text.at(newOffset))) + while (text.size() > newOffset && !isWordDelimiter(text.at(newOffset))) { ++newOffset; - if (newOffset == offset) + } + if (newOffset == offset) { return offset; + } if (m_hasCaseSensitivityOverride) { - if (m_keywordList->contains(QStringView(text).mid(offset, newOffset - offset), - m_caseSensitivityOverride)) + if (m_keywordList->contains(text.mid(offset, newOffset - offset), m_caseSensitivityOverride)) { return newOffset; + } } else { - if (m_keywordList->contains(QStringView(text).mid(offset, newOffset - offset))) + if (m_keywordList->contains(text.mid(offset, newOffset - offset))) { return newOffset; + } } // we don't match, but we can skip until newOffset as we can't start a keyword in-between @@ -546,17 +614,19 @@ MatchResult KeywordListRule::doMatch(const QString &text, int offset, const QStr bool LineContinue::doLoad(QXmlStreamReader &reader) { const auto s = reader.attributes().value(QLatin1String("char")); - if (s.isEmpty()) + if (s.isEmpty()) { m_char = QLatin1Char('\\'); - else + } else { m_char = s.at(0); + } return true; } -MatchResult LineContinue::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult LineContinue::doMatch(QStringView text, int offset, const QStringList &) const { - if (offset == text.size() - 1 && text.at(offset) == m_char) + if (offset == text.size() - 1 && text.at(offset) == m_char) { return offset + 1; + } return offset; } @@ -564,24 +634,28 @@ bool RangeDetect::doLoad(QXmlStreamReader &reader) { const auto s1 = reader.attributes().value(QLatin1String("char")); const auto s2 = reader.attributes().value(QLatin1String("char1")); - if (s1.isEmpty() || s2.isEmpty()) + if (s1.isEmpty() || s2.isEmpty()) { return false; + } m_begin = s1.at(0); m_end = s2.at(0); return true; } -MatchResult RangeDetect::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult RangeDetect::doMatch(QStringView text, int offset, const QStringList &) const { - if (text.size() - offset < 2) + if (text.size() - offset < 2) { return offset; - if (text.at(offset) != m_begin) + } + if (text.at(offset) != m_begin) { return offset; + } auto newOffset = offset + 1; while (newOffset < text.size()) { - if (text.at(newOffset) == m_end) + if (text.at(newOffset) == m_end) { return newOffset + 1; + } ++newOffset; } return offset; @@ -596,7 +670,9 @@ bool RegExpr::doLoad(QXmlStreamReader &reader) m_regexp.setPatternOptions((isMinimal ? QRegularExpression::InvertedGreedinessOption : QRegularExpression::NoPatternOption) | (isCaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption) // DontCaptureOption is removed by resolvePostProcessing() when necessary - | QRegularExpression::DontCaptureOption); + | QRegularExpression::DontCaptureOption + // ensure Unicode support is enabled + | QRegularExpression::UseUnicodePropertiesOption); m_dynamic = Xml::attrToBool(reader.attributes().value(QLatin1String("dynamic"))); @@ -605,8 +681,9 @@ bool RegExpr::doLoad(QXmlStreamReader &reader) void KSyntaxHighlighting::RegExpr::resolvePostProcessing() { - if (m_isResolved) + if (m_isResolved) { return; + } m_isResolved = true; bool hasCapture = false; @@ -641,7 +718,7 @@ void KSyntaxHighlighting::RegExpr::resolvePostProcessing() } } -MatchResult RegExpr::doMatch(const QString &text, int offset, const QStringList &captures) const +MatchResult RegExpr::doMatch(QStringView text, int offset, const QStringList &captures) const { /** * for dynamic case: create new pattern with right instantiation @@ -651,7 +728,11 @@ MatchResult RegExpr::doMatch(const QString &text, int offset, const QStringList /** * match the pattern */ +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 2) + const auto result = regexp.match(text.toString(), offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption); +#else const auto result = regexp.match(text, offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption); +#endif if (result.capturedStart() == offset) { /** * we only need to compute the captured texts if we have real capture groups @@ -683,16 +764,16 @@ bool StringDetect::doLoad(QXmlStreamReader &reader) return !m_string.isEmpty(); } -MatchResult StringDetect::doMatch(const QString &text, int offset, const QStringList &captures) const +MatchResult StringDetect::doMatch(QStringView text, int offset, const QStringList &captures) const { /** * for dynamic case: create new pattern with right instantiation */ const auto &pattern = m_dynamic ? replaceCaptures(m_string, captures, false) : m_string; - if (offset + pattern.size() <= text.size() - && QStringView(text).mid(offset, pattern.size()).compare(pattern, m_caseSensitivity) == 0) + if (offset + pattern.size() <= text.size() && text.mid(offset, pattern.size()).compare(pattern, m_caseSensitivity) == 0) { return offset + pattern.size(); + } return offset; } @@ -704,23 +785,27 @@ bool WordDetect::doLoad(QXmlStreamReader &reader) return !m_word.isEmpty(); } -MatchResult WordDetect::doMatch(const QString &text, int offset, const QStringList &) const +MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList &) const { - if (text.size() - offset < m_word.size()) + if (text.size() - offset < m_word.size()) { return offset; + } /** * detect delimiter characters on the inner and outer boundaries of the string * NOTE: m_word isn't empty */ - if (offset > 0 && !isWordDelimiter(text.at(offset - 1)) && !isWordDelimiter(text.at(offset))) + if (offset > 0 && !isWordDelimiter(text.at(offset - 1)) && !isWordDelimiter(text.at(offset))) { return offset; + } - if (QStringView(text).mid(offset, m_word.size()).compare(m_word, m_caseSensitivity) != 0) + if (text.mid(offset, m_word.size()).compare(m_word, m_caseSensitivity) != 0) { return offset; + } - if (text.size() == offset + m_word.size() || isWordDelimiter(text.at(offset + m_word.size())) || isWordDelimiter(text.at(offset + m_word.size() - 1))) + if (text.size() == offset + m_word.size() || isWordDelimiter(text.at(offset + m_word.size())) || isWordDelimiter(text.at(offset + m_word.size() - 1))) { return offset + m_word.size(); + } return offset; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h index 22c786eaa2..374eb87dfa 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h @@ -87,7 +87,7 @@ public: { } - virtual MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const = 0; + virtual MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const = 0; static Rule::Ptr create(QStringView name); @@ -121,58 +121,58 @@ protected: bool m_dynamic = false; }; -class AnyChar : public Rule +class AnyChar final : public Rule { protected: bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: QString m_chars; }; -class DetectChar : public Rule +class DetectChar final : public Rule { protected: bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; private: QChar m_char; int m_captureIndex = 0; }; -class Detect2Char : public Rule +class Detect2Char final : public Rule { protected: bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; private: QChar m_char1; QChar m_char2; }; -class DetectIdentifier : public Rule +class DetectIdentifier final : public Rule { protected: - MatchResult doMatch(const QString &text, int offset, const QStringList &) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; }; -class DetectSpaces : public Rule +class DetectSpaces final : public Rule { protected: - MatchResult doMatch(const QString &text, int offset, const QStringList &) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; }; -class Float : public Rule +class Float final : public Rule { protected: bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; }; -class IncludeRules : public Rule +class IncludeRules final : public Rule { public: QString contextName() const; @@ -181,7 +181,7 @@ public: protected: bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: QString m_contextName; @@ -189,44 +189,44 @@ private: bool m_includeAttribute; }; -class Int : public Rule +class Int final : public Rule { protected: bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; }; -class HlCChar : public Rule +class HlCChar final : public Rule { protected: - MatchResult doMatch(const QString &text, int offset, const QStringList &) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; }; -class HlCHex : public Rule +class HlCHex final : public Rule { protected: bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; }; -class HlCOct : public Rule +class HlCOct final : public Rule { protected: bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; }; -class HlCStringChar : public Rule +class HlCStringChar final : public Rule { protected: - MatchResult doMatch(const QString &text, int offset, const QStringList &) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; }; -class KeywordListRule : public Rule +class KeywordListRule final : public Rule { protected: bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: KeywordList *m_keywordList; @@ -234,55 +234,55 @@ private: Qt::CaseSensitivity m_caseSensitivityOverride; }; -class LineContinue : public Rule +class LineContinue final : public Rule { protected: bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: QChar m_char; }; -class RangeDetect : public Rule +class RangeDetect final : public Rule { protected: bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: QChar m_begin; QChar m_end; }; -class RegExpr : public Rule +class RegExpr final : public Rule { protected: void resolvePostProcessing() override; bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; private: QRegularExpression m_regexp; bool m_isResolved = false; }; -class StringDetect : public Rule +class StringDetect final : public Rule { protected: bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; private: QString m_string; Qt::CaseSensitivity m_caseSensitivity; }; -class WordDetect : public Rule +class WordDetect final : public Rule { protected: bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; private: QString m_word; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp index f9b4f4b4ab..ea21fef215 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp @@ -104,7 +104,8 @@ bool State::operator!=(const State &other) const bool State::indentationBasedFoldingEnabled() const { - if (!d || d->m_contextStack.isEmpty()) + if (!d || d->m_contextStack.isEmpty()) { return false; + } return d->m_contextStack.last().first->indentationBasedFoldingEnabled(); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp index d0c4ee98ae..41551e96da 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp @@ -37,11 +37,13 @@ public: FoldingRegion SyntaxHighlighterPrivate::foldingRegion(const QTextBlock &startBlock) { const auto data = dynamic_cast<TextBlockUserData *>(startBlock.userData()); - if (!data) + if (!data) { return FoldingRegion(); + } for (int i = data->foldingRegions.size() - 1; i >= 0; --i) { - if (data->foldingRegions.at(i).type() == FoldingRegion::Begin) + if (data->foldingRegions.at(i).type() == FoldingRegion::Begin) { return data->foldingRegions.at(i); + } } return FoldingRegion(); } @@ -68,8 +70,9 @@ void SyntaxHighlighter::setDefinition(const Definition &def) { const auto needsRehighlight = definition() != def; AbstractHighlighter::setDefinition(def); - if (needsRehighlight) + if (needsRehighlight) { rehighlight(); + } } bool SyntaxHighlighter::startsFoldingRegion(const QTextBlock &startBlock) const @@ -86,17 +89,21 @@ QTextBlock SyntaxHighlighter::findFoldingRegionEnd(const QTextBlock &startBlock) while (block.isValid()) { block = block.next(); const auto data = dynamic_cast<TextBlockUserData *>(block.userData()); - if (!data) + if (!data) { continue; + } for (auto it = data->foldingRegions.constBegin(); it != data->foldingRegions.constEnd(); ++it) { - if ((*it).id() != region.id()) + if ((*it).id() != region.id()) { continue; - if ((*it).type() == FoldingRegion::End) + } + if ((*it).type() == FoldingRegion::End) { --depth; - else if ((*it).type() == FoldingRegion::Begin) + } else if ((*it).type() == FoldingRegion::Begin) { ++depth; - if (depth == 0) + } + if (depth == 0) { return block; + } } } @@ -111,8 +118,9 @@ void SyntaxHighlighter::highlightBlock(const QString &text) if (currentBlock().position() > 0) { const auto prevBlock = currentBlock().previous(); const auto prevData = dynamic_cast<TextBlockUserData *>(prevBlock.userData()); - if (prevData) + if (prevData) { state = prevData->state; + } } d->foldingRegions.clear(); state = highlightLine(text, state); @@ -126,35 +134,43 @@ void SyntaxHighlighter::highlightBlock(const QString &text) return; } - if (data->state == state && data->foldingRegions == d->foldingRegions) // we ended up in the same state, so we are done here + if (data->state == state && data->foldingRegions == d->foldingRegions) { // we ended up in the same state, so we are done here return; + } data->state = state; data->foldingRegions = d->foldingRegions; const auto nextBlock = currentBlock().next(); - if (nextBlock.isValid()) + if (nextBlock.isValid()) { QMetaObject::invokeMethod(this, "rehighlightBlock", Qt::QueuedConnection, Q_ARG(QTextBlock, nextBlock)); + } } void SyntaxHighlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format) { - if (length == 0) + if (length == 0) { return; + } QTextCharFormat tf; // always set the foreground color to avoid palette issues tf.setForeground(format.textColor(theme())); - if (format.hasBackgroundColor(theme())) + if (format.hasBackgroundColor(theme())) { tf.setBackground(format.backgroundColor(theme())); - if (format.isBold(theme())) + } + if (format.isBold(theme())) { tf.setFontWeight(QFont::Bold); - if (format.isItalic(theme())) + } + if (format.isItalic(theme())) { tf.setFontItalic(true); - if (format.isUnderline(theme())) + } + if (format.isUnderline(theme())) { tf.setFontUnderline(true); - if (format.isStrikeThrough(theme())) + } + if (format.isStrikeThrough(theme())) { tf.setFontStrikeOut(true); + } QSyntaxHighlighter::setFormat(offset, length, tf); } @@ -165,13 +181,15 @@ void SyntaxHighlighter::applyFolding(int offset, int length, FoldingRegion regio Q_UNUSED(length); Q_D(SyntaxHighlighter); - if (region.type() == FoldingRegion::Begin) + if (region.type() == FoldingRegion::Begin) { d->foldingRegions.push_back(region); + } if (region.type() == FoldingRegion::End) { for (int i = d->foldingRegions.size() - 1; i >= 0; --i) { - if (d->foldingRegions.at(i).id() != region.id() || d->foldingRegions.at(i).type() != FoldingRegion::Begin) + if (d->foldingRegions.at(i).id() != region.id() || d->foldingRegions.at(i).type() != FoldingRegion::Begin) { continue; + } d->foldingRegions.remove(i); return; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h index 076e8d0318..37f9de1694 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h @@ -64,6 +64,8 @@ class RepositoryPrivate; class KSYNTAXHIGHLIGHTING_EXPORT Theme { Q_GADGET + Q_PROPERTY(QString name READ name) + Q_PROPERTY(QString translatedName READ translatedName) public: // TODO KF6: // - make TextStyle an enum class diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp index 2919a31a6e..f9c386bc2a 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp @@ -160,8 +160,9 @@ bool ThemeData::load(const QString &filePath) for (auto it = customStyles.begin(); it != customStyles.end(); ++it) { const auto obj = it.value().toObject(); auto &overrideStyle = m_textStyleOverrides[it.key()]; - for (auto it2 = obj.begin(); it2 != obj.end(); ++it2) + for (auto it2 = obj.begin(); it2 != obj.end(); ++it2) { overrideStyle.insert(it2.key(), readThemeData(it2.value().toObject())); + } } return true; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp index 82d3e4ea80..98daff19d6 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp @@ -4,14 +4,16 @@ SPDX-License-Identifier: MIT */ -#include "wildcardmatcher_p.h" +#include "wildcardmatcher.h" using namespace KSyntaxHighlighting; #include <QChar> -#include <QString> +#include <QStringView> -static bool exactMatch(const QString &candidate, const QString &wildcard, int candidatePosFromRight, int wildcardPosFromRight, bool caseSensitive = true) +namespace +{ +bool wildcardMatch(QStringView candidate, QStringView wildcard, int candidatePosFromRight, int wildcardPosFromRight) { for (; wildcardPosFromRight >= 0; wildcardPosFromRight--) { const auto ch = wildcard.at(wildcardPosFromRight).unicode(); @@ -27,7 +29,7 @@ static bool exactMatch(const QString &candidate, const QString &wildcard, int ca // Eat all we can and go back as far as we have to for (int j = -1; j <= candidatePosFromRight; j++) { - if (exactMatch(candidate, wildcard, j, wildcardPosFromRight - 1)) { + if (wildcardMatch(candidate, wildcard, j, wildcardPosFromRight - 1)) { return true; } } @@ -47,18 +49,19 @@ static bool exactMatch(const QString &candidate, const QString &wildcard, int ca } const auto candidateCh = candidate.at(candidatePosFromRight).unicode(); - const auto match = caseSensitive ? (candidateCh == ch) : (QChar::toLower(candidateCh) == QChar::toLower(ch)); - if (match) { + if (candidateCh == ch) { candidatePosFromRight--; } else { return false; } } } - return true; + return candidatePosFromRight == -1; } -bool WildcardMatcher::exactMatch(const QString &candidate, const QString &wildcard, bool caseSensitive) +} // unnamed namespace + +bool WildcardMatcher::exactMatch(QStringView candidate, QStringView wildcard) { - return ::exactMatch(candidate, wildcard, candidate.length() - 1, wildcard.length() - 1, caseSensitive); + return ::wildcardMatch(candidate, wildcard, candidate.length() - 1, wildcard.length() - 1); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.h b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.h new file mode 100644 index 0000000000..4042de3788 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.h @@ -0,0 +1,33 @@ +/* + SPDX-FileCopyrightText: 2007 Sebastian Pipping <webmaster@hartwork.org> + + SPDX-License-Identifier: MIT +*/ + +#ifndef KSYNTAXHIGHLIGHTING_WILDCARDMATCHER_H +#define KSYNTAXHIGHLIGHTING_WILDCARDMATCHER_H + +#include "ksyntaxhighlighting_export.h" + +#include <QStringView> + +namespace KSyntaxHighlighting +{ +namespace WildcardMatcher +{ +/** + * Matches a string against a given wildcard case-sensitively. + * The wildcard supports '*' (".*" in regex) and '?' ("." in regex), not more. + * + * @param candidate Text to match + * @param wildcard Wildcard to use + * @return True for an exact match, false otherwise + * + * @since 5.86 + */ +KSYNTAXHIGHLIGHTING_EXPORT bool exactMatch(QStringView candidate, QStringView wildcard); +} + +} + +#endif // KSYNTAXHIGHLIGHTING_WILDCARDMATCHER_H diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp index 634eeb70bb..f9079ea1f3 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp @@ -11,15 +11,17 @@ using namespace KSyntaxHighlighting; WordDelimiters::WordDelimiters() : asciiDelimiters{} { - for (const char *p = "\t !%&()*+,-./:;<=>?[\\]^{|}~"; *p; ++p) + for (const char *p = "\t !%&()*+,-./:;<=>?[\\]^{|}~"; *p; ++p) { // int(*p) fix -Wchar-subscripts asciiDelimiters[int(*p)] = true; + } } bool WordDelimiters::contains(QChar c) const { - if (c.unicode() < 128) + if (c.unicode() < 128) { return asciiDelimiters[c.unicode()]; + } // perf tells contains is MUCH faster than binary search here, very short array return notAsciiDelimiters.contains(c); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h index 3fa5db10a4..c1afaaa6bb 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h @@ -12,7 +12,7 @@ namespace KSyntaxHighlighting { /** - * Repesents a list of character that separates 2 words. + * Represents a list of character that separates 2 words. * * Default delimiters are .():!+*,-<=>%&/;?[]^{|}~\, space (' ') and tabulator ('\t'). * diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h index 5aae9eebb5..2e1dd25cc8 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h @@ -17,7 +17,7 @@ namespace Xml /** Parse a xs:boolean attribute. */ inline bool attrToBool(QStringView str) { - return str == QLatin1String("1") || str.compare(QString("true"), Qt::CaseInsensitive) == 0; + return str == QStringLiteral("1") || str.compare(QStringLiteral("true"), Qt::CaseInsensitive) == 0; } } diff --git a/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.pro b/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.pro index 333af297a8..e9354a2f69 100644 --- a/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.pro +++ b/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.pro @@ -3,7 +3,7 @@ include(autogenerated/autogenerated.pri) QT += network -DEFINES += KSYNTAXHIGHLIGHTING_LIBRARY +DEFINES += KF5SyntaxHighlighting_EXPORTS RESOURCES += \ data/themes/theme-data.qrc diff --git a/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs b/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs index 27b5987e1a..985264440f 100644 --- a/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs +++ b/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs @@ -25,7 +25,7 @@ Project { name: "KSyntaxHighlighting_bundled" condition: !qtc.preferSystemSyntaxHighlighting || !Qt.KSyntaxHighlighting.present - cpp.defines: base.concat("KSYNTAXHIGHLIGHTING_LIBRARY") + cpp.defines: base.concat("KF5SyntaxHighlighting_EXPORTS") cpp.includePaths: [ product.sourceDirectory + "/src/lib/", product.sourceDirectory + "/autogenerated/src/lib/", @@ -66,7 +66,6 @@ Project { "htmlhighlighter.h", "keywordlist.cpp", "keywordlist_p.h", - "ksyntaxhighlighting_export.h", "matchresult_p.h", "repository.cpp", "repository.h", diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 5eaa04baf4..3f7e791115 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -38,6 +38,7 @@ #include <cplusplus/Control.h> #include <utils/algorithm.h> +#include <utils/porting.h> #include <QStack> #include <QHash> @@ -150,9 +151,9 @@ bool operator==(const FullyQualifiedName &left, const FullyQualifiedName &right) return compareFullyQualifiedName(left.fqn, right.fqn); } -uint qHash(const FullyQualifiedName &fullyQualifiedName) +Utils::QHashValueType qHash(const FullyQualifiedName &fullyQualifiedName) { - uint h = 0; + Utils::QHashValueType h = 0; for (int i = 0; i < fullyQualifiedName.fqn.size(); ++i) { if (const Name *n = fullyQualifiedName.fqn.at(i)) { if (const Identifier *id = n->identifier()) { diff --git a/src/libs/cplusplus/LookupItem.cpp b/src/libs/cplusplus/LookupItem.cpp index 7fc73ba240..f4fce6e4ed 100644 --- a/src/libs/cplusplus/LookupItem.cpp +++ b/src/libs/cplusplus/LookupItem.cpp @@ -33,10 +33,10 @@ using namespace CPlusPlus; -uint CPlusPlus::qHash(const LookupItem &key) +Utils::QHashValueType CPlusPlus::qHash(const LookupItem &key) { - const uint h1 = QT_PREPEND_NAMESPACE(qHash)(key.type().type()); - const uint h2 = QT_PREPEND_NAMESPACE(qHash)(key.scope()); + const Utils::QHashValueType h1 = QT_PREPEND_NAMESPACE(qHash)(key.type().type()); + const Utils::QHashValueType h2 = QT_PREPEND_NAMESPACE(qHash)(key.scope()); return ((h1 << 16) | (h1 >> 16)) ^ h2; } diff --git a/src/libs/cplusplus/LookupItem.h b/src/libs/cplusplus/LookupItem.h index e2683c2877..bc760f8d8b 100644 --- a/src/libs/cplusplus/LookupItem.h +++ b/src/libs/cplusplus/LookupItem.h @@ -26,6 +26,7 @@ #pragma once #include <cplusplus/FullySpecifiedType.h> +#include <utils/porting.h> #include <QHash> @@ -70,6 +71,6 @@ private: ClassOrNamespace *_binding; }; -uint qHash(const CPlusPlus::LookupItem &result); +Utils::QHashValueType qHash(const CPlusPlus::LookupItem &result); } // namespace CPlusPlus diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp index ea83933b7e..e3b2b07080 100644 --- a/src/libs/extensionsystem/pluginspec.cpp +++ b/src/libs/extensionsystem/pluginspec.cpp @@ -155,7 +155,7 @@ using namespace ExtensionSystem::Internal; \fn uint ExtensionSystem::qHash(const ExtensionSystem::PluginDependency &value) \internal */ -uint ExtensionSystem::qHash(const PluginDependency &value) +Utils::QHashValueType ExtensionSystem::qHash(const PluginDependency &value) { return qHash(value.name); } diff --git a/src/libs/extensionsystem/pluginspec.h b/src/libs/extensionsystem/pluginspec.h index d8d85ba520..4b2bcc1306 100644 --- a/src/libs/extensionsystem/pluginspec.h +++ b/src/libs/extensionsystem/pluginspec.h @@ -27,6 +27,8 @@ #include "extensionsystem_global.h" +#include <utils/porting.h> + #include <QString> #include <QHash> #include <QVector> @@ -65,7 +67,7 @@ struct EXTENSIONSYSTEM_EXPORT PluginDependency QString toString() const; }; -uint qHash(const ExtensionSystem::PluginDependency &value); +Utils::QHashValueType qHash(const ExtensionSystem::PluginDependency &value); struct EXTENSIONSYSTEM_EXPORT PluginArgumentDescription { diff --git a/src/libs/languageserverprotocol/jsonrpcmessages.cpp b/src/libs/languageserverprotocol/jsonrpcmessages.cpp index 64045f1e3a..2b71d34a75 100644 --- a/src/libs/languageserverprotocol/jsonrpcmessages.cpp +++ b/src/libs/languageserverprotocol/jsonrpcmessages.cpp @@ -37,6 +37,7 @@ #include <QTextCodec> namespace LanguageServerProtocol { +Q_LOGGING_CATEGORY(timingLog, "qtc.languageserverprotocol.timing", QtWarningMsg) constexpr const char CancelRequest::methodName[]; @@ -148,4 +149,10 @@ CancelRequest::CancelRequest(const CancelParameter ¶ms) : Notification(methodName, params) { } +void logElapsedTime(const QString &method, const QElapsedTimer &t) +{ + qCDebug(timingLog) << "received server reply to" << method + << "after" << t.elapsed() << "ms"; +} + } // namespace LanguageServerProtocol diff --git a/src/libs/languageserverprotocol/jsonrpcmessages.h b/src/libs/languageserverprotocol/jsonrpcmessages.h index bb20ca8a3c..010bc770f8 100644 --- a/src/libs/languageserverprotocol/jsonrpcmessages.h +++ b/src/libs/languageserverprotocol/jsonrpcmessages.h @@ -34,6 +34,7 @@ #include <utils/variant.h> #include <QDebug> +#include <QElapsedTimer> #include <QHash> #include <QJsonObject> #include <QJsonValue> @@ -294,6 +295,8 @@ public: { return JsonRpcMessage::isValid(errorMessage) && id().isValid(); } }; +void LANGUAGESERVERPROTOCOL_EXPORT logElapsedTime(const QString &method, const QElapsedTimer &t); + template <typename Result, typename ErrorDataType, typename Params> class Request : public Notification<Params> { @@ -316,9 +319,13 @@ public: Utils::optional<ResponseHandler> responseHandler() const final { - auto callback = [callback = m_callBack](const QByteArray &content, QTextCodec *codec) { + QElapsedTimer timer; + timer.start(); + auto callback = [callback = m_callBack, method = this->method(), t = std::move(timer)] + (const QByteArray &content, QTextCodec *codec) { if (!callback) return; + logElapsedTime(method, t); QString parseError; const QJsonObject &object = JsonRpcMessageHandler::toJsonObject(content, codec, diff --git a/src/libs/languageserverprotocol/lsptypes.cpp b/src/libs/languageserverprotocol/lsptypes.cpp index 820f4b6c4b..65651366a3 100644 --- a/src/libs/languageserverprotocol/lsptypes.cpp +++ b/src/libs/languageserverprotocol/lsptypes.cpp @@ -293,6 +293,14 @@ QTextCursor Position::toTextCursor(QTextDocument *doc) const return cursor; } +Position Position::withOffset(int offset, const QTextDocument *doc) const +{ + int line; + int character; + Utils::Text::convertPosition(doc, toPositionInDocument(doc) + offset, &line, &character); + return Position(line - 1, character - 1); +} + Range::Range(const Position &start, const Position &end) { setStart(start); @@ -323,7 +331,7 @@ bool Range::contains(const Range &other) const bool Range::overlaps(const Range &range) const { - return end() > range.start() && start() < range.end(); + return !isLeftOf(range) && !range.isLeftOf(*this); } QString expressionForGlob(QString globPattern) diff --git a/src/libs/languageserverprotocol/lsptypes.h b/src/libs/languageserverprotocol/lsptypes.h index 7cbe045563..7bd004ca6c 100644 --- a/src/libs/languageserverprotocol/lsptypes.h +++ b/src/libs/languageserverprotocol/lsptypes.h @@ -90,6 +90,7 @@ public: int toPositionInDocument(const QTextDocument *doc) const; QTextCursor toTextCursor(QTextDocument *doc) const; + Position withOffset(int offset, const QTextDocument *doc) const; }; inline bool operator<(const Position &first, const Position &second) @@ -103,6 +104,11 @@ inline bool operator>(const Position &first, const Position &second) return second < first; } +inline bool operator>=(const Position &first, const Position &second) +{ + return !(first < second); +} + inline bool operator<=(const Position &first, const Position &second) { return !(first > second); @@ -124,9 +130,12 @@ public: Position end() const { return typedValue<Position>(endKey); } void setEnd(const Position &end) { insert(endKey, end); } + bool isEmpty() const { return start() == end(); } bool contains(const Position &pos) const { return start() <= pos && pos <= end(); } bool contains(const Range &other) const; bool overlaps(const Range &range) const; + bool isLeftOf(const Range &other) const + { return isEmpty() || other.isEmpty() ? end() < other.start() : end() <= other.start(); } bool isValid() const override { return JsonObject::contains(startKey) && JsonObject::contains(endKey); } diff --git a/src/libs/modelinglib/qmt/infrastructure/handle.h b/src/libs/modelinglib/qmt/infrastructure/handle.h index b7333a1146..7558ec9699 100644 --- a/src/libs/modelinglib/qmt/infrastructure/handle.h +++ b/src/libs/modelinglib/qmt/infrastructure/handle.h @@ -74,7 +74,7 @@ private: }; template<class T> -inline int qHash(const Handle<T> &handle) +inline auto qHash(const Handle<T> &handle) { return qHash(handle.uid()); } diff --git a/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp b/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp index f2da9a9292..47706f91fc 100644 --- a/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp +++ b/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp @@ -38,6 +38,7 @@ #include "qmt/infrastructure/qmtassert.h" #include <utils/algorithm.h> +#include <utils/porting.h> #include <QSet> @@ -82,7 +83,7 @@ public: ObjectVisuals m_objectVisuals; }; -uint qHash(const ObjectStyleKey &styleKey) +Utils::QHashValueType qHash(const ObjectStyleKey &styleKey) { return ::qHash(styleKey.m_elementType) ^ qHash(styleKey.m_objectVisuals); } @@ -106,7 +107,7 @@ public: DObject::VisualPrimaryRole m_visualPrimaryRole = DObject::PrimaryRoleNormal; }; -uint qHash(const RelationStyleKey &styleKey) +Utils::QHashValueType qHash(const RelationStyleKey &styleKey) { return ::qHash(styleKey.m_elementType) ^ ::qHash(styleKey.m_visualPrimaryRole); } @@ -127,7 +128,7 @@ public: DAnnotation::VisualRole m_visualRole = DAnnotation::RoleNormal; }; -uint qHash(const AnnotationStyleKey &styleKey) +Utils::QHashValueType qHash(const AnnotationStyleKey &styleKey) { return ::qHash(styleKey.m_visualRole); } @@ -142,11 +143,11 @@ class BoundaryStyleKey { }; -uint qHash(const BoundaryStyleKey &styleKey) +Utils::QHashValueType qHash(const BoundaryStyleKey &styleKey) { Q_UNUSED(styleKey) - return 1; + return ::qHash(1); } bool operator==(const BoundaryStyleKey &lhs, const BoundaryStyleKey &rhs) @@ -162,11 +163,11 @@ class SwimlaneStyleKey { }; -uint qHash(const SwimlaneStyleKey &styleKey) +Utils::QHashValueType qHash(const SwimlaneStyleKey &styleKey) { Q_UNUSED(styleKey) - return 1; + return ::qHash(1); } bool operator==(const SwimlaneStyleKey &lhs, const SwimlaneStyleKey &rhs) diff --git a/src/libs/modelinglib/qmt/style/objectvisuals.cpp b/src/libs/modelinglib/qmt/style/objectvisuals.cpp index a4bdadc26e..7db69f6965 100644 --- a/src/libs/modelinglib/qmt/style/objectvisuals.cpp +++ b/src/libs/modelinglib/qmt/style/objectvisuals.cpp @@ -82,7 +82,7 @@ bool operator==(const ObjectVisuals &lhs, const ObjectVisuals &rhs) && lhs.depth() == rhs.depth(); } -uint qHash(const ObjectVisuals &objectVisuals) +Utils::QHashValueType qHash(const ObjectVisuals &objectVisuals) { return ::qHash(static_cast<int>(objectVisuals.visualPrimaryRole())) ^ ::qHash(static_cast<int>(objectVisuals.visualSecondaryRole())) diff --git a/src/libs/modelinglib/qmt/style/objectvisuals.h b/src/libs/modelinglib/qmt/style/objectvisuals.h index 0d708fe0a5..dcc4bee623 100644 --- a/src/libs/modelinglib/qmt/style/objectvisuals.h +++ b/src/libs/modelinglib/qmt/style/objectvisuals.h @@ -27,6 +27,8 @@ #include "qmt/diagram/dobject.h" +#include <utils/porting.h> + #include <QColor> namespace qmt { @@ -60,6 +62,6 @@ private: }; bool operator==(const ObjectVisuals &lhs, const ObjectVisuals &rhs); -uint qHash(const ObjectVisuals &objectVisuals); +Utils::QHashValueType qHash(const ObjectVisuals &objectVisuals); } // namespace qmt diff --git a/src/libs/qlitehtml b/src/libs/qlitehtml -Subproject 2fbaad08a01d611858bef5e747addea7f42318b +Subproject e6fcc8ddb4e435160cca6a94bd7b011fd169865 diff --git a/src/libs/qmldebug/qpacketprotocol.cpp b/src/libs/qmldebug/qpacketprotocol.cpp index 76822d34d4..24d4d29c54 100644 --- a/src/libs/qmldebug/qpacketprotocol.cpp +++ b/src/libs/qmldebug/qpacketprotocol.cpp @@ -225,7 +225,7 @@ void QPacketProtocol::send(const QByteArray &p) return; } - const qint32 sendSize = p.size() + sizeof(qint32); + const qint32 sendSize = qint32(p.size() + sizeof(qint32)); d->sendingPackets.append(sendSize); const qint32 sendSizeLE = qToLittleEndian(sendSize); diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 3ce402589c..38595a8b36 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -1263,13 +1263,28 @@ static bool equalIsAlwaysFalse(const Value *lhs, const Value *rhs) return false; } +static bool isIntegerValue(const Value *value) +{ + if (value->asNumberValue() || value->asIntValue()) + return true; + if (auto obj = value->asObjectValue()) + return obj->className() == "Number"; + + return false; +} + static bool strictCompareConstant(const Value *lhs, const Value *rhs) { if (lhs->asUnknownValue() || rhs->asUnknownValue()) return false; + if (lhs->asFunctionValue() || rhs->asFunctionValue()) // function evaluation not implemented + return false; + if (isIntegerValue(lhs) && isIntegerValue(rhs)) + return false; if (lhs->asBooleanValue() && !rhs->asBooleanValue()) return true; - if (lhs->asNumberValue() && !rhs->asNumberValue()) + // attached properties and working at runtime cases may be undefined at evaluation time + if (lhs->asNumberValue() && (!rhs->asNumberValue() && !rhs->asUndefinedValue())) return true; if (lhs->asStringValue() && !rhs->asStringValue()) return true; diff --git a/src/libs/qmljs/qmljsdialect.cpp b/src/libs/qmljs/qmljsdialect.cpp index cfe71b2265..d0b922a720 100644 --- a/src/libs/qmljs/qmljsdialect.cpp +++ b/src/libs/qmljs/qmljsdialect.cpp @@ -221,9 +221,9 @@ QList<Dialect> Dialect::companionLanguages() const return langs; } -uint qHash(const Dialect &o) +Utils::QHashValueType qHash(const Dialect &o) { - return uint(o.dialect()); + return Utils::QHashValueType(o.dialect()); } QDebug operator << (QDebug &dbg, const Dialect &dialect) diff --git a/src/libs/qmljs/qmljsdialect.h b/src/libs/qmljs/qmljsdialect.h index a2f2822599..e594164278 100644 --- a/src/libs/qmljs/qmljsdialect.h +++ b/src/libs/qmljs/qmljsdialect.h @@ -28,6 +28,7 @@ #include "qmljs_global.h" #include <utils/fileutils.h> +#include <utils/porting.h> #include <QDebug> #include <QString> @@ -73,7 +74,7 @@ private: Enum m_dialect; }; -QMLJS_EXPORT uint qHash(const Dialect &o); +QMLJS_EXPORT Utils::QHashValueType qHash(const Dialect &o); QMLJS_EXPORT QDebug operator << (QDebug &dbg, const Dialect &dialect); diff --git a/src/libs/qmljs/qmljsimportdependencies.cpp b/src/libs/qmljs/qmljsimportdependencies.cpp index 3cf94cb342..757ff2c388 100644 --- a/src/libs/qmljs/qmljsimportdependencies.cpp +++ b/src/libs/qmljs/qmljsimportdependencies.cpp @@ -502,9 +502,9 @@ QString ImportKey::toString() const return res; } -uint qHash(const ImportKey &info) +Utils::QHashValueType qHash(const ImportKey &info) { - uint res = ::qHash(info.type) ^ + Utils::QHashValueType res = ::qHash(info.type) ^ ::qHash(info.majorVersion) ^ ::qHash(info.minorVersion); foreach (const QString &s, info.splitPath) res = res ^ ::qHash(s); diff --git a/src/libs/qmljs/qmljsimportdependencies.h b/src/libs/qmljs/qmljsimportdependencies.h index 41f8491551..a05bf1b408 100644 --- a/src/libs/qmljs/qmljsimportdependencies.h +++ b/src/libs/qmljs/qmljsimportdependencies.h @@ -29,6 +29,7 @@ #include "qmljsdialect.h" #include <languageutils/componentversion.h> +#include <utils/porting.h> #include <QObject> #include <QString> @@ -117,7 +118,7 @@ public: QString toString() const; }; -uint qHash(const ImportKey &info); +Utils::QHashValueType qHash(const ImportKey &info); bool operator ==(const ImportKey &i1, const ImportKey &i2); bool operator !=(const ImportKey &i1, const ImportKey &i2); bool operator <(const ImportKey &i1, const ImportKey &i2); diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index 9ae98e3530..47951eeb28 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -175,7 +175,7 @@ bool FakeMetaObjectWithOrigin::operator ==(const FakeMetaObjectWithOrigin &o) co return fakeMetaObject == o.fakeMetaObject; } -uint qHash(const FakeMetaObjectWithOrigin &fmoo) +Utils::QHashValueType qHash(const FakeMetaObjectWithOrigin &fmoo) { return qHash(fmoo.fakeMetaObject); } diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index 6929386785..7322541e1a 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -31,6 +31,7 @@ #include <qmljs/parser/qmljsastfwd_p.h> #include <languageutils/fakemetaobject.h> +#include <utils/porting.h> #include <QFileInfoList> #include <QHash> @@ -734,7 +735,7 @@ public: bool operator ==(const FakeMetaObjectWithOrigin &o) const; }; -QMLJS_EXPORT uint qHash(const FakeMetaObjectWithOrigin &fmoo); +QMLJS_EXPORT Utils::QHashValueType qHash(const FakeMetaObjectWithOrigin &fmoo); class QMLJS_EXPORT CppQmlTypes { diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index 4fcdb0a748..58ead76afc 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -32,6 +32,7 @@ #include "qmljsmodelmanagerinterface.h" #include "qmljsconstants.h" +#include <utils/porting.h> #include <utils/qrcparser.h> #include <QDir> @@ -54,7 +55,7 @@ public: {} private: - friend uint qHash(const ImportCacheKey &); + friend Utils::QHashValueType qHash(const ImportCacheKey &); friend bool operator==(const ImportCacheKey &, const ImportCacheKey &); int m_type; @@ -63,7 +64,7 @@ private: int m_minorVersion; }; -uint qHash(const ImportCacheKey &info) +Utils::QHashValueType qHash(const ImportCacheKey &info) { return ::qHash(info.m_type) ^ ::qHash(info.m_path) ^ ::qHash(info.m_majorVersion) ^ ::qHash(info.m_minorVersion); diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index 34048e8185..db08418ca7 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -1329,7 +1329,7 @@ bool rescanExports(const QString &fileName, FindExportedCppTypes &finder, QList<LanguageUtils::FakeMetaObject::ConstPtr> exported = finder.exportedTypes(); QHash<QString, QString> contextProperties = finder.contextProperties(); if (exported.isEmpty() && contextProperties.isEmpty()) { - hasNewInfo = hasNewInfo || newData.remove(fileName) > 0; + hasNewInfo = hasNewInfo || newData.remove(fileName); } else { ModelManagerInterface::CppData &data = newData[fileName]; if (!hasNewInfo && (data.exportedTypes.size() != exported.size() @@ -1382,7 +1382,7 @@ void ModelManagerInterface::updateCppQmlTypes( const bool scan = pair.second; const QString fileName = doc->fileName(); if (!scan) { - hasNewInfo = newData.remove(fileName) > 0 || hasNewInfo; + hasNewInfo = newData.remove(fileName) || hasNewInfo; const auto savedDocs = newDeclarations.value(fileName); for (const CPlusPlus::Document::Ptr &savedDoc : savedDocs) { finder(savedDoc); diff --git a/src/libs/tracing/CMakeLists.txt b/src/libs/tracing/CMakeLists.txt index 9378c0e4e0..c34f583810 100644 --- a/src/libs/tracing/CMakeLists.txt +++ b/src/libs/tracing/CMakeLists.txt @@ -46,7 +46,7 @@ else() # < Qt 6.2 find_package(Qt6 COMPONENTS ShaderTools QUIET) add_qtc_library(Tracing - CONDITION TARGET Qt6::ShaderTools + CONDITION TARGET Qt6::ShaderTools AND TARGET Qt5::Quick FEATURE_INFO DEPENDS Utils Qt5::Qml Qt5::Quick PUBLIC_DEPENDS Qt5::Widgets diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 9db6ea5f1e..b94b2b4222 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -168,6 +168,7 @@ add_qtc_library(Utils textfileformat.cpp textfileformat.h textutils.cpp textutils.h theme/theme.cpp theme/theme.h theme/theme_p.h + threadutils.cpp threadutils.h tooltip/effects.h tooltip/tips.cpp tooltip/tips.h tooltip/tooltip.cpp tooltip/tooltip.h diff --git a/src/libs/utils/elfreader.cpp b/src/libs/utils/elfreader.cpp index 3ff3388041..1883585bc8 100644 --- a/src/libs/utils/elfreader.cpp +++ b/src/libs/utils/elfreader.cpp @@ -113,7 +113,7 @@ bool ElfMapper::map() return fdlen > 0; } - file.setFileName(binary.fileName()); + file.setFileName(binary.path()); if (!file.open(QIODevice::ReadOnly)) return false; diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index fd68683ace..065f96809e 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -819,6 +819,24 @@ FilePath FilePath::symLinkTarget() const return FilePath::fromString(info.symLinkTarget()); } +FilePath FilePath::mapToGlobalPath() const +{ + if (needsDevice()) { + QTC_ASSERT(s_deviceHooks.mapToGlobalPath, return {}); + return s_deviceHooks.mapToGlobalPath(*this); + } + return *this; +} + +QString FilePath::mapToDevicePath() const +{ + if (needsDevice()) { + QTC_ASSERT(s_deviceHooks.mapToDevicePath, return {}); + return s_deviceHooks.mapToDevicePath(*this); + } + return m_data; +} + FilePath FilePath::withExecutableSuffix() const { FilePath res = *this; @@ -1280,7 +1298,7 @@ FilePath FilePath::stringAppended(const QString &str) const return fn; } -uint FilePath::hash(uint seed) const +QHashValueType FilePath::hash(uint seed) const { if (Utils::HostOsInfo::fileNameCaseSensitivity() == Qt::CaseInsensitive) return qHash(m_data.toUpper(), seed); diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 409421eaf5..a83c0aa517 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -26,6 +26,7 @@ #pragma once #include "utils_global.h" +#include "porting.h" #include "hostosinfo.h" @@ -140,7 +141,7 @@ public: void clear(); bool isEmpty() const; - uint hash(uint seed) const; + QHashValueType hash(uint seed) const; [[nodiscard]] FilePath resolvePath(const FilePath &tail) const; [[nodiscard]] FilePath resolvePath(const QString &tail) const; @@ -161,6 +162,9 @@ public: QDir::Filters filters = QDir::NoFilter, QDirIterator::IteratorFlags flags = QDirIterator::NoIteratorFlags) const; + [[nodiscard]] FilePath mapToGlobalPath() const; + [[nodiscard]] QString mapToDevicePath() const; + // makes sure that capitalization of directories is canonical // on Windows and macOS. This is rarely needed. [[nodiscard]] FilePath normalizedPathName() const; @@ -198,6 +202,11 @@ private: using FilePaths = QList<FilePath>; +inline QHashValueType qHash(const Utils::FilePath &a, uint seed = 0) +{ + return a.hash(seed); +} + } // namespace Utils QT_BEGIN_NAMESPACE @@ -205,3 +214,13 @@ QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug dbg, const Utils::FilePath &c); QT_END_NAMESPACE Q_DECLARE_METATYPE(Utils::FilePath) + +namespace std { +template<> +struct QTCREATOR_UTILS_EXPORT hash<Utils::FilePath> +{ + using argument_type = Utils::FilePath; + using result_type = size_t; + result_type operator()(const argument_type &fn) const; +}; +} // namespace std diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index a92017f770..c87ca5d5dd 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -78,6 +78,8 @@ public: std::function<bool(const FilePath &, const FilePath &)> renameFile; std::function<FilePath(const FilePath &, const QList<FilePath> &)> searchInPath; std::function<FilePath(const FilePath &)> symLinkTarget; + std::function<FilePath(const FilePath &)> mapToGlobalPath; + std::function<QString(const FilePath &)> mapToDevicePath; std::function<QList<FilePath>(const FilePath &, const QStringList &, QDir::Filters, QDir::SortFlags)> dirEntries; std::function<QByteArray(const FilePath &, qint64, qint64)> fileContents; @@ -314,16 +316,5 @@ private: QTCREATOR_UTILS_EXPORT QTextStream &operator<<(QTextStream &s, const FilePath &fn); -inline uint qHash(const Utils::FilePath &a, uint seed = 0) { return a.hash(seed); } - } // namespace Utils -namespace std { -template<> struct QTCREATOR_UTILS_EXPORT hash<Utils::FilePath> -{ - using argument_type = Utils::FilePath; - using result_type = size_t; - result_type operator()(const argument_type &fn) const; -}; -} // namespace std - diff --git a/src/libs/utils/id.cpp b/src/libs/utils/id.cpp index 26430a2938..1349dd8488 100644 --- a/src/libs/utils/id.cpp +++ b/src/libs/utils/id.cpp @@ -84,7 +84,7 @@ static bool operator==(const StringHolder &sh1, const StringHolder &sh2) } -static uint qHash(const StringHolder &sh) +static auto qHash(const StringHolder &sh) { return QT_PREPEND_NAMESPACE(qHash)(sh.h, 0); } diff --git a/src/libs/utils/id.h b/src/libs/utils/id.h index e0af61099c..5c6440bd56 100644 --- a/src/libs/utils/id.h +++ b/src/libs/utils/id.h @@ -26,6 +26,7 @@ #pragma once #include "utils_global.h" +#include "porting.h" #include <QList> #include <QMetaType> @@ -79,7 +80,7 @@ private: quintptr m_id = 0; }; -inline uint qHash(Id id) { return static_cast<uint>(id.uniqueIdentifier()); } +inline QHashValueType qHash(Id id) { return static_cast<QHashValueType>(id.uniqueIdentifier()); } } // namespace Utils diff --git a/src/libs/utils/link.cpp b/src/libs/utils/link.cpp index 884936a7bb..1df67837b1 100644 --- a/src/libs/utils/link.cpp +++ b/src/libs/utils/link.cpp @@ -63,7 +63,7 @@ Link Link::fromFilePath(const FilePath &filePath, bool canContainLineNumber, QSt return Link{filePath.withNewPath(fileName.left(postfixPos)), lineColumn.line, lineColumn.column}; } -uint qHash(const Link &l) +QHashValueType qHash(const Link &l) { QString s = l.targetFilePath.toString(); return qHash(s.append(':').append(QString::number(l.targetLine)).append(':') diff --git a/src/libs/utils/link.h b/src/libs/utils/link.h index 34c2c5a5cf..6d9fbb8ac1 100644 --- a/src/libs/utils/link.h +++ b/src/libs/utils/link.h @@ -25,7 +25,8 @@ #pragma once -#include <utils/fileutils.h> +#include "fileutils.h" +#include "porting.h" #include <QString> #include <qmetatype.h> @@ -75,7 +76,7 @@ public: int targetColumn; }; -uint QTCREATOR_UTILS_EXPORT qHash(const Link &l); +QTCREATOR_UTILS_EXPORT QHashValueType qHash(const Link &l); using ProcessLinkCallback = std::function<void(const Link &)>; diff --git a/src/libs/utils/mimetypes/mimeglobpattern.cpp b/src/libs/utils/mimetypes/mimeglobpattern.cpp index 9ab335b862..ae0899dd0e 100644 --- a/src/libs/utils/mimetypes/mimeglobpattern.cpp +++ b/src/libs/utils/mimetypes/mimeglobpattern.cpp @@ -83,6 +83,39 @@ void MimeGlobMatchResult::addMatch(const QString &mimeType, int weight, const QS } } +MimeGlobPattern::PatternType MimeGlobPattern::detectPatternType(const QString &pattern) const +{ + const int patternLength = pattern.length(); + if (!patternLength) + return OtherPattern; + + const bool starCount = pattern.count(QLatin1Char('*')) == 1; + const bool hasSquareBracket = pattern.indexOf(QLatin1Char('[')) != -1; + const bool hasQuestionMark = pattern.indexOf(QLatin1Char('?')) != -1; + + if (!hasSquareBracket && !hasQuestionMark) { + if (starCount == 1) { + // Patterns like "*~", "*.extension" + if (pattern.at(0) == QLatin1Char('*')) + return SuffixPattern; + // Patterns like "README*" (well this is currently the only one like that...) + if (pattern.at(patternLength - 1) == QLatin1Char('*')) + return PrefixPattern; + } + // Names without any wildcards like "README" + if (starCount == 0) + return LiteralPattern; + } + + if (pattern == QLatin1String("[0-9][0-9][0-9].vdr")) + return VdrPattern; + + if (pattern == QLatin1String("*.anim[1-9j]")) + return AnimPattern; + + return OtherPattern; +} + /*! \internal \class MimeGlobPattern @@ -92,55 +125,63 @@ void MimeGlobMatchResult::addMatch(const QString &mimeType, int weight, const QS \sa MimeType, MimeDatabase, MimeMagicRuleMatcher, MimeMagicRule */ -bool MimeGlobPattern::matchFileName(const QString &inputFilename) const +bool MimeGlobPattern::matchFileName(const QString &inputFileName) const { // "Applications MUST match globs case-insensitively, except when the case-sensitive // attribute is set to true." // The constructor takes care of putting case-insensitive patterns in lowercase. - const QString filename = m_caseSensitivity == Qt::CaseInsensitive ? inputFilename.toLower() : inputFilename; + const QString fileName = m_caseSensitivity == Qt::CaseInsensitive + ? inputFileName.toLower() : inputFileName; - const int pattern_len = m_pattern.length(); - if (!pattern_len) + const int patternLength = m_pattern.length(); + if (!patternLength) return false; - const int len = filename.length(); + const int fileNameLength = fileName.length(); - const int starCount = m_pattern.count(QLatin1Char('*')); + switch (m_patternType) { + case SuffixPattern: { + if (fileNameLength + 1 < patternLength) + return false; - // Patterns like "*~", "*.extension" - if (m_pattern[0] == QLatin1Char('*') && m_pattern.indexOf(QLatin1Char('[')) == -1 && starCount == 1) - { - if (len + 1 < pattern_len) return false; - - const QChar *c1 = m_pattern.unicode() + pattern_len - 1; - const QChar *c2 = filename.unicode() + len - 1; + const QChar *c1 = m_pattern.unicode() + patternLength - 1; + const QChar *c2 = fileName.unicode() + fileNameLength - 1; int cnt = 1; - while (cnt < pattern_len && *c1-- == *c2--) + while (cnt < patternLength && *c1-- == *c2--) ++cnt; - return cnt == pattern_len; + return cnt == patternLength; } - - // Patterns like "README*" (well this is currently the only one like that...) - if (starCount == 1 && m_pattern.at(pattern_len - 1) == QLatin1Char('*')) { - if (len + 1 < pattern_len) return false; - if (m_pattern.at(0) == QLatin1Char('*')) - return filename.indexOf(QStringView(m_pattern).mid(1, pattern_len - 2)) != -1; + case PrefixPattern: { + if (fileNameLength + 1 < patternLength) + return false; const QChar *c1 = m_pattern.unicode(); - const QChar *c2 = filename.unicode(); + const QChar *c2 = fileName.unicode(); int cnt = 1; - while (cnt < pattern_len && *c1++ == *c2++) + while (cnt < patternLength && *c1++ == *c2++) ++cnt; - return cnt == pattern_len; + return cnt == patternLength; } - - // Names without any wildcards like "README" - if (m_pattern.indexOf(QLatin1Char('[')) == -1 && starCount == 0 && m_pattern.indexOf(QLatin1Char('?'))) - return (m_pattern == filename); - - // Other (quite rare) patterns, like "*.anim[1-9j]": use slow but correct method - const QRegularExpression rx(QRegularExpression::anchoredPattern( + case LiteralPattern: + return (m_pattern == fileName); + case VdrPattern: // "[0-9][0-9][0-9].vdr" case + return fileNameLength == 7 + && fileName.at(0).isDigit() && fileName.at(1).isDigit() && fileName.at(2).isDigit() + && QStringView{fileName}.mid(3, 4) == QLatin1String(".vdr"); + case AnimPattern: { // "*.anim[1-9j]" case + if (fileNameLength < 6) + return false; + const QChar lastChar = fileName.at(fileNameLength - 1); + const bool lastCharOK = (lastChar.isDigit() && lastChar != QLatin1Char('0')) + || lastChar == QLatin1Char('j'); + return lastCharOK && QStringView{fileName}.mid(fileNameLength - 6, 5) == QLatin1String(".anim"); + } + case OtherPattern: + // Other fallback patterns: slow but correct method + const QRegularExpression rx(QRegularExpression::anchoredPattern( QRegularExpression::wildcardToRegularExpression(m_pattern))); - return rx.match(filename).hasMatch(); + return rx.match(fileName).hasMatch(); + } + return false; } static bool isFastPattern(const QString &pattern) diff --git a/src/libs/utils/mimetypes/mimeglobpattern_p.h b/src/libs/utils/mimetypes/mimeglobpattern_p.h index ecbfb02ce9..990a5b07d2 100644 --- a/src/libs/utils/mimetypes/mimeglobpattern_p.h +++ b/src/libs/utils/mimetypes/mimeglobpattern_p.h @@ -73,16 +73,27 @@ public: static const unsigned DefaultWeight = 50; static const unsigned MinWeight = 1; - explicit MimeGlobPattern(const QString &thePattern, const QString &theMimeType, unsigned theWeight = DefaultWeight, Qt::CaseSensitivity s = Qt::CaseInsensitive) : - m_pattern(thePattern), m_mimeType(theMimeType), m_weight(theWeight), m_caseSensitivity(s) + explicit MimeGlobPattern(const QString &thePattern, const QString &theMimeType, + unsigned theWeight = DefaultWeight, + Qt::CaseSensitivity s = Qt::CaseInsensitive) : + m_pattern(s == Qt::CaseInsensitive ? thePattern.toLower() : thePattern), + m_mimeType(theMimeType), + m_weight(theWeight), + m_caseSensitivity(s), + m_patternType(detectPatternType(m_pattern)) { - if (s == Qt::CaseInsensitive) { - m_pattern = m_pattern.toLower(); - } } - ~MimeGlobPattern() {} - bool matchFileName(const QString &filename) const; + void swap(MimeGlobPattern &other) noexcept + { + qSwap(m_pattern, other.m_pattern); + qSwap(m_mimeType, other.m_mimeType); + qSwap(m_weight, other.m_weight); + qSwap(m_caseSensitivity, other.m_caseSensitivity); + qSwap(m_patternType, other.m_patternType); + } + + bool matchFileName(const QString &inputFileName) const; inline const QString &pattern() const { return m_pattern; } inline unsigned weight() const { return m_weight; } @@ -90,10 +101,21 @@ public: inline bool isCaseSensitive() const { return m_caseSensitivity == Qt::CaseSensitive; } private: + enum PatternType { + SuffixPattern, + PrefixPattern, + LiteralPattern, + VdrPattern, // special handling for "[0-9][0-9][0-9].vdr" pattern + AnimPattern, // special handling for "*.anim[1-9j]" pattern + OtherPattern + }; + PatternType detectPatternType(const QString &pattern) const; + QString m_pattern; QString m_mimeType; int m_weight; Qt::CaseSensitivity m_caseSensitivity; + PatternType m_patternType; }; class MimeGlobPatternList : public QList<MimeGlobPattern> diff --git a/src/libs/utils/outputformatter.cpp b/src/libs/utils/outputformatter.cpp index 4efcae7646..cf6930cbe5 100644 --- a/src/libs/utils/outputformatter.cpp +++ b/src/libs/utils/outputformatter.cpp @@ -136,8 +136,10 @@ bool OutputLineParser::demoteErrorsToWarnings() const FilePath OutputLineParser::absoluteFilePath(const FilePath &filePath) const { - if (filePath.isEmpty() || filePath.toFileInfo().isAbsolute()) + if (filePath.isEmpty()) return filePath; + if (filePath.toFileInfo().isAbsolute()) + return filePath.cleanPath(); FilePaths candidates; for (const FilePath &dir : searchDirectories()) { FilePath candidate = dir.pathAppended(filePath.toString()); diff --git a/src/libs/utils/set_algorithm.h b/src/libs/utils/set_algorithm.h index 42a21f3f2d..97e33a047f 100644 --- a/src/libs/utils/set_algorithm.h +++ b/src/libs/utils/set_algorithm.h @@ -99,6 +99,24 @@ bool set_intersection_compare( return false; } +template<class InputIt1, class InputIt2, class Callable, class Compare> +void set_greedy_difference( + InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable call, Compare comp) +{ + while (first1 != last1 && first2 != last2) { + if (comp(*first1, *first2)) { + call(*first1++); + } else if (comp(*first2, *first1)) { + ++first2; + } else { + ++first1; + } + } + + while (first1 != last1) + call(*first1++); +} + template<typename InputIt1, typename InputIt2, typename BinaryPredicate, typename Callable, typename Value> Value mismatch_collect(InputIt1 first1, InputIt1 last1, diff --git a/src/libs/utils/threadutils.cpp b/src/libs/utils/threadutils.cpp new file mode 100644 index 0000000000..7d10199c4a --- /dev/null +++ b/src/libs/utils/threadutils.cpp @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "threadutils.h" + +#include <QCoreApplication> +#include <QThread> + +namespace Utils { + +bool isMainThread() +{ + return QThread::currentThread() == qApp->thread(); +} + +} // namespace Utils diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/ksyntaxhighlighting_export.h b/src/libs/utils/threadutils.h index a39adb5ed6..cc59658c27 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/ksyntaxhighlighting_export.h +++ b/src/libs/utils/threadutils.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -25,10 +25,11 @@ #pragma once -#include <QtGlobal> +#include "utils_global.h" + +namespace Utils { + +QTCREATOR_UTILS_EXPORT bool isMainThread(); + +} // namespace Utils -#if defined(KSYNTAXHIGHLIGHTING_LIBRARY) -# define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_EXPORT -#else -# define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_IMPORT -#endif diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index ddaae4bb69..a8280ba326 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -143,6 +143,7 @@ SOURCES += \ $$PWD/link.cpp \ $$PWD/linecolumn.cpp \ $$PWD/multitextcursor.cpp \ + $$PWD/threadutils.cpp \ $$PWD/singleton.cpp HEADERS += \ @@ -310,6 +311,7 @@ HEADERS += \ $$PWD/launchersocket.h \ $$PWD/qtcsettings.h \ $$PWD/multitextcursor.h \ + $$PWD/threadutils.h \ $$PWD/singleton.h FORMS += $$PWD/filewizardpage.ui \ diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index 77f80dd81b..6d888f87ac 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -298,6 +298,8 @@ Project { "textfileformat.h", "textutils.cpp", "textutils.h", + "threadutils.cpp", + "threadutils.h", "treemodel.cpp", "treemodel.h", "treeviewcombobox.cpp", diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index c769a744d2..7bc1c6310d 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -418,6 +418,28 @@ QString AndroidConfig::apiLevelNameFor(const SdkPlatform *platform) QString("android-%1").arg(platform->apiLevel()) : ""; } +int AndroidConfig::platformNameToApiLevel(const QString &platformName) +{ + int apiLevel = -1; + static const QRegularExpression re("(android-)(?<apiLevel>[0-9A-Z]{1,})", + QRegularExpression::CaseInsensitiveOption); + QRegularExpressionMatch match = re.match(platformName); + if (match.hasMatch()) { + QString apiLevelStr = match.captured("apiLevel"); + bool isUInt; + apiLevel = apiLevelStr.toUInt(&isUInt); + if (!isUInt) { + if (apiLevelStr == 'Q') + apiLevel = 29; + else if (apiLevelStr == 'R') + apiLevel = 30; + else if (apiLevelStr == 'S') + apiLevel = 31; + } + } + return apiLevel; +} + bool AndroidConfig::isCmdlineSdkToolsInstalled() const { QString toolPath("cmdline-tools/latest/bin/sdkmanager"); @@ -563,15 +585,10 @@ FilePath AndroidConfig::keytoolPath() const QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(QString *error) const { - return connectedDevices(adbToolPath(), error); -} - -QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(const FilePath &adbToolPath, QString *error) -{ QVector<AndroidDeviceInfo> devices; QtcProcess adbProc; adbProc.setTimeoutS(30); - CommandLine cmd{adbToolPath, {"devices"}}; + CommandLine cmd{adbToolPath(), {"devices"}}; adbProc.setCommand(cmd); adbProc.runBlocking(); if (adbProc.result() != QtcProcess::FinishedWithSuccess) { @@ -597,8 +614,8 @@ QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(const FilePath &adbTo AndroidDeviceInfo dev; dev.serialNumber = serialNo; dev.type = serialNo.startsWith(QLatin1String("emulator")) ? AndroidDeviceInfo::Emulator : AndroidDeviceInfo::Hardware; - dev.sdk = getSDKVersion(adbToolPath, dev.serialNumber); - dev.cpuAbi = getAbis(adbToolPath, dev.serialNumber); + dev.sdk = getSDKVersion(dev.serialNumber); + dev.cpuAbi = getAbis(dev.serialNumber); if (deviceType == QLatin1String("unauthorized")) dev.state = AndroidDeviceInfo::UnAuthorizedState; else if (deviceType == QLatin1String("offline")) @@ -633,10 +650,11 @@ bool AndroidConfig::isConnected(const QString &serialNumber) const return false; } -QString AndroidConfig::getDeviceProperty(const FilePath &adbToolPath, const QString &device, const QString &property) +QString AndroidConfig::getDeviceProperty(const QString &device, const QString &property) { // workaround for '????????????' serial numbers - CommandLine cmd(adbToolPath, AndroidDeviceInfo::adbSelector(device)); + CommandLine cmd(AndroidConfigurations::currentConfig().adbToolPath(), + AndroidDeviceInfo::adbSelector(device)); cmd.addArgs({"shell", "getprop", property}); QtcProcess adbProc; @@ -649,9 +667,9 @@ QString AndroidConfig::getDeviceProperty(const FilePath &adbToolPath, const QStr return adbProc.allOutput(); } -int AndroidConfig::getSDKVersion(const FilePath &adbToolPath, const QString &device) +int AndroidConfig::getSDKVersion(const QString &device) { - QString tmp = getDeviceProperty(adbToolPath, device, "ro.build.version.sdk"); + QString tmp = getDeviceProperty(device, "ro.build.version.sdk"); if (tmp.isEmpty()) return -1; return tmp.trimmed().toInt(); @@ -690,15 +708,37 @@ QString AndroidConfig::getAvdName(const QString &serialnumber) return QString::fromLatin1(name).trimmed(); } +static SdkToolResult emulatorNameAdbCommand(const QString &serialNumber) +{ + QStringList args = AndroidDeviceInfo::adbSelector(serialNumber); + args.append({"emu", "avd", "name"}); + return AndroidManager::runAdbCommand(args); +} + +QString AndroidConfig::getRunningAvdsSerialNumber(const QString &name) const +{ + for (const AndroidDeviceInfo &dev : connectedDevices()) { + if (!dev.serialNumber.startsWith("emulator")) + continue; + SdkToolResult result = emulatorNameAdbCommand(dev.serialNumber); + const QString stdOut = result.stdOut(); + if (stdOut.isEmpty()) + continue; // Not an avd + const QStringList outputLines = stdOut.split('\n'); + if (outputLines.size() > 1 && outputLines.first() == name) + return dev.serialNumber; + } + + return {}; +} + QStringList AndroidConfig::getRunningAvdsFromDevices(const QVector<AndroidDeviceInfo> &devs) { QStringList runningDevs; for (const AndroidDeviceInfo &dev : devs) { if (!dev.serialNumber.startsWith("emulator")) continue; - QStringList args = AndroidDeviceInfo::adbSelector(dev.serialNumber); - args.append({"emu", "avd", "name"}); - SdkToolResult result = AndroidManager::runAdbCommand(args); + SdkToolResult result = emulatorNameAdbCommand(dev.serialNumber); const QString stdOut = result.stdOut(); if (stdOut.isEmpty()) continue; // Not an avd @@ -742,7 +782,7 @@ QString AndroidConfig::getProductModel(const QString &device) const if (m_serialNumberToDeviceName.contains(device)) return m_serialNumberToDeviceName.value(device); - QString model = getDeviceProperty(adbToolPath(), device, "ro.product.model").trimmed(); + QString model = getDeviceProperty(device, "ro.product.model").trimmed(); if (model.isEmpty()) return device; @@ -751,15 +791,16 @@ QString AndroidConfig::getProductModel(const QString &device) const return model; } -QStringList AndroidConfig::getAbis(const FilePath &adbToolPath, const QString &device) +QStringList AndroidConfig::getAbis(const QString &device) { + const FilePath adbTool = AndroidConfigurations::currentConfig().adbToolPath(); QStringList result; // First try via ro.product.cpu.abilist QStringList arguments = AndroidDeviceInfo::adbSelector(device); arguments << "shell" << "getprop" << "ro.product.cpu.abilist"; QtcProcess adbProc; adbProc.setTimeoutS(10); - adbProc.setCommand({adbToolPath, arguments}); + adbProc.setCommand({adbTool, arguments}); adbProc.runBlocking(); if (adbProc.result() != QtcProcess::FinishedWithSuccess) return result; @@ -782,7 +823,7 @@ QStringList AndroidConfig::getAbis(const FilePath &adbToolPath, const QString &d QtcProcess abiProc; abiProc.setTimeoutS(10); - abiProc.setCommand({adbToolPath, arguments}); + abiProc.setCommand({adbTool, arguments}); abiProc.runBlocking(); if (abiProc.result() != QtcProcess::FinishedWithSuccess) return result; diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 09f7ac85f1..2fc22ddbc2 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -91,6 +91,7 @@ public: static QStringList apiLevelNamesFor(const SdkPlatformList &platforms); static QString apiLevelNameFor(const SdkPlatform *platform); + static int platformNameToApiLevel(const QString &platformName); Utils::FilePath sdkLocation() const; void setSdkLocation(const Utils::FilePath &sdkLocation); @@ -144,7 +145,6 @@ public: Utils::FilePath keytoolPath() const; QVector<AndroidDeviceInfo> connectedDevices(QString *error = nullptr) const; - static QVector<AndroidDeviceInfo> connectedDevices(const Utils::FilePath &adbToolPath, QString *error = nullptr); QString bestNdkPlatformMatch(int target, const QtSupport::BaseQtVersion *qtVersion) const; @@ -171,16 +171,16 @@ public: void setOpenSslLocation(const Utils::FilePath &openSslLocation); static Utils::FilePath getJdkPath(); - static QStringList getAbis(const Utils::FilePath &adbToolPath, const QString &device); + static QStringList getAbis(const QString &device); + QString getRunningAvdsSerialNumber(const QString &name) const; static QStringList getRunningAvdsFromDevices(const QVector<AndroidDeviceInfo> &devs); private: - static QString getDeviceProperty(const Utils::FilePath &adbToolPath, - const QString &device, const QString &property); + static QString getDeviceProperty(const QString &device, const QString &property); Utils::FilePath openJDKBinPath() const; - static int getSDKVersion(const Utils::FilePath &adbToolPath, const QString &device); + static int getSDKVersion(const QString &device); static QString getAvdName(const QString &serialnumber); void parseDependenciesJson(); diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 8c50c7a52c..0910f483d6 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -88,10 +88,11 @@ AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Utils::Id id) : BuildStep(parent, id) { setImmutable(true); + setUserExpanded(true); m_uninstallPreviousPackage = addAspect<BoolAspect>(); m_uninstallPreviousPackage->setSettingsKey(UninstallPreviousPackageKey); - m_uninstallPreviousPackage->setLabel(tr("Uninstall the existing app first"), + m_uninstallPreviousPackage->setLabel(tr("Uninstall the existing app before deployment"), BoolAspect::LabelPlacement::AtCheckBox); m_uninstallPreviousPackage->setValue(false); diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index bba148dda8..ea4ddbf8e1 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -151,7 +151,7 @@ AndroidDevice::AndroidDevice() setOsType(Utils::OsTypeOtherUnix); setDeviceState(DeviceConnected); - addDeviceAction({tr("Refresh"), [](const IDevice::Ptr &device, QWidget *parent) { + addDeviceAction({tr("Refresh"), [](const IDevice::Ptr &, QWidget *) { AndroidDeviceManager::instance()->updateDevicesListOnce(); }}); @@ -334,7 +334,11 @@ bool AndroidDevice::isValid() const QString AndroidDevice::serialNumber() const { - return extraData(Constants::AndroidSerialNumber).toString(); + const QString serialNumber = extraData(Constants::AndroidSerialNumber).toString(); + if (machineType() == Hardware) + return serialNumber; + + return AndroidConfigurations::currentConfig().getRunningAvdsSerialNumber(avdName()); } QString AndroidDevice::avdName() const @@ -614,8 +618,8 @@ AndroidDeviceManager *AndroidDeviceManager::instance() AndroidDeviceManager::AndroidDeviceManager(QObject *parent) : QObject(parent), - m_androidConfig(AndroidConfigurations::currentConfig()), - m_avdManager(m_androidConfig) + m_avdManager(m_androidConfig), + m_androidConfig(AndroidConfigurations::currentConfig()) { connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() { m_devicesUpdaterTimer.stop(); diff --git a/src/plugins/android/androidqmlpreviewworker.cpp b/src/plugins/android/androidqmlpreviewworker.cpp index 3c2adca572..bb95616eac 100644 --- a/src/plugins/android/androidqmlpreviewworker.cpp +++ b/src/plugins/android/androidqmlpreviewworker.cpp @@ -254,7 +254,7 @@ bool AndroidQmlPreviewWorker::ensureAvdIsRunning() appendMessage(tr("Could not start AVD."), ErrorMessageFormat); } else { m_serialNumber = devInfoLocal.serialNumber; - m_avdAbis = m_androidConfig.getAbis(m_androidConfig.adbToolPath(), m_serialNumber); + m_avdAbis = m_androidConfig.getAbis(m_serialNumber); } return !devInfoLocal.serialNumber.isEmpty(); } else { @@ -262,7 +262,7 @@ bool AndroidQmlPreviewWorker::ensureAvdIsRunning() } return false; } - m_avdAbis = m_androidConfig.getAbis(m_androidConfig.adbToolPath(), m_serialNumber); + m_avdAbis = m_androidConfig.getAbis(m_serialNumber); return true; } diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp index e1477c2615..b0b3c58f99 100644 --- a/src/plugins/android/androidrunconfiguration.cpp +++ b/src/plugins/android/androidrunconfiguration.cpp @@ -90,17 +90,10 @@ AndroidRunConfiguration::AndroidRunConfiguration(Target *target, Utils::Id id) auto amStartArgsAspect = addAspect<StringAspect>(); amStartArgsAspect->setId(Constants::ANDROID_AM_START_ARGS); amStartArgsAspect->setSettingsKey("Android.AmStartArgsKey"); - amStartArgsAspect->setLabelText(tr("Activity manager start options:")); + amStartArgsAspect->setLabelText(tr("Activity manager start arguments:")); amStartArgsAspect->setDisplayStyle(StringAspect::LineEditDisplay); amStartArgsAspect->setHistoryCompleter("Android.AmStartArgs.History"); - auto warning = addAspect<StringAspect>(); - warning->setDisplayStyle(StringAspect::LabelDisplay); - warning->setLabelPixmap(Icons::WARNING.pixmap()); - warning->setValue(tr("If the \"am start\" options conflict, the application might not start.\n" - "%1 uses: am start -n <package_name>/<Activity_name> [-D].") - .arg(Core::Constants::IDE_DISPLAY_NAME)); - auto preStartShellCmdAspect = addAspect<BaseStringListAspect>(); preStartShellCmdAspect->setDisplayStyle(StringAspect::TextEditDisplay); preStartShellCmdAspect->setId(Constants::ANDROID_PRESTARTSHELLCMDLIST); diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 83c512a46a..759eba59e4 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -552,7 +552,6 @@ void AndroidRunnerWorker::asyncStartHelper() runAdb(entry.split(' ', Qt::SkipEmptyParts)); QStringList args({"shell", "am", "start"}); - args << m_amStartExtraArgs; args << "-n" << m_intentName; if (m_useCppDebugger) { args << "-D"; @@ -636,6 +635,7 @@ void AndroidRunnerWorker::asyncStartHelper() } } + args << m_amStartExtraArgs; if (!m_extraAppParams.isEmpty()) { QStringList appArgs = diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index 943e371178..eaa6996014 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -69,28 +69,6 @@ Q_GLOBAL_STATIC_WITH_ARGS(QRegularExpression, assertionReg, using namespace Utils; using SdkCmdFutureInterface = QFutureInterface<AndroidSdkManager::OperationOutput>; -int platformNameToApiLevel(const QString &platformName) -{ - int apiLevel = -1; - QRegularExpression re("(android-)(?<apiLevel>[0-9A-Z]{1,})", - QRegularExpression::CaseInsensitiveOption); - QRegularExpressionMatch match = re.match(platformName); - if (match.hasMatch()) { - QString apiLevelStr = match.captured("apiLevel"); - bool isUInt; - apiLevel = apiLevelStr.toUInt(&isUInt); - if (!isUInt) { - if (apiLevelStr == 'Q') - apiLevel = 29; - else if (apiLevelStr == 'R') - apiLevel = 30; - else if (apiLevelStr == 'S') - apiLevel = 31; - } - } - return apiLevel; -} - /*! Parses the \a line for a [spaces]key[spaces]value[spaces] pattern and returns \c true if \a key is found, false otherwise. Result is copied into \a value. @@ -714,7 +692,7 @@ AndroidSdkPackage *SdkManagerOutputParser::parsePlatform(const QStringList &data SdkPlatform *platform = nullptr; GenericPackageData packageData; if (parseAbstractData(packageData, data, 2, "Platform")) { - int apiLevel = platformNameToApiLevel(packageData.headerParts.at(1)); + const int apiLevel = AndroidConfig::platformNameToApiLevel(packageData.headerParts.at(1)); if (apiLevel == -1) { qCDebug(sdkManagerLog) << "Platform: Cannot parse api level:"<< data; return nullptr; @@ -734,7 +712,7 @@ QPair<SystemImage *, int> SdkManagerOutputParser::parseSystemImage(const QString QPair <SystemImage *, int> result(nullptr, -1); GenericPackageData packageData; if (parseAbstractData(packageData, data, 4, "System-image")) { - int apiLevel = platformNameToApiLevel(packageData.headerParts.at(1)); + const int apiLevel = AndroidConfig::platformNameToApiLevel(packageData.headerParts.at(1)); if (apiLevel == -1) { qCDebug(sdkManagerLog) << "System-image: Cannot parse api level:"<< data; return result; diff --git a/src/plugins/android/androidsdkmanagerwidget.cpp b/src/plugins/android/androidsdkmanagerwidget.cpp index c576571d32..0fe8b83d31 100644 --- a/src/plugins/android/androidsdkmanagerwidget.cpp +++ b/src/plugins/android/androidsdkmanagerwidget.cpp @@ -98,12 +98,10 @@ AndroidSdkManagerWidget::AndroidSdkManagerWidget(AndroidConfig &config, auto proxyModel = new PackageFilterModel(m_sdkModel); m_ui->packagesView->setModel(proxyModel); + m_ui->packagesView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); m_ui->packagesView->header()->setSectionResizeMode(AndroidSdkModel::packageNameColumn, - QHeaderView::ResizeToContents); - m_ui->packagesView->header()->setSectionResizeMode(AndroidSdkModel::apiLevelColumn, - QHeaderView::ResizeToContents); - m_ui->packagesView->header()->setSectionResizeMode(AndroidSdkModel::packageRevisionColumn, - QHeaderView::ResizeToContents); + QHeaderView::Stretch); + m_ui->packagesView->header()->setStretchLastSection(false); connect(m_ui->expandCheck, &QCheckBox::stateChanged, [this](int state) { if (state == Qt::Checked) m_ui->packagesView->expandAll(); @@ -133,7 +131,6 @@ AndroidSdkManagerWidget::AndroidSdkManagerWidget(AndroidConfig &config, m_ui->searchField->setPlaceholderText("Filter"); connect(m_ui->searchField, &QLineEdit::textChanged, [this, proxyModel](const QString &text) { - const bool isExpanded = m_ui->expandCheck->isChecked(); proxyModel->setAcceptedSearchPackage(text); m_sdkModel->resetSelection(); // It is more convenient to expand the view with the results @@ -513,7 +510,7 @@ bool PackageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sour } } - return showTopLevel || (packageState(srcIndex) & m_packageState) && packageFound(srcIndex); + return showTopLevel || ((packageState(srcIndex) & m_packageState) && packageFound(srcIndex)); } OptionsDialog::OptionsDialog(AndroidSdkManager *sdkManager, const QStringList &args, diff --git a/src/plugins/android/androidsdkmodel.cpp b/src/plugins/android/androidsdkmodel.cpp index 2f83e86156..2d0e7af83e 100644 --- a/src/plugins/android/androidsdkmodel.cpp +++ b/src/plugins/android/androidsdkmodel.cpp @@ -40,7 +40,7 @@ static Q_LOGGING_CATEGORY(androidSdkModelLog, "qtc.android.sdkmodel", QtWarningM namespace Android { namespace Internal { -const int packageColCount = 4; +const int packageColCount = 3; AndroidSdkModel::AndroidSdkModel(const AndroidConfig &config, AndroidSdkManager *sdkManager, QObject *parent) @@ -74,9 +74,6 @@ QVariant AndroidSdkModel::headerData(int section, Qt::Orientation orientation, i case apiLevelColumn: data = tr("API"); break; - case operationColumn: - data = tr("Operation"); - break; default: break; } @@ -162,7 +159,6 @@ QVariant AndroidSdkModel::data(const QModelIndex &index, int role) const if (!index.isValid()) return QVariant(); - if (!index.parent().isValid()) { // Top level tools if (index.row() == 0) { @@ -202,25 +198,29 @@ QVariant AndroidSdkModel::data(const QModelIndex &index, int role) const return p->revision().toString(); case apiLevelColumn: return apiLevelStr; - case operationColumn: - if (p->type() == AndroidSdkPackage::SdkToolsPackage && - p->state() == AndroidSdkPackage::Installed) { - return tr("Update Only"); - } else { - return p->state() == AndroidSdkPackage::Installed ? tr("Uninstall") : tr("Install"); - } default: break; } } - if (role == Qt::DecorationRole && index.column() == packageNameColumn) { - return p->state() == AndroidSdkPackage::Installed ? Utils::Icons::OK.icon() : - Utils::Icons::EMPTY16.icon(); + if (index.column() == packageNameColumn) { + if (role == Qt::CheckStateRole) { + if (p->state() == AndroidSdkPackage::Installed) + return m_changeState.contains(p) ? Qt::Unchecked : Qt::Checked; + else + return m_changeState.contains(p) ? Qt::Checked : Qt::Unchecked; + } + + if (role == Qt::FontRole) { + QFont font; + if (m_changeState.contains(p)) + font.setBold(true); + return font; + } } - if (role == Qt::CheckStateRole && index.column() == operationColumn ) - return m_changeState.contains(p) ? Qt::Checked : Qt::Unchecked; + if (role == Qt::TextAlignmentRole && index.column() == packageRevisionColumn) + return Qt::AlignRight; if (role == Qt::ToolTipRole) return QString("%1 - (%2)").arg(p->descriptionText()).arg(p->sdkStylePath()); @@ -245,14 +245,14 @@ QHash<int, QByteArray> AndroidSdkModel::roleNames() const Qt::ItemFlags AndroidSdkModel::flags(const QModelIndex &index) const { Qt::ItemFlags f = QAbstractItemModel::flags(index); - if (index.column() == operationColumn) + if (index.column() == packageNameColumn) f |= Qt::ItemIsUserCheckable; void *ip = index.internalPointer(); - if (ip && index.column() == operationColumn) { + if (ip && index.column() == packageNameColumn) { auto package = static_cast<const AndroidSdkPackage *>(ip); - if (package->state() == AndroidSdkPackage::Installed && - package->type() == AndroidSdkPackage::SdkToolsPackage) { + if (package->state() == AndroidSdkPackage::Installed + && package->type() == AndroidSdkPackage::SdkToolsPackage) { f &= ~Qt::ItemIsEnabled; } } @@ -264,11 +264,14 @@ bool AndroidSdkModel::setData(const QModelIndex &index, const QVariant &value, i void *ip = index.internalPointer(); if (ip && role == Qt::CheckStateRole) { auto package = static_cast<const AndroidSdkPackage *>(ip); - if (value.toInt() == Qt::Checked) { + if (value.toInt() == Qt::Checked && package->state() != AndroidSdkPackage::Installed) { m_changeState << package; emit dataChanged(index, index, {Qt::CheckStateRole}); } else if (m_changeState.remove(package)) { emit dataChanged(index, index, {Qt::CheckStateRole}); + } else if (value.toInt() == Qt::Unchecked) { + m_changeState.insert(package); + emit dataChanged(index, index, {Qt::CheckStateRole}); } return true; } diff --git a/src/plugins/android/androidsdkmodel.h b/src/plugins/android/androidsdkmodel.h index af25edfbb8..4a8d363a13 100644 --- a/src/plugins/android/androidsdkmodel.h +++ b/src/plugins/android/androidsdkmodel.h @@ -42,8 +42,7 @@ public: enum PackageColumn { packageNameColumn = 0, apiLevelColumn, - packageRevisionColumn, - operationColumn + packageRevisionColumn }; enum ExtraRoles { diff --git a/src/plugins/android/avdmanageroutputparser.cpp b/src/plugins/android/avdmanageroutputparser.cpp index 0ca8a74e73..ac758f41c7 100644 --- a/src/plugins/android/avdmanageroutputparser.cpp +++ b/src/plugins/android/avdmanageroutputparser.cpp @@ -24,6 +24,7 @@ ****************************************************************************/ #include "avdmanageroutputparser.h" +#include "androidconfigurations.h" #include <projectexplorer/projectexplorerconstants.h> #include <utils/algorithm.h> @@ -97,7 +98,7 @@ static Utils::optional<AndroidDeviceInfo> parseAvd(const QStringList &deviceInfo QSettings avdInfo(avdInfoFile.toString(), QSettings::IniFormat); value = avdInfo.value(avdInfoTargetKey).toString(); if (!value.isEmpty()) - avd.sdk = value.section('-', -1).toInt(); + avd.sdk = AndroidConfig::platformNameToApiLevel(value); else qCDebug(avdOutputParserLog) << "Avd Parsing: Cannot find sdk API:" << avdInfoFile.toString(); diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index a6ead8c3fe..3a13c4542d 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -82,7 +82,7 @@ void ClangCodeModelPlugin::generateCompilationDB() QFuture<GenerateCompilationDbResult> task = QtConcurrent::run(&Internal::generateCompilationDB, projectInfo, - CompilationDbPurpose::Project, + projectInfo->buildRoot(), CompilationDbPurpose::Project, warningsConfigForProject(target->project()), optionsForProject(target->project())); Core::ProgressManager::addTask(task, tr("Generating Compilation DB"), "generate compilation db"); diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index af964f5be9..1d924f8b2d 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -36,6 +36,7 @@ #include <cppeditor/cppdoxygen.h> #include <cppeditor/cppmodelmanager.h> +#include <cppeditor/cpptoolsreuse.h> #include <cppeditor/editordocumenthandle.h> #include <texteditor/codeassist/assistproposalitem.h> @@ -44,10 +45,7 @@ #include <texteditor/codeassist/ifunctionhintproposalmodel.h> #include <texteditor/texteditorsettings.h> -#include <cplusplus/BackwardsScanner.h> -#include <cplusplus/ExpressionUnderCursor.h> #include <cplusplus/Icons.h> -#include <cplusplus/SimpleLexer.h> #include <clangsupport/filecontainer.h> @@ -431,37 +429,8 @@ bool ClangCompletionAssistProcessor::accepts() const if (pos - startOfName >= TextEditorSettings::completionSettings().m_characterThreshold) { const QChar firstCharacter = m_interface->characterAt(startOfName); if (firstCharacter.isLetter() || firstCharacter == QLatin1Char('_')) { - // Finally check that we're not inside a comment or string (code copied from startOfOperator) - QTextCursor tc(m_interface->textDocument()); - tc.setPosition(pos); - - SimpleLexer tokenize; - LanguageFeatures lf = tokenize.languageFeatures(); - lf.qtMocRunEnabled = true; - lf.objCEnabled = true; - tokenize.setLanguageFeatures(lf); - tokenize.setSkipComments(false); - const Tokens &tokens = tokenize(tc.block().text(), BackwardsScanner::previousBlockState(tc.block())); - const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1)); - const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx); - - if (!tk.isComment() && !tk.isLiteral()) { - return true; - } else if (tk.isLiteral() - && tokens.size() == 3 - && tokens.at(0).kind() == T_POUND - && tokens.at(1).kind() == T_IDENTIFIER) { - const QString &line = tc.block().text(); - const Token &idToken = tokens.at(1); - QStringView identifier = Utils::midView(line, - idToken.utf16charsBegin(), - idToken.utf16chars()); - if (identifier == QLatin1String("include") - || identifier == QLatin1String("include_next") - || (m_interface->objcEnabled() && identifier == QLatin1String("import"))) { - return true; - } - } + return !CppEditor::isInCommentOrString(m_interface.data(), + m_interface->languageFeatures()); } } } diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 5b3e76bee8..2b6044f3ac 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -94,8 +94,22 @@ static Q_LOGGING_CATEGORY(clangdLogServer, "qtc.clangcodemodel.clangd.server", Q static Q_LOGGING_CATEGORY(clangdLogAst, "qtc.clangcodemodel.clangd.ast", QtWarningMsg); static Q_LOGGING_CATEGORY(clangdLogHighlight, "qtc.clangcodemodel.clangd.highlight", QtWarningMsg); static Q_LOGGING_CATEGORY(clangdLogTiming, "qtc.clangcodemodel.clangd.timing", QtWarningMsg); +static Q_LOGGING_CATEGORY(clangdLogCompletion, "qtc.clangcodemodel.clangd.completion", + QtWarningMsg); static QString indexingToken() { return "backgroundIndexProgress"; } +static QStringView subViewLen(const QString &s, qsizetype start, qsizetype length) +{ + if (start < 0 || length < 0 || start + length > s.length()) + return {}; + return QStringView(s).mid(start, length); +} + +static QStringView subViewEnd(const QString &s, qsizetype start, qsizetype end) +{ + return subViewLen(s, start, end - start); +} + class AstNode : public JsonObject { public: @@ -277,6 +291,58 @@ public: - openingQuoteOffset - 1); } + enum class FileStatus { Ours, Foreign, Mixed, Unknown }; + FileStatus fileStatus(const Utils::FilePath &thisFile) const + { + const Utils::optional<QString> arcanaString = arcana(); + if (!arcanaString) + return FileStatus::Unknown; + + // Example arcanas: + // "FunctionDecl 0x7fffb5d0dbd0 </tmp/test.cpp:1:1, line:5:1> line:1:6 func 'void ()'" + // "VarDecl 0x7fffb5d0dcf0 </tmp/test.cpp:2:5, /tmp/test.h:1:1> /tmp/test.cpp:2:10 b 'bool' cinit" + // The second one is for a particularly silly construction where the RHS of an + // initialization comes from an included header. + const int openPos = arcanaString->indexOf('<'); + if (openPos == -1) + return FileStatus::Unknown; + const int closePos = arcanaString->indexOf('>', openPos + 1); + if (closePos == -1) + return FileStatus::Unknown; + bool hasOurs = false; + bool hasOther = false; + for (int startPos = openPos + 1; startPos < closePos;) { + int colon1Pos = arcanaString->indexOf(':', startPos); + if (colon1Pos == -1 || colon1Pos > closePos) + break; + if (Utils::HostOsInfo::isWindowsHost()) + colon1Pos = arcanaString->indexOf(':', colon1Pos + 1); + if (colon1Pos == -1 || colon1Pos > closePos) + break; + const int colon2Pos = arcanaString->indexOf(':', colon1Pos + 2); + if (colon2Pos == -1 || colon2Pos > closePos) + break; + const int line = subViewEnd(*arcanaString, colon1Pos + 1, colon2Pos).toString().toInt(); // TODO: Drop toString() once we require >= Qt 5.15 + if (line == 0) + break; + const QStringView fileOrLineString = subViewEnd(*arcanaString, startPos, colon1Pos); + if (fileOrLineString != QLatin1String("line")) { + if (Utils::FilePath::fromUserInput(fileOrLineString.toString()) == thisFile) + hasOurs = true; + else + hasOther = true; + } + const int commaPos = arcanaString->indexOf(',', colon2Pos + 2); + if (commaPos != -1) + startPos = commaPos + 2; + else + break; + } + if (hasOurs) + return hasOther ? FileStatus::Mixed : FileStatus::Ours; + return hasOther ? FileStatus::Foreign : FileStatus::Unknown; + } + // For debugging. void print(int indent = 0) const { @@ -298,6 +364,7 @@ static QList<AstNode> getAstPath(const AstNode &root, const Range &range) QList<AstNode> path; QList<AstNode> queue{root}; bool isRoot = true; + while (!queue.isEmpty()) { AstNode curNode = queue.takeFirst(); if (!isRoot && !curNode.hasRange()) @@ -309,13 +376,39 @@ static QList<AstNode> getAstPath(const AstNode &root, const Range &range) const auto children = curNode.children(); if (!children) break; - queue = children.value(); + if (curNode.kind() == "Function" || curNode.role() == "expression") { + // Functions and expressions can contain implicit nodes that make the list unsorted. + // They cannot be ignored, as we need to consider them in certain contexts. + // Therefore, the binary search cannot be used here. + queue = *children; + } else { + queue.clear(); + + // Class and struct nodes can contain implicit constructors, destructors and + // operators, which appear at the end of the list, but whose range is the same + // as the class name. Therefore, we must force them not to compare less to + // anything else. + static const auto leftOfRange = [](const AstNode &node, const Range &range) { + return node.range().isLeftOf(range) && !node.arcanaContains(" implicit "); + }; + + for (auto it = std::lower_bound(children->cbegin(), children->cend(), range, + leftOfRange); + it != children->cend() && !range.isLeftOf(it->range()); ++it) { + queue << *it; + } + } } isRoot = false; } return path; } +static QList<AstNode> getAstPath(const AstNode &root, const Position &pos) +{ + return getAstPath(root, Range(pos, pos)); +} + static Usage::Type getUsageType(const QList<AstNode> &path) { bool potentialWrite = false; @@ -685,20 +778,12 @@ private: case CustomAssistMode::Preprocessor: static QIcon macroIcon = Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::Macro); for (const QString &completion - : CppEditor::CppCompletionAssistProcessor::preprocessorCompletions()) + : CppEditor::CppCompletionAssistProcessor::preprocessorCompletions()) { completions << createItem(completion, macroIcon); - const CppEditor::ProjectFile::Kind fileType - = CppEditor::ProjectFile::classify(interface->filePath().toString()); - switch (fileType) { - case CppEditor::ProjectFile::ObjCHeader: - case CppEditor::ProjectFile::ObjCXXHeader: - case CppEditor::ProjectFile::ObjCSource: - case CppEditor::ProjectFile::ObjCXXSource: - completions << createItem("import", macroIcon); - break; - default: - break; } + if (CppEditor::ProjectFile::isObjC(interface->filePath().toString())) + completions << createItem("import", macroIcon); + break; } GenericProposalModelPtr model(new GenericProposalModel); model->loadContent(completions); @@ -1030,12 +1115,14 @@ public: ClangdCompletionAssistProvider(ClangdClient *client); private: - IAssistProcessor *createProcessor(const AssistInterface *assistInterface) const override; + IAssistProcessor *createProcessor(const AssistInterface *interface) const override; int activationCharSequenceLength() const override { return 3; } bool isActivationCharSequence(const QString &sequence) const override; bool isContinuationChar(const QChar &c) const override; + bool isInCommentOrString(const AssistInterface *interface) const; + ClangdClient * const m_client; }; @@ -1048,6 +1135,7 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir) "text/x-c++hdr", "text/x-c++src", "text/x-objc++src", "text/x-objcsrc"}; setSupportedLanguage(langFilter); setActivateDocumentAutomatically(true); + setLogTarget(LogTarget::Console); setCompletionAssistProvider(new ClangdCompletionAssistProvider(this)); if (!project) { QJsonObject initOptions; @@ -1643,7 +1731,7 @@ void ClangdClient::findLocalUsages(TextDocument *document, const QTextCursor &cu } const Position linkPos(link.targetLine - 1, link.targetColumn); - const QList<AstNode> astPath = getAstPath(ast, Range(linkPos, linkPos)); + const QList<AstNode> astPath = getAstPath(ast, linkPos); bool isVar = false; for (auto it = astPath.rbegin(); it != astPath.rend(); ++it) { if (it->role() == "declaration" && it->kind() == "Function") { @@ -2128,7 +2216,8 @@ class ExtraHighlightingResultsCollector { public: ExtraHighlightingResultsCollector(QFutureInterface<HighlightingResult> &future, - HighlightingResults &results, const AstNode &ast, + HighlightingResults &results, + const Utils::FilePath &filePath, const AstNode &ast, const QTextDocument *doc, const QString &docContent); void collect(); @@ -2145,6 +2234,7 @@ private: QFutureInterface<HighlightingResult> &m_future; HighlightingResults &m_results; + const Utils::FilePath m_filePath; const AstNode &m_ast; const QTextDocument * const m_doc; const QString &m_docContent; @@ -2174,7 +2264,7 @@ static QList<BlockRange> cleanupDisabledCode(HighlightingResults &results, const if (!wasIfdefedOut) rangeStartPos = doc->findBlockByNumber(it->line - 1).position(); const int pos = Utils::Text::positionInText(doc, it->line, it->column); - const QStringView content(QStringView(docContent).mid(pos, it->length).trimmed()); + const QStringView content = subViewLen(docContent, pos, it->length).trimmed(); if (!content.startsWith(QLatin1String("#if")) && !content.startsWith(QLatin1String("#elif")) && !content.startsWith(QLatin1String("#else")) @@ -2210,6 +2300,7 @@ static QList<BlockRange> cleanupDisabledCode(HighlightingResults &results, const } static void semanticHighlighter(QFutureInterface<HighlightingResult> &future, + const Utils::FilePath &filePath, const QList<ExpandedSemanticToken> &tokens, const QString &docContents, const AstNode &ast, const QPointer<TextEditorWidget> &widget, @@ -2222,13 +2313,17 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future, } const QTextDocument doc(docContents); - const auto isOutputParameter = [&ast](const ExpandedSemanticToken &token) { + const auto tokenRange = [&doc](const ExpandedSemanticToken &token) { + const Position startPos(token.line - 1, token.column - 1); + const Position endPos = startPos.withOffset(token.length, &doc); + return Range(startPos, endPos); + }; + const auto isOutputParameter = [&ast, &doc, &tokenRange](const ExpandedSemanticToken &token) { if (token.modifiers.contains("usedAsMutableReference")) return true; if (token.type != "variable" && token.type != "property" && token.type != "parameter") return false; - const Position pos(token.line - 1, token.column - 1); - const QList<AstNode> path = getAstPath(ast, Range(pos, pos)); + const QList<AstNode> path = getAstPath(ast, tokenRange(token)); if (path.size() < 2) return false; if (path.last().hasConstType()) @@ -2249,7 +2344,8 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future, }; const std::function<HighlightingResult(const ExpandedSemanticToken &)> toResult - = [&ast, &isOutputParameter, &clangdVersion](const ExpandedSemanticToken &token) { + = [&ast, &isOutputParameter, &clangdVersion, &tokenRange] + (const ExpandedSemanticToken &token) { TextStyles styles; if (token.type == "variable") { if (token.modifiers.contains("functionScope")) { @@ -2263,8 +2359,7 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future, } else if (token.type == "function" || token.type == "method") { styles.mainStyle = token.modifiers.contains("virtual") ? C_VIRTUAL_METHOD : C_FUNCTION; if (ast.isValid()) { - const Position pos(token.line - 1, token.column - 1); - const QList<AstNode> path = getAstPath(ast, Range(pos, pos)); + const QList<AstNode> path = getAstPath(ast, tokenRange(token)); if (path.length() > 1) { const AstNode declNode = path.at(path.length() - 2); if (declNode.kind() == "Function" || declNode.kind() == "CXXMethod") { @@ -2283,8 +2378,7 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future, // clang hardly ever differentiates between constructors and the associated class, // whereas we highlight constructors as functions. if (ast.isValid()) { - const Position pos(token.line - 1, token.column - 1); - const QList<AstNode> path = getAstPath(ast, Range(pos, pos)); + const QList<AstNode> path = getAstPath(ast, tokenRange(token)); if (!path.isEmpty()) { if (path.last().kind() == "CXXConstructor") { if (!path.last().arcanaContains("implicit")) @@ -2338,7 +2432,7 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future, if (widget && widget->textDocument()->document()->revision() == docRevision) widget->setIfdefedOutBlocks(ifdefedOutBlocks); }, Qt::QueuedConnection); - ExtraHighlightingResultsCollector(future, results, ast, &doc, docContents).collect(); + ExtraHighlightingResultsCollector(future, results, filePath, ast, &doc, docContents).collect(); if (!future.isCanceled()) { qCDebug(clangdLog) << "reporting" << results.size() << "highlighting results"; future.reportResults(QVector<HighlightingResult>(results.cbegin(), @@ -2378,10 +2472,12 @@ void ClangdClient::Private::handleSemanticTokens(TextDocument *doc, IEditor * const editor = Utils::findOrDefault(EditorManager::visibleEditors(), [doc](const IEditor *editor) { return editor->document() == doc; }); const auto editorWidget = TextEditorWidget::fromEditor(editor); - const auto runner = [tokens, text = doc->document()->toPlainText(), ast, + const auto runner = [tokens, filePath = doc->filePath(), + text = doc->document()->toPlainText(), ast, w = QPointer(editorWidget), rev = doc->document()->revision(), clangdVersion = q->versionNumber()] { - return Utils::runAsync(semanticHighlighter, tokens, text, ast, w, rev, clangdVersion); + return Utils::runAsync(semanticHighlighter, filePath, tokens, text, ast, w, rev, + clangdVersion); }; if (isTesting) { @@ -2543,21 +2639,28 @@ ClangdClient::ClangdCompletionAssistProvider::ClangdCompletionAssistProvider(Cla {} IAssistProcessor *ClangdClient::ClangdCompletionAssistProvider::createProcessor( - const AssistInterface *assistInterface) const -{ - ClangCompletionContextAnalyzer contextAnalyzer(assistInterface->textDocument(), - assistInterface->position(), false, {}); + const AssistInterface *interface) const +{ + qCDebug(clangdLogCompletion) << "completion processor requested for" << interface->filePath(); + qCDebug(clangdLogCompletion) << "text before cursor is" + << interface->textAt(interface->position(), -10); + qCDebug(clangdLogCompletion) << "text after cursor is" + << interface->textAt(interface->position(), 10); + ClangCompletionContextAnalyzer contextAnalyzer(interface->textDocument(), + interface->position(), false, {}); contextAnalyzer.analyze(); switch (contextAnalyzer.completionAction()) { case ClangCompletionContextAnalyzer::PassThroughToLibClangAfterLeftParen: - qCDebug(clangdLog) << "completion changed to function hint"; + qCDebug(clangdLogCompletion) << "creating function hint processor"; return new ClangdFunctionHintProcessor(m_client); case ClangCompletionContextAnalyzer::CompleteDoxygenKeyword: + qCDebug(clangdLogCompletion) << "creating doxygen processor"; return new CustomAssistProcessor(m_client, contextAnalyzer.positionForProposal(), contextAnalyzer.completionOperator(), CustomAssistMode::Doxygen); case ClangCompletionContextAnalyzer::CompletePreprocessorDirective: + qCDebug(clangdLogCompletion) << "creating macro processor"; return new CustomAssistProcessor(m_client, contextAnalyzer.positionForProposal(), contextAnalyzer.completionOperator(), @@ -2565,9 +2668,11 @@ IAssistProcessor *ClangdClient::ClangdCompletionAssistProvider::createProcessor( default: break; } - const QString snippetsGroup = contextAnalyzer.addSnippets() + const QString snippetsGroup = contextAnalyzer.addSnippets() && !isInCommentOrString(interface) ? CppEditor::Constants::CPP_SNIPPETS_GROUP_ID : QString(); + qCDebug(clangdLogCompletion) << "creating proper completion processor" + << (snippetsGroup.isEmpty() ? "without" : "with") << "snippets"; return new ClangdCompletionAssistProcessor(m_client, snippetsGroup); } @@ -2588,6 +2693,7 @@ bool ClangdClient::ClangdCompletionAssistProvider::isActivationCharSequence(cons // contexts, such as '(', '<' or '/'. switch (kind) { case T_DOT: case T_COLON_COLON: case T_ARROW: case T_DOT_STAR: case T_ARROW_STAR: case T_POUND: + qCDebug(clangdLogCompletion) << "detected" << sequence << "as activation char sequence"; return true; } return false; @@ -2598,6 +2704,14 @@ bool ClangdClient::ClangdCompletionAssistProvider::isContinuationChar(const QCha return CppEditor::isValidIdentifierChar(c); } +bool ClangdClient::ClangdCompletionAssistProvider::isInCommentOrString( + const AssistInterface *interface) const +{ + LanguageFeatures features = LanguageFeatures::defaultFeatures(); + features.objCEnabled = CppEditor::ProjectFile::isObjC(interface->filePath().toString()); + return CppEditor::isInCommentOrString(interface, features); +} + void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, int /*basePosition*/) const { @@ -2607,35 +2721,27 @@ void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, if (!edit) return; - const auto kind = static_cast<CompletionItemKind::Kind>( - item.kind().value_or(CompletionItemKind::Text)); - if (kind != CompletionItemKind::Function && kind != CompletionItemKind::Method - && kind != CompletionItemKind::Constructor) { - applyTextEdit(manipulator, *edit, true); - return; - } - const QString rawInsertText = edit->newText(); const int firstParenOffset = rawInsertText.indexOf('('); const int lastParenOffset = rawInsertText.lastIndexOf(')'); - if (firstParenOffset == -1 || lastParenOffset == -1) { - applyTextEdit(manipulator, *edit, true); - return; - } - const QString detail = item.detail().value_or(QString()); const CompletionSettings &completionSettings = TextEditorSettings::completionSettings(); QString textToBeInserted = rawInsertText.left(firstParenOffset); QString extraCharacters; + int extraLength = 0; int cursorOffset = 0; bool setAutoCompleteSkipPos = false; - const QTextDocument * const doc = manipulator.textCursorAt( - manipulator.currentPosition()).document(); + int currentPos = manipulator.currentPosition(); + const QTextDocument * const doc = manipulator.textCursorAt(currentPos).document(); const Range range = edit->range(); const int rangeStart = range.start().toPositionInDocument(doc); - const int rangeLength = range.end().toPositionInDocument(doc) - rangeStart; - if (completionSettings.m_autoInsertBrackets) { + const auto kind = static_cast<CompletionItemKind::Kind>( + item.kind().value_or(CompletionItemKind::Text)); + const bool isFunctionLike = kind == CompletionItemKind::Function + || kind == CompletionItemKind::Method || kind == CompletionItemKind::Constructor + || (firstParenOffset != -1 && lastParenOffset != -1); + if (isFunctionLike && completionSettings.m_autoInsertBrackets) { // If the user typed the opening parenthesis, they'll likely also type the closing one, // in which case it would be annoying if we put the cursor after the already automatically // inserted closing parenthesis. @@ -2663,7 +2769,7 @@ void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, // If the function doesn't return anything, automatically place the semicolon, // unless we're doing a scope completion (then it might be function definition). - const QChar characterAtCursor = manipulator.characterAt(manipulator.currentPosition()); + const QChar characterAtCursor = manipulator.characterAt(currentPos); bool endWithSemicolon = typedChar == ';'; const QChar semicolon = typedChar.isNull() ? QLatin1Char(';') : typedChar; if (endWithSemicolon && characterAtCursor == semicolon) { @@ -2679,7 +2785,7 @@ void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, typedChar = {}; } } else { - const QChar lookAhead = manipulator.characterAt(manipulator.currentPosition() + 1); + const QChar lookAhead = manipulator.characterAt(currentPos + 1); if (MatchingText::shouldInsertMatchingText(lookAhead)) { extraCharacters += ')'; --cursorOffset; @@ -2701,9 +2807,26 @@ void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, --cursorOffset; } - textToBeInserted += extraCharacters; + // Avoid inserting characters that are already there + QTextCursor cursor = manipulator.textCursorAt(rangeStart); + cursor.movePosition(QTextCursor::EndOfWord); + const QString textAfterCursor = manipulator.textAt(currentPos, cursor.position() - currentPos); + if (textToBeInserted != textAfterCursor + && textToBeInserted.indexOf(textAfterCursor, currentPos - rangeStart) >= 0) { + currentPos = cursor.position(); + } + for (int i = 0; i < extraCharacters.length(); ++i) { + const QChar a = extraCharacters.at(i); + const QChar b = manipulator.characterAt(currentPos + i); + if (a == b) + ++extraLength; + else + break; + } - const bool isReplaced = manipulator.replace(rangeStart, rangeLength, textToBeInserted); + textToBeInserted += extraCharacters; + const int length = currentPos - rangeStart + extraLength; + const bool isReplaced = manipulator.replace(rangeStart, length, textToBeInserted); manipulator.setCursorPosition(rangeStart + textToBeInserted.length()); if (isReplaced) { if (cursorOffset) @@ -2806,10 +2929,11 @@ MessageId ClangdClient::Private::getAndHandleAst(const TextDocOrFile &doc, ExtraHighlightingResultsCollector::ExtraHighlightingResultsCollector( QFutureInterface<HighlightingResult> &future, HighlightingResults &results, - const AstNode &ast, const QTextDocument *doc, const QString &docContent) - : m_future(future), m_results(results), m_ast(ast), m_doc(doc), m_docContent(docContent) + const Utils::FilePath &filePath, const AstNode &ast, const QTextDocument *doc, + const QString &docContent) + : m_future(future), m_results(results), m_filePath(filePath), m_ast(ast), m_doc(doc), + m_docContent(docContent) { - } void ExtraHighlightingResultsCollector::collect() @@ -2881,7 +3005,7 @@ void ExtraHighlightingResultsCollector::insertAngleBracketInfo(int searchStart1, int searchStart2, int searchEnd2) { const int openingAngleBracketPos = onlyIndexOf( - QStringView(m_docContent).mid(searchStart1, searchEnd1 - searchStart1), + subViewEnd(m_docContent, searchStart1, searchEnd1), QStringView(QStringLiteral("<"))); if (openingAngleBracketPos == -1) return; @@ -2891,7 +3015,7 @@ void ExtraHighlightingResultsCollector::insertAngleBracketInfo(int searchStart1, if (searchStart2 >= searchEnd2) return; const int closingAngleBracketPos = onlyIndexOf( - QStringView(m_docContent).mid(searchStart2, searchEnd2 - searchStart2), + subViewEnd(m_docContent, searchStart2, searchEnd2), QStringView(QStringLiteral(">"))); if (closingAngleBracketPos == -1) return; @@ -2926,6 +3050,8 @@ void ExtraHighlightingResultsCollector::setResultPosFromRange(HighlightingResult void ExtraHighlightingResultsCollector::collectFromNode(const AstNode &node) { + if (node.kind() == "UserDefinedLiteral") + return; if (node.kind().endsWith("Literal")) { HighlightingResult result; result.useTextSyles = true; @@ -2969,16 +3095,14 @@ void ExtraHighlightingResultsCollector::collectFromNode(const AstNode &node) // sub-expressions 2 and 3. const int searchStartPosQuestionMark = posForNodeEnd(children.first()); const int searchEndPosQuestionMark = posForNodeStart(children.at(1)); - QStringView content = QStringView(m_docContent).mid( - searchStartPosQuestionMark, - searchEndPosQuestionMark - searchStartPosQuestionMark); + QStringView content = subViewEnd(m_docContent, searchStartPosQuestionMark, + searchEndPosQuestionMark); const int questionMarkPos = onlyIndexOf(content, QStringView(QStringLiteral("?"))); if (questionMarkPos == -1) return; const int searchStartPosColon = posForNodeEnd(children.at(1)); const int searchEndPosColon = posForNodeStart(children.at(2)); - content = QStringView(m_docContent).mid(searchStartPosColon, - searchEndPosColon - searchStartPosColon); + content = subViewEnd(m_docContent, searchStartPosColon, searchEndPosColon); const int colonPos = onlyIndexOf(content, QStringView(QStringLiteral(":"))); if (colonPos == -1) return; @@ -3155,8 +3279,7 @@ void ExtraHighlightingResultsCollector::collectFromNode(const AstNode &node) if (isDeclaration) result.textStyles.mixinStyles.push_back(C_DECLARATION); - const QStringView nodeText = QStringView(m_docContent) - .mid(nodeStartPos, nodeEndPos - nodeStartPos); + const QStringView nodeText = subViewEnd(m_docContent, nodeStartPos, nodeEndPos); if (isCallToNew || isCallToDelete) { result.line = node.range().start().line() + 1; @@ -3255,12 +3378,22 @@ void ExtraHighlightingResultsCollector::visitNode(const AstNode &node) { if (m_future.isCanceled()) return; - collectFromNode(node); - const auto children = node.children(); - if (!children) + switch (node.fileStatus(m_filePath)) { + case AstNode::FileStatus::Foreign: return; - for (const AstNode &childNode : *children) - visitNode(childNode); + case AstNode::FileStatus::Ours: + case AstNode::FileStatus::Unknown: + collectFromNode(node); + [[fallthrough]]; + case ClangCodeModel::Internal::AstNode::FileStatus::Mixed: { + const auto children = node.children(); + if (!children) + return; + for (const AstNode &childNode : *children) + visitNode(childNode); + break; + } + } } } // namespace Internal diff --git a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp index ffdd3c4396..195c4f4ead 100644 --- a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp +++ b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp @@ -104,9 +104,9 @@ public: } QWidget *createWidget(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics, - const std::function<bool()> &canApplyFixIt) + const std::function<bool()> &canApplyFixIt, const QString &source) { - const QString text = htmlText(diagnostics); + const QString text = htmlText(diagnostics, source); auto *label = new QLabel; label->setTextFormat(Qt::RichText); @@ -154,13 +154,20 @@ public: return label; } - QString htmlText(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics) + QString htmlText(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics, + const QString &source) { // For debugging, add: style='border-width:1px;border-color:black' QString text = "<table cellspacing='0' cellpadding='0' width='100%'>"; foreach (const ClangBackEnd::DiagnosticContainer &diagnostic, diagnostics) text.append(tableRows(diagnostic)); + if (!source.isEmpty()) { + text.append(QString::fromUtf8("<tr><td colspan='2' align='left'>" + "<font color='gray'>%1</font></td></tr>") + .arg(QCoreApplication::translate("ClangDiagnosticWidget", "[Source: %1]")) + .arg(source)); + } text.append("</table>"); @@ -396,7 +403,8 @@ QString ClangDiagnosticWidget::createText( const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics, const ClangDiagnosticWidget::Destination &destination) { - const QString htmlText = WidgetFromDiagnostics(toHints(destination, {})).htmlText(diagnostics); + const QString htmlText = WidgetFromDiagnostics(toHints(destination, {})) + .htmlText(diagnostics, {}); QTextDocument document; document.setHtml(htmlText); @@ -410,11 +418,13 @@ QString ClangDiagnosticWidget::createText( return text; } -QWidget *ClangDiagnosticWidget::createWidget(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics, - const Destination &destination, const std::function<bool()> &canApplyFixIt) +QWidget *ClangDiagnosticWidget::createWidget( + const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics, + const Destination &destination, const std::function<bool()> &canApplyFixIt, + const QString &source) { return WidgetFromDiagnostics(toHints(destination, canApplyFixIt)) - .createWidget(diagnostics, canApplyFixIt); + .createWidget(diagnostics, canApplyFixIt, source); } } // namespace Internal diff --git a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.h b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.h index afe35812ae..92f98a59ca 100644 --- a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.h +++ b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.h @@ -48,7 +48,8 @@ public: static QWidget *createWidget(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics, const Destination &destination, - const std::function<bool()> &canApplyFixIt); + const std::function<bool()> &canApplyFixIt, + const QString &source); }; } // namespace Internal diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index a9d4f01c72..94a4408505 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -506,7 +506,8 @@ ClangEditorDocumentProcessor::creatorForHeaderErrorDiagnosticWidget( vbox->setSpacing(2); vbox->addWidget(ClangDiagnosticWidget::createWidget({firstHeaderErrorDiagnostic}, - ClangDiagnosticWidget::InfoBar, {})); + ClangDiagnosticWidget::InfoBar, {}, + "libclang")); auto widget = new QWidget; widget->setLayout(vbox); diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 52be361305..d1c6b0d0ce 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -286,7 +286,7 @@ void ClangModelManagerSupport::updateLanguageClient( if (const ProjectExplorer::Target * const target = project->activeTarget()) { if (const ProjectExplorer::BuildConfiguration * const bc = target->activeBuildConfiguration()) { - return bc->buildDirectory(); + return bc->buildDirectory() / ".qtc_clangd"; } } return Utils::FilePath(); @@ -363,7 +363,7 @@ void ClangModelManagerSupport::updateLanguageClient( }); }); - auto future = Utils::runAsync(&Internal::generateCompilationDB, projectInfo, + auto future = Utils::runAsync(&Internal::generateCompilationDB, projectInfo, jsonDbDir, CompilationDbPurpose::CodeModel, warningsConfigForProject(project), optionsForProject(project)); @@ -483,10 +483,6 @@ void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor) // TODO: Ensure that not fully loaded documents are updated? - // TODO: If the file does not belong to any project and it is a header file, - // it might make sense to check whether the file is included by any file - // that does belong to a project, and if so, use the respective client - // instead. Is this feasible? ProjectExplorer::Project * const project = ProjectExplorer::SessionManager::projectForFile(document->filePath()); if (ClangdClient * const client = clientForProject(project)) diff --git a/src/plugins/clangcodemodel/clangtextmark.cpp b/src/plugins/clangcodemodel/clangtextmark.cpp index 38227008a9..01cfae6ae6 100644 --- a/src/plugins/clangcodemodel/clangtextmark.cpp +++ b/src/plugins/clangcodemodel/clangtextmark.cpp @@ -281,7 +281,7 @@ bool ClangTextMark::addToolTipContent(QLayout *target) const && diagMgr->diagnosticsWithFixIts().contains(diag); }; QWidget *widget = ClangDiagnosticWidget::createWidget( - {m_diagnostic}, ClangDiagnosticWidget::ToolTip, canApplyFixIt); + {m_diagnostic}, ClangDiagnosticWidget::ToolTip, canApplyFixIt, "libclang"); target->addWidget(widget); return true; @@ -398,7 +398,7 @@ bool ClangdTextMark::addToolTipContent(QLayout *target) const return c && c->reachable() && c->hasDiagnostic(DocumentUri::fromFilePath(fp), diag); }; target->addWidget(ClangDiagnosticWidget::createWidget({m_diagnostic}, - ClangDiagnosticWidget::ToolTip, canApplyFixIt)); + ClangDiagnosticWidget::ToolTip, canApplyFixIt, "clangd")); return true; } diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index bbe9817380..a089248d03 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -372,18 +372,15 @@ static QJsonObject createFileObject(const FilePath &buildDir, } GenerateCompilationDbResult generateCompilationDB(const CppEditor::ProjectInfo::ConstPtr projectInfo, + const Utils::FilePath &baseDir, CompilationDbPurpose purpose, const ClangDiagnosticConfig &warningsConfig, const QStringList &projectOptions) { - const FilePath buildDir = projectInfo->buildRoot(); - QTC_ASSERT(!buildDir.isEmpty(), return GenerateCompilationDbResult(QString(), + QTC_ASSERT(!baseDir.isEmpty(), return GenerateCompilationDbResult(QString(), QCoreApplication::translate("ClangUtils", "Could not retrieve build directory."))); - - QDir dir(buildDir.toString()); - if (!dir.exists()) - dir.mkpath(dir.path()); - QFile compileCommandsFile(buildDir.toString() + "/compile_commands.json"); + QTC_CHECK(baseDir.ensureWritableDir()); + QFile compileCommandsFile(baseDir.toString() + "/compile_commands.json"); const bool fileOpened = compileCommandsFile.open(QIODevice::WriteOnly | QIODevice::Truncate); if (!fileOpened) { return GenerateCompilationDbResult(QString(), @@ -397,7 +394,7 @@ GenerateCompilationDbResult generateCompilationDB(const CppEditor::ProjectInfo:: if (purpose == CompilationDbPurpose::Project) args = projectPartArguments(*projectPart); for (const ProjectFile &projFile : projectPart->files) { - const QJsonObject json = createFileObject(buildDir, args, *projectPart, projFile, + const QJsonObject json = createFileObject(baseDir, args, *projectPart, projFile, purpose, warningsConfig, projectOptions); if (compileCommandsFile.size() > 1) compileCommandsFile.write(","); diff --git a/src/plugins/clangcodemodel/clangutils.h b/src/plugins/clangcodemodel/clangutils.h index 1d46e6a49b..c3a496f779 100644 --- a/src/plugins/clangcodemodel/clangutils.h +++ b/src/plugins/clangcodemodel/clangutils.h @@ -88,8 +88,8 @@ public: enum class CompilationDbPurpose { Project, CodeModel }; GenerateCompilationDbResult generateCompilationDB(const CppEditor::ProjectInfo::ConstPtr projectInfo, - CompilationDbPurpose purpose, const CppEditor::ClangDiagnosticConfig &warningsConfig, - const QStringList &projectOptions); + const Utils::FilePath &baseDir, CompilationDbPurpose purpose, + const CppEditor::ClangDiagnosticConfig &warningsConfig, const QStringList &projectOptions); class DiagnosticTextInfo { diff --git a/src/plugins/clangformat/clangformatfile.cpp b/src/plugins/clangformat/clangformatfile.cpp index 8e532ea797..c9955ef2a3 100644 --- a/src/plugins/clangformat/clangformatfile.cpp +++ b/src/plugins/clangformat/clangformatfile.cpp @@ -105,7 +105,7 @@ void ClangFormatFile::saveNewFormat() // workaround: configurationAsText() add comment "# " before BasedOnStyle line const int pos = style.find("# BasedOnStyle"); - if (pos < style.size()) + if (pos < int(style.size())) style.erase(pos, 2); m_filePath.writeFileContents(QByteArray::fromStdString(style)); } diff --git a/src/plugins/clangtools/clangtoolsdiagnostic.cpp b/src/plugins/clangtools/clangtoolsdiagnostic.cpp index 7fe7098c22..42ec9f5f2a 100644 --- a/src/plugins/clangtools/clangtoolsdiagnostic.cpp +++ b/src/plugins/clangtools/clangtoolsdiagnostic.cpp @@ -62,7 +62,7 @@ QIcon Diagnostic::icon() const return {}; } -quint32 qHash(const Diagnostic &diagnostic) +Utils::QHashValueType qHash(const Diagnostic &diagnostic) { return qHash(diagnostic.name) ^ qHash(diagnostic.description) diff --git a/src/plugins/clangtools/clangtoolsdiagnostic.h b/src/plugins/clangtools/clangtoolsdiagnostic.h index e64d91a29f..10534ff0b2 100644 --- a/src/plugins/clangtools/clangtoolsdiagnostic.h +++ b/src/plugins/clangtools/clangtoolsdiagnostic.h @@ -27,6 +27,8 @@ #include <debugger/analyzer/diagnosticlocation.h> +#include <utils/porting.h> + #include <QMetaType> #include <QString> #include <QVector> @@ -68,7 +70,7 @@ bool operator==(const Diagnostic &lhs, const Diagnostic &rhs); using Diagnostics = QList<Diagnostic>; -quint32 qHash(const Diagnostic &diagnostic); +Utils::QHashValueType qHash(const Diagnostic &diagnostic); } // namespace Internal } // namespace ClangTools diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index 6d0486650f..a878f8864c 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -1826,12 +1826,8 @@ bool ClearCasePluginPrivate::vcsOpen(const FilePath &workingDir, const QString & setStatus(absPath, FileStatus::CheckedOut); } - foreach (DocumentModel::Entry *e, DocumentModel::entries()) { - if (e->fileName().toString() == absPath) { - e->document->checkPermissions(); - break; - } - } + if (DocumentModel::Entry *e = DocumentModel::entryForFilePath(FilePath::fromString(absPath))) + e->document->checkPermissions(); return !response.error; } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index d1c9d9a22b..4eb6fdc97f 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -934,18 +934,10 @@ void CMakeBuildSystem::runCTest() process.setCommand(cmd); process.start(); - if (!process.waitForStarted(1000) || !process.waitForFinished()) { - if (process.state() == QProcess::NotRunning) - return; - process.terminate(); - if (process.waitForFinished(1000)) - return; - process.kill(); - process.waitForFinished(1000); + if (!process.waitForStarted(1000) || !process.waitForFinished() + || process.exitCode() || process.exitStatus() != QProcess::NormalExit) { return; } - if (process.exitCode() || process.exitStatus() != QProcess::NormalExit) - return; futureInterface.reportResult(process.readAllStandardOutput()); }); diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp index 93e6e6232a..bd5556d215 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp @@ -472,7 +472,7 @@ bool CMakeConfigItem::operator==(const CMakeConfigItem &o) const return o.key == key && o.value == value && o.isUnset == isUnset; } -uint qHash(const CMakeConfigItem &it) +Utils::QHashValueType qHash(const CMakeConfigItem &it) { return ::qHash(it.key) ^ ::qHash(it.value) ^ ::qHash(it.isUnset); } diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h index dae93455d7..19bbbfd7d6 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h @@ -27,6 +27,7 @@ #include "cmake_global.h" +#include <utils/porting.h> #include <utils/optional.h> #include <QByteArray> @@ -78,7 +79,7 @@ public: QStringList values; }; -uint qHash(const CMakeConfigItem &it); // needed for MSVC +Utils::QHashValueType qHash(const CMakeConfigItem &it); // needed for MSVC class CMAKE_EXPORT CMakeConfig : public QList<CMakeConfigItem> { diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index 64e59109dd..d8f24b4362 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -92,10 +92,8 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & } } - const QString srcDir = parameters.sourceDirectory.path(); - const auto parser = new CMakeParser; - parser->setSourceDirectory(srcDir); + parser->setSourceDirectory(parameters.sourceDirectory.path()); m_parser.addLineParser(parser); // Always use the sourceDir: If we are triggered because the build directory is getting deleted @@ -121,7 +119,13 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & connect(process.get(), &QtcProcess::finished, this, &CMakeProcess::handleProcessFinished); - CommandLine commandLine(cmake->cmakeExecutable(), QStringList({"-S", srcDir, "-B", buildDirectory.path()}) + arguments); + const FilePath cmakeExecutable = cmake->cmakeExecutable(); + const FilePath sourceDirectory = parameters.sourceDirectory.onDevice(cmakeExecutable); + + CommandLine commandLine(cmakeExecutable); + commandLine.addArgs({"-S", sourceDirectory.mapToDevicePath(), + "-B", buildDirectory.mapToDevicePath()}); + commandLine.addArgs(arguments); TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM); diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index cabac0b3b9..d5836605f4 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -28,9 +28,10 @@ #include "fileapiparser.h" #include "projecttreehelper.h" -#include <cppeditor/cppprojectfilecategorizer.h> +#include <cppeditor/cppeditorconstants.h> #include <utils/algorithm.h> +#include <utils/mimetypes/mimedatabase.h> #include <utils/qtcassert.h> #include <utils/qtcprocess.h> #include <utils/utilsicons.h> @@ -336,16 +337,6 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input, int counter = 0; for (const TargetDetails &t : input.targetDetails) { QDir sourceDir(sourceDirectory.toString()); - - // Do not tread generated files and CMake precompiled headers as project files - const auto sourceFiles = Utils::filtered(t.sources, [buildDirectory](const SourceInfo &si) { - return !si.isGenerated && !isPchFile(buildDirectory, FilePath::fromString(si.path)); - }); - CppEditor::ProjectFileCategorizer - categorizer({}, transform<QList>(sourceFiles, [&sourceDir](const SourceInfo &si) { - return sourceDir.absoluteFilePath(si.path); - })); - bool needPostfix = t.compileGroups.size() > 1; int count = 1; for (const CompileInfo &ci : t.compileGroups) { @@ -387,20 +378,45 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input, QStringList fragments = splitFragments(ci.fragments); + // Get all sources from the compiler group, except generated sources + QStringList sources; + for (auto idx: ci.sources) { + SourceInfo si = t.sources.at(idx); + if (si.isGenerated) + continue; + sources.push_back(sourceDir.absoluteFilePath(si.path)); + } + + // If we are not in a pch compiler group, add all the headers that are not generated + const bool hasPchSource = anyOf(sources, [buildDirectory](const QString &path) { + return isPchFile(buildDirectory, FilePath::fromString(path)); + }); + if (!hasPchSource) { + QString headerMimeType; + if (ci.language == "C") + headerMimeType = CppEditor::Constants::C_HEADER_MIMETYPE; + else if (ci.language == "CXX") + headerMimeType = CppEditor::Constants::CPP_HEADER_MIMETYPE; + + for (const SourceInfo &si : t.sources) { + if (si.isGenerated) + continue; + const auto mimeTypes = Utils::mimeTypesForFileName(si.path); + for (auto mime : mimeTypes) + if (mime.name() == headerMimeType) + sources.push_back(sourceDir.absoluteFilePath(si.path)); + } + } + + // Set project files except pch files + rpp.setFiles(Utils::filtered(sources, [buildDirectory](const QString &path) { + return !isPchFile(buildDirectory, FilePath::fromString(path)); + })); + FilePath precompiled_header = FilePath::fromString(findOrDefault(t.sources, [&ending](const SourceInfo &si) { return si.path.endsWith(ending); }).path); - - CppEditor::ProjectFiles sources; - if (ci.language == "C") - sources = categorizer.cSources(); - else if (ci.language == "CXX") - sources = categorizer.cxxSources(); - - rpp.setFiles(transform<QList>(sources, [](const CppEditor::ProjectFile &pf) { - return pf.path; - })); if (!precompiled_header.isEmpty()) { if (precompiled_header.toFileInfo().isRelative()) { const FilePath parentDir = FilePath::fromString(sourceDir.absolutePath()); @@ -595,9 +611,20 @@ void addTargets(const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cm const FilePath &sourceDir, const FilePath &buildDir) { + QHash<QString, const TargetDetails *> targetDetailsHash; + for (const TargetDetails &t : targetDetails) + targetDetailsHash.insert(t.id, &t); + const TargetDetails defaultTargetDetails; + auto getTargetDetails = [&targetDetailsHash, &defaultTargetDetails](const QString &id) + -> const TargetDetails & { + auto it = targetDetailsHash.constFind(id); + if (it != targetDetailsHash.constEnd()) + return *it.value(); + return defaultTargetDetails; + }; + for (const FileApiDetails::Target &t : config.targets) { - const TargetDetails &td = Utils::findOrDefault(targetDetails, - Utils::equal(&TargetDetails::id, t.id)); + const TargetDetails &td = getTargetDetails(t.id); const FilePath dir = directorySourceDir(config, sourceDir, t.directory); @@ -730,7 +757,7 @@ FileApiQtcData extractData(FileApiData &input, result.projectParts = generateRawProjectParts(data, sourceDirectory, buildDirectory); auto rootProjectNode = generateRootProjectNode(data, sourceDirectory, buildDirectory); - ProjectTree::applyTreeManager(rootProjectNode.get()); // QRC nodes + ProjectTree::applyTreeManager(rootProjectNode.get(), ProjectTree::AsyncPhase); // QRC nodes result.rootProjectNode = std::move(rootProjectNode); setupLocationInfoForTargets(result.rootProjectNode.get(), result.buildTargets); diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.h b/src/plugins/cmakeprojectmanager/fileapidataextractor.h index 2b65c76e07..1bc99bf1a8 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.h +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.h @@ -56,7 +56,7 @@ public: bool isGenerated = false; }; -inline uint qHash(const CMakeFileInfo &info, uint seed = 0) { return info.path.hash(seed); } +inline auto qHash(const CMakeFileInfo &info, uint seed = 0) { return info.path.hash(seed); } class FileApiQtcData { diff --git a/src/plugins/coreplugin/dialogs/codecselector.cpp b/src/plugins/coreplugin/dialogs/codecselector.cpp index a84b0fa112..9b5786c1b4 100644 --- a/src/plugins/coreplugin/dialogs/codecselector.cpp +++ b/src/plugins/coreplugin/dialogs/codecselector.cpp @@ -87,6 +87,8 @@ CodecSelector::CodecSelector(QWidget *parent, Core::BaseTextDocument *doc) int currentIndex = -1; foreach (int mib, sortedMibs) { QTextCodec *c = QTextCodec::codecForMib(mib); + if (!doc->supportsCodec(c)) + continue; if (!buf.isEmpty()) { // slow, should use a feature from QTextCodec or QTextDecoder (but those are broken currently) diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 6fa127e255..4fd4213dbb 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -55,6 +55,7 @@ #include <utils/pathchooser.h> #include <utils/qtcassert.h> #include <utils/reloadpromptutils.h> +#include <utils/threadutils.h> #include <QStringList> #include <QDateTime> @@ -326,6 +327,7 @@ static void addFileInfo(IDocument *document, const FilePath &filePath, const Fil (The added file names are guaranteed to be absolute and cleaned.) */ static void addFileInfos(const QList<IDocument *> &documents) { + QTC_ASSERT(isMainThread(), return); FilePaths pathsToWatch; FilePaths linkPathsToWatch; for (IDocument *document : documents) { @@ -400,6 +402,7 @@ void DocumentManager::addDocuments(const QList<IDocument *> &documents, bool add */ static void removeFileInfo(IDocument *document) { + QTC_ASSERT(isMainThread(), return); if (!d->m_documentsWithWatch.contains(document)) return; foreach (const FilePath &filePath, d->m_documentsWithWatch.value(document)) { @@ -1186,10 +1189,10 @@ void DocumentManager::checkForReload() bool success = true; QString errorString; // we've got some modification + document->checkPermissions(); // check if it's contents or permissions: if (!type) { // Only permission change - document->checkPermissions(); success = true; // now we know it's a content change or file was removed } else if (defaultBehavior == IDocument::ReloadUnmodified && type == IDocument::TypeContents diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index c2b432d05a..7944c88285 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -2110,7 +2110,7 @@ void EditorManagerPrivate::updateWindowTitleForDocument(IDocument *document, QWi if (!documentName.isEmpty()) windowTitle.append(documentName); - const QString filePath = document ? document->filePath().toFileInfo().absoluteFilePath() + const QString filePath = document ? document->filePath().absoluteFilePath().path() : QString(); const QString windowTitleAddition = d->m_titleAdditionHandler ? d->m_titleAdditionHandler(filePath) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index bc44cfb1f7..4867987869 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -31,9 +31,10 @@ #include <utils/id.h> #include <utils/optional.h> -#include <QVariant> #include <QFutureInterface> #include <QIcon> +#include <QMetaType> +#include <QVariant> namespace Core { @@ -74,12 +75,6 @@ struct LocatorFilterEntry , displayIcon(icon) {} - bool operator==(const LocatorFilterEntry &other) const { - if (internalData.canConvert(QVariant::String)) - return (internalData.toString() == other.internalData.toString()); - return internalData.constData() == other.internalData.constData(); - } - /* backpointer to creating filter */ ILocatorFilter *filter = nullptr; /* displayed string */ diff --git a/src/plugins/coreplugin/locator/locatorsearchutils.cpp b/src/plugins/coreplugin/locator/locatorsearchutils.cpp index a9eb1a7de2..cefe9481c0 100644 --- a/src/plugins/coreplugin/locator/locatorsearchutils.cpp +++ b/src/plugins/coreplugin/locator/locatorsearchutils.cpp @@ -29,21 +29,10 @@ #include <QString> #include <QVariant> -namespace Core { - -uint qHash(const LocatorFilterEntry &entry) -{ - if (entry.internalData.canConvert(QVariant::String)) - return QT_PREPEND_NAMESPACE(qHash)(entry.internalData.toString()); - return QT_PREPEND_NAMESPACE(qHash)(entry.internalData.constData()); -} - -} // namespace Core - void Core::Internal::runSearch(QFutureInterface<Core::LocatorFilterEntry> &future, const QList<ILocatorFilter *> &filters, const QString &searchText) { - QSet<LocatorFilterEntry> alreadyAdded; + QSet<QString> alreadyAdded; const bool checkDuplicates = (filters.size() > 1); for (ILocatorFilter *filter : filters) { if (future.isCanceled()) @@ -53,11 +42,15 @@ void Core::Internal::runSearch(QFutureInterface<Core::LocatorFilterEntry> &futur QVector<LocatorFilterEntry> uniqueFilterResults; uniqueFilterResults.reserve(filterResults.size()); for (const LocatorFilterEntry &entry : filterResults) { - if (checkDuplicates && alreadyAdded.contains(entry)) - continue; + if (checkDuplicates) { + const QString stringData = entry.internalData.toString(); + if (!stringData.isEmpty()) { + if (alreadyAdded.contains(stringData)) + continue; + alreadyAdded.insert(stringData); + } + } uniqueFilterResults.append(entry); - if (checkDuplicates) - alreadyAdded.insert(entry); } if (!uniqueFilterResults.isEmpty()) future.reportResults(uniqueFilterResults); diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 50837d9f15..a6b94660f6 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -73,10 +73,13 @@ bool styleEnabled(const QWidget *widget) return true; } -static bool isInDialogOrPopup(const QWidget *widget) +static bool isInUnstyledDialogOrPopup(const QWidget *widget) { - // Do not style dialogs or explicitly ignored widgets - const Qt::WindowType windowType = widget->window()->windowType(); + // Do not style contents of dialogs or popups without "panelwidget" property + const QWidget *window = widget->window(); + if (window->property("panelwidget").toBool()) + return false; + const Qt::WindowType windowType = window->windowType(); return (windowType == Qt::Dialog || windowType == Qt::Popup); } @@ -86,7 +89,7 @@ bool panelWidget(const QWidget *widget) if (!widget) return false; - if (isInDialogOrPopup(widget)) + if (isInUnstyledDialogOrPopup(widget)) return false; if (qobject_cast<const FancyMainWindow *>(widget)) @@ -113,7 +116,7 @@ bool lightColored(const QWidget *widget) if (!widget) return false; - if (isInDialogOrPopup(widget)) + if (isInUnstyledDialogOrPopup(widget)) return false; const QWidget *p = widget; diff --git a/src/plugins/coreplugin/textdocument.cpp b/src/plugins/coreplugin/textdocument.cpp index 4d6c45dadf..448854926d 100644 --- a/src/plugins/coreplugin/textdocument.cpp +++ b/src/plugins/coreplugin/textdocument.cpp @@ -183,7 +183,13 @@ void BaseTextDocument::setCodec(const QTextCodec *codec) { if (debug) qDebug() << Q_FUNC_INFO << this << (codec ? codec->name() : QByteArray()); - d->m_format.codec = codec; + if (supportsCodec(codec)) + d->m_format.codec = codec; +} + +bool BaseTextDocument::supportsCodec(const QTextCodec *) const +{ + return true; } void BaseTextDocument::switchUtf8Bom() diff --git a/src/plugins/coreplugin/textdocument.h b/src/plugins/coreplugin/textdocument.h index 7d16b6fa81..83450b8395 100644 --- a/src/plugins/coreplugin/textdocument.h +++ b/src/plugins/coreplugin/textdocument.h @@ -46,6 +46,7 @@ public: Utils::TextFileFormat format() const; const QTextCodec *codec() const; void setCodec(const QTextCodec *); + virtual bool supportsCodec(const QTextCodec *) const; void switchUtf8Bom(); bool supportsUtf8Bom() const; Utils::TextFileFormat::LineTerminationMode lineTerminationMode() const; diff --git a/src/plugins/cppcheck/cppcheckdiagnostic.cpp b/src/plugins/cppcheck/cppcheckdiagnostic.cpp index 6534018fc5..a1b8235e82 100644 --- a/src/plugins/cppcheck/cppcheckdiagnostic.cpp +++ b/src/plugins/cppcheck/cppcheckdiagnostic.cpp @@ -34,7 +34,7 @@ bool Diagnostic::operator==(const Diagnostic &r) const == std::tie(r.severity, r.message, r.fileName, r.lineNumber); } -quint32 qHash(const Diagnostic &diagnostic) +Utils::QHashValueType qHash(const Diagnostic &diagnostic) { return qHash(diagnostic.message) ^ qHash(diagnostic.fileName) ^ diagnostic.lineNumber; } diff --git a/src/plugins/cppcheck/cppcheckdiagnostic.h b/src/plugins/cppcheck/cppcheckdiagnostic.h index eea6ef430e..1983af68de 100644 --- a/src/plugins/cppcheck/cppcheckdiagnostic.h +++ b/src/plugins/cppcheck/cppcheckdiagnostic.h @@ -26,6 +26,7 @@ #pragma once #include <utils/fileutils.h> +#include <utils/porting.h> namespace Cppcheck { namespace Internal { @@ -49,7 +50,7 @@ public: int lineNumber = 0; }; -quint32 qHash(const Diagnostic &diagnostic); +Utils::QHashValueType qHash(const Diagnostic &diagnostic); } // namespace Internal } // namespace Cppcheck diff --git a/src/plugins/cppeditor/compileroptionsbuilder.cpp b/src/plugins/cppeditor/compileroptionsbuilder.cpp index 14921c51eb..09f71fa93f 100644 --- a/src/plugins/cppeditor/compileroptionsbuilder.cpp +++ b/src/plugins/cppeditor/compileroptionsbuilder.cpp @@ -123,7 +123,7 @@ CompilerOptionsBuilder::~CompilerOptionsBuilder() = default; QStringList CompilerOptionsBuilder::build(ProjectFile::Kind fileKind, UsePrecompiledHeaders usePrecompiledHeaders) { - m_options.clear(); + reset(); evaluateCompilerFlags(); if (fileKind == ProjectFile::CHeader || fileKind == ProjectFile::CSource) { @@ -251,9 +251,12 @@ void CompilerOptionsBuilder::addWordWidth() void CompilerOptionsBuilder::addTargetTriple() { + const QString target = m_explicitTarget.isEmpty() + ? m_projectPart.toolChainTargetTriple : m_explicitTarget; + // Only "--target=" style is accepted in both g++ and cl driver modes. - if (!m_projectPart.toolChainTargetTriple.isEmpty()) - add("--target=" + m_projectPart.toolChainTargetTriple); + if (!target.isEmpty()) + add("--target=" + target); } void CompilerOptionsBuilder::addExtraCodeModelFlags() @@ -771,6 +774,7 @@ void CompilerOptionsBuilder::undefineClangVersionMacrosForMsvc() void CompilerOptionsBuilder::reset() { m_options.clear(); + m_explicitTarget.clear(); } // Some example command lines for a "Qt Console Application": @@ -786,12 +790,18 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() const Id toolChain = m_projectPart.toolchainType; bool containsDriverMode = false; bool skipNext = false; - const QStringList allFlags = m_projectPart.compilerFlags + m_projectPart.extraCodeModelFlags; + bool nextIsTarget = false; + const QStringList allFlags = m_projectPart.extraCodeModelFlags + m_projectPart.compilerFlags; for (const QString &option : allFlags) { if (skipNext) { skipNext = false; continue; } + if (nextIsTarget) { + nextIsTarget = false; + m_explicitTarget = option; + continue; + } if (userBlackList.contains(option)) continue; @@ -812,14 +822,15 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() continue; } - // As we always set the target explicitly, filter out target args. - if (!m_projectPart.toolChainTargetTriple.isEmpty()) { - if (option.startsWith("--target=")) - continue; - if (option == "-target") { - skipNext = true; - continue; - } + // An explicit target triple from the build system takes precedence over the generic one + // from the toolchain. + if (option.startsWith("--target=")) { + m_explicitTarget = option.mid(9); + continue; + } + if (option == "-target") { + nextIsTarget = true; + continue; } if (option == includeUserPathOption || option == includeSystemPathOption diff --git a/src/plugins/cppeditor/compileroptionsbuilder.h b/src/plugins/cppeditor/compileroptionsbuilder.h index 0211d58a18..cc75e984be 100644 --- a/src/plugins/cppeditor/compileroptionsbuilder.h +++ b/src/plugins/cppeditor/compileroptionsbuilder.h @@ -122,6 +122,7 @@ private: } m_compilerFlags; QStringList m_options; + QString m_explicitTarget; bool m_clStyle = false; }; diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index 1a7cf1255f..66c07bed7a 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -402,7 +402,8 @@ QVariantMap ClangdSettings::Data::toMap() const { QVariantMap map; map.insert(useClangdKey(), useClangd); - map.insert(clangdPathKey(), executableFilePath.toString()); + if (executableFilePath != fallbackClangdFilePath()) + map.insert(clangdPathKey(), executableFilePath.toString()); map.insert(clangdIndexingKey(), enableIndexing); map.insert(clangdThreadLimitKey(), workerThreadLimit); map.insert(clangdDocumentThresholdKey(), documentUpdateThreshold); diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp index 2c775e3843..1c6621e070 100644 --- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp @@ -33,11 +33,14 @@ #include <coreplugin/icore.h> #include <utils/algorithm.h> +#include <utils/infolabel.h> #include <utils/pathchooser.h> +#include <utils/qtcprocess.h> #include <QFormLayout> #include <QSpinBox> #include <QTextStream> +#include <QVersionNumber> namespace CppEditor::Internal { @@ -197,6 +200,7 @@ public: QSpinBox threadLimitSpinBox; QSpinBox documentUpdateThreshold; Utils::PathChooser clangdChooser; + Utils::InfoLabel versionWarningLabel; }; ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsData) @@ -230,6 +234,7 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD const auto formLayout = new QFormLayout; const auto chooserLabel = new QLabel(tr("Path to executable:")); formLayout->addRow(chooserLabel, &d->clangdChooser); + formLayout->addRow(QString(), &d->versionWarningLabel); const auto indexingLabel = new QLabel(tr("Enable background indexing:")); formLayout->addRow(indexingLabel, &d->indexingCheckBox); const auto threadLimitLayout = new QHBoxLayout; @@ -251,11 +256,58 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD indexingLabel->setEnabled(checked); d->indexingCheckBox.setEnabled(checked); d->threadLimitSpinBox.setEnabled(checked); + d->versionWarningLabel.setEnabled(checked); }; connect(&d->useClangdCheckBox, &QCheckBox::toggled, toggleEnabled); toggleEnabled(d->useClangdCheckBox.isChecked()); d->threadLimitSpinBox.setEnabled(d->useClangdCheckBox.isChecked()); + d->versionWarningLabel.setType(Utils::InfoLabel::Warning); + const auto updateWarningLabel = [this] { + class WarningLabelSetter { + public: + WarningLabelSetter(QLabel &label) : m_label(label) { m_label.clear(); } + ~WarningLabelSetter() { m_label.setVisible(!m_label.text().isEmpty()); } + void setWarning(const QString &text) { m_label.setText(text); } + private: + QLabel &m_label; + }; + WarningLabelSetter labelSetter(d->versionWarningLabel); + + if (!d->clangdChooser.isValid()) + return; + const Utils::FilePath clangdPath = d->clangdChooser.filePath(); + Utils::QtcProcess clangdProc; + clangdProc.setCommand({clangdPath, {"--version"}}); + clangdProc.start(); + if (!clangdProc.waitForStarted() || !clangdProc.waitForFinished()) { + labelSetter.setWarning(tr("Failed to retrieve clangd version: %1") + .arg(clangdProc.exitMessage())); + return; + } + const QString output = clangdProc.allOutput(); + static const QString versionPrefix = "clangd version "; + const int prefixOffset = output.indexOf(versionPrefix); + QVersionNumber clangdVersion; + if (prefixOffset != -1) { + clangdVersion = QVersionNumber::fromString(output.mid(prefixOffset + + versionPrefix.length())); + } + if (clangdVersion.isNull()) { + labelSetter.setWarning(tr("Failed to retrieve clangd version: " + "Unexpected clangd output.")); + return; + } + if (clangdVersion < QVersionNumber(13)) { + labelSetter.setWarning(tr("The clangd version is %1, but %2 or greater is " + "recommended for full functionality.") + .arg(clangdVersion.toString()).arg(13)); + return; + } + }; + connect(&d->clangdChooser, &Utils::PathChooser::pathChanged, this, updateWarningLabel); + updateWarningLabel(); + connect(&d->useClangdCheckBox, &QCheckBox::toggled, this, &ClangdSettingsWidget::settingsDataChanged); connect(&d->indexingCheckBox, &QCheckBox::toggled, diff --git a/src/plugins/cppeditor/cppcompletionassist.cpp b/src/plugins/cppeditor/cppcompletionassist.cpp index cd2c70b78c..ee04a15957 100644 --- a/src/plugins/cppeditor/cppcompletionassist.cpp +++ b/src/plugins/cppeditor/cppcompletionassist.cpp @@ -858,38 +858,8 @@ bool InternalCppCompletionAssistProcessor::accepts() const if (pos - startOfName >= TextEditorSettings::completionSettings().m_characterThreshold) { const QChar firstCharacter = m_interface->characterAt(startOfName); if (isValidFirstIdentifierChar(firstCharacter)) { - // Finally check that we're not inside a comment or string (code copied from startOfOperator) - QTextCursor tc(m_interface->textDocument()); - tc.setPosition(pos); - - SimpleLexer tokenize; - tokenize.setLanguageFeatures(m_interface->languageFeatures()); - tokenize.setSkipComments(false); - - const Tokens &tokens = tokenize(tc.block().text(), BackwardsScanner::previousBlockState(tc.block())); - const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1)); - const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx); - - if (!tk.isComment() && !tk.isLiteral()) { - return true; - } else if (tk.isLiteral() - && tokens.size() == 3 - && tokens.at(0).kind() == T_POUND - && tokens.at(1).kind() == T_IDENTIFIER) { - const QString &line = tc.block().text(); - const Token &idToken = tokens.at(1); - QStringView identifier = idToken.utf16charsEnd() > line.size() - ? QStringView(line).mid( - idToken.utf16charsBegin()) - : QStringView(line) - .mid(idToken.utf16charsBegin(), - idToken.utf16chars()); - if (identifier == QLatin1String("include") - || identifier == QLatin1String("include_next") - || (m_interface->languageFeatures().objCEnabled && identifier == QLatin1String("import"))) { - return true; - } - } + return !isInCommentOrString(m_interface.data(), + m_interface->languageFeatures()); } } } diff --git a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp index ac2747cad7..11a3a70be0 100644 --- a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp +++ b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp @@ -417,17 +417,18 @@ bool maybeAppendArgumentOrParameterList(QString *expression, const QTextCursor & bool isCursorOnTrailingReturnType(const QList<AST *> &astPath) { - for (auto it = astPath.cend() - 1, begin = astPath.cbegin(); it >= begin; --it) { + if (astPath.size() < 3) + return false; + for (auto it = astPath.cend() - 3, begin = astPath.cbegin(); it >= begin; --it) { + if (!(*it)->asTrailingReturnType()) + continue; const auto nextIt = it + 1; const auto nextNextIt = nextIt + 1; - if (nextNextIt != astPath.cend() && (*it)->asTrailingReturnType()) { - return (*nextIt)->asNamedTypeSpecifier() - && ((*nextNextIt)->asSimpleName() - || (*nextNextIt)->asQualifiedName() - || (*nextNextIt)->asTemplateId()); - } + return (*nextIt)->asNamedTypeSpecifier() + && ((*nextNextIt)->asSimpleName() + || (*nextNextIt)->asQualifiedName() + || (*nextNextIt)->asTemplateId()); } - return false; } diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 40b37263d8..4ddd690b42 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -694,6 +694,10 @@ CppModelManager::CppModelManager() connect(KitManager::instance(), &KitManager::kitsChanged, this, &CppModelManager::setupFallbackProjectPart); + connect(this, &CppModelManager::projectPartsRemoved, this, + &CppModelManager::setupFallbackProjectPart); + connect(this, &CppModelManager::projectPartsUpdated, this, + &CppModelManager::setupFallbackProjectPart); setupFallbackProjectPart(); qRegisterMetaType<CPlusPlus::Document::Ptr>("CPlusPlus::Document::Ptr"); diff --git a/src/plugins/cppeditor/cppprojectfile.cpp b/src/plugins/cppeditor/cppprojectfile.cpp index fa3bf8c023..58196521ca 100644 --- a/src/plugins/cppeditor/cppprojectfile.cpp +++ b/src/plugins/cppeditor/cppprojectfile.cpp @@ -87,6 +87,20 @@ bool ProjectFile::isAmbiguousHeader(const QString &filePath) return filePath.endsWith(".h"); } +bool ProjectFile::isObjC(const QString &filePath) +{ + const Kind kind = classify(filePath); + switch (kind) { + case CppEditor::ProjectFile::ObjCHeader: + case CppEditor::ProjectFile::ObjCXXHeader: + case CppEditor::ProjectFile::ObjCSource: + case CppEditor::ProjectFile::ObjCXXSource: + return true; + default: + return false; + } +} + ProjectFile::Kind ProjectFile::sourceForHeaderKind(ProjectFile::Kind kind) { ProjectFile::Kind sourceKind; diff --git a/src/plugins/cppeditor/cppprojectfile.h b/src/plugins/cppeditor/cppprojectfile.h index 078b93cce9..1bd80fdf65 100644 --- a/src/plugins/cppeditor/cppprojectfile.h +++ b/src/plugins/cppeditor/cppprojectfile.h @@ -61,6 +61,7 @@ public: static bool isC(Kind kind); static bool isCxx(Kind kind); static bool isAmbiguousHeader(const QString &filePath); + static bool isObjC(const QString &filePath); bool isHeader() const; bool isSource() const; diff --git a/src/plugins/cppeditor/cppprojectupdater.h b/src/plugins/cppeditor/cppprojectupdater.h index 165ec27910..b716ef3183 100644 --- a/src/plugins/cppeditor/cppprojectupdater.h +++ b/src/plugins/cppeditor/cppprojectupdater.h @@ -47,7 +47,7 @@ public: CppProjectUpdaterFactory(); // keep the namespace, for the type name in the invokeMethod call - Q_INVOKABLE CppProjectUpdaterInterface *create(); + Q_INVOKABLE CppEditor::CppProjectUpdaterInterface *create(); }; } // namespace Internal diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 8b9fdce190..91974761c2 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -2483,7 +2483,7 @@ void CompleteSwitchCaseStatement::match(const CppQuickFixInterface &interface, AST *ast = path.at(depth); SwitchStatementAST *switchStatement = ast->asSwitchStatement(); if (switchStatement) { - if (!switchStatement->statement) + if (!switchStatement->statement || !switchStatement->symbol) return; CompoundStatementAST *compoundStatement = switchStatement->statement->asCompoundStatement(); if (!compoundStatement) // we ignore pathologic case "switch (t) case A: ;" diff --git a/src/plugins/cppeditor/cpptoolsreuse.cpp b/src/plugins/cppeditor/cpptoolsreuse.cpp index 15a1bea88a..04f679824a 100644 --- a/src/plugins/cppeditor/cpptoolsreuse.cpp +++ b/src/plugins/cppeditor/cpptoolsreuse.cpp @@ -39,11 +39,15 @@ #include <coreplugin/idocument.h> #include <coreplugin/messagemanager.h> #include <projectexplorer/session.h> +#include <texteditor/codeassist/assistinterface.h> #include <texteditor/textdocument.h> -#include <cplusplus/Overview.h> +#include <cplusplus/BackwardsScanner.h> #include <cplusplus/LookupContext.h> +#include <cplusplus/Overview.h> +#include <cplusplus/SimpleLexer.h> #include <utils/algorithm.h> +#include <utils/porting.h> #include <utils/textutils.h> #include <utils/qtcassert.h> @@ -300,6 +304,40 @@ const Macro *findCanonicalMacro(const QTextCursor &cursor, Document::Ptr documen return nullptr; } +bool isInCommentOrString(const TextEditor::AssistInterface *interface, + CPlusPlus::LanguageFeatures features) +{ + QTextCursor tc(interface->textDocument()); + tc.setPosition(interface->position()); + + SimpleLexer tokenize; + features.qtMocRunEnabled = true; + tokenize.setLanguageFeatures(features); + tokenize.setSkipComments(false); + const Tokens &tokens = tokenize(tc.block().text(), + BackwardsScanner::previousBlockState(tc.block())); + const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1)); + const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx); + + if (tk.isComment()) + return true; + if (!tk.isLiteral()) + return false; + if (tokens.size() == 3 && tokens.at(0).kind() == T_POUND + && tokens.at(1).kind() == T_IDENTIFIER) { + const QString &line = tc.block().text(); + const Token &idToken = tokens.at(1); + QStringView identifier = Utils::midView(line, idToken.utf16charsBegin(), + idToken.utf16chars()); + if (identifier == QLatin1String("include") + || identifier == QLatin1String("include_next") + || (features.objCEnabled && identifier == QLatin1String("import"))) { + return false; + } + } + return true; +} + CppCodeModelSettings *codeModelSettings() { return Internal::CppEditorPlugin::instance()->codeModelSettings(); diff --git a/src/plugins/cppeditor/cpptoolsreuse.h b/src/plugins/cppeditor/cpptoolsreuse.h index b3fd7a274b..e7023b7be7 100644 --- a/src/plugins/cppeditor/cpptoolsreuse.h +++ b/src/plugins/cppeditor/cpptoolsreuse.h @@ -35,6 +35,7 @@ #include <cplusplus/ASTVisitor.h> #include <cplusplus/CppDocument.h> +#include <cplusplus/Token.h> QT_BEGIN_NAMESPACE class QChar; @@ -48,6 +49,8 @@ class Symbol; class LookupContext; } // namespace CPlusPlus +namespace TextEditor { class AssistInterface; } + namespace CppEditor { class CppRefactoringFile; class ProjectInfo; @@ -71,6 +74,9 @@ bool CPPEDITOR_EXPORT isOwnershipRAIIType(CPlusPlus::Symbol *symbol, const CPlusPlus::Macro CPPEDITOR_EXPORT *findCanonicalMacro(const QTextCursor &cursor, CPlusPlus::Document::Ptr document); +bool CPPEDITOR_EXPORT isInCommentOrString(const TextEditor::AssistInterface *interface, + CPlusPlus::LanguageFeatures features); + enum class CacheUsage { ReadWrite, ReadOnly }; QString CPPEDITOR_EXPORT correspondingHeaderOrSource(const QString &fileName, bool *wasHeader = nullptr, diff --git a/src/plugins/cppeditor/semantichighlighter.cpp b/src/plugins/cppeditor/semantichighlighter.cpp index f3112a725b..eb6e90fb2b 100644 --- a/src/plugins/cppeditor/semantichighlighter.cpp +++ b/src/plugins/cppeditor/semantichighlighter.cpp @@ -180,6 +180,7 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) QPair<QTextBlock, Parentheses> parentheses; for (int i = from; i < to; ++i) { const HighlightingResult &result = m_watcher->future().resultAt(i); + QTC_ASSERT(result.line <= m_baseTextDocument->document()->blockCount(), continue); if (result.kind != AngleBracketOpen && result.kind != AngleBracketClose && result.kind != DoubleAngleBracketClose && result.kind != TernaryIf && result.kind != TernaryElse) { diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index debdcaafdd..87d52ad74b 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -1891,7 +1891,7 @@ QString DebuggerEngine::nativeStartupCommands() const return !trimmed.isEmpty() && !trimmed.startsWith('#'); }); - return lines.join('\n'); + return expand(lines.join('\n')); } Perspective *DebuggerEngine::perspective() const @@ -2827,7 +2827,7 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp) globalRegExpSourceMap.reserve(sourcePathMap.size()); for (auto it = sourcePathMap.begin(), end = sourcePathMap.end(); it != end; ++it) { if (it.key().startsWith('(')) { - const QString expanded = Utils::globalMacroExpander()->expand(it.value()); + const QString expanded = rp.macroExpander->expand(it.value()); if (!expanded.isEmpty()) globalRegExpSourceMap.push_back( qMakePair(QRegularExpression(it.key()), expanded)); diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 8611e4668d..2099bc2f95 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -195,7 +195,7 @@ public: bool isCppDebugging() const; bool isNativeMixedDebugging() const; - Utils::MacroExpander *macroExpander = nullptr; + const Utils::MacroExpander *macroExpander = nullptr; Utils::optional<int> exitCode = {}; diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index 36e066e09a..3a5060cbe5 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -225,7 +225,7 @@ void DebuggerItem::reinitializeFromFile(const Environment &sysEnv, QString *erro return; } - qWarning() << "Unable to determine gdb target ABI"; + qWarning() << "Unable to determine gdb target ABI via" << proc.commandLine().toUserOutput(); //! \note If unable to determine the GDB ABI, no ABI is appended to m_abis here. return; } diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index ffece20708..8b92c7d31d 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -885,7 +885,7 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm QTC_ASSERT(kit, return); m_runParameters.sysRoot = SysRootKitAspect::sysRoot(kit); - m_runParameters.macroExpander = kit->macroExpander(); + m_runParameters.macroExpander = runControl->macroExpander(); m_runParameters.debugger = DebuggerKitAspect::runnable(kit); m_runParameters.cppEngineType = DebuggerKitAspect::engineType(kit); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 8109a3f91e..2251f4d9e6 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3800,8 +3800,11 @@ static SourcePathMap mergeStartParametersSourcePathMap(const DebuggerRunParamete { // Do not overwrite user settings. SourcePathMap rc = sp.sourcePathMap; - for (auto it = in.constBegin(), end = in.constEnd(); it != end; ++it) - rc.insert(it.key(), it.value()); + for (auto it = in.constBegin(), end = in.constEnd(); it != end; ++it) { + // Entries that start with parenthesis are handled in CppDebuggerEngine::validateRunParameters + if (!it.key().startsWith('(')) + rc.insert(it.key(), sp.macroExpander->expand(it.value())); + } return rc; } @@ -3850,6 +3853,7 @@ void GdbEngine::setupEngine() gdbCommand.addArg("-n"); Environment gdbEnv = rp.debugger.environment; + gdbEnv.setupEnglishOutput(); if (rp.runAsRoot) { CommandLine wrapped("sudo", {"-A"}); wrapped.addCommandLineAsArgs(gdbCommand); diff --git a/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp b/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp index 18fcdce5dc..9ac3cee8ee 100644 --- a/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp +++ b/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp @@ -215,9 +215,9 @@ bool CdbSymbolPathListEditor::isSymbolServerPath(const QString &path, QString *c if (!path.startsWith(QLatin1String(symbolServerPrefixC)) || !path.endsWith(QLatin1String(symbolServerPostfixC))) return false; if (cacheDir) { - static const unsigned prefixLength = qstrlen(symbolServerPrefixC); - static const unsigned postfixLength = qstrlen(symbolServerPostfixC); - if (path.length() == int(prefixLength + postfixLength)) + static const unsigned prefixLength = unsigned(qstrlen(symbolServerPrefixC)); + static const unsigned postfixLength = unsigned(qstrlen(symbolServerPostfixC)); + if (unsigned(path.length()) == prefixLength + postfixLength) return true; // Split apart symbol server post/prefixes *cacheDir = path.mid(prefixLength, path.size() - prefixLength - qstrlen(symbolServerPostfixC) + 1); @@ -230,7 +230,7 @@ bool CdbSymbolPathListEditor::isSymbolCachePath(const QString &path, QString *ca if (!path.startsWith(QLatin1String(symbolCachePrefixC))) return false; if (cacheDir) { - static const unsigned prefixLength = qstrlen(symbolCachePrefixC); + static const unsigned prefixLength = unsigned(qstrlen(symbolCachePrefixC)); // Split apart symbol cach prefixes *cacheDir = path.mid(prefixLength); } diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 1dc061c508..20a5c95108 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -133,7 +133,7 @@ template <class T> void readNumericVectorHelper(std::vector<double> *v, const QByteArray &ba) { const auto p = (const T*)ba.data(); - const int n = ba.size() / sizeof(T); + const int n = int(ba.size() / sizeof(T)); v->resize(n); // Losing precision in case of 64 bit ints is ok here, as the result // is only used to plot data. diff --git a/src/plugins/designer/codemodelhelpers.cpp b/src/plugins/designer/codemodelhelpers.cpp index b0d91f0a74..009bf83f53 100644 --- a/src/plugins/designer/codemodelhelpers.cpp +++ b/src/plugins/designer/codemodelhelpers.cpp @@ -82,7 +82,7 @@ private: }; SearchFunction::SearchFunction(const char *name) : - m_length(qstrlen(name)), + m_length(uint(qstrlen(name))), m_name(name) { } diff --git a/src/plugins/designer/formwindowfile.cpp b/src/plugins/designer/formwindowfile.cpp index 5744256813..192a1383eb 100644 --- a/src/plugins/designer/formwindowfile.cpp +++ b/src/plugins/designer/formwindowfile.cpp @@ -247,6 +247,11 @@ QString FormWindowFile::fallbackSaveAsFileName() const return m_suggestedName; } +bool FormWindowFile::supportsCodec(const QTextCodec *codec) const +{ + return codec == QTextCodec::codecForName("UTF-8"); +} + bool FormWindowFile::writeFile(const Utils::FilePath &filePath, QString *errorString) const { if (Designer::Constants::Internal::debug) diff --git a/src/plugins/designer/formwindowfile.h b/src/plugins/designer/formwindowfile.h index ca0ad50b3f..845a8ce0dc 100644 --- a/src/plugins/designer/formwindowfile.h +++ b/src/plugins/designer/formwindowfile.h @@ -58,6 +58,7 @@ public: bool isSaveAsAllowed() const override; bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override; QString fallbackSaveAsFileName() const override; + bool supportsCodec(const QTextCodec *codec) const override; // Internal void setFallbackSaveAsFileName(const QString &fileName); diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 638fb91db0..4461c7a1e8 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -833,14 +833,7 @@ void DockerDevicePrivate::startContainer() for (QString mount : qAsConst(m_data.mounts)) { if (mount.isEmpty()) continue; - // make sure to convert windows style paths to unix style paths with the file system case: - // C:/dev/src -> /c/dev/src - if (const FilePath mountPath = FilePath::fromUserInput(mount).normalizedPathName(); - mountPath.startsWithDriveLetter()) { - const QChar lowerDriveLetter = mountPath.path().at(0).toLower(); - const FilePath path = FilePath::fromUserInput(mountPath.path().mid(2)); // strip C: - mount = '/' + lowerDriveLetter + path.path(); - } + mount = q->mapToDevicePath(FilePath::fromUserInput(mount)); dockerCreate.addArgs({"-v", mount + ':' + mount}); } @@ -1069,6 +1062,19 @@ FilePath DockerDevice::mapToGlobalPath(const FilePath &pathOnDevice) const return result; } +QString DockerDevice::mapToDevicePath(const Utils::FilePath &globalPath) const +{ + // make sure to convert windows style paths to unix style paths with the file system case: + // C:/dev/src -> /c/dev/src + const FilePath normalized = FilePath::fromString(globalPath.path()).normalizedPathName(); + QString path = normalized.path(); + if (normalized.startsWithDriveLetter()) { + const QChar lowerDriveLetter = path.at(0).toLower(); + path = '/' + lowerDriveLetter + path.mid(2); // strip C: + } + return path; +} + bool DockerDevice::handlesFile(const FilePath &filePath) const { return filePath.scheme() == "docker" && filePath.host() == d->m_data.imageId; @@ -1570,7 +1576,7 @@ void DockerDevice::runProcess(QtcProcess &process) const CommandLine cmd{"docker", {"exec"}}; if (!workingDir.isEmpty()) { - cmd.addArgs({"-w", workingDir.path()}); + cmd.addArgs({"-w", mapToDevicePath(workingDir)}); if (QTC_GUARD(workingDir.needsDevice())) // warn on local working directory for docker cmd process.setWorkingDirectory(FileUtils::homePath()); // reset working dir for docker exec } diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h index ded9a93b06..c4d0efe703 100644 --- a/src/plugins/docker/dockerdevice.h +++ b/src/plugins/docker/dockerdevice.h @@ -76,6 +76,7 @@ public: ProjectExplorer::DeviceEnvironmentFetcher::Ptr environmentFetcher() const override; Utils::FilePath mapToGlobalPath(const Utils::FilePath &pathOnDevice) const override; + QString mapToDevicePath(const Utils::FilePath &globalPath) const override; bool handlesFile(const Utils::FilePath &filePath) const override; bool isExecutableFile(const Utils::FilePath &filePath) const override; diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 862dfc12b5..38ab02e0a9 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -1285,7 +1285,7 @@ public: << quoteUnprintable(m_text); } - friend uint qHash(const Input &i) + friend auto qHash(const Input &i) { return ::qHash(i.m_key); } @@ -6598,13 +6598,12 @@ bool FakeVimHandler::Private::handleExSourceCommand(const ExCommand &cmd) while (!file.atEnd() || !line.isEmpty()) { QByteArray nextline = !file.atEnd() ? file.readLine() : QByteArray(); - // remove comment - int i = nextline.lastIndexOf('"'); - if (i != -1) - nextline = nextline.remove(i, nextline.size() - i); - nextline = nextline.trimmed(); + // remove full line comment. for being precise, check :help comment in vim. + if (nextline.startsWith('"')) + continue; + // multi-line command? if (nextline.startsWith('\\')) { line += nextline.mid(1); @@ -8201,9 +8200,9 @@ void FakeVimHandler::Private::saveLastVisualMode() if (isVisualMode() && g.mode == CommandMode && g.submode == NoSubMode) { setMark('<', markLessPosition()); setMark('>', markGreaterPosition()); + m_buffer->lastVisualModeInverted = anchor() > position(); + m_buffer->lastVisualMode = g.visualMode; } - m_buffer->lastVisualModeInverted = anchor() > position(); - m_buffer->lastVisualMode = g.visualMode; } QWidget *FakeVimHandler::Private::editor() const diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 8be735072d..fae4f7c835 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -380,7 +380,6 @@ private: void copyTextEditorSettings(); void setQtStyle(); void setPlainStyle(); - void updateVimRcWidgets(); }; void FakeVimOptionPage::layoutPage(QWidget *widget) @@ -449,15 +448,14 @@ void FakeVimOptionPage::layoutPage(QWidget *widget) }.attachTo(widget, true); + s.vimRcPath.setEnabler(&s.readVimRc); + connect(copyTextEditorSettings, &QAbstractButton::clicked, this, &FakeVimOptionPage::copyTextEditorSettings); connect(setQtStyle, &QAbstractButton::clicked, this, &FakeVimOptionPage::setQtStyle); connect(setPlainStyle, &QAbstractButton::clicked, this, &FakeVimOptionPage::setPlainStyle); - connect(&s.readVimRc, &FvBaseAspect::changed, - this, &FakeVimOptionPage::updateVimRcWidgets); - updateVimRcWidgets(); } void FakeVimOptionPage::copyTextEditorSettings() @@ -503,13 +501,6 @@ void FakeVimOptionPage::setPlainStyle() s.passKeys.setVolatileValue(false); } -void FakeVimOptionPage::updateVimRcWidgets() -{ - FakeVimSettings &s = *fakeVimSettings(); - s.vimRcPath.setEnabled(s.readVimRc.value()); -} - - /////////////////////////////////////////////////////////////////////// // // FakeVimPluginPrivate diff --git a/src/plugins/ios/iosprobe.cpp b/src/plugins/ios/iosprobe.cpp index 79fddd3779..7fafba0ef4 100644 --- a/src/plugins/ios/iosprobe.cpp +++ b/src/plugins/ios/iosprobe.cpp @@ -160,12 +160,12 @@ bool XcodePlatform::operator==(const XcodePlatform &other) const return developerPath == other.developerPath; } -uint qHash(const XcodePlatform &platform) +Utils::QHashValueType qHash(const XcodePlatform &platform) { return qHash(platform.developerPath); } -uint qHash(const XcodePlatform::ToolchainTarget &target) +Utils::QHashValueType qHash(const XcodePlatform::ToolchainTarget &target) { return qHash(target.name); } diff --git a/src/plugins/ios/iosprobe.h b/src/plugins/ios/iosprobe.h index 52cf3015c5..966f669d08 100644 --- a/src/plugins/ios/iosprobe.h +++ b/src/plugins/ios/iosprobe.h @@ -24,6 +24,9 @@ ****************************************************************************/ #pragma once + +#include <utils/porting.h> + #include <QSettings> #include <QSharedPointer> #include <QString> @@ -61,8 +64,8 @@ public: bool operator==(const XcodePlatform &other) const; }; -uint qHash(const XcodePlatform &platform); -uint qHash(const XcodePlatform::ToolchainTarget &target); +Utils::QHashValueType qHash(const XcodePlatform &platform); +Utils::QHashValueType qHash(const XcodePlatform::ToolchainTarget &target); class XcodeProbe { diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 5f2b44d5e9..b177f82c52 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -1133,7 +1133,14 @@ void Client::handleMessage(const BaseMessage &message) void Client::log(const QString &message) const { - Core::MessageManager::writeFlashing(QString("LanguageClient %1: %2").arg(name(), message)); + switch (m_logTarget) { + case LogTarget::Ui: + Core::MessageManager::writeFlashing(QString("LanguageClient %1: %2").arg(name(), message)); + break; + case LogTarget::Console: + qCDebug(LOGLSPCLIENT) << message; + break; + } } const ServerCapabilities &Client::capabilities() const diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index bf06359ef4..59f23599a4 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -189,6 +189,8 @@ public: void setCompletionAssistProvider(LanguageClientCompletionAssistProvider *provider); // logging + enum class LogTarget { Console, Ui }; + void setLogTarget(LogTarget target) { m_logTarget = target; } void log(const QString &message) const; template<typename Error> void log(const LanguageServerProtocol::ResponseError<Error> &responseError) const @@ -288,6 +290,7 @@ private: QString m_serverName; QString m_serverVersion; LanguageServerProtocol::SymbolStringifier m_symbolStringifier; + LogTarget m_logTarget = LogTarget::Ui; bool m_locatorsEnabled = true; bool m_autoRequestCodeActions = true; }; diff --git a/src/plugins/languageclient/languageclientcompletionassist.cpp b/src/plugins/languageclient/languageclientcompletionassist.cpp index ca38029dc1..3eec6cbbd9 100644 --- a/src/plugins/languageclient/languageclientcompletionassist.cpp +++ b/src/plugins/languageclient/languageclientcompletionassist.cpp @@ -425,7 +425,7 @@ void LanguageClientCompletionAssistProcessor::handleCompletionResponse( items = Utils::get<QList<CompletionItem>>(*result); } auto proposalItems = generateCompletionItems(items); - if (!m_snippetsGroup.isEmpty()) { + if (!proposalItems.isEmpty() && !m_snippetsGroup.isEmpty()) { proposalItems << TextEditor::SnippetAssistCollector( m_snippetsGroup, QIcon(":/texteditor/images/snippet.png")).collect(); } diff --git a/src/plugins/modeleditor/modelindexer.cpp b/src/plugins/modeleditor/modelindexer.cpp index be4e49d9cd..d05cf9ecb3 100644 --- a/src/plugins/modeleditor/modelindexer.cpp +++ b/src/plugins/modeleditor/modelindexer.cpp @@ -46,6 +46,7 @@ #include <utils/mimetypes/mimetype.h> #include <utils/mimetypes/mimedatabase.h> #include <utils/qtcassert.h> +#include <utils/porting.h> #include <QQueue> #include <QMutex> @@ -62,7 +63,7 @@ namespace Internal { class ModelIndexer::QueuedFile { - friend uint qHash(const ModelIndexer::QueuedFile &queuedFile); + friend Utils::QHashValueType qHash(const ModelIndexer::QueuedFile &queuedFile); friend bool operator==(const ModelIndexer::QueuedFile &lhs, const ModelIndexer::QueuedFile &rhs); @@ -99,7 +100,7 @@ bool operator==(const ModelIndexer::QueuedFile &lhs, const ModelIndexer::QueuedF return lhs.m_file == rhs.m_file && lhs.m_project == rhs.m_project; } -uint qHash(const ModelIndexer::QueuedFile &queuedFile) +Utils::QHashValueType qHash(const ModelIndexer::QueuedFile &queuedFile) { return qHash(queuedFile.m_project) + qHash(queuedFile.m_project); } diff --git a/src/plugins/modeleditor/modelindexer.h b/src/plugins/modeleditor/modelindexer.h index 708ec26e9b..e6df8bdeed 100644 --- a/src/plugins/modeleditor/modelindexer.h +++ b/src/plugins/modeleditor/modelindexer.h @@ -25,6 +25,8 @@ #pragma once +#include <utils/porting.h> + #include <QObject> namespace qmt { class Uid; } @@ -50,7 +52,7 @@ class ModelIndexer : class DiagramsCollectorVisitor; class ModelIndexerPrivate; - friend uint qHash(const ModelIndexer::QueuedFile &queuedFile); + friend Utils::QHashValueType qHash(const ModelIndexer::QueuedFile &queuedFile); friend bool operator==(const ModelIndexer::QueuedFile &lhs, const ModelIndexer::QueuedFile &rhs); diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index be00bbf30c..16dd673959 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -36,6 +36,7 @@ #include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/command.h> #include <coreplugin/coreconstants.h> +#include <coreplugin/editormanager/documentmodel.h> #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/documentmanager.h> #include <coreplugin/icore.h> @@ -1043,7 +1044,12 @@ bool PerforcePluginPrivate::vcsOpen(const FilePath &workingDir, const QString &f flags |= SilentStdOut; } const PerforceResponse result = runP4Cmd(workingDir, args, flags); - return !result.error; + if (result.error) + return false; + const FilePath absPath = workingDir.resolvePath(fileName); + if (DocumentModel::Entry *e = DocumentModel::entryForFilePath(absPath)) + e->document->checkPermissions(); + return true; } bool PerforcePluginPrivate::vcsAdd(const FilePath &workingDir, const QString &fileName) diff --git a/src/plugins/projectexplorer/buildtargetinfo.h b/src/plugins/projectexplorer/buildtargetinfo.h index 7d786de3ca..34d5f19624 100644 --- a/src/plugins/projectexplorer/buildtargetinfo.h +++ b/src/plugins/projectexplorer/buildtargetinfo.h @@ -30,6 +30,7 @@ #include <utils/algorithm.h> #include <utils/environment.h> #include <utils/fileutils.h> +#include <utils/porting.h> #include <QList> @@ -48,7 +49,7 @@ public: bool isQtcRunnable = true; bool usesTerminal = false; - uint runEnvModifierHash = 0; // Make sure to update this when runEnvModifier changes! + Utils::QHashValueType runEnvModifierHash = 0; // Make sure to update this when runEnvModifier changes! std::function<void(Utils::Environment &, bool)> runEnvModifier; }; diff --git a/src/plugins/projectexplorer/deployablefile.cpp b/src/plugins/projectexplorer/deployablefile.cpp index 78fbcb165e..7ecfb59409 100644 --- a/src/plugins/projectexplorer/deployablefile.cpp +++ b/src/plugins/projectexplorer/deployablefile.cpp @@ -53,7 +53,7 @@ bool DeployableFile::isExecutable() const return m_type == TypeExecutable; } -uint qHash(const DeployableFile &d) +Utils::QHashValueType qHash(const DeployableFile &d) { return qHash(qMakePair(d.localFilePath().toString(), d.remoteDirectory())); } diff --git a/src/plugins/projectexplorer/deployablefile.h b/src/plugins/projectexplorer/deployablefile.h index 4709206b16..e3760e4a02 100644 --- a/src/plugins/projectexplorer/deployablefile.h +++ b/src/plugins/projectexplorer/deployablefile.h @@ -28,6 +28,7 @@ #include "projectexplorer_export.h" #include <utils/fileutils.h> +#include <utils/porting.h> #include <QString> @@ -71,6 +72,6 @@ inline bool operator!=(const DeployableFile &d1, const DeployableFile &d2) return !(d1 == d2); } -PROJECTEXPLORER_EXPORT uint qHash(const DeployableFile &d); +PROJECTEXPLORER_EXPORT Utils::QHashValueType qHash(const DeployableFile &d); } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp index f7470cd079..1e671e5fe3 100644 --- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp @@ -484,6 +484,18 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique<DeviceManager return device->symLinkTarget(filePath); }; + deviceHooks.mapToGlobalPath = [](const FilePath &filePath) { + auto device = DeviceManager::deviceForPath(filePath); + QTC_ASSERT(device, return FilePath{}); + return device->mapToGlobalPath(filePath); + }; + + deviceHooks.mapToDevicePath = [](const FilePath &filePath) { + auto device = DeviceManager::deviceForPath(filePath); + QTC_ASSERT(device, return QString{}); + return device->mapToDevicePath(filePath); + }; + deviceHooks.dirEntries = [](const FilePath &filePath, const QStringList &nameFilters, QDir::Filters filters, QDir::SortFlags sort) { auto device = DeviceManager::deviceForPath(filePath); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 8c90a7fc14..f1bedcc441 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -212,6 +212,11 @@ FilePath IDevice::mapToGlobalPath(const FilePath &pathOnDevice) const return pathOnDevice; } +QString IDevice::mapToDevicePath(const FilePath &globalPath) const +{ + return globalPath.path(); +} + bool IDevice::handlesFile(const FilePath &filePath) const { Q_UNUSED(filePath); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 873eb380bb..56bdbb5bd2 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -237,6 +237,7 @@ public: bool isAnyUnixDevice() const; virtual Utils::FilePath mapToGlobalPath(const Utils::FilePath &pathOnDevice) const; + virtual QString mapToDevicePath(const Utils::FilePath &globalPath) const; virtual bool handlesFile(const Utils::FilePath &filePath) const; virtual bool isExecutableFile(const Utils::FilePath &filePath) const; diff --git a/src/plugins/projectexplorer/expanddata.cpp b/src/plugins/projectexplorer/expanddata.cpp index bf3876475d..4b005b8fe5 100644 --- a/src/plugins/projectexplorer/expanddata.cpp +++ b/src/plugins/projectexplorer/expanddata.cpp @@ -50,7 +50,7 @@ QVariant ExpandData::toSettings() const return QVariant::fromValue(QStringList({path, displayName})); } -int ProjectExplorer::Internal::qHash(const ExpandData &data) +Utils::QHashValueType ProjectExplorer::Internal::qHash(const ExpandData &data) { return qHash(data.path) ^ qHash(data.displayName); } diff --git a/src/plugins/projectexplorer/expanddata.h b/src/plugins/projectexplorer/expanddata.h index 9d6a656449..a7ff078680 100644 --- a/src/plugins/projectexplorer/expanddata.h +++ b/src/plugins/projectexplorer/expanddata.h @@ -25,6 +25,8 @@ #pragma once +#include <utils/porting.h> + #include <QString> #include <QHash> #include <QDebug> @@ -46,7 +48,7 @@ public: QString displayName; }; -int qHash(const ExpandData &data); +Utils::QHashValueType qHash(const ExpandData &data); } // namespace Internal } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/gccparser.cpp b/src/plugins/projectexplorer/gccparser.cpp index 6479240c2b..30ebe45bf8 100644 --- a/src/plugins/projectexplorer/gccparser.cpp +++ b/src/plugins/projectexplorer/gccparser.cpp @@ -1367,6 +1367,14 @@ void ProjectExplorerPlugin::testGccOutputParsers_data() CompileTask(Task::Error, ".pch/Qt6Core5Compat: No such file or directory", ".pch/Qt6Core5Compat"), CompileTask(Task::Warning, "-Wformat-security ignored without -Wformat [-Wformat-security]")} << QString(); + + QTest::newRow("clean path") + << QString("/home/tim/path/to/sources/./and/more.h:15:22: error: blubb") + << OutputParserTester::STDERR + << QString() << QString() + << Tasks{CompileTask(Task::Error, "blubb", "/home/tim/path/to/sources/and/more.h", + 15, 22)} + << QString(); } void ProjectExplorerPlugin::testGccOutputParsers() diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp index ac73d2a047..31155c276c 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp @@ -87,6 +87,7 @@ const char PAGE_SHORT_TITLE_KEY[] = "trShortTitle"; const char PAGE_INDEX_KEY[] = "index"; const char OPTIONS_KEY[] = "options"; const char PLATFORM_INDEPENDENT_KEY[] = "platformIndependent"; +const char DEFAULT_VALUES[] = "defaultValues"; static QList<JsonWizardPageFactory *> s_pageFactories; static QList<JsonWizardGeneratorFactory *> s_generatorFactories; @@ -153,7 +154,131 @@ static JsonWizardFactory::Generator parseGenerator(const QVariant &value, QStrin return gen; } -static JsonWizardFactory::Page parsePage(const QVariant &value, QString *errorMessage) +//FIXME: createWizardFactories() has an almost identical loop. Make the loop return the results instead of +//internal processing and create a separate function for it. Then process the results in +//loadDefaultValues() and createWizardFactories() +QVariantMap JsonWizardFactory::loadDefaultValues(const QString &fileName) +{ + QString verboseLog; + + if (fileName.isEmpty()) { + return {}; + } + + QList <Core::IWizardFactory *> result; + foreach (const Utils::FilePath &path, searchPaths()) { + if (path.isEmpty()) + continue; + + FilePath dir = FilePath::fromString(path.toString()); + if (!dir.exists()) { + if (verbose()) + verboseLog.append(tr("Path \"%1\" does not exist when checking Json wizard search paths.\n") + .arg(path.toUserOutput())); + continue; + } + + const QDir::Filters filters = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot; + FilePaths dirs = dir.dirEntries(filters); + + while (!dirs.isEmpty()) { + const FilePath current = dirs.takeFirst(); + if (verbose()) + verboseLog.append(tr("Checking \"%1\" for %2.\n") + .arg(QDir::toNativeSeparators(current.absolutePath().toString())) + .arg(fileName)); + if (current.pathAppended(fileName).exists()) { + QFile configFile(current.pathAppended(fileName).toString()); + configFile.open(QIODevice::ReadOnly); + QJsonParseError error; + const QByteArray fileData = configFile.readAll(); + const QJsonDocument json = QJsonDocument::fromJson(fileData, &error); + configFile.close(); + + if (error.error != QJsonParseError::NoError) { + int line = 1; + int column = 1; + for (int i = 0; i < error.offset; ++i) { + if (fileData.at(i) == '\n') { + ++line; + column = 1; + } else { + ++column; + } + } + verboseLog.append(tr("* Failed to parse \"%1\":%2:%3: %4\n") + .arg(configFile.fileName()) + .arg(line).arg(column) + .arg(error.errorString())); + continue; + } + + if (!json.isObject()) { + verboseLog.append(tr("* Did not find a JSON object in \"%1\".\n") + .arg(configFile.fileName())); + continue; + } + + if (verbose()) + verboseLog.append(tr("* Configuration found and parsed.\n")); + + return json.object().toVariantMap(); + } + FilePaths subDirs = current.dirEntries(filters); + if (!subDirs.isEmpty()) { + // There is no QList::prepend(QList)... + dirs.swap(subDirs); + dirs.append(subDirs); + } else if (verbose()) { + verboseLog.append(tr("JsonWizard: \"%1\" not found\n").arg(fileName)); + } + } + } + + if (verbose()) { // Print to output pane for Windows. + qWarning("%s", qPrintable(verboseLog)); + Core::MessageManager::writeDisrupting(verboseLog); + } + + return {}; +} + +QVariant JsonWizardFactory::mergeDataValueMaps(const QVariant &valueMap, const QVariant &defaultValueMap) +{ + QVariantMap retVal; + +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + const QVariantMap &map = defaultValueMap.toMap(); + for (auto it = map.begin(), end = map.end(); it != end; ++it) + retVal.insert(it.key(), it.value()); + + const QVariantMap &map2 = valueMap.toMap(); + for (auto it = map2.begin(), end = map2.end(); it != end; ++it) + retVal.insert(it.key(), it.value()); +#else + retVal.insert(defaultValueMap.toMap()); + retVal.insert(valueMap.toMap()); +#endif + return retVal; +} + +QVariant JsonWizardFactory::getDataValue(const QLatin1String &key, const QVariantMap &valueSet, + const QVariantMap &defaultValueSet, const QVariant ¬ExistValue) +{ + QVariant retVal = {}; + + if ((valueSet.contains(key) && valueSet.value(key).type() == QVariant::Map) || + (defaultValueSet.contains(key) && defaultValueSet.value(key).type() == QVariant::Map)) { + retVal = mergeDataValueMaps(valueSet.value(key), defaultValueSet.value(key)); + } else { + QVariant defaultValue = defaultValueSet.value(key, notExistValue); + retVal = valueSet.value(key, defaultValue); + } + + return retVal; +} + +JsonWizardFactory::Page JsonWizardFactory::parsePage(const QVariant &value, QString *errorMessage) { JsonWizardFactory::Page p; @@ -163,7 +288,12 @@ static JsonWizardFactory::Page parsePage(const QVariant &value, QString *errorMe } const QVariantMap data = value.toMap(); - const QString strVal = data.value(QLatin1String(TYPE_ID_KEY)).toString(); + QString defaultValueFile = data.value(QLatin1String(DEFAULT_VALUES)).toString(); + if (!defaultValueFile.isEmpty()) + defaultValueFile.append(QLatin1String(".json")); + const QVariantMap defaultData = loadDefaultValues(defaultValueFile); + + const QString strVal = getDataValue(QLatin1String(TYPE_ID_KEY), data, defaultData).toString(); if (strVal.isEmpty()) { *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizardFactory", "Page has no typeId set."); return p; @@ -180,21 +310,31 @@ static JsonWizardFactory::Page parsePage(const QVariant &value, QString *errorMe return p; } - const QString title = JsonWizardFactory::localizedString(data.value(QLatin1String(DISPLAY_NAME_KEY))); - const QString subTitle = JsonWizardFactory::localizedString(data.value(QLatin1String(PAGE_SUB_TITLE_KEY))); - const QString shortTitle = JsonWizardFactory::localizedString(data.value(QLatin1String(PAGE_SHORT_TITLE_KEY))); + const QString title = JsonWizardFactory::localizedString(getDataValue(QLatin1String(DISPLAY_NAME_KEY), data, defaultData)); + const QString subTitle = JsonWizardFactory::localizedString(getDataValue(QLatin1String(PAGE_SUB_TITLE_KEY), data, defaultData)); + const QString shortTitle = JsonWizardFactory::localizedString(getDataValue(QLatin1String(PAGE_SHORT_TITLE_KEY), data, defaultData)); bool ok; - int index = data.value(QLatin1String(PAGE_INDEX_KEY), -1).toInt(&ok); + int index = getDataValue(QLatin1String(PAGE_INDEX_KEY), data, defaultData, -1).toInt(&ok); if (!ok) { *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizardFactory", "Page with typeId \"%1\" has invalid \"index\".") .arg(typeId.toString()); return p; } - QVariant enabled = data.value(QLatin1String(ENABLED_EXPRESSION_KEY), true); + QVariant enabled = getDataValue(QLatin1String(ENABLED_EXPRESSION_KEY), data, defaultData, true); + + QVariant specifiedSubData = data.value(QLatin1String(DATA_KEY)); + QVariant defaultSubData = defaultData.value(QLatin1String(DATA_KEY)); + QVariant subData; + + if (specifiedSubData.isNull()) + subData = defaultSubData; + else if (specifiedSubData.type() == QVariant::Map) + subData = mergeDataValueMaps(specifiedSubData.toMap(), defaultSubData.toMap()); + else if (specifiedSubData.type() == QVariant::List) + subData = specifiedSubData; - QVariant subData = data.value(QLatin1String(DATA_KEY)); if (!factory->validateData(typeId, subData, errorMessage)) return p; @@ -209,6 +349,9 @@ static JsonWizardFactory::Page parsePage(const QVariant &value, QString *errorMe return p; } +//FIXME: loadDefaultValues() has an almost identical loop. Make the loop return the results instead of +//internal processing and create a separate function for it. Then process the results in +//loadDefaultValues() and loadDefaultValues() QList<Core::IWizardFactory *> JsonWizardFactory::createWizardFactories() { QString errorMessage; @@ -258,14 +401,12 @@ QList<Core::IWizardFactory *> JsonWizardFactory::createWizardFactories() .arg(currentFile.fileName()) .arg(line).arg(column) .arg(error.errorString())); - qWarning() << "Failed to parse wizard: " << currentFile.fileName(); continue; } if (!json.isObject()) { verboseLog.append(tr("* Did not find a JSON object in \"%1\".\n") .arg(currentFile.fileName())); - qWarning() << "Failed to parse wizard: " << currentFile.fileName(); continue; } @@ -283,7 +424,6 @@ QList<Core::IWizardFactory *> JsonWizardFactory::createWizardFactories() JsonWizardFactory *factory = createWizardFactory(data, currentDir, &errorMessage); if (!factory) { verboseLog.append(tr("* Failed to create: %1\n").arg(errorMessage)); - qWarning() << "Failed to create wizard: " << currentFile.fileName(); continue; } diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h index c3c6c5bd34..d69aaa00f0 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h @@ -100,6 +100,12 @@ private: static void destroyAllFactories(); bool initialize(const QVariantMap &data, const Utils::FilePath &baseDir, QString *errorMessage); + JsonWizardFactory::Page parsePage(const QVariant &value, QString *errorMessage); + QVariantMap loadDefaultValues(const QString &fileName); + QVariant getDataValue(const QLatin1String &key, const QVariantMap &valueSet, + const QVariantMap &defaultValueSet, const QVariant ¬ExistValue={}); + QVariant mergeDataValueMaps(const QVariant &valueMap, const QVariant &defaultValueMap); + QVariant m_enabledExpression; Utils::FilePath m_wizardDir; QList<Generator> m_generators; diff --git a/src/plugins/projectexplorer/parseissuesdialog.cpp b/src/plugins/projectexplorer/parseissuesdialog.cpp index 75be7e7bcb..f81db2da7d 100644 --- a/src/plugins/projectexplorer/parseissuesdialog.cpp +++ b/src/plugins/projectexplorer/parseissuesdialog.cpp @@ -32,9 +32,6 @@ #include "projectexplorerconstants.h" #include "taskhub.h" -#include <coreplugin/progressmanager/progressmanager.h> -#include <utils/runextensions.h> - #include <QButtonGroup> #include <QCheckBox> #include <QDialogButtonBox> @@ -137,21 +134,6 @@ ParseIssuesDialog::~ParseIssuesDialog() delete d; } -static void parse(QFutureInterface<void> &future, const QString &output, - const std::unique_ptr<Utils::OutputFormatter> &parser, bool isStderr) -{ - const QStringList lines = output.split('\n'); - future.setProgressRange(0, lines.count()); - const Utils::OutputFormat format = isStderr ? Utils::StdErrFormat : Utils::StdOutFormat; - for (const QString &line : lines) { - parser->appendMessage(line + '\n', format); - future.setProgressValue(future.progressValue() + 1); - if (future.isCanceled()) - return; - } - parser->flush(); -} - void ParseIssuesDialog::accept() { const QList<Utils::OutputLineParser *> lineParsers = @@ -161,14 +143,16 @@ void ParseIssuesDialog::accept() "not provide an output parser.")); return; } - std::unique_ptr<Utils::OutputFormatter> parser(new Utils::OutputFormatter); - parser->setLineParsers(lineParsers); + Utils::OutputFormatter parser; + parser.setLineParsers(lineParsers); if (d->clearTasksCheckBox.isChecked()) TaskHub::clearTasks(); - const QFuture<void> f = Utils::runAsync(&parse, d->compileOutputEdit.toPlainText(), - std::move(parser), d->stderrCheckBox.isChecked()); - Core::ProgressManager::addTask(f, tr("Parsing build output"), - "ProgressExplorer.ParseExternalBuildOutput"); + const QStringList lines = d->compileOutputEdit.toPlainText().split('\n'); + const Utils::OutputFormat format = d->stderrCheckBox.isChecked() + ? Utils::StdErrFormat : Utils::StdOutFormat; + for (const QString &line : lines) + parser.appendMessage(line + '\n', format); + parser.flush(); QDialog::accept(); } diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index a49011bc41..b283862c46 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -376,7 +376,7 @@ void Project::setExtraProjectFiles(const QSet<FilePath> &projectDocumentPaths, const QSet<FilePath> toAdd = uniqueNewFiles - existingWatches; const QSet<FilePath> toRemove = existingWatches - uniqueNewFiles; - erase(d->m_extraProjectDocuments, [&toRemove](const std::unique_ptr<IDocument> &d) { + Utils::erase(d->m_extraProjectDocuments, [&toRemove](const std::unique_ptr<IDocument> &d) { return toRemove.contains(d->filePath()); }); if (docUpdater) { @@ -586,7 +586,8 @@ void Project::setRootProjectNode(std::unique_ptr<ProjectNode> &&root) } if (root) { - ProjectTree::applyTreeManager(root.get()); + ProjectTree::applyTreeManager(root.get(), ProjectTree::AsyncPhase); + ProjectTree::applyTreeManager(root.get(), ProjectTree::FinalPhase); root->setParentFolderNode(d->m_containerNode.get()); } @@ -804,8 +805,9 @@ void Project::createTargetFromMap(const QVariantMap &map, int index) deviceTypeId = Constants::DESKTOP_DEVICE_TYPE; const QString formerKitName = targetMap.value(Target::displayNameKey()).toString(); k = KitManager::registerKit([deviceTypeId, &formerKitName](Kit *kit) { - const QString tempKitName = makeUniquelyNumbered( - tr("Replacement for \"%1\"").arg(formerKitName), + const QString kitNameSuggestion = formerKitName.contains(tr("Replacement for")) + ? formerKitName : tr("Replacement for \"%1\"").arg(formerKitName); + const QString tempKitName = makeUniquelyNumbered(kitNameSuggestion, transform(KitManager::kits(), &Kit::unexpandedDisplayName)); kit->setUnexpandedDisplayName(tempKitName); DeviceTypeKitAspect::setDeviceTypeId(kit, deviceTypeId); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index f7fe67d213..46db91993a 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2602,7 +2602,7 @@ void ProjectExplorerPluginPrivate::restoreSession() dd->m_arguments = arguments; // delay opening projects from the command line even more QTimer::singleShot(0, m_instance, []() { - ICore::openFiles(Utils::transform(dd->m_arguments, &FilePath::fromString), + ICore::openFiles(Utils::transform(dd->m_arguments, &FilePath::fromUserInput), ICore::OpenFilesFlags(ICore::CanContainLineAndColumnNumbers | ICore::SwitchMode)); emit m_instance->finishedInitialization(); }); diff --git a/src/plugins/projectexplorer/projecttree.cpp b/src/plugins/projectexplorer/projecttree.cpp index aa8e79f9ef..ee040d5a37 100644 --- a/src/plugins/projectexplorer/projecttree.cpp +++ b/src/plugins/projectexplorer/projecttree.cpp @@ -402,13 +402,13 @@ void ProjectTree::registerTreeManager(const TreeManagerFunction &treeChange) s_instance->m_treeManagers.append(treeChange); } -void ProjectTree::applyTreeManager(FolderNode *folder) +void ProjectTree::applyTreeManager(FolderNode *folder, ConstructionPhase phase) { if (!folder) return; for (TreeManagerFunction &f : s_instance->m_treeManagers) - f(folder); + f(folder, phase); } bool ProjectTree::hasNode(const Node *node) diff --git a/src/plugins/projectexplorer/projecttree.h b/src/plugins/projectexplorer/projecttree.h index 060dad2290..3947666d3a 100644 --- a/src/plugins/projectexplorer/projecttree.h +++ b/src/plugins/projectexplorer/projecttree.h @@ -68,6 +68,11 @@ public: const bool m_active = false; }; + enum ConstructionPhase { + AsyncPhase, + FinalPhase + }; + // Integration with ProjectTreeWidget static void registerWidget(Internal::ProjectTreeWidget *widget); static void unregisterWidget(Internal::ProjectTreeWidget *widget); @@ -79,9 +84,9 @@ public: static void highlightProject(Project *project, const QString &message); - using TreeManagerFunction = std::function<void(FolderNode *)>; + using TreeManagerFunction = std::function<void(FolderNode *, ConstructionPhase)>; static void registerTreeManager(const TreeManagerFunction &treeChange); - static void applyTreeManager(FolderNode *folder); + static void applyTreeManager(FolderNode *folder, ConstructionPhase phase); // Nodes: static bool hasNode(const Node *node); diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index 0a3a2634b0..2291a86fbd 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -251,7 +251,9 @@ FilePath WorkingDirectoryAspect::workingDirectory() const const Environment env = m_envAspect ? m_envAspect->environment() : Environment::systemEnvironment(); FilePath res = m_workingDirectory; - const QString workingDir = m_workingDirectory.path(); + QString workingDir = m_workingDirectory.path(); + if (m_macroExpander) + workingDir = m_macroExpander->expandProcessArgs(workingDir); res.setPath(PathChooser::expandedDirectory(workingDir, env, QString())); return res; } diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 4cd0665f09..9ca0e228c3 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -349,7 +349,7 @@ public: IDevice::ConstPtr device; Utils::Id runMode; Utils::Icon icon; - const MacroExpander *macroExpander; + const MacroExpander *macroExpander = nullptr; QPointer<RunConfiguration> runConfiguration; // Not owned. Avoid use. QString buildKey; QMap<Utils::Id, QVariantMap> settingsData; @@ -389,11 +389,12 @@ void RunControl::setRunConfiguration(RunConfiguration *runConfig) d->runConfigId = runConfig->id(); d->runnable = runConfig->runnable(); d->displayName = runConfig->expandedDisplayName(); - d->macroExpander = runConfig->macroExpander(); d->buildKey = runConfig->buildKey(); d->settingsData = runConfig->aspectData(); setTarget(runConfig->target()); + + d->macroExpander = runConfig->macroExpander(); } void RunControl::setTarget(Target *target) @@ -412,6 +413,7 @@ void RunControl::setTarget(Target *target) } setKit(target->kit()); + d->macroExpander = target->macroExpander(); d->project = target->project(); } @@ -420,6 +422,7 @@ void RunControl::setKit(Kit *kit) QTC_ASSERT(kit, return); QTC_CHECK(!d->kit); d->kit = kit; + d->macroExpander = kit->macroExpander(); if (d->runnable.device) setDevice(d->runnable.device); diff --git a/src/plugins/projectexplorer/task.cpp b/src/plugins/projectexplorer/task.cpp index fe880442ba..3ef9e397a9 100644 --- a/src/plugins/projectexplorer/task.cpp +++ b/src/plugins/projectexplorer/task.cpp @@ -171,7 +171,7 @@ bool operator<(const Task &a, const Task &b) } -uint qHash(const Task &task) +Utils::QHashValueType qHash(const Task &task) { return task.taskId; } diff --git a/src/plugins/projectexplorer/task.h b/src/plugins/projectexplorer/task.h index a21332c708..b95d51d34e 100644 --- a/src/plugins/projectexplorer/task.h +++ b/src/plugins/projectexplorer/task.h @@ -29,6 +29,7 @@ #include <utils/id.h> #include <utils/fileutils.h> +#include <utils/porting.h> #include <QIcon> #include <QMetaType> @@ -135,13 +136,13 @@ public: using Tasks = QVector<Task>; -bool PROJECTEXPLORER_EXPORT operator==(const Task &t1, const Task &t2); -uint PROJECTEXPLORER_EXPORT qHash(const Task &task); +PROJECTEXPLORER_EXPORT bool operator==(const Task &t1, const Task &t2); +PROJECTEXPLORER_EXPORT Utils::QHashValueType qHash(const Task &task); -bool PROJECTEXPLORER_EXPORT operator<(const Task &a, const Task &b); +PROJECTEXPLORER_EXPORT bool operator<(const Task &a, const Task &b); -QString PROJECTEXPLORER_EXPORT toHtml(const Tasks &issues); -bool PROJECTEXPLORER_EXPORT containsType(const Tasks &issues, Task::TaskType); +PROJECTEXPLORER_EXPORT QString toHtml(const Tasks &issues); +PROJECTEXPLORER_EXPORT bool containsType(const Tasks &issues, Task::TaskType); } //namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/treescanner.cpp b/src/plugins/projectexplorer/treescanner.cpp index ce6da40b1c..88e7b8d4a8 100644 --- a/src/plugins/projectexplorer/treescanner.cpp +++ b/src/plugins/projectexplorer/treescanner.cpp @@ -159,7 +159,7 @@ static std::unique_ptr<FolderNode> createFolderNode(const Utils::FilePath &direc std::unique_ptr<FileNode> node(fn->clone()); fileSystemNode->addNestedNode(std::move(node)); } - ProjectTree::applyTreeManager(fileSystemNode.get()); // QRC nodes + ProjectTree::applyTreeManager(fileSystemNode.get(), ProjectTree::AsyncPhase); // QRC nodes return fileSystemNode; } diff --git a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp index c481975753..7e3c31c378 100644 --- a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp +++ b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp @@ -232,7 +232,7 @@ QbsProjectNode *QbsNodeTreeBuilder::buildTree(const QString &projectName, } buildSystemFiles->compress(); root->addNode(std::move(buildSystemFiles)); - ProjectTree::applyTreeManager(root.get()); // QRC nodes + ProjectTree::applyTreeManager(root.get(), ProjectTree::AsyncPhase); // QRC nodes return root.release(); } diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index f64aecd296..b9c048764e 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -69,8 +69,8 @@ namespace QmakeProjectManager { static Q_LOGGING_CATEGORY(qmakeParse, "qtc.qmake.parsing", QtWarningMsg); -uint qHash(Variable key, uint seed) { return ::qHash(static_cast<int>(key), seed); } -uint qHash(FileOrigin fo) { return ::qHash(int(fo)); } +Utils::QHashValueType qHash(Variable key, uint seed) { return ::qHash(static_cast<int>(key), seed); } +Utils::QHashValueType qHash(FileOrigin fo) { return ::qHash(int(fo)); } namespace Internal { diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h index cfa86b181f..9a4a22690e 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h @@ -31,6 +31,7 @@ #include <coreplugin/idocument.h> #include <cppeditor/generatedcodemodelsupport.h> +#include <utils/porting.h> #include <utils/textfileformat.h> #include <QFutureWatcher> @@ -109,7 +110,7 @@ enum class Variable { QmakeCc, QmakeCxx }; -uint qHash(Variable key, uint seed = 0); +Utils::QHashValueType qHash(Variable key, uint seed = 0); namespace Internal { Q_DECLARE_LOGGING_CATEGORY(qmakeNodesLog) @@ -121,7 +122,7 @@ class QmakePriFileEvalResult; class InstallsList; enum class FileOrigin { ExactParse, CumulativeParse }; -uint qHash(FileOrigin fo); +Utils::QHashValueType qHash(FileOrigin fo); using SourceFile = QPair<Utils::FilePath, FileOrigin>; using SourceFiles = QSet<SourceFile>; diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index ce73af5161..0fe3867a7e 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -4,6 +4,7 @@ if (APPLE) endif() add_qtc_plugin(QmlDesigner + CONDITION TARGET Qt5::QuickWidgets DEPENDS QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem Qt5::QuickWidgets Qt5::CorePrivate Sqlite @@ -27,6 +28,7 @@ add_qtc_plugin(QmlDesigner documentmanager.cpp documentmanager.h documentwarningwidget.cpp documentwarningwidget.h generateresource.cpp generateresource.h + generatecmakelists.cpp generatecmakelists.h openuiqmlfiledialog.cpp openuiqmlfiledialog.h openuiqmlfiledialog.ui qmldesignerconstants.h qmldesignericons.h diff --git a/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.cpp b/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.cpp index 872a004fcc..5b8a4934dd 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.cpp @@ -46,7 +46,7 @@ AbstractEditorDialog::AbstractEditorDialog(QWidget *parent, const QString &title { setWindowFlag(Qt::Tool, true); setWindowTitle(defaultTitle()); - setModal(false); + setModal(true); setupJSEditor(); setupUIComponents(); @@ -111,11 +111,10 @@ void AbstractEditorDialog::setupJSEditor() { static BindingEditorFactory f; m_editor = qobject_cast<TextEditor::BaseTextEditor*>(f.createEditor()); - m_editorWidget = qobject_cast<BindingEditorWidget*>(m_editor->editorWidget()); + Q_ASSERT(m_editor); - Core::Context context = m_editor->context(); - context.prepend(BINDINGEDITOR_CONTEXT_ID); - m_editorWidget->m_context->setContext(context); + m_editorWidget = qobject_cast<BindingEditorWidget*>(m_editor->editorWidget()); + Q_ASSERT(m_editorWidget); auto qmlDesignerEditor = QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor(); diff --git a/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.h b/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.h index ed8cdd0a13..76de79b195 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.h +++ b/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.h @@ -26,9 +26,10 @@ #ifndef ABSTRACTEDITORDIALOG_H #define ABSTRACTEDITORDIALOG_H -#include <bindingeditor/bindingeditorwidget.h> #include <qmldesignercorelib_global.h> + #include <texteditor/texteditor.h> +#include <bindingeditor/bindingeditorwidget.h> #include <QDialog> diff --git a/src/plugins/qmldesigner/components/bindingeditor/actioneditor.cpp b/src/plugins/qmldesigner/components/bindingeditor/actioneditor.cpp index 89364c5116..1f2a8224d3 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/actioneditor.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/actioneditor.cpp @@ -286,10 +286,13 @@ void ActionEditor::prepareConnections() m_dialog->setAllConnections(connections, singletons, states); } -void ActionEditor::updateWindowName() +void ActionEditor::updateWindowName(const QString &targetName) { if (!m_dialog.isNull()) { - m_dialog->setWindowTitle(m_dialog->defaultTitle()); + if (targetName.isEmpty()) + m_dialog->setWindowTitle(m_dialog->defaultTitle()); + else + m_dialog->setWindowTitle(m_dialog->defaultTitle() + " [" + targetName + "]"); m_dialog->raise(); } } diff --git a/src/plugins/qmldesigner/components/bindingeditor/actioneditor.h b/src/plugins/qmldesigner/components/bindingeditor/actioneditor.h index c0356e81c4..09597bc8d1 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/actioneditor.h +++ b/src/plugins/qmldesigner/components/bindingeditor/actioneditor.h @@ -64,7 +64,7 @@ public: void prepareConnections(); - Q_INVOKABLE void updateWindowName(); + Q_INVOKABLE void updateWindowName(const QString &targetName = {}); signals: void accepted(); diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp index d28457e1f5..eff90366a0 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp @@ -42,8 +42,6 @@ namespace QmlDesigner { -static BindingEditor *s_lastBindingEditor = nullptr; - BindingEditor::BindingEditor(QObject *) { } @@ -62,11 +60,6 @@ void BindingEditor::prepareDialog() { QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_BINDINGEDITOR_OPENED); - if (s_lastBindingEditor) - s_lastBindingEditor->hideWidget(); - - s_lastBindingEditor = this; - m_dialog = new BindingEditorDialog(Core::ICore::dialogParent()); QObject::connect(m_dialog, &AbstractEditorDialog::accepted, @@ -91,9 +84,6 @@ void BindingEditor::showWidget(int x, int y) void BindingEditor::hideWidget() { - if (s_lastBindingEditor == this) - s_lastBindingEditor = nullptr; - if (m_dialog) { m_dialog->unregisterAutoCompletion(); //we have to do it separately, otherwise we have an autocompletion action override m_dialog->close(); @@ -125,6 +115,12 @@ void BindingEditor::setBackendValue(const QVariant &backendValue) if (node.isValid()) { m_backendValueTypeName = node.metaInfo().propertyTypeName(propertyEditorValue->name()); + QString nodeId = node.id(); + if (nodeId.isEmpty()) + nodeId = node.simplifiedTypeName(); + + m_targetName = nodeId + "." + propertyEditorValue->name(); + if (m_backendValueTypeName == "alias" || m_backendValueTypeName == "unknown") if (QmlObjectNode::isValidQmlObjectNode(node)) m_backendValueTypeName = QmlObjectNode(node).instanceType(propertyEditorValue->name()); @@ -164,6 +160,12 @@ void BindingEditor::setStateModelNode(const QVariant &stateModelNode) } } +void BindingEditor::setStateName(const QString &name) +{ + m_targetName = name; + m_targetName += ".when"; +} + void BindingEditor::setModelNode(const ModelNode &modelNode) { if (modelNode.isValid()) @@ -177,6 +179,11 @@ void BindingEditor::setBackendValueTypeName(const TypeName &backendValueTypeName emit backendValueChanged(); } +void BindingEditor::setTargetName(const QString &target) +{ + m_targetName = target; +} + void BindingEditor::prepareBindings() { if (!m_modelNode.isValid() || m_backendValueTypeName.isEmpty()) @@ -279,8 +286,26 @@ void BindingEditor::prepareBindings() void BindingEditor::updateWindowName() { - if (!m_dialog.isNull() && !m_backendValueTypeName.isEmpty()) - m_dialog->setWindowTitle(m_dialog->defaultTitle() + " [" + m_backendValueTypeName + "]"); + if (!m_dialog.isNull() && !m_backendValueTypeName.isEmpty()) { + const QString targetString = " [" + + (m_targetName.isEmpty() ? QString() : (m_targetName + ": ")) + + QString::fromUtf8(m_backendValueTypeName) + "]"; + + m_dialog->setWindowTitle(m_dialog->defaultTitle() + targetString); + } +} + +QString BindingEditor::targetName() const +{ + return m_targetName; +} + +QString BindingEditor::stateName() const +{ + if (m_targetName.endsWith(".when")) + return m_targetName.chopped(5); + + return {}; } QVariant BindingEditor::backendValue() const diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h index 495462128f..738d9c7101 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h @@ -44,6 +44,7 @@ class BindingEditor : public QObject Q_PROPERTY(QVariant backendValueProperty READ backendValue WRITE setBackendValue NOTIFY backendValueChanged) Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged) Q_PROPERTY(QVariant stateModelNodeProperty READ stateModelNode WRITE setStateModelNode NOTIFY stateModelNodeChanged) + Q_PROPERTY(QString stateNameProperty READ stateName WRITE setStateName) public: BindingEditor(QObject *parent = nullptr); @@ -64,15 +65,21 @@ public: void setModelNodeBackend(const QVariant &modelNodeBackend); //2. modelnode (this one also sets backend value type name to bool) + //State Name is not mandatory, but used in bindingEditor dialog name void setStateModelNode(const QVariant &stateModelNode); + void setStateName(const QString &name); - //3. modelnode + backend value type name + //3. modelnode + backend value type name + optional target name void setModelNode(const ModelNode &modelNode); void setBackendValueTypeName(const TypeName &backendValueTypeName); + void setTargetName(const QString &target); Q_INVOKABLE void prepareBindings(); Q_INVOKABLE void updateWindowName(); + QString targetName() const; + QString stateName() const; + signals: void accepted(); void rejected(); @@ -93,6 +100,7 @@ private: QVariant m_stateModelNode; QmlDesigner::ModelNode m_modelNode; TypeName m_backendValueTypeName; + QString m_targetName; }; } diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp index 6cd810df37..5b9c54b4d4 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp @@ -35,6 +35,10 @@ #include <qmljseditor/qmljseditordocument.h> #include <qmljseditor/qmljssemantichighlighter.h> #include <qmljstools/qmljsindenter.h> +#include <qmljstools/qmljstoolsconstants.h> + +#include <projectexplorer/projectexplorerconstants.h> +#include <utils/fancylineedit.h> #include <QAction> @@ -43,17 +47,19 @@ namespace QmlDesigner { BindingEditorWidget::BindingEditorWidget() : m_context(new Core::IContext(this)) { + Core::Context context(BINDINGEDITOR_CONTEXT_ID, + ProjectExplorer::Constants::QMLJS_LANGUAGE_ID); + m_context->setWidget(this); + m_context->setContext(context); Core::ICore::addContextObject(m_context); - const Core::Context context(BINDINGEDITOR_CONTEXT_ID); - /* * We have to register our own active auto completion shortcut, because the original short cut will * use the cursor position of the original editor in the editor manager. */ - m_completionAction = new QAction(tr("Trigger Completion"), this); + Core::Command *command = Core::ActionManager::registerAction( m_completionAction, TextEditor::Constants::COMPLETE_THIS, context); command->setDefaultKeySequence(QKeySequence( @@ -84,11 +90,9 @@ bool BindingEditorWidget::event(QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); - if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { + if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) && !keyEvent->modifiers()) { emit returnKeyClicked(); return true; - } else { - return QmlJSEditor::QmlJSEditorWidget::event(event); } } return QmlJSEditor::QmlJSEditorWidget::event(event); @@ -133,8 +137,12 @@ void BindingDocument::triggerPendingUpdates() BindingEditorFactory::BindingEditorFactory() { setId(BINDINGEDITOR_CONTEXT_ID); - setDisplayName(QCoreApplication::translate("OpenWith::Editors", QmlDesigner::BINDINGEDITOR_CONTEXT_ID)); + setDisplayName(QCoreApplication::translate("OpenWith::Editors", BINDINGEDITOR_CONTEXT_ID)); setEditorActionHandlers(0); + addMimeType(BINDINGEDITOR_CONTEXT_ID); + addMimeType(QmlJSTools::Constants::QML_MIMETYPE); + addMimeType(QmlJSTools::Constants::QMLTYPES_MIMETYPE); + addMimeType(QmlJSTools::Constants::JS_MIMETYPE); setDocumentCreator([]() { return new BindingDocument; }); setEditorWidgetCreator([]() { return new BindingEditorWidget; }); diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index 8ca977e742..d9a67a8400 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -290,8 +290,8 @@ QHash<QString, QStringList> DesignerActionManager::handleExternalAssetsDrop(cons for (const QString &category : categories) { AddResourceOperation operation = categoryOperation.value(category); QStringList files = categoryFiles.value(category); - bool success = operation(files, {}); - if (success) + AddFilesResult result = operation(files, {}); + if (result == AddFilesResult::Succeeded) addedCategoryFiles.insert(category, files); } diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h index 60e2c7562f..e86e441b14 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h @@ -28,6 +28,7 @@ #include <qmldesignercorelib_global.h> #include "actioninterface.h" #include "modelnode.h" +#include "modelnodeoperations.h" #include <coreplugin/actionmanager/command.h> #include <utils/styledbar.h> @@ -45,7 +46,7 @@ namespace QmlDesigner { class DesignerActionManagerView; -using AddResourceOperation = std::function<bool (const QStringList &, const QString &)>; +using AddResourceOperation = std::function<AddFilesResult (const QStringList &, const QString &)>; using ModelNodePreviewImageOperation = std::function<QVariant (const ModelNode &)>; struct AddResourceHandler diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index ab2853354c..b486740495 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -992,13 +992,15 @@ Utils::FilePath projectFilePath() return Utils::FilePath(); } -static bool addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory) +static AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory) { QString directory = AddImagesDialog::getDirectory(fileNames, defaultDirectory); if (directory.isEmpty()) - return false; + return AddFilesResult::Cancelled; + + DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); + QTC_ASSERT(document, return AddFilesResult::Failed); - bool allSuccessful = true; QList<QPair<QString, QString>> copyList; QStringList removeList; for (const QString &fileName : fileNames) { @@ -1021,26 +1023,21 @@ static bool addFilesToProject(const QStringList &fileNames, const QString &defau // unnecessarily refreshing file models multiple times during the operation for (const auto &file : qAsConst(removeList)) QFile::remove(file); + for (const auto &filePair : qAsConst(copyList)) { const bool success = QFile::copy(filePair.first, filePair.second); - - auto document = QmlDesignerPlugin::instance()->currentDesignDocument(); - - QTC_ASSERT(document, return false); - - if (success) { - ProjectExplorer::Node *node = ProjectExplorer::ProjectTree::nodeForFile(document->fileName()); - if (node) { - ProjectExplorer::FolderNode *containingFolder = node->parentFolderNode(); - if (containingFolder) - containingFolder->addFiles({Utils::FilePath::fromString(filePair.second)}); - } - } else { - allSuccessful = false; + if (!success) + return AddFilesResult::Failed; + + ProjectExplorer::Node *node = ProjectExplorer::ProjectTree::nodeForFile(document->fileName()); + if (node) { + ProjectExplorer::FolderNode *containingFolder = node->parentFolderNode(); + if (containingFolder) + containingFolder->addFiles({Utils::FilePath::fromString(filePair.second)}); } } - return allSuccessful; + return AddFilesResult::Succeeded; } static QString getAssetDefaultDirectory(const QString &assetDir, const QString &defaultDirectory) @@ -1060,22 +1057,22 @@ static QString getAssetDefaultDirectory(const QString &assetDir, const QString & return adjustedDefaultDirectory; } -bool addFontToProject(const QStringList &fileNames, const QString &defaultDirectory) +AddFilesResult addFontToProject(const QStringList &fileNames, const QString &defaultDirectory) { return addFilesToProject(fileNames, getAssetDefaultDirectory("fonts", defaultDirectory)); } -bool addSoundToProject(const QStringList &fileNames, const QString &defaultDirectory) +AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &defaultDirectory) { return addFilesToProject(fileNames, getAssetDefaultDirectory("sounds", defaultDirectory)); } -bool addShaderToProject(const QStringList &fileNames, const QString &defaultDirectory) +AddFilesResult addShaderToProject(const QStringList &fileNames, const QString &defaultDirectory) { return addFilesToProject(fileNames, getAssetDefaultDirectory("shaders", defaultDirectory)); } -bool addImageToProject(const QStringList &fileNames, const QString &defaultDirectory) +AddFilesResult addImageToProject(const QStringList &fileNames, const QString &defaultDirectory) { return addFilesToProject(fileNames, getAssetDefaultDirectory("images", defaultDirectory)); } diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h index 0e302a3c65..feb7faa556 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -28,6 +28,9 @@ #include "selectioncontext.h" namespace QmlDesigner { + +enum class AddFilesResult { Succeeded, Failed, Cancelled }; + namespace ModelNodeOperations { bool goIntoComponent(const ModelNode &modelNode); @@ -73,10 +76,10 @@ void addItemToStackedContainer(const SelectionContext &selectionContext); void increaseIndexOfStackedContainer(const SelectionContext &selectionContext); void decreaseIndexOfStackedContainer(const SelectionContext &selectionContext); void addTabBarToStackedContainer(const SelectionContext &selectionContext); -bool addImageToProject(const QStringList &fileNames, const QString &directory); -bool addFontToProject(const QStringList &fileNames, const QString &directory); -bool addSoundToProject(const QStringList &fileNames, const QString &directory); -bool addShaderToProject(const QStringList &fileNames, const QString &directory); +AddFilesResult addImageToProject(const QStringList &fileNames, const QString &directory); +AddFilesResult addFontToProject(const QStringList &fileNames, const QString &directory); +AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &directory); +AddFilesResult addShaderToProject(const QStringList &fileNames, const QString &directory); void createFlowActionArea(const SelectionContext &selectionContext); void addTransition(const SelectionContext &selectionState); void addFlowEffect(const SelectionContext &selectionState, const TypeName &typeName); diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp index 11bfebe5e7..095b8b6262 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp @@ -159,17 +159,20 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) QMenu menu(this); - menu.addAction(tr("Open Connection Editor"), [&]() { + menu.addAction(tr("Open Connection Editor"), this, [&]() { auto *connectionModel = qobject_cast<ConnectionModel *>(targetView->model()); const SignalHandlerProperty property = connectionModel->signalHandlerPropertyForRow(index.row()); const ModelNode node = property.parentModelNode(); + const QString targetName = index.siblingAtColumn(ConnectionModel::TargetModelNodeRow).data().toString() + + "." + property.name(); + m_connectionEditor->showWidget(); m_connectionEditor->setConnectionValue(index.data().toString()); m_connectionEditor->setModelIndex(index); m_connectionEditor->setModelNode(node); m_connectionEditor->prepareConnections(); - m_connectionEditor->updateWindowName(); + m_connectionEditor->updateWindowName(targetName); }); QMap<QString, QVariant> data; @@ -179,7 +182,7 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) const auto actions = designerActionManager.actionsForTargetView( ActionInterface::TargetView::ConnectionEditor); - for (auto actionInterface : actions) { + for (const auto &actionInterface : actions) { auto *action = actionInterface->action(); action->setData(data); menu.addAction(action); @@ -198,7 +201,7 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) QMenu menu(this); - menu.addAction(tr("Open Binding Editor"), [&]() { + menu.addAction(tr("Open Binding Editor"), this, [&]() { BindingModel *bindingModel = qobject_cast<BindingModel*>(targetView->model()); const BindingProperty property = bindingModel->bindingPropertyForRow(index.row()); @@ -209,10 +212,13 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) const TypeName typeName = property.isDynamic() ? property.dynamicTypeName() : node.metaInfo().propertyTypeName(property.name()); + const QString targetName = node.displayName() + "." + property.name(); + m_bindingEditor->showWidget(); m_bindingEditor->setBindingValue(property.expression()); m_bindingEditor->setModelNode(node); m_bindingEditor->setBackendValueTypeName(typeName); + m_bindingEditor->setTargetName(targetName); m_bindingEditor->prepareBindings(); m_bindingEditor->updateWindowName(); @@ -232,7 +238,7 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) DynamicPropertiesModel *propertiesModel = qobject_cast<DynamicPropertiesModel *>(targetView->model()); QMenu menu(this); - menu.addAction(tr("Open Binding Editor"), [&]() { + menu.addAction(tr("Open Binding Editor"), this, [&]() { AbstractProperty abstractProperty = propertiesModel->abstractPropertyForRow(index.row()); if (!abstractProperty.isValid()) return; @@ -247,17 +253,20 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) else return; + const QString targetName = node.displayName() + "." + abstractProperty.name(); + m_dynamicEditor->showWidget(); m_dynamicEditor->setBindingValue(newExpression); m_dynamicEditor->setModelNode(node); m_dynamicEditor->setBackendValueTypeName(abstractProperty.dynamicTypeName()); + m_dynamicEditor->setTargetName(targetName); m_dynamicEditor->prepareBindings(); m_dynamicEditor->updateWindowName(); m_dynamicIndex = index; }); - menu.addAction(tr("Reset Property"), [&]() { + menu.addAction(tr("Reset Property"), this, [&]() { propertiesModel->resetProperty(propertiesModel->abstractPropertyForRow(index.row()).name()); }); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index 10e1373dde..187bc4ca17 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -339,26 +339,13 @@ static inline bool hasNodeSourceParent(const ModelNode &node) void FormEditorView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/) { - // If node is not connected to scene root, don't do anything yet to avoid duplicated effort, - // as any removal or addition will remove or add descendants as well. - if (!node.isInHierarchy()) - return; + addOrRemoveFormEditorItem(node); +} - QmlItemNode itemNode(node); - if (hasNodeSourceParent(node)) { - if (FormEditorItem *item = m_scene->itemForQmlItemNode(itemNode)) { - QList<FormEditorItem *> removed = scene()->itemsForQmlItemNodes(itemNode.allSubModelNodes()); - removed.append(item); - m_currentTool->itemsAboutToRemoved(removed); - removeNodeFromScene(itemNode); - } - } else if (itemNode.isValid() && node.nodeSourceType() == ModelNode::NodeWithoutSource) { - if (!m_scene->itemForQmlItemNode(itemNode)) { - setupFormEditorItemTree(itemNode); - // Simulate selection change to refresh tools - selectedNodesChanged(selectedModelNodes(), {}); - } - } +void FormEditorView::nodeSourceChanged(const ModelNode &node, const QString &newNodeSource) +{ + Q_UNUSED(newNodeSource) + addOrRemoveFormEditorItem(node); } WidgetInfo FormEditorView::widgetInfo() @@ -863,6 +850,38 @@ void FormEditorView::resetNodeInstanceView() resetPuppet(); } +void FormEditorView::addOrRemoveFormEditorItem(const ModelNode &node) +{ + // If node is not connected to scene root, don't do anything yet to avoid duplicated effort, + // as any removal or addition will remove or add descendants as well. + if (!node.isInHierarchy()) + return; + + QmlItemNode itemNode(node); + + auto removeItemFromScene = [this, &itemNode]() { + if (FormEditorItem *item = m_scene->itemForQmlItemNode(itemNode)) { + QList<FormEditorItem *> removed = scene()->itemsForQmlItemNodes(itemNode.allSubModelNodes()); + removed.append(item); + m_currentTool->itemsAboutToRemoved(removed); + removeNodeFromScene(itemNode); + } + }; + if (hasNodeSourceParent(node)) { + removeItemFromScene(); + } else if (itemNode.isValid()) { + if (node.nodeSourceType() == ModelNode::NodeWithoutSource) { + if (!m_scene->itemForQmlItemNode(itemNode)) { + setupFormEditorItemTree(itemNode); + // Simulate selection change to refresh tools + selectedNodesChanged(selectedModelNodes(), {}); + } + } else { + removeItemFromScene(); + } + } +} + void FormEditorView::reset() { QTimer::singleShot(200, this, &FormEditorView::delayedReset); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.h b/src/plugins/qmldesigner/components/formeditor/formeditorview.h index 04b7d1e83e..ca3fb72bb0 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.h @@ -70,6 +70,7 @@ public: void nodeCreated(const ModelNode &createdNode) override; void nodeAboutToBeRemoved(const ModelNode &removedNode) override; void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override; + void nodeSourceChanged(const ModelNode &node, const QString &newNodeSource) override; void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) override; void propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList) override; void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override; @@ -147,6 +148,7 @@ private: void createFormEditorWidget(); void temporaryBlockView(int duration = 1000); void resetNodeInstanceView(); + void addOrRemoveFormEditorItem(const ModelNode &node); QPointer<FormEditorWidget> m_formEditorWidget; QPointer<FormEditorScene> m_scene; diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp index 9374e61776..0b7d7fa2c9 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp @@ -634,8 +634,11 @@ void DesignDocument::setEditor(Core::IEditor *editor) connect(Core::EditorManager::instance(), &Core::EditorManager::aboutToSave, this, [this](Core::IDocument *document) { if (m_textEditor && m_textEditor->document() == document) { - if (m_documentModel && m_documentModel->rewriterView()) + if (m_documentModel && m_documentModel->rewriterView()) { + if (fileName().completeSuffix() == "ui.qml") + m_documentModel->rewriterView()->sanitizeModel(); m_documentModel->rewriterView()->writeAuxiliaryData(); + } } }); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp index 04bc51284b..135eaaf5aa 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp @@ -788,7 +788,10 @@ void ItemLibraryAssetImportDialog::onClose() addInfo(tr("Canceling import.")); m_importer.cancelImport(); } else { - reject(); + if (ui->progressBar->value() == 100) // import done successfully + accept(); + else + reject(); close(); deleteLater(); } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp index d351232e36..4962f5d6b4 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp @@ -147,20 +147,19 @@ void ItemLibraryCategoriesModel::resetModel() bool ItemLibraryCategoriesModel::isAllCategoriesHidden() const { for (const auto &category : std::as_const(m_categoryList)) { - // ignore "All Other Components" as its categoryVisible is always true - if (category->isCategoryVisible() && category->categoryName() != "All Other Components") + if (category->isCategoryVisible()) return false; } return true; } -void ItemLibraryCategoriesModel::showAllCategories(bool show) +void ItemLibraryCategoriesModel::showAllCategories() { for (const auto &category : std::as_const(m_categoryList)) { - if (category->isCategoryVisible() != show) { - category->setCategoryVisible(show); - ItemLibraryModel::saveCategoryVisibleState(show, category->categoryName(), + if (!category->isCategoryVisible()) { + category->setCategoryVisible(true); + ItemLibraryModel::saveCategoryVisibleState(true, category->categoryName(), category->ownerImport()->importName()); } } @@ -168,37 +167,56 @@ void ItemLibraryCategoriesModel::showAllCategories(bool show) emit dataChanged(index(0), index(m_categoryList.size() - 1), {m_roleNames.key("categoryVisible")}); } -QObject *ItemLibraryCategoriesModel::selectFirstVisibleCategory() +void ItemLibraryCategoriesModel::hideCategory(const QString &categoryName) +{ + for (int i = 0; i < m_categoryList.size(); ++i) { + const auto category = m_categoryList.at(i); + if (category->categoryName() == categoryName) { + category->setCategoryVisible(false); + ItemLibraryModel::saveCategoryVisibleState(false, category->categoryName(), + category->ownerImport()->importName()); + emit dataChanged(index(i), index(i), {m_roleNames.key("categoryVisible")}); + break; + } + } +} + +int ItemLibraryCategoriesModel::selectFirstVisibleCategory() { for (int i = 0; i < m_categoryList.length(); ++i) { const auto category = m_categoryList.at(i); if (category->isCategoryVisible()) { category->setCategorySelected(true); - emit dataChanged(index(i),index(i), {m_roleNames.key("categorySelected")}); - return category; + emit dataChanged(index(i), index(i), {m_roleNames.key("categorySelected")}); + return i; } } - return nullptr; + return -1; } -void ItemLibraryCategoriesModel::clearSelectedCategories() +void ItemLibraryCategoriesModel::clearSelectedCategory(int categoryIndex) { - for (const auto &category : std::as_const(m_categoryList)) - category->setCategorySelected(false); + if (categoryIndex == -1 || m_categoryList.isEmpty()) + return; - emit dataChanged(index(0), index(m_categoryList.size() - 1), {m_roleNames.key("categorySelected")}); + m_categoryList.at(categoryIndex)->setCategorySelected(false); + emit dataChanged(index(categoryIndex), index(categoryIndex), {m_roleNames.key("categorySelected")}); } -void ItemLibraryCategoriesModel::selectCategory(int categoryIndex) +QPointer<ItemLibraryCategory> ItemLibraryCategoriesModel::selectCategory(int categoryIndex) { - const auto category = m_categoryList.at(categoryIndex); + if (categoryIndex == -1 || m_categoryList.isEmpty()) + return nullptr; + + const QPointer<ItemLibraryCategory> category = m_categoryList.at(categoryIndex); if (!category->categorySelected()) { - clearSelectedCategories(); category->setCategorySelected(true); emit dataChanged(index(categoryIndex),index(categoryIndex), {m_roleNames.key("categorySelected")}); } + + return category; } void ItemLibraryCategoriesModel::addRoleNames() diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h index 9433af804f..36437a0ed6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h @@ -55,10 +55,11 @@ public: bool isAllCategoriesHidden() const; void sortCategorySections(); void resetModel(); - void showAllCategories(bool show = true); - void clearSelectedCategories(); - QObject *selectFirstVisibleCategory(); - void selectCategory(int categoryIndex); + void showAllCategories(); + void hideCategory(const QString &categoryName); + void clearSelectedCategory(int categoryIndex); + int selectFirstVisibleCategory(); + QPointer<ItemLibraryCategory> selectCategory(int categoryIndex); private: void addRoleNames(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp index 0744b7b2b3..ce04b298fe 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp @@ -137,6 +137,7 @@ void ItemLibraryCategory::setExpanded(bool expanded) void ItemLibraryCategory::setCategorySelected(bool selected) { m_categorySelected = selected; + emit categorySelectedChanged(); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp index 7e696e43ef..ebf13d0fe5 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp @@ -133,28 +133,38 @@ bool ItemLibraryImport::updateCategoryVisibility(const QString &searchText, bool return hasVisibleCategories; } -void ItemLibraryImport::showAllCategories(bool show) +void ItemLibraryImport::showAllCategories() { - m_categoryModel.showAllCategories(show); + m_categoryModel.showAllCategories(); + setAllCategoriesVisible(true); } -void ItemLibraryImport::selectCategory(int categoryIndex) +void ItemLibraryImport::hideCategory(const QString &categoryName) { - m_categoryModel.selectCategory(categoryIndex); + m_categoryModel.hideCategory(categoryName); + setAllCategoriesVisible(false); } -QObject *ItemLibraryImport::selectFirstVisibleCategory() +ItemLibraryCategory *ItemLibraryImport::selectCategory(int categoryIndex) +{ + return m_categoryModel.selectCategory(categoryIndex); +} + +int ItemLibraryImport::selectFirstVisibleCategory() { return m_categoryModel.selectFirstVisibleCategory(); } -void ItemLibraryImport::clearSelectedCategories() +void ItemLibraryImport::clearSelectedCategory(int categoryIndex) { - m_categoryModel.clearSelectedCategories(); + m_categoryModel.clearSelectedCategory(categoryIndex); } bool ItemLibraryImport::isAllCategoriesHidden() const { + if (!m_isVisible) + return true; + return m_categoryModel.isAllCategoriesHidden(); } @@ -221,7 +231,7 @@ void ItemLibraryImport::setImportExpanded(bool expanded) } } -ItemLibraryCategory *ItemLibraryImport::getCategorySection(const QString &categoryName) const +ItemLibraryCategory *ItemLibraryImport::getCategoryByName(const QString &categoryName) const { for (ItemLibraryCategory *catSec : std::as_const(m_categoryModel.categorySections())) { if (catSec->categoryName() == categoryName) @@ -231,6 +241,16 @@ ItemLibraryCategory *ItemLibraryImport::getCategorySection(const QString &catego return nullptr; } +ItemLibraryCategory *ItemLibraryImport::getCategoryAt(int categoryIndex) const +{ + const QList<QPointer<ItemLibraryCategory>> categories = m_categoryModel.categorySections(); + + if (categoryIndex != -1 && !categories.isEmpty()) + return categories.at(categoryIndex); + + return nullptr; +} + // static QString ItemLibraryImport::userComponentsTitle() { @@ -264,22 +284,14 @@ void ItemLibraryImport::updateRemovable() } } -// returns true if all categories are visible, otherwise false -bool ItemLibraryImport::importCatVisibleState() const +bool ItemLibraryImport::allCategoriesVisible() const { - if (m_categoryModel.rowCount() > 0) { - for (ItemLibraryCategory *cat : m_categoryModel.categorySections()) { - if (!cat->isCategoryVisible()) - return false; - } - } - - return true; + return m_allCategoriesVisible; } -void ItemLibraryImport::setImportCatVisibleState(bool show) +void ItemLibraryImport::setAllCategoriesVisible(bool visible) { - m_categoryModel.showAllCategories(show); + m_allCategoriesVisible = visible; } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h index f5a1cd0279..89aaca8e02 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h @@ -43,7 +43,7 @@ class ItemLibraryImport : public QObject Q_PROPERTY(bool importExpanded READ importExpanded WRITE setImportExpanded NOTIFY importExpandChanged FINAL) Q_PROPERTY(bool importRemovable READ importRemovable NOTIFY importRemovableChanged FINAL) Q_PROPERTY(bool importUnimported READ importUnimported FINAL) - Q_PROPERTY(bool importCatVisibleState READ importCatVisibleState WRITE setImportCatVisibleState NOTIFY importCatVisibleStateChanged FINAL) + Q_PROPERTY(bool allCategoriesVisible READ allCategoriesVisible WRITE setAllCategoriesVisible NOTIFY allCategoriesVisibleChanged FINAL) Q_PROPERTY(QObject *categoryModel READ categoryModel NOTIFY categoryModelChanged FINAL) public: @@ -65,11 +65,12 @@ public: bool importVisible() const; bool importUsed() const; bool importRemovable() const; - bool importCatVisibleState() const; + bool allCategoriesVisible() const; bool hasCategories() const; bool hasSingleCategory() const; bool isAllCategoriesHidden() const; - ItemLibraryCategory *getCategorySection(const QString &categoryName) const; + ItemLibraryCategory *getCategoryByName(const QString &categoryName) const; + ItemLibraryCategory *getCategoryAt(int categoryIndex) const; void addCategory(ItemLibraryCategory *category); QObject *categoryModel(); @@ -78,12 +79,14 @@ public: void setImportUsed(bool importUsed); void sortCategorySections(); void setImportExpanded(bool expanded = true); - void setImportCatVisibleState(bool show); + void setAllCategoriesVisible(bool visible); void expandCategories(bool expand = true); - void showAllCategories(bool show = true); - void selectCategory(int categoryIndex); - QObject *selectFirstVisibleCategory(); - void clearSelectedCategories(); + void showAllCategories(); + void hideCategory(const QString &categoryName); + ItemLibraryCategory *selectCategory(int categoryIndex); + int selectFirstVisibleCategory(); + void clearSelectedCategory(int categoryIndex); + bool importUnimported() const { return m_sectionType == SectionType::Unimported; } static QString userComponentsTitle(); static QString quick3DAssetsTitle(); @@ -97,17 +100,17 @@ signals: void importUsedChanged(); void importExpandChanged(); void importRemovableChanged(); - void importCatVisibleStateChanged(); + void allCategoriesVisibleChanged(); private: void updateRemovable(); - bool importUnimported() const { return m_sectionType == SectionType::Unimported; } Import m_import; bool m_importExpanded = true; bool m_isVisible = true; bool m_importUsed = false; bool m_importRemovable = false; + bool m_allCategoriesVisible = true; SectionType m_sectionType = SectionType::Default; ItemLibraryCategoriesModel m_categoryModel; }; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index ebef71f63f..b571cc4981 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -59,8 +59,8 @@ bool ItemLibraryModel::loadExpandedState(const QString §ionName) return expandedStateHash.value(sectionName, true); } -void ItemLibraryModel::saveCategoryVisibleState(bool isVisible, const QString &categoryName, const - QString &importName) +void ItemLibraryModel::saveCategoryVisibleState(bool isVisible, const QString &categoryName, + const QString &importName) { categoryVisibleStateHash.insert(categoryName + '_' + importName, isVisible); } @@ -70,58 +70,61 @@ bool ItemLibraryModel::loadCategoryVisibleState(const QString &categoryName, con return categoryVisibleStateHash.value(categoryName + '_' + importName, true); } -void ItemLibraryModel::showHiddenCategories() +void ItemLibraryModel::selectImportCategory(const QString &importUrl, int categoryIndex) { - for (const QPointer<ItemLibraryImport> &import : std::as_const(m_importList)) { - if (import->hasCategories()) - import->showAllCategories(true); - } - - categoryVisibleStateHash.clear(); -} + clearSelectedCategory(); -bool ItemLibraryModel::getIsAnyCategoryHidden() const -{ - for (const bool &catState : std::as_const(categoryVisibleStateHash)) { - if (!catState) - return true; - } + m_selectedImportUrl = importUrl; + m_selectedCategoryIndex = categoryIndex; - return false; + updateSelection(); } -void ItemLibraryModel::selectImportCategory(const QString importUrl, int categoryIndex) +void ItemLibraryModel::clearSelectedCategory() { - ItemLibraryImport *selectedCategoryImport = importByUrl(importUrl); - - for (int i = 0; i < m_importList.length(); ++i) { - const auto importToSelect = m_importList.at(i); - - if (selectedCategoryImport == importToSelect) - importToSelect->selectCategory(categoryIndex); - else - importToSelect->clearSelectedCategories(); + if (m_selectedCategoryIndex != -1) { + ItemLibraryImport *selectedImport = importByUrl(m_selectedImportUrl); + if (selectedImport) + selectedImport->clearSelectedCategory(m_selectedCategoryIndex); } } -bool ItemLibraryModel::isAllCategoriesHidden() const +void ItemLibraryModel::selectImportFirstVisibleCategory() { - for (int i = 0; i < m_importList.length(); ++i) { - if (!m_importList.at(i)->isAllCategoriesHidden()) - return false; - } + if (m_selectedCategoryIndex != -1) { + ItemLibraryImport *selectedImport = importByUrl(m_selectedImportUrl); + if (selectedImport) { + ItemLibraryCategory *selectedCategory = selectedImport->getCategoryAt(m_selectedCategoryIndex); + if (selectedCategory) { + bool isUnimported = selectedImport->sectionType() == ItemLibraryImport::SectionType::Unimported; + // unimported category is always visible so checking its Import visibility instead + bool isVisible = isUnimported ? selectedImport->importVisible() + : selectedCategory->isCategoryVisible(); + if (isVisible) + return; // there is already a selected visible category - return true; -} + clearSelectedCategory(); + } + } + } -QObject *ItemLibraryModel::selectImportFirstVisibleCategory() -{ for (const QPointer<ItemLibraryImport> &import : std::as_const(m_importList)) { - if (!import->isAllCategoriesHidden()) - return import->selectFirstVisibleCategory(); + if (!import->isAllCategoriesHidden()) { + m_selectedImportUrl = import->importUrl(); + m_selectedCategoryIndex = import->selectFirstVisibleCategory(); + + ItemLibraryCategory *selectedCategory = import->getCategoryAt(m_selectedCategoryIndex); + if (selectedCategory) { + setItemsModel(selectedCategory->itemModel()); + setImportUnimportedSelected(import->importUnimported()); + return; + } + } } - return nullptr; + m_selectedImportUrl.clear(); + m_selectedCategoryIndex = -1; + setItemsModel(nullptr); } bool ItemLibraryModel::isAnyCategoryHidden() const @@ -137,6 +140,30 @@ void ItemLibraryModel::setIsAnyCategoryHidden(bool state) } } +bool ItemLibraryModel::importUnimportedSelected() const +{ + return m_importUnimportedSelected; +} + +void ItemLibraryModel::setImportUnimportedSelected(bool state) +{ + if (state != m_importUnimportedSelected) { + m_importUnimportedSelected = state; + emit importUnimportedSelectedChanged(); + } +} + +QObject *ItemLibraryModel::itemsModel() const +{ + return m_itemsModel; +} + +void ItemLibraryModel::setItemsModel(QObject *model) +{ + m_itemsModel = model; + emit itemsModelChanged(); +} + void ItemLibraryModel::expandAll() { int i = 0; @@ -164,6 +191,46 @@ void ItemLibraryModel::collapseAll() } } +void ItemLibraryModel::hideCategory(const QString &importUrl, const QString &categoryName) +{ + ItemLibraryImport *import = importByUrl(importUrl); + if (!import) + return; + + import->hideCategory(categoryName); + + selectImportFirstVisibleCategory(); + setIsAnyCategoryHidden(true); +} + +void ItemLibraryModel::showImportHiddenCategories(const QString &importUrl) +{ + ItemLibraryImport *targetImport = nullptr; + bool hiddenCatsExist = false; + for (const QPointer<ItemLibraryImport> &import : std::as_const(m_importList)) { + if (import->importUrl() == importUrl) + targetImport = import; + else + hiddenCatsExist |= !import->allCategoriesVisible(); + } + + if (targetImport) { + targetImport->showAllCategories(); + updateSelection(); // useful when all categories are hidden + setIsAnyCategoryHidden(hiddenCatsExist); + } +} + +void ItemLibraryModel::showAllHiddenCategories() +{ + for (const QPointer<ItemLibraryImport> &import : std::as_const(m_importList)) + import->showAllCategories(); + + updateSelection(); // useful when all categories are hidden + setIsAnyCategoryHidden(false); + categoryVisibleStateHash.clear(); +} + void ItemLibraryModel::setFlowMode(bool b) { m_flowMode = b; @@ -242,6 +309,8 @@ void ItemLibraryModel::setSearchText(const QString &searchText) bool changed = false; updateVisibility(&changed); + + selectImportFirstVisibleCategory(); } } @@ -411,7 +480,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) } // get or create category section - ItemLibraryCategory *categorySection = importSection->getCategorySection(catName); + ItemLibraryCategory *categorySection = importSection->getCategoryByName(catName); if (!categorySection) { categorySection = new ItemLibraryCategory(catName, importSection); importSection->addCategory(categorySection); @@ -428,8 +497,11 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) } sortSections(); + bool changed = false; updateVisibility(&changed); + + updateSelection(); endResetModel(); } @@ -453,6 +525,23 @@ void ItemLibraryModel::clearSections() m_importList.clear(); } +void ItemLibraryModel::updateSelection() +{ + if (m_selectedCategoryIndex != -1) { + ItemLibraryImport *selectedImport = importByUrl(m_selectedImportUrl); + if (selectedImport) { + ItemLibraryCategory *selectedCategory = selectedImport->selectCategory(m_selectedCategoryIndex); + if (selectedCategory) { + setItemsModel(selectedCategory->itemModel()); + setImportUnimportedSelected(selectedImport->importUnimported()); + return; + } + } + } + + selectImportFirstVisibleCategory(); +} + void ItemLibraryModel::registerQmlTypes() { qmlRegisterAnonymousType<QmlDesigner::ItemLibraryModel>("ItemLibraryModel", 1); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h index ad9803821f..7852999edd 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h @@ -33,15 +33,19 @@ QT_FORWARD_DECLARE_CLASS(QMimeData) namespace QmlDesigner { -class ItemLibraryInfo; +class ItemLibraryCategory; class ItemLibraryEntry; -class Model; class ItemLibraryImport; +class ItemLibraryInfo; +class Model; class ItemLibraryModel : public QAbstractListModel { Q_OBJECT + Q_PROPERTY(bool isAnyCategoryHidden READ isAnyCategoryHidden WRITE setIsAnyCategoryHidden NOTIFY isAnyCategoryHiddenChanged FINAL) + Q_PROPERTY(QObject *itemsModel READ itemsModel WRITE setItemsModel NOTIFY itemsModelChanged) + Q_PROPERTY(bool importUnimportedSelected READ importUnimportedSelected WRITE setImportUnimportedSelected NOTIFY importUnimportedSelectedChanged) public: explicit ItemLibraryModel(QObject *parent = nullptr); @@ -66,20 +70,26 @@ public: bool isAnyCategoryHidden() const; void setIsAnyCategoryHidden(bool state); + bool importUnimportedSelected() const; + void setImportUnimportedSelected(bool state); + + QObject *itemsModel() const; + void setItemsModel(QObject *model); + static void registerQmlTypes(); static void saveExpandedState(bool expanded, const QString §ionName); static bool loadExpandedState(const QString §ionName); static void saveCategoryVisibleState(bool isVisible, const QString &categoryName, const QString &importName); static bool loadCategoryVisibleState(const QString &categoryName, const QString &importName); + void selectImportFirstVisibleCategory(); Q_INVOKABLE void expandAll(); Q_INVOKABLE void collapseAll(); - Q_INVOKABLE void showHiddenCategories(); - Q_INVOKABLE bool getIsAnyCategoryHidden() const; - Q_INVOKABLE void selectImportCategory(const QString importUrl, int categoryIndex); - Q_INVOKABLE QObject *selectImportFirstVisibleCategory(); - Q_INVOKABLE bool isAllCategoriesHidden() const; + Q_INVOKABLE void hideCategory(const QString &importUrl, const QString &categoryName); + Q_INVOKABLE void showImportHiddenCategories(const QString &importUrl); + Q_INVOKABLE void showAllHiddenCategories(); + Q_INVOKABLE void selectImportCategory(const QString &importUrl, int categoryIndex); Import entryToImport(const ItemLibraryEntry &entry); @@ -87,12 +97,18 @@ public: signals: void isAnyCategoryHiddenChanged(); + void importUnimportedSelectedChanged(); + void selectedCategoryChanged(); + void selectedImportUrlChanged(); + void itemsModelChanged(); private: void updateVisibility(bool *changed); void addRoleNames(); void sortSections(); void clearSections(); + void updateSelection(); + void clearSelectedCategory(); QList<QPointer<ItemLibraryImport>> m_importList; QHash<int, QByteArray> m_roleNames; @@ -100,6 +116,10 @@ private: QString m_searchText; bool m_flowMode = false; bool m_isAnyCategoryHidden = false; + bool m_importUnimportedSelected = false; + QString m_selectedImportUrl; + int m_selectedCategoryIndex = -1; + QObject *m_itemsModel = nullptr; // items model for the horizontal layout inline static QHash<QString, bool> expandedStateHash; inline static QHash<QString, bool> categoryVisibleStateHash; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp index 06b84d83f8..9c8b4e09f9 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp @@ -245,13 +245,15 @@ void ItemLibraryView::updateImport3DSupport(const QVariantMap &supportMap) m_importableExtensions3DMap = extMap; - auto import3DModelOperation = [this](const QStringList &fileNames, const QString &defaultDir) -> bool { + AddResourceOperation import3DModelOperation = [this](const QStringList &fileNames, + const QString &defaultDir) -> AddFilesResult { auto importDlg = new ItemLibraryAssetImportDialog(fileNames, defaultDir, m_importableExtensions3DMap, m_importOptions3DMap, {}, {}, Core::ICore::mainWindow()); - importDlg->exec(); - return true; + int result = importDlg->exec(); + + return result == QDialog::Accepted ? AddFilesResult::Succeeded : AddFilesResult::Cancelled; }; auto add3DHandler = [&](const QString &group, const QString &ext) { diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index de15fde7cf..ef1e85287a 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -38,6 +38,7 @@ #include <itemlibrarymodel.h> #include <itemlibraryaddimportmodel.h> #include "itemlibraryassetsiconprovider.h" +#include "modelnodeoperations.h" #include <metainfo.h> #include <model.h> #include <rewritingexception.h> @@ -560,45 +561,31 @@ void ItemLibraryWidget::addImportForItem(const QString &importUrl) void ItemLibraryWidget::addResources(const QStringList &files) { - auto document = QmlDesignerPlugin::instance()->currentDesignDocument(); + DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); QTC_ASSERT(document, return); - QList<AddResourceHandler> handlers = QmlDesignerPlugin::instance()->viewManager().designerActionManager().addResourceHandler(); - - QMultiMap<QString, QString> map; - for (const AddResourceHandler &handler : handlers) { - map.insert(handler.category, handler.filter); - } - - QMap<QString, QString> reverseMap; - for (const AddResourceHandler &handler : handlers) { - reverseMap.insert(handler.filter, handler.category); - } - - QMap<QString, int> priorities; - for (const AddResourceHandler &handler : handlers) { - priorities.insert(handler.category, handler.piority); - } - - QStringList sortedKeys = map.uniqueKeys(); - Utils::sort(sortedKeys, [&priorities](const QString &first, - const QString &second){ - return priorities.value(first) < priorities.value(second); - }); + const QList<AddResourceHandler> handlers = QmlDesignerPlugin::instance()->viewManager() + .designerActionManager().addResourceHandler(); QStringList fileNames = files; - if (fileNames.isEmpty()) { - QStringList filters; - - for (const QString &key : qAsConst(sortedKeys)) { - QString str = key + " ("; - str.append(map.values(key).join(" ")); - str.append(")"); - filters.append(str); + if (fileNames.isEmpty()) { // if no files, show the "add assets" dialog + QMultiMap<QString, QString> map; + QHash<QString, int> priorities; + for (const AddResourceHandler &handler : handlers) { + map.insert(handler.category, handler.filter); + priorities.insert(handler.category, handler.piority); } - filters.prepend(tr("All Files (%1)").arg(map.values().join(" "))); + QStringList sortedKeys = map.uniqueKeys(); + Utils::sort(sortedKeys, [&priorities](const QString &first, const QString &second) { + return priorities.value(first) < priorities.value(second); + }); + + QStringList filters { tr("All Files (%1)").arg(map.values().join(' ')) }; + QString filterTemplate = "%1 (%2)"; + for (const QString &key : qAsConst(sortedKeys)) + filters.append(filterTemplate.arg(key, map.values(key).join(' '))); static QString lastDir; const QString currentDir = lastDir.isEmpty() ? document->fileName().parentDir().toString() : lastDir; @@ -616,24 +603,30 @@ void ItemLibraryWidget::addResources(const QStringList &files) } } - QMultiMap<QString, QString> partitionedFileNames; + QHash<QString, QString> filterToCategory; + QHash<QString, AddResourceOperation> categoryToOperation; + for (const AddResourceHandler &handler : handlers) { + filterToCategory.insert(handler.filter, handler.category); + categoryToOperation.insert(handler.category, handler.operation); + } + + QMultiMap<QString, QString> categoryFileNames; // filenames grouped by category for (const QString &fileName : qAsConst(fileNames)) { const QString suffix = "*." + QFileInfo(fileName).suffix().toLower(); - const QString category = reverseMap.value(suffix); - partitionedFileNames.insert(category, fileName); + const QString category = filterToCategory.value(suffix); + categoryFileNames.insert(category, fileName); } - for (const QString &category : partitionedFileNames.uniqueKeys()) { - for (const AddResourceHandler &handler : handlers) { - QStringList fileNames = partitionedFileNames.values(category); - if (handler.category == category) { - QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category); - if (!handler.operation(fileNames, document->fileName().parentDir().toString())) - Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), tr("Could not add %1 to project.").arg(fileNames.join(" "))); - break; - } - } + for (const QString &category : categoryFileNames.uniqueKeys()) { + QStringList fileNames = categoryFileNames.values(category); + AddResourceOperation operation = categoryToOperation.value(category); + QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category); + AddFilesResult result = operation(fileNames, document->fileName().parentDir().toString()); + if (result == AddFilesResult::Failed) { + Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), + tr("Could not add %1 to project.").arg(fileNames.join(' '))); + } } } diff --git a/src/plugins/qmldesigner/designercore/include/import.h b/src/plugins/qmldesigner/designercore/include/import.h index 99612fa2ad..c797a19ae4 100644 --- a/src/plugins/qmldesigner/designercore/include/import.h +++ b/src/plugins/qmldesigner/designercore/include/import.h @@ -25,6 +25,8 @@ #pragma once +#include <utils/porting.h> + #include <QString> #include <QStringList> #include <QMetaType> @@ -74,7 +76,7 @@ private: QStringList m_importPathList; }; -QMLDESIGNERCORE_EXPORT uint qHash(const Import &import); +QMLDESIGNERCORE_EXPORT Utils::QHashValueType qHash(const Import &import); } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/include/projectstorageids.h b/src/plugins/qmldesigner/designercore/include/projectstorageids.h index 76f547eeb1..765f2c9c65 100644 --- a/src/plugins/qmldesigner/designercore/include/projectstorageids.h +++ b/src/plugins/qmldesigner/designercore/include/projectstorageids.h @@ -37,7 +37,7 @@ public: constexpr explicit BasicId() = default; - BasicId(const char *) = delete; + constexpr BasicId(const char *) = delete; constexpr explicit BasicId(InternalIntergerType id) : id{id} diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h index ac251ef064..44e804f25d 100644 --- a/src/plugins/qmldesigner/designercore/include/rewriterview.h +++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h @@ -177,6 +177,8 @@ public: ModelNode getNodeForCanonicalIndex(int index); + void sanitizeModel(); + signals: void modelInterfaceProjectUpdated(); diff --git a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp index 28d8e02826..46ad1270e7 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp @@ -89,6 +89,7 @@ void MetaInfoReader::setQualifcation(const TypeName &qualification) void MetaInfoReader::elementStart(const QString &name, const QmlJS::SourceLocation &nameLocation) { + Q_UNUSED(nameLocation) switch (parserState()) { case ParsingDocument: setParserState(readDocument(name)); break; case ParsingMetaInfo: setParserState(readMetaInfoRootElement(name)); break; @@ -133,6 +134,8 @@ void MetaInfoReader::propertyDefinition(const QString &name, const QVariant &value, const QmlJS::SourceLocation &valueLocation) { + Q_UNUSED(nameLocation) + Q_UNUSED(valueLocation) switch (parserState()) { case ParsingType: readTypeProperty(name, value); break; case ParsingImports: readImportsProperty(name, value); break; diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp index 33693210a9..97ff30850f 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp @@ -1505,6 +1505,8 @@ QVariant NodeMetaInfo::propertyCastedValue(const PropertyName &propertyName, con return variant.toFloat(); } else if (typeName == "<cpp>.int") { return variant.toInt(); + } else if (typeName == "<cpp>.bool") { + return variant.toBool(); } else if (copyVariant.convert(typeId)) { return copyVariant; } diff --git a/src/plugins/qmldesigner/designercore/model/import.cpp b/src/plugins/qmldesigner/designercore/model/import.cpp index d895b07764..1c217bf47b 100644 --- a/src/plugins/qmldesigner/designercore/model/import.cpp +++ b/src/plugins/qmldesigner/designercore/model/import.cpp @@ -109,7 +109,7 @@ int Import::majorFromVersion(const QString &version) return version.split('.').first().toInt(); } -uint qHash(const Import &import) +Utils::QHashValueType qHash(const Import &import) { return ::qHash(import.url()) ^ ::qHash(import.file()) ^ ::qHash(import.version()) ^ ::qHash(import.alias()); } diff --git a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp index 55305c72d1..2445042fbb 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp @@ -332,7 +332,7 @@ static void removeStateOperationsForChildren(const QmlObjectNode &node) stateOperation.modelNode().destroy(); //remove of belonging StatesOperations } - for (const QmlObjectNode &childNode : node.modelNode().directSubModelNodes()) { + for (const QmlObjectNode childNode : node.modelNode().directSubModelNodes()) { removeStateOperationsForChildren(childNode); } } diff --git a/src/plugins/qmldesigner/designercore/model/qmltimelinekeyframegroup.cpp b/src/plugins/qmldesigner/designercore/model/qmltimelinekeyframegroup.cpp index 85eb51de44..924a4e0ee6 100644 --- a/src/plugins/qmldesigner/designercore/model/qmltimelinekeyframegroup.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmltimelinekeyframegroup.cpp @@ -310,7 +310,7 @@ QList<QmlTimelineKeyframeGroup> QmlTimelineKeyframeGroup::allInvalidTimelineKeyf QTC_ASSERT(view->rootModelNode().isValid(), return ret); const auto groups = view->rootModelNode().subModelNodesOfType("QtQuick.Timeline.KeyframeGroup"); - for (const QmlTimelineKeyframeGroup &group : groups) { + for (const QmlTimelineKeyframeGroup group : groups) { if (group.isDangling()) ret.append(group); } diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index af066b81c2..e33c82b124 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -39,6 +39,8 @@ #include <modelnodepositionstorage.h> #include <modelnode.h> #include <nodeproperty.h> +#include <qmlobjectnode.h> +#include <qmltimelinekeyframegroup.h> #ifndef QMLDESIGNER_TEST #include <qmldesignerplugin.h> @@ -57,6 +59,7 @@ #include <utility> #include <vector> +#include <algorithm> using namespace QmlDesigner::Internal; @@ -658,6 +661,36 @@ ModelNode RewriterView::getNodeForCanonicalIndex(int index) return m_canonicalIntModelNode.value(index); } +void RewriterView::sanitizeModel() +{ + if (inErrorState()) + return; + + QmlObjectNode root = rootModelNode(); + + QTC_ASSERT(root.isValid(), return); + + QList<ModelNode> danglingNodes; + + const auto danglingStates = root.allInvalidStateOperations(); + const auto danglingKeyframeGroups = QmlTimelineKeyframeGroup::allInvalidTimelineKeyframeGroups(this); + + std::transform(danglingStates.begin(), + danglingStates.end(), + std::back_inserter(danglingNodes), + [](const auto &node) { return node.modelNode(); }); + + std::transform(danglingKeyframeGroups.begin(), + danglingKeyframeGroups.end(), + std::back_inserter(danglingNodes), + [](const auto &node) { return node.modelNode(); }); + + executeInTransaction("RewriterView::sanitizeModel", [&]() { + for (auto node : std::as_const(danglingNodes)) + node.destroy(); + }); +} + Internal::ModelNodePositionStorage *RewriterView::positionStorage() const { return m_positionStorage.data(); diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index 2a428c6533..5df23b7385 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -28,6 +28,7 @@ #include "projectstorageexceptions.h" #include "projectstorageinterface.h" #include "sourcepathcachetypes.h" +#include "storagecache.h" #include <sqlitealgorithms.h> #include <sqlitetable.h> @@ -35,7 +36,9 @@ #include <utils/algorithm.h> #include <utils/optional.h> +#include <utils/set_algorithm.h> +#include <algorithm> #include <tuple> namespace QmlDesigner { @@ -53,65 +56,73 @@ public: ProjectStorage(Database &database, bool isInitialized) : database{database} , initializer{database, isInitialized} - {} + { + moduleCache.populate(); + } - void synchronize(Storage::Modules modules, - Storage::Imports imports, - Storage::Types types, - SourceIds sourceIds, - FileStatuses fileStatuses) override + void synchronize(Storage::SynchronizationPackage package) override { Sqlite::ImmediateTransaction transaction{database}; - std::vector<AliasPropertyDeclaration> insertedAliasPropertyDeclarations; - std::vector<AliasPropertyDeclaration> updatedAliasPropertyDeclarations; + AliasPropertyDeclarations insertedAliasPropertyDeclarations; + AliasPropertyDeclarations updatedAliasPropertyDeclarations; + + AliasPropertyDeclarations relinkableAliasPropertyDeclarations; + PropertyDeclarations relinkablePropertyDeclarations; + Prototypes relinkablePrototypes; + TypeIds deletedTypeIds; TypeIds updatedTypeIds; - updatedTypeIds.reserve(types.size()); + updatedTypeIds.reserve(package.types.size()); TypeIds typeIdsToBeDeleted; - auto sourceIdValues = Utils::transform<std::vector>(sourceIds, [](SourceId sourceId) { + auto sourceIdValues = Utils::transform<std::vector>(package.sourceIds, [](SourceId sourceId) { return &sourceId; }); std::sort(sourceIdValues.begin(), sourceIdValues.end()); - synchronizeFileStatuses(fileStatuses, sourceIdValues); - synchronizeModules(modules, typeIdsToBeDeleted, sourceIdValues); - synchronizeImports(imports, sourceIdValues); - synchronizeTypes(types, + synchronizeFileStatuses(package.fileStatuses, sourceIdValues); + synchronizeImports(package.imports, sourceIdValues); + synchronizeTypes(package.types, updatedTypeIds, insertedAliasPropertyDeclarations, - updatedAliasPropertyDeclarations); - - deleteNotUpdatedTypes(updatedTypeIds, sourceIdValues, typeIdsToBeDeleted); + updatedAliasPropertyDeclarations, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + sourceIdValues); + + deleteNotUpdatedTypes(updatedTypeIds, + sourceIdValues, + typeIdsToBeDeleted, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + deletedTypeIds); + + relink(relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + deletedTypeIds); linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations); transaction.commit(); } - ModuleId fetchModuleId(Utils::SmallStringView moduleName) + ModuleId moduleId(Utils::SmallStringView moduleName) override { - Sqlite::DeferredTransaction transaction{database}; - - ModuleId moduleId = fetchModuleIdUnguarded(moduleName); - - transaction.commit(); - - return moduleId; + return moduleCache.id(moduleName); } - ModuleIds fetchModuleIds(const Storage::Modules &modules) + Utils::SmallString moduleName(ModuleId moduleId) { - Sqlite::DeferredTransaction transaction{database}; - - ModuleIds moduleIds = fetchModuleIdsUnguarded(modules); - - transaction.commit(); + if (!moduleId) + throw ModuleDoesNotExists{}; - return moduleIds; + return moduleCache.value(moduleId); } PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId, @@ -132,9 +143,9 @@ public: static_cast<void *>(moduleIds.data()), static_cast<long long>(moduleIds.size()), name); } - TypeId fetchTypeIdByName(ModuleId moduleId, Utils::SmallStringView name) + TypeId fetchTypeIdByName(SourceId sourceId, Utils::SmallStringView name) { - return selectTypeIdByModuleIdAndNameStatement.template valueWithTransaction<TypeId>(&moduleId, + return selectTypeIdBySourceIdAndNameStatement.template valueWithTransaction<TypeId>(&sourceId, name); } @@ -283,11 +294,6 @@ public: return writeSourceId(sourceContextId, sourceName); } - auto fetchAllModules() const - { - return selectAllModulesStatement.template valuesWithTransaction<Storage::Module>(128); - } - auto fetchAllFileStatuses() const { return selectAllFileStatusesStatement.template rangeWithTransaction<FileStatus>(); @@ -299,9 +305,79 @@ public: &sourceId); } - SourceIds fetchSourceDependencieIds(SourceId sourceId) const override { return {}; } + Storage::ProjectDatas fetchProjectDatas(SourceId sourceId) const override + { + return Storage::ProjectDatas{}; + } private: + class ModuleStorageAdapter + { + public: + auto fetchId(const Utils::SmallStringView name) { return storage.fetchModuleId(name); } + + auto fetchValue(ModuleId id) { return storage.fetchModuleName(id); } + + auto fetchAll() { return storage.fetchAllModules(); } + + ProjectStorage &storage; + }; + + class Module : public StorageCacheEntry<Utils::PathString, Utils::SmallStringView, ModuleId> + { + using Base = StorageCacheEntry<Utils::PathString, Utils::SmallStringView, ModuleId>; + + public: + using Base::Base; + + friend bool operator==(const Module &first, const Module &second) + { + return first.id == second.id && first.value == second.value; + } + }; + + friend ModuleStorageAdapter; + + static bool moduleNameLess(Utils::SmallStringView first, Utils::SmallStringView second) noexcept + { + return Utils::reverseCompare(first, second) < 0; + } + + using ModuleCache = StorageCache<Utils::PathString, + Utils::SmallStringView, + ModuleId, + ModuleStorageAdapter, + NonLockingMutex, + moduleNameLess, + Module>; + + ModuleId fetchModuleId(Utils::SmallStringView moduleName) + { + Sqlite::DeferredTransaction transaction{database}; + + ModuleId moduleId = fetchModuleIdUnguarded(moduleName); + + transaction.commit(); + + return moduleId; + } + + auto fetchModuleName(ModuleId id) + { + Sqlite::DeferredTransaction transaction{database}; + + auto moduleName = fetchModuleNameUnguarded(id); + + transaction.commit(); + + return moduleName; + } + + auto fetchAllModules() const + { + return selectAllModulesStatement.template valuesWithTransaction<Module>(128); + } + class AliasPropertyDeclaration { public: @@ -318,6 +394,13 @@ private: , aliasPropertyDeclarationId{aliasPropertyDeclarationId} {} + friend bool operator<(const AliasPropertyDeclaration &first, + const AliasPropertyDeclaration &second) + { + return std::tie(first.typeId, first.propertyDeclarationId) + < std::tie(second.typeId, second.propertyDeclarationId); + } + public: TypeId typeId; PropertyDeclarationId propertyDeclarationId; @@ -326,6 +409,8 @@ private: PropertyDeclarationId aliasPropertyDeclarationId; }; + using AliasPropertyDeclarations = std::vector<AliasPropertyDeclaration>; + class PropertyDeclaration { public: @@ -345,12 +430,20 @@ private: , importedTypeNameId{importedTypeNameId} {} + friend bool operator<(const PropertyDeclaration &first, const PropertyDeclaration &second) + { + return std::tie(first.typeId, first.propertyDeclarationId) + < std::tie(second.typeId, second.propertyDeclarationId); + } + public: TypeId typeId; PropertyDeclarationId propertyDeclarationId; ImportedTypeNameId importedTypeNameId; }; + using PropertyDeclarations = std::vector<PropertyDeclaration>; + class Prototype { public: @@ -359,15 +452,58 @@ private: , prototypeNameId{std::move(prototypeNameId)} {} + friend bool operator<(Prototype first, Prototype second) + { + return first.typeId < second.typeId; + } + public: TypeId typeId; ImportedTypeNameId prototypeNameId; }; + using Prototypes = std::vector<Prototype>; + + template<typename Type> + struct TypeCompare + { + bool operator()(const Type &type, TypeId typeId) { return type.typeId < typeId; }; + + bool operator()(TypeId typeId, const Type &type) { return typeId < type.typeId; }; + + bool operator()(const Type &first, const Type &second) + { + return first.typeId < second.typeId; + }; + }; + + template<typename Property> + struct PropertyCompare + { + bool operator()(const Property &property, PropertyDeclarationId id) + { + return property.propertyDeclarationId < id; + }; + + bool operator()(PropertyDeclarationId id, const Property &property) + { + return id < property.propertyDeclarationId; + }; + + bool operator()(const Property &first, const Property &second) + { + return first.propertyDeclarationId < second.propertyDeclarationId; + }; + }; + void synchronizeTypes(Storage::Types &types, TypeIds &updatedTypeIds, - std::vector<AliasPropertyDeclaration> &insertedAliasPropertyDeclarations, - std::vector<AliasPropertyDeclaration> &updatedAliasPropertyDeclarations) + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + const std::vector<int> &sourceIdValues) { Storage::ExportedTypes exportedTypes; exportedTypes.reserve(types.size() * 3); @@ -381,16 +517,19 @@ private: extractExportedTypes(typeId, type, exportedTypes); } - synchronizeExportedTypes(updatedTypeIds, exportedTypes); + synchronizeExportedTypes(sourceIdValues, + updatedTypeIds, + exportedTypes, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes); - for (auto &&type : types) - syncPrototypes(type); - - for (auto &&type : types) - resetRemovedAliasPropertyDeclarationsToNull(type.typeId, type.propertyDeclarations); - - for (auto &&type : types) - syncDeclarations(type, insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations); + syncPrototypes(types, relinkablePrototypes); + resetRemovedAliasPropertyDeclarationsToNull(types, relinkableAliasPropertyDeclarations); + syncDeclarations(types, + insertedAliasPropertyDeclarations, + updatedAliasPropertyDeclarations, + relinkablePropertyDeclarations); } void synchronizeFileStatuses(FileStatuses &fileStatuses, const std::vector<int> &sourceIdValues) @@ -428,43 +567,10 @@ private: Sqlite::insertUpdateDelete(range, fileStatuses, compareKey, insert, update, remove); } - void synchronizeModules(Storage::Modules &modules, - TypeIds &typeIdsToBeDeleted, - const std::vector<int> &moduleIdValues) - { - auto compareKey = [](auto &&first, auto &&second) { - return first.sourceId.id - second.sourceId.id; - }; - - std::sort(modules.begin(), modules.end(), [&](auto &&first, auto &&second) { - return compareKey(first, second) < 0; - }); - - auto range = selectModulesForIdsStatement.template range<Storage::ModuleView>( - Utils::span(moduleIdValues)); - - auto insert = [&](Storage::Module &module) { - insertModuleStatement.write(module.name, &module.sourceId); - }; - - auto update = [&](const Storage::ModuleView &moduleView, Storage::Module &module) { - if (moduleView.name != module.name) - updateModuleStatement.write(&moduleView.sourceId, module.name); - }; - - auto remove = [&](const Storage::ModuleView &moduleView) { - deleteModuleStatement.write(&moduleView.sourceId); - selectTypeIdsForModuleIdStatement.readTo(typeIdsToBeDeleted, &moduleView.sourceId); - }; - - Sqlite::insertUpdateDelete(range, modules, compareKey, insert, update, remove); - } - void synchronizeImports(Storage::Imports &imports, std::vector<int> &sourceIdValues) { deleteDocumentImportsForDeletedDocuments(imports, sourceIdValues); - addModuleIdToImports(imports); synchronizeDocumentImports(imports, sourceIdValues); } @@ -487,50 +593,28 @@ private: deleteDocumentImportsWithSourceIdsStatement.write(Utils::span{documentSourceIdsToBeDeleted}); } - void synchronizeModulesAndUpdatesModuleIds(Storage::Modules &modules, - TypeIds &typeIdsToBeDeleted, - const std::vector<int> &moduleIds) + ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name) const { - auto compareKey = [](auto &&first, auto &&second) { - return first.sourceId.id - second.sourceId.id; - }; - - std::sort(modules.begin(), modules.end(), [&](auto &&first, auto &&second) { - return compareKey(first, second) < 0; - }); - - auto range = selectModulesForIdsStatement.template range<Storage::ModuleView>( - Utils::span(moduleIds)); - - auto insert = [&](Storage::Module &module) { - insertModuleStatement.write(module.name, &module.sourceId); - }; - - auto update = [&](const Storage::ModuleView &moduleView, Storage::Module &module) { - if (moduleView.name != module.name) - updateModuleStatement.write(&moduleView.sourceId, module.name); - }; + auto moduleId = selectModuleIdByNameStatement.template value<ModuleId>(name); - auto remove = [&](const Storage::ModuleView &moduleView) { - deleteModuleStatement.write(&moduleView.sourceId); - selectTypeIdsForModuleIdStatement.readTo(typeIdsToBeDeleted, &moduleView.sourceId); - }; + if (moduleId) + return moduleId; - Sqlite::insertUpdateDelete(range, modules, compareKey, insert, update, remove); + return insertModuleNameStatement.template value<ModuleId>(name); } - ModuleId fetchModuleIdUnguarded(const Storage::Module &module) const + auto fetchModuleNameUnguarded(ModuleId id) const { - return fetchModuleIdUnguarded(module.name); - } + auto moduleName = selectModuleNameStatement.template value<Utils::PathString>(&id); - ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name) const - { - return selectModuleIdByNameStatement.template value<ModuleId>(name); + if (moduleName.empty()) + throw ModuleDoesNotExists{}; + + return moduleName; } void handleAliasPropertyDeclarationsWithPropertyType( - TypeId typeId, std::vector<AliasPropertyDeclaration> &relinkableAliasPropertyDeclarations) + TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) { auto callback = [&](long long typeId, long long propertyDeclarationId, @@ -555,8 +639,7 @@ private: } void prepareLinkingOfAliasPropertiesDeclarationsWithAliasId( - PropertyDeclarationId aliasId, - std::vector<AliasPropertyDeclaration> &relinkableAliasPropertyDeclarations) + PropertyDeclarationId aliasId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) { auto callback = [&](long long propertyDeclarationId, long long propertyImportedTypeNameId, @@ -578,14 +661,14 @@ private: &aliasId); } - void handlePropertyDeclarationWithPropertyType( - TypeId typeId, std::vector<PropertyDeclaration> &relinkablePropertyDeclarations) + void handlePropertyDeclarationWithPropertyType(TypeId typeId, + PropertyDeclarations &relinkablePropertyDeclarations) { updatesPropertyDeclarationPropertyTypeToNullStatement.readTo(relinkablePropertyDeclarations, &typeId); } - void handlePrototypes(TypeId prototypeId, std::vector<Prototype> &relinkablePrototypes) + void handlePrototypes(TypeId prototypeId, Prototypes &relinkablePrototypes) { auto callback = [&](long long typeId, long long prototypeNameId) { relinkablePrototypes.emplace_back(TypeId{typeId}, ImportedTypeNameId{prototypeNameId}); @@ -597,9 +680,9 @@ private: } void deleteType(TypeId typeId, - std::vector<AliasPropertyDeclaration> &relinkableAliasPropertyDeclarations, - std::vector<PropertyDeclaration> &relinkablePropertyDeclarations, - std::vector<Prototype> &relinkablePrototypes) + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes) { handlePropertyDeclarationWithPropertyType(typeId, relinkablePropertyDeclarations); handleAliasPropertyDeclarationsWithPropertyType(typeId, relinkableAliasPropertyDeclarations); @@ -612,72 +695,85 @@ private: deleteTypeStatement.write(&typeId); } - void relinkAliasPropertyDeclarations( - const std::vector<AliasPropertyDeclaration> &aliasPropertyDeclarations, - const TypeIds &deletedTypeIds) + void relinkAliasPropertyDeclarations(AliasPropertyDeclarations &aliasPropertyDeclarations, + const TypeIds &deletedTypeIds) { - for (const AliasPropertyDeclaration &alias : aliasPropertyDeclarations) { - if (std::binary_search(deletedTypeIds.begin(), deletedTypeIds.end(), alias.typeId)) - continue; + std::sort(aliasPropertyDeclarations.begin(), aliasPropertyDeclarations.end()); - auto typeId = fetchTypeId(alias.aliasImportedTypeNameId); + Utils::set_greedy_difference( + aliasPropertyDeclarations.cbegin(), + aliasPropertyDeclarations.cend(), + deletedTypeIds.begin(), + deletedTypeIds.end(), + [&](const AliasPropertyDeclaration &alias) { + auto typeId = fetchTypeId(alias.aliasImportedTypeNameId); - if (!typeId) - throw TypeNameDoesNotExists{}; + if (!typeId) + throw TypeNameDoesNotExists{}; - auto [propertyTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeIdAndNameUngarded( - typeId, alias.aliasPropertyName); + auto [propertyTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeIdAndNameUngarded( + typeId, alias.aliasPropertyName); - updatePropertyDeclarationWithAliasAndTypeStatement.write(&alias.propertyDeclarationId, - &propertyTypeId, - propertyTraits, - &alias.aliasImportedTypeNameId, - &aliasId); - } + updatePropertyDeclarationWithAliasAndTypeStatement.write(&alias.propertyDeclarationId, + &propertyTypeId, + propertyTraits, + &alias.aliasImportedTypeNameId, + &aliasId); + }, + TypeCompare<AliasPropertyDeclaration>{}); } - void relinkPropertyDeclarations(const std::vector<PropertyDeclaration> &relinkablePropertyDeclaration, + void relinkPropertyDeclarations(PropertyDeclarations &relinkablePropertyDeclaration, const TypeIds &deletedTypeIds) { - for (const PropertyDeclaration &property : relinkablePropertyDeclaration) { - if (std::binary_search(deletedTypeIds.begin(), deletedTypeIds.end(), property.typeId)) - continue; + std::sort(relinkablePropertyDeclaration.begin(), relinkablePropertyDeclaration.end()); - TypeId propertyTypeId = fetchTypeId(property.importedTypeNameId); + Utils::set_greedy_difference( + relinkablePropertyDeclaration.cbegin(), + relinkablePropertyDeclaration.cend(), + deletedTypeIds.begin(), + deletedTypeIds.end(), + [&](const PropertyDeclaration &property) { + TypeId propertyTypeId = fetchTypeId(property.importedTypeNameId); - if (!propertyTypeId) - throw TypeNameDoesNotExists{}; + if (!propertyTypeId) + throw TypeNameDoesNotExists{}; - updatePropertyDeclarationTypeStatement.write(&property.propertyDeclarationId, - &propertyTypeId); - } + updatePropertyDeclarationTypeStatement.write(&property.propertyDeclarationId, + &propertyTypeId); + }, + TypeCompare<PropertyDeclaration>{}); } - void relinkPrototypes(std::vector<Prototype> relinkablePrototypes, const TypeIds &deletedTypeIds) + void relinkPrototypes(Prototypes &relinkablePrototypes, const TypeIds &deletedTypeIds) { - for (const Prototype &prototype : relinkablePrototypes) { - if (std::binary_search(deletedTypeIds.begin(), deletedTypeIds.end(), prototype.typeId)) - continue; + std::sort(relinkablePrototypes.begin(), relinkablePrototypes.end()); - TypeId prototypeId = fetchTypeId(prototype.prototypeNameId); + Utils::set_greedy_difference( + relinkablePrototypes.cbegin(), + relinkablePrototypes.cend(), + deletedTypeIds.begin(), + deletedTypeIds.end(), + [&](const Prototype &prototype) { + TypeId prototypeId = fetchTypeId(prototype.prototypeNameId); - if (!prototypeId) - throw TypeNameDoesNotExists{}; + if (!prototypeId) + throw TypeNameDoesNotExists{}; - updateTypePrototypeStatement.write(&prototype.typeId, &prototypeId); - checkForPrototypeChainCycle(prototype.typeId); - } + updateTypePrototypeStatement.write(&prototype.typeId, &prototypeId); + checkForPrototypeChainCycle(prototype.typeId); + }, + TypeCompare<Prototype>{}); } void deleteNotUpdatedTypes(const TypeIds &updatedTypeIds, const std::vector<int> &sourceIdValues, - const TypeIds &typeIdsToBeDeleted) + const TypeIds &typeIdsToBeDeleted, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + TypeIds &deletedTypeIds) { - std::vector<AliasPropertyDeclaration> relinkableAliasPropertyDeclarations; - std::vector<PropertyDeclaration> relinkablePropertyDeclarations; - std::vector<Prototype> relinkablePrototypes; - TypeIds deletedTypeIds; - auto updatedTypeIdValues = Utils::transform<std::vector>(updatedTypeIds, [](TypeId typeId) { return &typeId; }); @@ -696,7 +792,13 @@ private: Utils::span(updatedTypeIdValues)); for (TypeId typeIdToBeDeleted : typeIdsToBeDeleted) callback(&typeIdToBeDeleted); + } + void relink(AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + TypeIds &deletedTypeIds) + { std::sort(deletedTypeIds.begin(), deletedTypeIds.end()); relinkPrototypes(relinkablePrototypes, deletedTypeIds); @@ -704,7 +806,7 @@ private: relinkAliasPropertyDeclarations(relinkableAliasPropertyDeclarations, deletedTypeIds); } - void linkAliasPropertyDeclarationAliasIds(const std::vector<AliasPropertyDeclaration> &aliasDeclarations) + void linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations) { for (const auto &aliasDeclaration : aliasDeclarations) { auto aliasTypeId = fetchTypeId(aliasDeclaration.aliasImportedTypeNameId); @@ -722,7 +824,7 @@ private: } } - void updateAliasPropertyDeclarationValues(const std::vector<AliasPropertyDeclaration> &aliasDeclarations) + void updateAliasPropertyDeclarationValues(const AliasPropertyDeclarations &aliasDeclarations) { for (const auto &aliasDeclaration : aliasDeclarations) { updatetPropertiesDeclarationValuesOfAliasStatement.write( @@ -732,14 +834,14 @@ private: } } - void checkAliasPropertyDeclarationCycles(const std::vector<AliasPropertyDeclaration> &aliasDeclarations) + void checkAliasPropertyDeclarationCycles(const AliasPropertyDeclarations &aliasDeclarations) { for (const auto &aliasDeclaration : aliasDeclarations) checkForAliasChainCycle(aliasDeclaration.propertyDeclarationId); } - void linkAliases(const std::vector<AliasPropertyDeclaration> &insertedAliasPropertyDeclarations, - const std::vector<AliasPropertyDeclaration> &updatedAliasPropertyDeclarations) + void linkAliases(const AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + const AliasPropertyDeclarations &updatedAliasPropertyDeclarations) { linkAliasPropertyDeclarationAliasIds(insertedAliasPropertyDeclarations); linkAliasPropertyDeclarationAliasIds(updatedAliasPropertyDeclarations); @@ -751,16 +853,25 @@ private: updateAliasPropertyDeclarationValues(updatedAliasPropertyDeclarations); } - void synchronizeExportedTypes(const TypeIds &typeIds, Storage::ExportedTypes &exportedTypes) + void synchronizeExportedTypes(const std::vector<int> &sourceIdValues, + const TypeIds &updatedTypeIds, + Storage::ExportedTypes &exportedTypes, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes) { std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) { return std::tie(first.moduleId, first.name, first.version) < std::tie(second.moduleId, second.name, second.version); }); - auto range = selectExportedTypesForTypeIdStatement.template range<Storage::ExportedTypeView>( - const_cast<void *>(static_cast<const void *>(typeIds.data())), - static_cast<long long>(typeIds.size())); + Utils::span typeIdValues{static_cast<const TypeIds::value_type::DatabaseType *>( + &updatedTypeIds.data()->id), + updatedTypeIds.size()}; + + auto range = selectExportedTypesForSourceIdsStatement + .template range<Storage::ExportedTypeView>(Utils::span{sourceIdValues}, + typeIdValues); auto compareKey = [](const Storage::ExportedTypeView &view, const Storage::ExportedType &type) -> long long { @@ -780,53 +891,55 @@ private: }; auto insert = [&](const Storage::ExportedType &type) { - if (type.version) { - upsertExportedTypeNamesWithVersionStatement.write(&type.moduleId, - type.name, - static_cast<long long>( - Storage::TypeNameKind::Exported), - type.version.major.value, - type.version.minor.value, - &type.typeId); - - } else if (type.version.major) { - upsertExportedTypeNamesWithMajorVersionStatement - .write(&type.moduleId, - type.name, - static_cast<long long>(Storage::TypeNameKind::Exported), - type.version.major.value, - &type.typeId); - } else { - upsertExportedTypeNamesWithoutVersionStatement - .write(&type.moduleId, - type.name, - static_cast<long long>(Storage::TypeNameKind::Exported), - &type.typeId); + if (!type.moduleId) + throw QmlDesigner::ModuleDoesNotExists{}; + + try { + if (type.version) { + insertExportedTypeNamesWithVersionStatement.write(&type.moduleId, + type.name, + type.version.major.value, + type.version.minor.value, + &type.typeId); + + } else if (type.version.major) { + insertExportedTypeNamesWithMajorVersionStatement.write(&type.moduleId, + type.name, + type.version.major.value, + &type.typeId); + } else { + insertExportedTypeNamesWithoutVersionStatement.write(&type.moduleId, + type.name, + &type.typeId); + } + } catch (const Sqlite::ConstraintPreventsModification &) { + throw QmlDesigner::ModuleDoesNotExists{}; } }; auto update = [&](const Storage::ExportedTypeView &view, const Storage::ExportedType &type) { - if (view.typeId != type.typeId) + if (view.typeId != type.typeId) { + handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations); + handleAliasPropertyDeclarationsWithPropertyType(view.typeId, + relinkableAliasPropertyDeclarations); + handlePrototypes(view.typeId, relinkablePrototypes); updateExportedTypeNameTypeIdStatement.write(&view.exportedTypeNameId, &type.typeId); + } }; auto remove = [&](const Storage::ExportedTypeView &view) { + handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations); + handleAliasPropertyDeclarationsWithPropertyType(view.typeId, + relinkableAliasPropertyDeclarations); + handlePrototypes(view.typeId, relinkablePrototypes); deleteExportedTypeNameStatement.write(&view.exportedTypeNameId); }; Sqlite::insertUpdateDelete(range, exportedTypes, compareKey, insert, update, remove); } - void upsertNativeType(ModuleId moduleId, Utils::SmallStringView name, TypeId typeId) - { - upsertExportedTypeNameStatement.write(&moduleId, - name, - static_cast<long long>(Storage::TypeNameKind::Native), - &typeId); - } - void synchronizePropertyDeclarationsInsertAlias( - std::vector<AliasPropertyDeclaration> &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, const Storage::PropertyDeclaration &value, SourceId sourceId, TypeId typeId) @@ -872,7 +985,7 @@ private: } void synchronizePropertyDeclarationsUpdateAlias( - std::vector<AliasPropertyDeclaration> &updatedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, const Storage::PropertyDeclarationView &view, const Storage::PropertyDeclaration &value, SourceId sourceId) @@ -887,7 +1000,8 @@ private: void synchronizePropertyDeclarationsUpdateProperty(const Storage::PropertyDeclarationView &view, const Storage::PropertyDeclaration &value, - SourceId sourceId) + SourceId sourceId, + PropertyDeclarationIds &propertyDeclarationIds) { auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId); @@ -906,14 +1020,15 @@ private: &propertyImportedTypeNameId); updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement .write(&view.id, &propertyTypeId, static_cast<int>(value.traits)); + propertyDeclarationIds.push_back(view.id); } - void synchronizePropertyDeclarations( - TypeId typeId, - Storage::PropertyDeclarations &propertyDeclarations, - SourceId sourceId, - std::vector<AliasPropertyDeclaration> &insertedAliasPropertyDeclarations, - std::vector<AliasPropertyDeclaration> &updatedAliasPropertyDeclarations) + void synchronizePropertyDeclarations(TypeId typeId, + Storage::PropertyDeclarations &propertyDeclarations, + SourceId sourceId, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + PropertyDeclarationIds &propertyDeclarationIds) { std::sort(propertyDeclarations.begin(), propertyDeclarations.end(), @@ -947,8 +1062,12 @@ private: view, value, sourceId); + propertyDeclarationIds.push_back(view.id); } else { - synchronizePropertyDeclarationsUpdateProperty(view, value, sourceId); + synchronizePropertyDeclarationsUpdateProperty(view, + value, + sourceId, + propertyDeclarationIds); } }; @@ -962,14 +1081,20 @@ private: } deletePropertyDeclarationStatement.write(&view.id); + propertyDeclarationIds.push_back(view.id); }; Sqlite::insertUpdateDelete(range, propertyDeclarations, compareKey, insert, update, remove); } - void resetRemovedAliasPropertyDeclarationsToNull(TypeId typeId, - Storage::PropertyDeclarations &aliasDeclarations) + void resetRemovedAliasPropertyDeclarationsToNull(Storage::Type &type, + PropertyDeclarationIds &propertyDeclarationIds) { + if (type.changeLevel == Storage::ChangeLevel::Minimal) + return; + + Storage::PropertyDeclarations &aliasDeclarations = type.propertyDeclarations; + class AliasPropertyDeclarationView { public: @@ -992,7 +1117,7 @@ private: }); auto range = selectPropertyDeclarationsWithAliasForTypeIdStatement - .template range<AliasPropertyDeclarationView>(&typeId); + .template range<AliasPropertyDeclarationView>(&type.typeId); auto compareKey = [](const AliasPropertyDeclarationView &view, const Storage::PropertyDeclaration &value) { @@ -1006,29 +1131,24 @@ private: auto remove = [&](const AliasPropertyDeclarationView &view) { updatePropertyDeclarationAliasIdToNullStatement.write(&view.id); + propertyDeclarationIds.push_back(view.id); }; Sqlite::insertUpdateDelete(range, aliasDeclarations, compareKey, insert, update, remove); } - ModuleIds fetchModuleIdsUnguarded(const Storage::Modules &modules) + void resetRemovedAliasPropertyDeclarationsToNull( + Storage::Types &types, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) { - ModuleIds moduleIds; - moduleIds.reserve(moduleIds.size()); + PropertyDeclarationIds propertyDeclarationIds; + propertyDeclarationIds.reserve(types.size()); - for (auto &&module : modules) - moduleIds.push_back(fetchModuleIdUnguarded(module)); + for (auto &&type : types) + resetRemovedAliasPropertyDeclarationsToNull(type, propertyDeclarationIds); - return moduleIds; - } - - void addModuleIdToImports(Storage::Imports &imports) - { - for (Storage::Import &import : imports) { - import.moduleId = fetchModuleIdUnguarded(import.name); - if (!import.moduleId) - throw ModuleDoesNotExists{}; - } + removeRelinkableEntries(relinkableAliasPropertyDeclarations, + propertyDeclarationIds, + PropertyCompare<AliasPropertyDeclaration>{}); } void synchronizeDocumentImports(Storage::Imports &imports, const std::vector<int> &sourceIdValues) @@ -1096,7 +1216,7 @@ private: json.append(parameter.name); json.append("\",\"tn\":\""); json.append(parameter.typeName); - if (parameter.traits == Storage::PropertyDeclarationTraits::Non) { + if (parameter.traits == Storage::PropertyDeclarationTraits::None) { json.append("\"}"); } else { json.append("\",\"tr\":"); @@ -1257,60 +1377,88 @@ private: Storage::ExportedTypes &exportedTypes) { for (const auto &exportedType : type.exportedTypes) - exportedTypes.emplace_back(exportedType.name, exportedType.version, typeId, type.moduleId); + exportedTypes.emplace_back(exportedType.name, + exportedType.version, + typeId, + exportedType.moduleId); } - struct ModuleAndTypeId - { - ModuleAndTypeId() = default; - ModuleAndTypeId(int moduleId, long long typeId) - : moduleId{moduleId} - , typeId{typeId} - {} - - ModuleId moduleId; - TypeId typeId; - }; - TypeId declareType(Storage::Type &type) { - if (!type.moduleId && type.typeName.isEmpty()) { - auto [moduleId, typeId] = selectModuleAndTypeIdBySourceIdStatement - .template value<ModuleAndTypeId>(&type.sourceId); - type.typeId = typeId; - type.moduleId = moduleId; + if (type.typeName.isEmpty()) { + type.typeId = selectTypeIdBySourceIdStatement.template value<TypeId>(&type.sourceId); + return type.typeId; } - if (!type.moduleId) - throw ModuleDoesNotExists{}; - - type.typeId = upsertTypeStatement.template value<TypeId>(&type.moduleId, + type.typeId = upsertTypeStatement.template value<TypeId>(&type.sourceId, type.typeName, - static_cast<int>(type.accessSemantics), - &type.sourceId); + static_cast<int>( + type.accessSemantics)); if (!type.typeId) - type.typeId = selectTypeIdByModuleIdAndNameStatement.template value<TypeId>(&type.moduleId, + type.typeId = selectTypeIdBySourceIdAndNameStatement.template value<TypeId>(&type.sourceId, type.typeName); - upsertNativeType(type.moduleId, type.typeName, type.typeId); return type.typeId; } void syncDeclarations(Storage::Type &type, - std::vector<AliasPropertyDeclaration> &insertedAliasPropertyDeclarations, - std::vector<AliasPropertyDeclaration> &updatedAliasPropertyDeclarations) + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + PropertyDeclarationIds &propertyDeclarationIds) { - auto typeId = type.typeId; - synchronizePropertyDeclarations(typeId, + if (type.changeLevel == Storage::ChangeLevel::Minimal) + return; + + synchronizePropertyDeclarations(type.typeId, type.propertyDeclarations, type.sourceId, insertedAliasPropertyDeclarations, - updatedAliasPropertyDeclarations); - synchronizeFunctionDeclarations(typeId, type.functionDeclarations); - synchronizeSignalDeclarations(typeId, type.signalDeclarations); - synchronizeEnumerationDeclarations(typeId, type.enumerationDeclarations); + updatedAliasPropertyDeclarations, + propertyDeclarationIds); + synchronizeFunctionDeclarations(type.typeId, type.functionDeclarations); + synchronizeSignalDeclarations(type.typeId, type.signalDeclarations); + synchronizeEnumerationDeclarations(type.typeId, type.enumerationDeclarations); + } + + template<typename Relinkable, typename Ids, typename Compare> + void removeRelinkableEntries(std::vector<Relinkable> &relinkables, Ids &ids, Compare compare) + { + std::vector<Relinkable> newRelinkables; + newRelinkables.reserve(relinkables.size()); + + std::sort(ids.begin(), ids.end()); + std::sort(relinkables.begin(), relinkables.end(), compare); + + Utils::set_greedy_difference( + relinkables.begin(), + relinkables.end(), + ids.cbegin(), + ids.cend(), + [&](Relinkable &entry) { newRelinkables.push_back(std::move(entry)); }, + compare); + + relinkables = std::move(newRelinkables); + } + + void syncDeclarations(Storage::Types &types, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations) + { + PropertyDeclarationIds propertyDeclarationIds; + propertyDeclarationIds.reserve(types.size() * 10); + + for (auto &&type : types) + syncDeclarations(type, + insertedAliasPropertyDeclarations, + updatedAliasPropertyDeclarations, + propertyDeclarationIds); + + removeRelinkableEntries(relinkablePropertyDeclarations, + propertyDeclarationIds, + PropertyCompare<PropertyDeclaration>{}); } void checkForPrototypeChainCycle(TypeId typeId) const @@ -1338,7 +1486,7 @@ private: &propertyDeclarationId); } - void syncPrototypes(Storage::Type &type) + void syncPrototype(Storage::Type &type, TypeIds &typeIds) { if (type.changeLevel == Storage::ChangeLevel::Minimal) return; @@ -1358,22 +1506,35 @@ private: updatePrototypeStatement.write(&type.typeId, &prototypeId, &prototypeTypeNameId); checkForPrototypeChainCycle(type.typeId); } + + typeIds.push_back(type.typeId); + } + + void syncPrototypes(Storage::Types &types, Prototypes &relinkablePrototypes) + { + TypeIds typeIds; + typeIds.reserve(types.size()); + + for (auto &type : types) + syncPrototype(type, typeIds); + + removeRelinkableEntries(relinkablePrototypes, typeIds, TypeCompare<Prototype>{}); } ImportId fetchImportId(SourceId sourceId, const Storage::Import &import) const { if (import.version) { - return selectImportIdBySourceIdAndImportNameAndVersionStatement.template value<ImportId>( - &sourceId, import.name, import.version.major.value, import.version.minor.value); + return selectImportIdBySourceIdAndModuleIdAndVersionStatement.template value<ImportId>( + &sourceId, &import.moduleId, import.version.major.value, import.version.minor.value); } if (import.version.major) { - return selectImportIdBySourceIdAndImportNameAndMajorVersionStatement - .template value<ImportId>(&sourceId, import.name, import.version.major.value); + return selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement + .template value<ImportId>(&sourceId, &import.moduleId, import.version.major.value); } - return selectImportIdBySourceIdAndImportNameStatement.template value<ImportId>(&sourceId, - import.name); + return selectImportIdBySourceIdAndModuleIdStatement.template value<ImportId>(&sourceId, + &import.moduleId); } ImportedTypeNameId fetchImportedTypeNameId(const Storage::ImportedTypeName &name, SourceId sourceId) @@ -1440,9 +1601,6 @@ private: &typeNameId); } - if (kind == Storage::TypeNameKind::Native) - return selectTypeIdForNativeTypeNameNamesStatement.template value<TypeId>(&typeNameId); - return selectTypeIdForImportedTypeNameNamesStatement.template value<TypeId>(&typeNameId); } @@ -1649,21 +1807,16 @@ private: typesTable.setUseIfNotExists(true); typesTable.setName("types"); typesTable.addColumn("typeId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); - auto &moduleIdColumn = typesTable.addForeignKeyColumn("moduleId", - foreignModuleIdColumn, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::Enforment::Deferred); + auto &sourceIdColumn = typesTable.addColumn("sourceId"); auto &typesNameColumn = typesTable.addColumn("name"); typesTable.addColumn("accessSemantics"); - typesTable.addColumn("sourceId"); typesTable.addForeignKeyColumn("prototypeId", typesTable, Sqlite::ForeignKeyAction::NoAction, Sqlite::ForeignKeyAction::Restrict); typesTable.addColumn("prototypeNameId"); - typesTable.addUniqueIndex({moduleIdColumn, typesNameColumn}); + typesTable.addUniqueIndex({sourceIdColumn, typesNameColumn}); typesTable.initialize(database); @@ -1706,23 +1859,20 @@ private: auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", foreignModuleIdColumn, Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::Enforment::Deferred); + Sqlite::ForeignKeyAction::NoAction); auto &nameColumn = table.addColumn("name"); - auto &kindColumn = table.addColumn("kind"); auto &typeIdColumn = table.addColumn("typeId"); auto &majorVersionColumn = table.addColumn("majorVersion"); auto &minorVersionColumn = table.addColumn("minorVersion"); - table.addUniqueIndex({moduleIdColumn, nameColumn, kindColumn}, + table.addUniqueIndex({moduleIdColumn, nameColumn}, "majorVersion IS NULL AND minorVersion IS NULL"); - table.addUniqueIndex({moduleIdColumn, nameColumn, kindColumn, majorVersionColumn}, + table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn}, "majorVersion IS NOT NULL AND minorVersion IS NULL"); - table.addUniqueIndex( - {moduleIdColumn, nameColumn, kindColumn, majorVersionColumn, minorVersionColumn}, - "majorVersion IS NOT NULL AND minorVersion IS NOT NULL"); + table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn, minorVersionColumn}, + "majorVersion IS NOT NULL AND minorVersion IS NOT NULL"); - table.addIndex({typeIdColumn}, "kind=1"); + table.addIndex({typeIdColumn}); table.initialize(database); } @@ -1823,6 +1973,7 @@ private: Sqlite::Enforment::Deferred); auto &majorVersionColumn = table.addColumn("majorVersion"); auto &minorVersionColumn = table.addColumn("minorVersion"); + table.addColumn("kind"); table.addUniqueIndex({sourceIdColumn, moduleIdColumn}, "majorVersion IS NULL AND minorVersion IS NULL"); @@ -1856,18 +2007,18 @@ private: public: Database &database; Initializer initializer; + ModuleCache moduleCache{ModuleStorageAdapter{*this}}; ReadWriteStatement<1> upsertTypeStatement{ - "INSERT INTO types(moduleId, name, accessSemantics, sourceId) VALUES(?1, ?2, " - "?3, nullif(?4, -1)) ON CONFLICT DO UPDATE SET accessSemantics=excluded.accessSemantics, " - "sourceId=excluded.sourceId WHERE accessSemantics IS NOT excluded.accessSemantics OR " - "sourceId IS NOT excluded.sourceId RETURNING typeId", + "INSERT INTO types(sourceId, name, accessSemantics) VALUES(?1, ?2, ?3) ON CONFLICT DO " + "UPDATE SET accessSemantics=excluded.accessSemantics WHERE accessSemantics IS NOT " + "excluded.accessSemantics RETURNING typeId", database}; WriteStatement updatePrototypeStatement{ "UPDATE types SET prototypeId=?2, prototypeNameId=?3 WHERE typeId=?1 AND (prototypeId IS " "NOT ?2 OR prototypeNameId IS NOT ?3)", database}; mutable ReadStatement<1> selectTypeIdByExportedNameStatement{ - "SELECT typeId FROM exportedTypeNames WHERE name=?1 AND kind=1", database}; + "SELECT typeId FROM exportedTypeNames WHERE name=?1", database}; mutable ReadStatement<1> selectPrototypeIdStatement{ "WITH RECURSIVE " " typeSelection(typeId) AS (" @@ -1925,18 +2076,14 @@ public: "INSERT INTO sources(sourceContextId, sourceName) VALUES (?,?)", database}; mutable ReadStatement<3> selectAllSourcesStatement{ "SELECT sourceName, sourceContextId, sourceId FROM sources", database}; - mutable ReadStatement<5> selectTypeByTypeIdStatement{ - "SELECT moduleId, name, (SELECT name FROM types WHERE typeId=outerTypes.prototypeId), " - "accessSemantics, ifnull(sourceId, -1) FROM types AS outerTypes WHERE typeId=?", + mutable ReadStatement<4> selectTypeByTypeIdStatement{ + "SELECT sourceId, name, prototypeId, accessSemantics FROM types WHERE typeId=?", database}; + mutable ReadStatement<4> selectExportedTypesByTypeIdStatement{ + "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1) FROM " + "exportedTypeNames WHERE typeId=?", database}; - mutable ReadStatement<3> selectExportedTypesByTypeIdStatement{ - "SELECT name, ifnull(majorVersion, -1), ifnull(minorVersion, -1) FROM exportedTypeNames " - "WHERE typeId=? AND kind=1", - database}; - mutable ReadStatement<6> selectTypesStatement{ - "SELECT moduleId, name, typeId, (SELECT name FROM types WHERE " - "typeId=t.prototypeId), accessSemantics, ifnull(sourceId, -1) FROM types AS " - "t", + mutable ReadStatement<5> selectTypesStatement{ + "SELECT sourceId, name, typeId, ifnull(prototypeId, -1), accessSemantics FROM types", database}; ReadStatement<1> selectNotUpdatedTypesInSourcesStatement{ "SELECT typeId FROM types WHERE (sourceId IN carray(?1) AND typeId NOT IN carray(?2))", @@ -1953,10 +2100,9 @@ public: "DELETE FROM signalDeclarations WHERE typeId=?", database}; WriteStatement deleteTypeStatement{"DELETE FROM types WHERE typeId=?", database}; mutable ReadStatement<4> selectPropertyDeclarationsByTypeIdStatement{ - "SELECT name, (SELECT name FROM types WHERE typeId=pd.propertyTypeId), propertyTraits, " - "(SELECT name FROM propertyDeclarations WHERE " - "propertyDeclarationId=pd.aliasPropertyDeclarationId) FROM propertyDeclarations AS pd " - "WHERE typeId=?", + "SELECT name, nullif(propertyTypeId, -1), propertyTraits, (SELECT name FROM " + "propertyDeclarations WHERE propertyDeclarationId=pd.aliasPropertyDeclarationId) FROM " + "propertyDeclarations AS pd WHERE typeId=?", database}; ReadStatement<6> selectPropertyDeclarationsForTypeIdStatement{ "SELECT name, propertyTraits, propertyTypeId, propertyImportedTypeNameId, " @@ -2081,25 +2227,18 @@ public: database}; WriteStatement deleteEnumerationDeclarationStatement{ "DELETE FROM enumerationDeclarations WHERE enumerationDeclarationId=?", database}; - WriteStatement insertModuleStatement{"INSERT INTO modules(name, moduleId) VALUES(?1, ?2)", - database}; - WriteStatement updateModuleStatement{"UPDATE modules SET name=?2 WHERE moduleId=?1", database}; - WriteStatement deleteModuleStatement{"DELETE FROM modules WHERE moduleId=?", database}; mutable ReadStatement<1> selectModuleIdByNameStatement{ "SELECT moduleId FROM modules WHERE name=? LIMIT 1", database}; - mutable ReadStatement<2> selectModulesForIdsStatement{ - "SELECT name, moduleId FROM modules WHERE moduleId IN carray(?1) ORDER BY " - "moduleId", - database}; - mutable ReadStatement<2> selectAllModulesStatement{ - "SELECT name, moduleId FROM modules ORDER BY moduleId", database}; - mutable ReadStatement<1> selectTypeIdsForModuleIdStatement{ - "SELECT typeId FROM types WHERE moduleId=?", database}; - mutable ReadStatement<1> selectTypeIdByModuleIdAndNameStatement{ - "SELECT typeId FROM types WHERE moduleId=?1 and name=?2", database}; + mutable ReadWriteStatement<1> insertModuleNameStatement{ + "INSERT INTO modules(name) VALUES(?1) RETURNING moduleId", database}; + mutable ReadStatement<1> selectModuleNameStatement{ + "SELECT name FROM modules WHERE moduleId =?1", database}; + mutable ReadStatement<2> selectAllModulesStatement{"SELECT name, moduleId FROM modules", database}; + mutable ReadStatement<1> selectTypeIdBySourceIdAndNameStatement{ + "SELECT typeId FROM types WHERE sourceId=?1 and name=?2", database}; mutable ReadStatement<1> selectTypeIdByModuleIdsAndExportedNameStatement{ "SELECT typeId FROM exportedTypeNames WHERE moduleId IN carray(?1, ?2, 'int32') AND " - "name=?3 AND kind=1", + "name=?3", database}; mutable ReadStatement<5> selectDocumentImportForSourceIdStatement{ "SELECT importId, sourceId, moduleId, ifnull(majorVersion, -1), ifnull(minorVersion, -1) " @@ -2241,8 +2380,8 @@ public: WriteStatement deleteFileStatusStatement{"DELETE FROM fileStatuses WHERE sourceId=?1", database}; WriteStatement updateFileStatusStatement{ "UPDATE fileStatuses SET size=?2, lastModified=?3 WHERE sourceId=?1", database}; - ReadStatement<2> selectModuleAndTypeIdBySourceIdStatement{ - "SELECT moduleId, typeId FROM types WHERE sourceId=?", database}; + ReadStatement<1> selectTypeIdBySourceIdStatement{"SELECT typeId FROM types WHERE sourceId=?", + database}; mutable ReadStatement<1> selectImportedTypeNameIdStatement{ "SELECT importedTypeNameId FROM importedTypeNames WHERE kind=?1 AND importOrSourceId=?2 " "AND name=?3 LIMIT 1", @@ -2251,24 +2390,24 @@ public: "INSERT INTO importedTypeNames(kind, importOrSourceId, name) VALUES (?1, ?2, ?3) " "RETURNING importedTypeNameId", database}; - mutable ReadStatement<1> selectImportIdBySourceIdAndImportNameStatement{ - "SELECT importId FROM documentImports JOIN modules AS m USING(moduleId) WHERE sourceId=?1 " - "AND m.name=?2 AND majorVersion IS NULL AND minorVersion IS NULL LIMIT 1", + mutable ReadStatement<1> selectImportIdBySourceIdAndModuleIdStatement{ + "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND majorVersion " + "IS NULL AND minorVersion IS NULL LIMIT 1", database}; - mutable ReadStatement<1> selectImportIdBySourceIdAndImportNameAndMajorVersionStatement{ - "SELECT importId FROM documentImports JOIN modules AS m USING(moduleId) WHERE sourceId=?1 " - "AND m.name=?2 AND majorVersion=?3 AND minorVersion IS NULL LIMIT 1", + mutable ReadStatement<1> selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement{ + "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND " + "majorVersion=?3 AND minorVersion IS NULL LIMIT 1", database}; - mutable ReadStatement<1> selectImportIdBySourceIdAndImportNameAndVersionStatement{ - "SELECT importId FROM documentImports JOIN modules AS m USING(moduleId) WHERE sourceId=?1 " - "AND m.name=?2 AND majorVersion=?3 AND minorVersion=?4 LIMIT 1", + mutable ReadStatement<1> selectImportIdBySourceIdAndModuleIdAndVersionStatement{ + "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND " + "majorVersion=?3 AND minorVersion=?4 LIMIT 1", database}; mutable ReadStatement<1> selectKindFromImportedTypeNamesStatement{ "SELECT kind FROM importedTypeNames WHERE importedTypeNameId=?1", database}; mutable ReadStatement<1> selectTypeIdForQualifiedImportedTypeNameNamesStatement{ "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON " "importOrSourceId=importId JOIN exportedTypeNames AS etn USING(moduleId) WHERE " - "itn.kind=2 AND importedTypeNameId=?1 AND itn.name=etn.name AND etn.kind=1 AND " + "itn.kind=2 AND importedTypeNameId=?1 AND itn.name=etn.name AND " "(di.majorVersion IS NULL OR (di.majorVersion=etn.majorVersion AND (di.minorVersion IS " "NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY etn.majorVersion DESC NULLS FIRST, " "etn.minorVersion DESC NULLS FIRST LIMIT 1", @@ -2276,39 +2415,29 @@ public: mutable ReadStatement<1> selectTypeIdForImportedTypeNameNamesStatement{ "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON " "importOrSourceId=sourceId JOIN exportedTypeNames AS etn USING(moduleId) WHERE " - "itn.kind=1 AND importedTypeNameId=?1 AND itn.name=etn.name AND etn.kind=1 AND " + "itn.kind=1 AND importedTypeNameId=?1 AND itn.name=etn.name AND " "(di.majorVersion IS NULL OR (di.majorVersion=etn.majorVersion AND (di.minorVersion IS " "NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY etn.majorVersion DESC NULLS FIRST, " "etn.minorVersion DESC NULLS FIRST LIMIT 1", database}; - mutable ReadStatement<1> selectTypeIdForNativeTypeNameNamesStatement{ - "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON " - "importOrSourceId=sourceId JOIN exportedTypeNames AS etn USING(moduleId) WHERE itn.kind=0 " - "AND importedTypeNameId=?1 AND itn.name=etn.name AND etn.kind=0 LIMIT 1", - database}; WriteStatement deleteAllSourcesStatement{"DELETE FROM sources", database}; WriteStatement deleteAllSourceContextsStatement{"DELETE FROM sourceContexts", database}; - mutable ReadStatement<6> selectExportedTypesForTypeIdStatement{ - "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1), typeId, " - "exportedTypeNameId FROM exportedTypeNames WHERE typeId IN carray(?1, ?2, 'int64') AND " - "kind=1 ORDER BY moduleId, name, majorVersion, minorVersion", - database}; - WriteStatement upsertExportedTypeNamesWithVersionStatement{ - "INSERT INTO exportedTypeNames(moduleId, name, kind, majorVersion, minorVersion, typeId) " - "VALUES(?1, ?2, ?3, ?4, ?5, ?6) ON CONFLICT DO UPDATE SET typeId=excluded.typeId", - database}; - WriteStatement upsertExportedTypeNamesWithMajorVersionStatement{ - "INSERT INTO exportedTypeNames(moduleId, name, kind, majorVersion, typeId) " - "VALUES(?1, ?2, ?3, ?4, ?5) ON CONFLICT DO UPDATE SET typeId=excluded.typeId", - database}; - WriteStatement upsertExportedTypeNamesWithoutVersionStatement{ - "INSERT INTO exportedTypeNames(moduleId, name, kind, typeId) VALUES(?1, ?2, ?3, ?4) ON " - "CONFLICT DO UPDATE SET typeId=excluded.typeId", - database}; - WriteStatement upsertExportedTypeNameStatement{ - "INSERT INTO exportedTypeNames(moduleId, name, kind, typeId) VALUES(?1, ?2, ?3, ?4) ON " - "CONFLICT DO UPDATE SET typeId=excluded.typeId WHERE typeId IS NOT excluded.typeId", - database}; + mutable ReadStatement<6> selectExportedTypesForSourceIdsStatement{ + "SELECT moduleId, etn.name, ifnull(majorVersion, -1), ifnull(minorVersion, -1), typeId, " + "exportedTypeNameId FROM exportedTypeNames AS etn JOIN types USING(typeId) WHERE sourceId " + "IN carray(?1) OR typeId in carray(?2) ORDER BY moduleId, etn.name, majorVersion, " + "minorVersion", + database}; + WriteStatement insertExportedTypeNamesWithVersionStatement{ + "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, minorVersion, typeId) " + "VALUES(?1, ?2, ?3, ?4, ?5)", + database}; + WriteStatement insertExportedTypeNamesWithMajorVersionStatement{ + "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, typeId) " + "VALUES(?1, ?2, ?3, ?4)", + database}; + WriteStatement insertExportedTypeNamesWithoutVersionStatement{ + "INSERT INTO exportedTypeNames(moduleId, name, typeId) VALUES(?1, ?2, ?3)", database}; WriteStatement deleteExportedTypeNameStatement{ "DELETE FROM exportedTypeNames WHERE exportedTypeNameId=?", database}; WriteStatement updateExportedTypeNameTypeIdStatement{ diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h index 0d23e11605..42790bded6 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h @@ -101,4 +101,10 @@ public: const char *what() const noexcept override { return "There is a prototype chain cycle!"; } }; +class CannotParseQmlTypesFile : std::exception +{ +public: + const char *what() const noexcept override { return "Cannot parse qml types file!"; } +}; + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h index 302a1801a2..7d27bd22f1 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h @@ -33,15 +33,12 @@ namespace QmlDesigner { class ProjectStorageInterface { public: - virtual void synchronize(Storage::Modules modules, - Storage::Imports imports, - Storage::Types types, - SourceIds sourceIds, - FileStatuses fileStatuses) - = 0; + virtual void synchronize(Storage::SynchronizationPackage package) = 0; + + virtual ModuleId moduleId(Utils::SmallStringView name) = 0; virtual FileStatus fetchFileStatus(SourceId sourceId) const = 0; - virtual SourceIds fetchSourceDependencieIds(SourceId sourceId) const = 0; + virtual Storage::ProjectDatas fetchProjectDatas(SourceId sourceId) const = 0; protected: ~ProjectStorageInterface() = default; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h index 50db7c4853..ef05539076 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h @@ -25,6 +25,7 @@ #pragma once +#include "filestatus.h" #include "projectstorageids.h" #include <utils/smallstring.h> @@ -35,10 +36,10 @@ namespace QmlDesigner::Storage { -enum class TypeAccessSemantics : int { Invalid, Reference, Value, Sequence, IsEnum = 1 << 8 }; +enum class TypeAccessSemantics : int { None, Reference, Value, Sequence, IsEnum = 1 << 8 }; enum class PropertyDeclarationTraits : unsigned int { - Non = 0, + None = 0, IsReadOnly = 1 << 0, IsPointer = 1 << 1, IsList = 1 << 2 @@ -121,38 +122,6 @@ public: VersionNumber minor; }; -class Module -{ -public: - explicit Module() = default; - - explicit Module(Utils::SmallStringView name, SourceId sourceId = SourceId{}) - : name{name} - , sourceId{sourceId} - {} - - explicit Module(QStringView name, SourceId sourceId = SourceId{}) - : name{name} - , sourceId{sourceId} - {} - - explicit Module(Utils::SmallStringView name, int sourceId) - : name{name} - , sourceId{sourceId} - {} - - friend bool operator==(const Module &first, const Module &second) - { - return first.name == second.name; - } - -public: - Utils::PathString name; - SourceId sourceId; -}; - -using Modules = std::vector<Module>; - enum class IsQualified : int { No, Yes }; inline int operator-(IsQualified first, IsQualified second) @@ -165,34 +134,36 @@ inline int operator<(IsQualified first, IsQualified second) return static_cast<int>(first) < static_cast<int>(second); } +enum class ImportKind : char { Module, Directory, QmlTypesDependency }; + class Import { public: explicit Import() = default; - explicit Import(Utils::SmallStringView name, Version version, SourceId sourceId) - : name{name} - , version{version} + explicit Import(ModuleId moduleId, Version version, SourceId sourceId) + : version{version} + , moduleId{moduleId} , sourceId{sourceId} {} - explicit Import(Utils::SmallStringView name, int majorVersion, int minorVersion, int sourceId) - : name{name} + explicit Import(int moduleId, int majorVersion, int minorVersion, int sourceId) + : moduleId{moduleId} , version{majorVersion, minorVersion} , sourceId{sourceId} {} friend bool operator==(const Import &first, const Import &second) { - return first.name == second.name && first.version == second.version + return first.moduleId == second.moduleId && first.version == second.version && first.sourceId == second.sourceId; } public: - Utils::PathString name; Version version; ModuleId moduleId; SourceId sourceId; + Utils::SmallString aliasName; }; using Imports = std::vector<Import>; @@ -269,6 +240,12 @@ public: , version{version} {} + explicit ExportedType(ModuleId moduleId, Utils::SmallStringView name, Version version = Version{}) + : name{name} + , version{version} + , moduleId{moduleId} + {} + explicit ExportedType(Utils::SmallStringView name, Version version, TypeId typeId, ModuleId moduleId) : name{name} , version{version} @@ -276,9 +253,10 @@ public: , moduleId{moduleId} {} - explicit ExportedType(Utils::SmallStringView name, int majorVersion, int minorVersion) + explicit ExportedType(int moduleId, Utils::SmallStringView name, int majorVersion, int minorVersion) : name{name} , version{majorVersion, minorVersion} + , moduleId{moduleId} {} friend bool operator==(const ExportedType &first, const ExportedType &second) @@ -299,6 +277,11 @@ class ExportedTypeView { public: explicit ExportedTypeView() = default; + explicit ExportedTypeView(ModuleId moduleId, Utils::SmallStringView name, Storage::Version version) + : name{name} + , version{version} + , moduleId{moduleId} + {} explicit ExportedTypeView(int moduleId, Utils::SmallStringView name, int majorVersion, @@ -552,6 +535,15 @@ public: {} explicit PropertyDeclaration(Utils::SmallStringView name, + TypeId propertyTypeId, + PropertyDeclarationTraits traits) + : name{name} + , traits{traits} + , propertyTypeId{propertyTypeId} + , kind{PropertyKind::Property} + {} + + explicit PropertyDeclaration(Utils::SmallStringView name, ImportedTypeName typeName, PropertyDeclarationTraits traits, Utils::SmallStringView aliasPropertyName) @@ -563,13 +555,24 @@ public: {} explicit PropertyDeclaration(Utils::SmallStringView name, - Utils::SmallStringView typeName, + TypeId propetyTypeId, + PropertyDeclarationTraits traits, + Utils::SmallStringView aliasPropertyName) + : name{name} + , aliasPropertyName{aliasPropertyName} + , traits{traits} + , propertyTypeId{propertyTypeId} + , kind{PropertyKind::Property} + {} + + explicit PropertyDeclaration(Utils::SmallStringView name, + long long propertyTypeId, int traits, Utils::SmallStringView aliasPropertyName) : name{name} - , typeName{NativeType{typeName}} , aliasPropertyName{aliasPropertyName} , traits{static_cast<PropertyDeclarationTraits>(traits)} + , propertyTypeId{propertyTypeId} , kind{PropertyKind::Property} {} @@ -594,6 +597,7 @@ public: ImportedTypeName typeName; Utils::SmallString aliasPropertyName; PropertyDeclarationTraits traits = {}; + TypeId propertyTypeId; TypeId typeId; PropertyKind kind = PropertyKind::Property; }; @@ -632,8 +636,7 @@ class Type { public: explicit Type() = default; - explicit Type(ModuleId moduleId, - Utils::SmallStringView typeName, + explicit Type(Utils::SmallStringView typeName, ImportedTypeName prototype, TypeAccessSemantics accessSemantics, SourceId sourceId, @@ -650,37 +653,42 @@ public: , functionDeclarations{std::move(functionDeclarations)} , signalDeclarations{std::move(signalDeclarations)} , enumerationDeclarations{std::move(enumerationDeclarations)} - , moduleId{moduleId} , accessSemantics{accessSemantics} , sourceId{sourceId} , changeLevel{changeLevel} {} - explicit Type(ModuleId moduleId, - Utils::SmallStringView typeName, + explicit Type(Utils::SmallStringView typeName, + TypeId prototypeId, + TypeAccessSemantics accessSemantics, + SourceId sourceId) + : typeName{typeName} + , accessSemantics{accessSemantics} + , sourceId{sourceId} + , prototypeId{prototypeId} + {} + + explicit Type(Utils::SmallStringView typeName, Utils::SmallStringView prototype, int accessSemantics, int sourceId) : typeName{typeName} , prototype{NativeType{prototype}} - , moduleId{moduleId} , accessSemantics{static_cast<TypeAccessSemantics>(accessSemantics)} , sourceId{sourceId} {} - explicit Type(int moduleId, + explicit Type(int sourceId, Utils::SmallStringView typeName, long long typeId, - Utils::SmallStringView prototype, - int accessSemantics, - int sourceId) + long long prototypeId, + int accessSemantics) : typeName{typeName} - , prototype{NativeType{prototype}} - , moduleId{moduleId} , accessSemantics{static_cast<TypeAccessSemantics>(accessSemantics)} , sourceId{sourceId} , typeId{typeId} + , prototypeId{prototypeId} {} friend bool operator==(const Type &first, const Type &second) noexcept @@ -690,7 +698,6 @@ public: && first.propertyDeclarations == second.propertyDeclarations && first.functionDeclarations == second.functionDeclarations && first.signalDeclarations == second.signalDeclarations - && first.moduleId == second.moduleId && first.sourceId == second.sourceId && first.sourceId == second.sourceId; } @@ -702,31 +709,52 @@ public: FunctionDeclarations functionDeclarations; SignalDeclarations signalDeclarations; EnumerationDeclarations enumerationDeclarations; - TypeAccessSemantics accessSemantics = TypeAccessSemantics::Invalid; + TypeAccessSemantics accessSemantics = TypeAccessSemantics::None; SourceId sourceId; TypeId typeId; - ModuleId moduleId; + TypeId prototypeId; ChangeLevel changeLevel = ChangeLevel::Full; }; using Types = std::vector<Type>; -class ModuleView +class ProjectData { public: - explicit ModuleView(Utils::SmallStringView name, int sourceId) - : name{name} - , sourceId{sourceId} + ModuleId extraModuleId; + SourceId sourceId; +}; + +using ProjectDatas = std::vector<ProjectData>; + +class SynchronizationPackage +{ +public: + SynchronizationPackage() = default; + SynchronizationPackage(Imports imports, Types types, SourceIds sourceIds) + : imports{std::move(imports)} + , types{std::move(types)} + , sourceIds(std::move(sourceIds)) {} - friend bool operator==(const ModuleView &first, const ModuleView &second) - { - return first.name == second.name && first.sourceId == second.sourceId; - } + SynchronizationPackage(Types types) + : types{std::move(types)} + {} + + SynchronizationPackage(SourceIds sourceIds) + : sourceIds(std::move(sourceIds)) + {} + + SynchronizationPackage(SourceIds sourceIds, FileStatuses fileStatuses) + : sourceIds(std::move(sourceIds)) + , fileStatuses(std::move(fileStatuses)) + {} public: - Utils::SmallStringView name; - SourceId sourceId; + Imports imports; + Types types; + SourceIds sourceIds; + FileStatuses fileStatuses; }; } // namespace QmlDesigner::Storage diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp index b5a7945181..cc91a06fae 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp @@ -52,40 +52,34 @@ ComponentReferences createComponentReferences(const QMultiHash<QString, QmlDirPa void ProjectUpdater::update() { - Storage::Modules modules; - Storage::Imports imports; - Storage::Types types; - SourceIds sourceIds; - FileStatuses fileStatuses; + Storage::SynchronizationPackage package; for (const QString &qmldirPath : m_projectManager.qtQmlDirs()) { SourcePath qmldirSourcePath{qmldirPath}; SourceId qmlDirSourceId = m_pathCache.sourceId(qmldirSourcePath); - switch (fileState(qmlDirSourceId, fileStatuses)) { + switch (fileState(qmlDirSourceId, package.fileStatuses)) { case FileState::Changed: { QmlDirParser parser; parser.parse(m_fileSystem.contentAsQString(qmldirPath)); - modules.emplace_back(parser.typeNamespace(), qmlDirSourceId); - - sourceIds.push_back(qmlDirSourceId); + package.sourceIds.push_back(qmlDirSourceId); SourceContextId directoryId = m_pathCache.sourceContextId(qmlDirSourceId); - parseTypeInfos(parser.typeInfos(), directoryId, imports, types, sourceIds, fileStatuses); + Utils::PathString moduleName{parser.typeNamespace()}; + ModuleId moduleId = m_projectStorage.moduleId(moduleName); + + parseTypeInfos(parser.typeInfos(), directoryId, package); parseQmlComponents(createComponentReferences(parser.components()), directoryId, - ModuleId{&qmlDirSourceId}, - imports, - types, - sourceIds, - fileStatuses); + moduleId, + package); break; } case FileState::NotChanged: { - SourceIds qmltypesSourceIds = m_projectStorage.fetchSourceDependencieIds(qmlDirSourceId); - parseTypeInfos(qmltypesSourceIds, imports, types, sourceIds, fileStatuses); + auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId); + parseTypeInfos(qmlProjectDatas, package); break; } case FileState::NotExists: { @@ -95,21 +89,14 @@ void ProjectUpdater::update() } } - m_projectStorage.synchronize(std::move(modules), - std::move(imports), - std::move(types), - std::move(sourceIds), - std::move(fileStatuses)); + m_projectStorage.synchronize(std::move(package)); } void ProjectUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &idPaths) {} void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos, SourceContextId directoryId, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses) + Storage::SynchronizationPackage &package) { QString directory{m_pathCache.sourceContextPath(directoryId)}; @@ -117,44 +104,37 @@ void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos, SourceId sourceId = m_pathCache.sourceId(directoryId, Utils::SmallString{typeInfo}); QString qmltypesPath = directory + "/" + typeInfo; - parseTypeInfo(sourceId, qmltypesPath, imports, types, sourceIds, fileStatuses); + Storage::ProjectData projectData{ModuleId{}, sourceId}; + + parseTypeInfo(projectData, qmltypesPath, package); } } -void ProjectUpdater::parseTypeInfos(const SourceIds &qmltypesSourceIds, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses) +void ProjectUpdater::parseTypeInfos(const Storage::ProjectDatas &projectDatas, + Storage::SynchronizationPackage &package) { - for (SourceId sourceId : qmltypesSourceIds) { - QString qmltypesPath = m_pathCache.sourcePath(sourceId).toQString(); + for (const Storage::ProjectData &projectData : projectDatas) { + QString qmltypesPath = m_pathCache.sourcePath(projectData.sourceId).toQString(); - parseTypeInfo(sourceId, qmltypesPath, imports, types, sourceIds, fileStatuses); + parseTypeInfo(projectData, qmltypesPath, package); } } -void ProjectUpdater::parseTypeInfo(SourceId sourceId, +void ProjectUpdater::parseTypeInfo(const Storage::ProjectData &projectData, const QString &qmltypesPath, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses) + Storage::SynchronizationPackage &package) { - if (fileState(sourceId, fileStatuses) == FileState::Changed) { - sourceIds.push_back(sourceId); + if (fileState(projectData.sourceId, package.fileStatuses) == FileState::Changed) { + package.sourceIds.push_back(projectData.sourceId); const auto content = m_fileSystem.contentAsQString(qmltypesPath); - m_qmlTypesParser.parse(content, imports, types, sourceIds); + m_qmlTypesParser.parse(content, package.imports, package.types, projectData); } } void ProjectUpdater::parseQmlComponents(ComponentReferences components, SourceContextId directoryId, ModuleId moduleId, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses) + Storage::SynchronizationPackage &package) { std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) { return std::tie(first.get().typeName, first.get().majorVersion, first.get().minorVersion) @@ -174,23 +154,23 @@ void ProjectUpdater::parseQmlComponents(ComponentReferences components, Utils::SmallString fileName{component.fileName}; SourceId sourceId = m_pathCache.sourceId(directoryId, fileName); - if (fileState(sourceId, fileStatuses) != FileState::Changed) + if (fileState(sourceId, package.fileStatuses) != FileState::Changed) continue; - sourceIds.push_back(sourceId); + package.sourceIds.push_back(sourceId); const auto content = m_fileSystem.contentAsQString(directory + "/" + component.fileName); - auto type = m_qmlDocumentParser.parse(content, imports); + auto type = m_qmlDocumentParser.parse(content, package.imports); type.typeName = fileName; - type.moduleId = moduleId; type.accessSemantics = Storage::TypeAccessSemantics::Reference; type.sourceId = sourceId; type.exportedTypes.push_back( - Storage::ExportedType{Utils::SmallString{component.typeName}, + Storage::ExportedType{moduleId, + Utils::SmallString{component.typeName}, Storage::Version{component.majorVersion, component.minorVersion}}); - types.push_back(std::move(type)); + package.types.push_back(std::move(type)); } } diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h index dfe8ce05c4..e3323d7609 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h @@ -88,28 +88,16 @@ private: void parseTypeInfos(const QStringList &typeInfos, SourceContextId directoryId, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses); - void parseTypeInfos(const SourceIds &qmltypesSourceIds, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses); - void parseTypeInfo(SourceId sourceId, + Storage::SynchronizationPackage &package); + void parseTypeInfos(const Storage::ProjectDatas &projectDatas, + Storage::SynchronizationPackage &package); + void parseTypeInfo(const Storage::ProjectData &projectData, const QString &qmltypesPath, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses); + Storage::SynchronizationPackage &package); void parseQmlComponents(ComponentReferences components, SourceContextId directoryId, ModuleId moduleId, - Storage::Imports &imports, - Storage::Types &types, - SourceIds &sourceIds, - FileStatuses &fileStatuses); + Storage::SynchronizationPackage &package); FileState fileState(SourceId sourceId, FileStatuses &fileStatuses) const; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp new file mode 100644 index 0000000000..c4a2bae617 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "qmldocumentparser.h" + +#include "projectstorage.h" +#include "sourcepathcache.h" + +#include <sqlitedatabase.h> + +#include <qmldom/qqmldomtop_p.h> + +#include <QDateTime> + +namespace QmlDesigner { + +namespace QmlDom = QQmlJS::Dom; + +namespace { + +int convertVersionNumber(qint32 versionNumber) +{ + return versionNumber < 0 ? -1 : versionNumber; +} + +Storage::Version convertVersion(QmlDom::Version version) +{ + return Storage::Version{convertVersionNumber(version.majorVersion), + convertVersionNumber(version.minorVersion)}; +} + +Utils::PathString convertUri(const QString &uri) +{ + Utils::PathString path{QStringView{uri.begin() + 7, uri.end()}}; + if (path.endsWith("/.")) + return path; + if (path.endsWith("/")) { + path += "."; + return path; + } + + path += "/."; + return path; +} + +void addImports(Storage::Imports &imports, + const QList<QmlDom::Import> &qmlImports, + SourceId sourceId, + SourceContextId sourceContextId, + QmlDocumentParser::PathCache &pathCache, + QmlDocumentParser::ProjectStorage &storage) +{ + for (const QmlDom::Import &qmlImport : qmlImports) { + if (qmlImport.uri == u"file://.") { + auto moduleId = storage.moduleId(pathCache.sourceContextPath(sourceContextId)); + imports.emplace_back(moduleId, Storage::Version{}, sourceId); + } else if (qmlImport.uri.startsWith(u"file://")) { + auto moduleId = storage.moduleId(convertUri(qmlImport.uri)); + imports.emplace_back(moduleId, Storage::Version{}, sourceId); + } else { + auto moduleId = storage.moduleId(Utils::SmallString{qmlImport.uri}); + imports.emplace_back(moduleId, convertVersion(qmlImport.version), sourceId); + } + } +} + +void addPropertyDeclarations(Storage::Type &type, const QmlDom::QmlObject &rootObject) +{ + for (const QmlDom::PropertyDefinition &propertyDeclaration : rootObject.propertyDefs()) { + type.propertyDeclarations.emplace_back(Utils::SmallString{propertyDeclaration.name}, + Storage::ImportedType{ + Utils::SmallString{propertyDeclaration.typeName}}, + Storage::PropertyDeclarationTraits::None); + } +} + +void addParameterDeclaration(Storage::ParameterDeclarations ¶meterDeclarations, + const QList<QmlDom::MethodParameter> ¶meters) +{ + for (const QmlDom::MethodParameter ¶meter : parameters) { + parameterDeclarations.emplace_back(Utils::SmallString{parameter.name}, + Utils::SmallString{parameter.typeName}); + } +} + +void addFunctionAndSignalDeclarations(Storage::Type &type, const QmlDom::QmlObject &rootObject) +{ + for (const QmlDom::MethodInfo &methodInfo : rootObject.methods()) { + if (methodInfo.methodType == QmlDom::MethodInfo::Method) { + auto &functionDeclaration = type.functionDeclarations.emplace_back( + Utils::SmallString{methodInfo.name}, "", Storage::ParameterDeclarations{}); + addParameterDeclaration(functionDeclaration.parameters, methodInfo.parameters); + } else { + auto &signalDeclaration = type.signalDeclarations.emplace_back( + Utils::SmallString{methodInfo.name}); + addParameterDeclaration(signalDeclaration.parameters, methodInfo.parameters); + } + } +} + +Storage::EnumeratorDeclarations createEnumerators(const QmlDom::EnumDecl &enumeration) +{ + Storage::EnumeratorDeclarations enumeratorDeclarations; + for (const QmlDom::EnumItem &enumerator : enumeration.values()) { + enumeratorDeclarations.emplace_back(Utils::SmallString{enumerator.name()}, + static_cast<long long>(enumerator.value())); + } + return enumeratorDeclarations; +} + +void addEnumeraton(Storage::Type &type, const QmlDom::Component &component) +{ + for (const QmlDom::EnumDecl &enumeration : component.enumerations()) { + Storage::EnumeratorDeclarations enumeratorDeclarations = createEnumerators(enumeration); + type.enumerationDeclarations.emplace_back(Utils::SmallString{enumeration.name()}, + std::move(enumeratorDeclarations)); + } +} + +} // namespace + +Storage::Type QmlDocumentParser::parse(const QString &sourceContent, + Storage::Imports &imports, + SourceId sourceId, + SourceContextId sourceContextId) +{ + Storage::Type type; + + QmlDom::DomItem environment = QmlDom::DomEnvironment::create( + {}, + QmlDom::DomEnvironment::Option::SingleThreaded + | QmlDom::DomEnvironment::Option::NoDependencies); + + QmlDom::DomItem items; + + environment.loadFile( + {}, + {}, + sourceContent, + QDateTime{}, + [&](QmlDom::Path, const QmlDom::DomItem &, const QmlDom::DomItem &newItems) { + items = newItems; + }, + QmlDom::LoadOption::DefaultLoad, + QmlDom::DomType::QmlFile); + + environment.loadPendingDependencies(); + + QmlDom::DomItem file = items.field(QmlDom::Fields::currentItem); + const QmlDom::QmlFile *qmlFile = file.as<QmlDom::QmlFile>(); + const auto &components = qmlFile->components(); + + if (components.empty()) + return type; + + const auto &component = components.first(); + const auto &objects = component.objects(); + + if (objects.empty()) + return type; + + const QmlDom::QmlObject &qmlObject = objects.front(); + + type.prototype = Storage::ImportedType{Utils::SmallString{qmlObject.name()}}; + + addImports(imports, qmlFile->imports(), sourceId, sourceContextId, m_pathCache, m_storage); + + addPropertyDeclarations(type, qmlObject); + addFunctionAndSignalDeclarations(type, qmlObject); + addEnumeraton(type, component); + + return type; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h new file mode 100644 index 0000000000..e2dd243405 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "nonlockingmutex.h" +#include "qmldocumentparserinterface.h" + +namespace Sqlite { +class Database; +} + +namespace QmlDesigner { + +template<typename Database> +class ProjectStorage; + +template<typename ProjectStorage, typename Mutex> +class SourcePathCache; + +class QmlDocumentParser +{ +public: + using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>; + using PathCache = QmlDesigner::SourcePathCache<ProjectStorage, NonLockingMutex>; + + QmlDocumentParser(PathCache &pathCache, ProjectStorage &storage) + : m_pathCache{pathCache} + , m_storage{storage} + {} + + virtual Storage::Type parse(const QString &sourceContent, + Storage::Imports &imports, + SourceId sourceId, + SourceContextId sourceContextId); + +private: + PathCache &m_pathCache; + ProjectStorage &m_storage; +}; +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp new file mode 100644 index 0000000000..f5d09409aa --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "qmltypesparser.h" + +#include "projectstorage.h" +#include "sourcepathcache.h" + +#include <sqlitedatabase.h> + +#include <qmlcompiler/qqmljstypedescriptionreader_p.h> +#include <qmldom/qqmldomtop_p.h> + +#include <QDateTime> + +#include <algorithm> +#include <tuple> + +namespace QmlDesigner { + +namespace QmlDom = QQmlJS::Dom; + +namespace { + +void appendImports(Storage::Imports &imports, + const QString &dependency, + SourceId sourceId, + QmlTypesParser::ProjectStorage &storage) +{ + auto spaceFound = std::find_if(dependency.begin(), dependency.end(), [](QChar c) { + return c.isSpace(); + }); + + Utils::PathString moduleName{QStringView(dependency.begin(), spaceFound)}; + moduleName.append("-cppnative"); + ModuleId cppModuleId = storage.moduleId(moduleName); + + auto majorVersionFound = std::find_if(spaceFound, dependency.end(), [](QChar c) { + return c.isDigit(); + }); + auto majorVersionEnd = std::find_if(majorVersionFound, dependency.end(), [](QChar c) { + return !c.isDigit(); + }); + + Storage::Version version; + + QStringView majorVersionString(majorVersionFound, majorVersionEnd); + if (!majorVersionString.isEmpty()) { + version.major.value = majorVersionString.toInt(); + + auto minorVersionFound = std::find_if(majorVersionEnd, dependency.end(), [](QChar c) { + return c.isDigit(); + }); + auto minorVersionEnd = std::find_if(minorVersionFound, dependency.end(), [](QChar c) { + return !c.isDigit(); + }); + QStringView minorVersionString(minorVersionFound, minorVersionEnd); + if (!minorVersionString.isEmpty()) + version.minor.value = QStringView(minorVersionFound, minorVersionEnd).toInt(); + } + + imports.emplace_back(cppModuleId, version, sourceId); +} + +void addImports(Storage::Imports &imports, + SourceId sourceId, + const QStringList &dependencies, + QmlTypesParser::ProjectStorage &storage) +{ + for (const QString &dependency : dependencies) + appendImports(imports, dependency, sourceId, storage); + + imports.emplace_back(storage.moduleId("QML"), Storage::Version{}, sourceId); + imports.emplace_back(storage.moduleId("QtQml-cppnative"), Storage::Version{}, sourceId); +} + +Storage::TypeAccessSemantics createTypeAccessSemantics(QQmlJSScope::AccessSemantics accessSematics) +{ + switch (accessSematics) { + case QQmlJSScope::AccessSemantics::Reference: + return Storage::TypeAccessSemantics::Reference; + case QQmlJSScope::AccessSemantics::Value: + return Storage::TypeAccessSemantics::Value; + case QQmlJSScope::AccessSemantics::None: + return Storage::TypeAccessSemantics::None; + case QQmlJSScope::AccessSemantics::Sequence: + return Storage::TypeAccessSemantics::Sequence; + } + + return Storage::TypeAccessSemantics::None; +} + +Storage::Version createVersion(QTypeRevision qmlVersion) +{ + return Storage::Version{qmlVersion.majorVersion(), qmlVersion.minorVersion()}; +} + +Storage::ExportedTypes createExports(const QList<QQmlJSScope::Export> &qmlExports, + const QQmlJSScope &component, + QmlTypesParser::ProjectStorage &storage, + ModuleId cppModuleId) +{ + Storage::ExportedTypes exportedTypes; + exportedTypes.reserve(Utils::usize(qmlExports)); + + for (const QQmlJSScope::Export &qmlExport : qmlExports) { + exportedTypes.emplace_back(storage.moduleId(Utils::SmallString{qmlExport.package()}), + Utils::SmallString{qmlExport.type()}, + createVersion(qmlExport.version())); + } + + exportedTypes.emplace_back(cppModuleId, Utils::SmallString{component.internalName()}); + + return exportedTypes; +} + +Storage::PropertyDeclarationTraits createPropertyDeclarationTraits(const QQmlJSMetaProperty &qmlProperty) +{ + Storage::PropertyDeclarationTraits traits{}; + + if (qmlProperty.isList()) + traits = traits | Storage::PropertyDeclarationTraits::IsList; + + if (qmlProperty.isPointer()) + traits = traits | Storage::PropertyDeclarationTraits::IsPointer; + + if (!qmlProperty.isWritable()) + traits = traits | Storage::PropertyDeclarationTraits::IsReadOnly; + + return traits; +} + +Storage::PropertyDeclarations createProperties(const QHash<QString, QQmlJSMetaProperty> &qmlProperties) +{ + Storage::PropertyDeclarations propertyDeclarations; + propertyDeclarations.reserve(Utils::usize(qmlProperties)); + + for (const QQmlJSMetaProperty &qmlProperty : qmlProperties) { + propertyDeclarations.emplace_back(Utils::SmallString{qmlProperty.propertyName()}, + Storage::NativeType{ + Utils::SmallString{qmlProperty.typeName()}}, + createPropertyDeclarationTraits(qmlProperty)); + } + + return propertyDeclarations; +} + +Storage::ParameterDeclarations createParameters(const QQmlJSMetaMethod &qmlMethod) +{ + Storage::ParameterDeclarations parameterDeclarations; + + const QStringList ¶meterNames = qmlMethod.parameterNames(); + const QStringList ¶meterTypeNames = qmlMethod.parameterTypeNames(); + auto currentName = parameterNames.begin(); + auto currentType = parameterTypeNames.begin(); + auto nameEnd = parameterNames.end(); + auto typeEnd = parameterTypeNames.end(); + + for (; currentName != nameEnd && currentType != typeEnd; ++currentName, ++currentType) { + parameterDeclarations.emplace_back(Utils::SmallString{*currentName}, + Utils::SmallString{*currentType}); + } + + return parameterDeclarations; +} + +std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> createFunctionAndSignals( + const QMultiHash<QString, QQmlJSMetaMethod> &qmlMethods) +{ + std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> functionAndSignalDeclarations; + Storage::FunctionDeclarations &functionsDeclarations{std::get<0>(functionAndSignalDeclarations)}; + functionsDeclarations.reserve(Utils::usize(qmlMethods)); + Storage::SignalDeclarations &signalDeclarations{std::get<1>(functionAndSignalDeclarations)}; + signalDeclarations.reserve(Utils::usize(qmlMethods)); + + for (const QQmlJSMetaMethod &qmlMethod : qmlMethods) { + if (qmlMethod.methodType() != QQmlJSMetaMethod::Type::Signal) { + functionsDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()}, + Utils::SmallString{qmlMethod.returnTypeName()}, + createParameters(qmlMethod)); + } else { + signalDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()}, + createParameters(qmlMethod)); + } + } + + return functionAndSignalDeclarations; +} + +Storage::EnumeratorDeclarations createEnumeratorsWithValues(const QQmlJSMetaEnum &qmlEnumeration) +{ + Storage::EnumeratorDeclarations enumeratorDeclarations; + + const QStringList &keys = qmlEnumeration.keys(); + const QList<int> &values = qmlEnumeration.values(); + auto currentKey = keys.begin(); + auto currentValue = values.begin(); + auto keyEnd = keys.end(); + auto valueEnd = values.end(); + + for (; currentKey != keyEnd && currentValue != valueEnd; ++currentKey, ++currentValue) + enumeratorDeclarations.emplace_back(Utils::SmallString{*currentKey}, *currentValue); + + return enumeratorDeclarations; +} + +Storage::EnumeratorDeclarations createEnumeratorsWithoutValues(const QQmlJSMetaEnum &qmlEnumeration) +{ + Storage::EnumeratorDeclarations enumeratorDeclarations; + + for (const QString &key : qmlEnumeration.keys()) + enumeratorDeclarations.emplace_back(Utils::SmallString{key}); + + return enumeratorDeclarations; +} + +Storage::EnumeratorDeclarations createEnumerators(const QQmlJSMetaEnum &qmlEnumeration) +{ + if (qmlEnumeration.hasValues()) + return createEnumeratorsWithValues(qmlEnumeration); + + return createEnumeratorsWithoutValues(qmlEnumeration); +} + +Storage::EnumerationDeclarations createEnumeration(const QHash<QString, QQmlJSMetaEnum> &qmlEnumerations) +{ + Storage::EnumerationDeclarations enumerationDeclarations; + enumerationDeclarations.reserve(Utils::usize(qmlEnumerations)); + + for (const QQmlJSMetaEnum &qmlEnumeration : qmlEnumerations) { + enumerationDeclarations.emplace_back(Utils::SmallString{qmlEnumeration.name()}, + createEnumerators(qmlEnumeration)); + } + + return enumerationDeclarations; +} + +void addType(Storage::Types &types, + SourceId sourceId, + ModuleId cppModuleId, + const QQmlJSScope &component, + QmlTypesParser::ProjectStorage &storage) +{ + auto [functionsDeclarations, signalDeclarations] = createFunctionAndSignals(component.ownMethods()); + types.emplace_back(Utils::SmallString{component.internalName()}, + Storage::NativeType{Utils::SmallString{component.baseTypeName()}}, + createTypeAccessSemantics(component.accessSemantics()), + sourceId, + createExports(component.exports(), component, storage, cppModuleId), + createProperties(component.ownProperties()), + std::move(functionsDeclarations), + std::move(signalDeclarations), + createEnumeration(component.ownEnumerations())); +} + +void addTypes(Storage::Types &types, + const Storage::ProjectData &projectData, + const QHash<QString, QQmlJSScope::Ptr> &objects, + QmlTypesParser::ProjectStorage &storage) +{ + types.reserve(Utils::usize(objects) + types.size()); + + for (const auto &object : objects) + addType(types, projectData.sourceId, projectData.extraModuleId, *object.get(), storage); +} + +} // namespace + +void QmlTypesParser::parse(const QString &sourceContent, + Storage::Imports &imports, + Storage::Types &types, + const Storage::ProjectData &projectData) +{ + QQmlJSTypeDescriptionReader reader({}, sourceContent); + QHash<QString, QQmlJSScope::Ptr> components; + QStringList dependencies; + bool isValid = reader(&components, &dependencies); + if (!isValid) + throw CannotParseQmlTypesFile{}; + + addImports(imports, projectData.sourceId, dependencies, m_storage); + addTypes(types, projectData, components, m_storage); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h new file mode 100644 index 0000000000..40f88d240d --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "nonlockingmutex.h" +#include "qmltypesparserinterface.h" + +namespace Sqlite { +class Database; +} + +namespace QmlDesigner { + +template<typename Database> +class ProjectStorage; + +template<typename ProjectStorage, typename Mutex> +class SourcePathCache; + +class QmlTypesParser : public QmlTypesParserInterface +{ +public: + using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>; + using PathCache = QmlDesigner::SourcePathCache<ProjectStorage, NonLockingMutex>; + + QmlTypesParser(PathCache &pathCache, ProjectStorage &storage) + : m_pathCache{pathCache} + , m_storage{storage} + {} + + void parse(const QString &sourceContent, + Storage::Imports &imports, + Storage::Types &types, + const Storage::ProjectData &projectData) override; + +private: + PathCache &m_pathCache; + ProjectStorage &m_storage; +}; +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h index 40c9883835..3255c0b5aa 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h @@ -37,7 +37,7 @@ public: virtual void parse(const QString &sourceContent, Storage::Imports &imports, Storage::Types &types, - SourceIds &sourceIds) + const Storage::ProjectData &projectData) = 0; protected: diff --git a/src/plugins/qmldesigner/generatecmakelists.cpp b/src/plugins/qmldesigner/generatecmakelists.cpp new file mode 100644 index 0000000000..8e96c0ec95 --- /dev/null +++ b/src/plugins/qmldesigner/generatecmakelists.cpp @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "generatecmakelists.h" + +#include <coreplugin/actionmanager/actionmanager.h> +#include <coreplugin/actionmanager/actioncontainer.h> + +#include <projectexplorer/projectexplorerconstants.h> +#include <projectexplorer/project.h> +#include <projectexplorer/session.h> + +#include <qmlprojectmanager/qmlprojectmanagerconstants.h> + +#include <utils/fileutils.h> + +#include <QAction> +#include <QRegularExpression> +#include <QStringList> +#include <QTextStream> + +using namespace Utils; + +namespace QmlDesigner { +namespace GenerateCmakeLists { + +const QDir::Filters FILES_ONLY = QDir::Files; +const QDir::Filters DIRS_ONLY = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot; + +const char CMAKEFILENAME[] = "CMakeLists.txt"; +const char QMLDIRFILENAME[] = "qmldir"; + +void generateMenuEntry() +{ + Core::ActionContainer *buildMenu = + Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT); + const Core::Context projectCntext(QmlProjectManager::Constants::QML_PROJECT_ID); + auto action = new QAction("Generate CMakeLists.txt files"); + QObject::connect(action, &QAction::triggered, GenerateCmakeLists::onGenerateCmakeLists); + Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.CreateCMakeLists"); + buildMenu->addAction(cmd, ProjectExplorer::Constants::G_BUILD_RUN); + + action->setEnabled(ProjectExplorer::SessionManager::startupProject() != nullptr); + QObject::connect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::startupProjectChanged, [action]() { + action->setEnabled(ProjectExplorer::SessionManager::startupProject() != nullptr); + }); +} + +void onGenerateCmakeLists() +{ + generateMainCmake(ProjectExplorer::SessionManager::startupProject()->projectDirectory()); +} + +QStringList processDirectory(const FilePath &dir) +{ + QStringList moduleNames; + + FilePaths files = dir.dirEntries(FILES_ONLY); + for (FilePath &file : files) { + if (!file.fileName().compare(CMAKEFILENAME)) + files.removeAll(file); + } + + if (files.isEmpty()) { + generateSubdirCmake(dir); + FilePaths subDirs = dir.dirEntries(DIRS_ONLY); + for (FilePath &subDir : subDirs) { + QStringList subDirModules = processDirectory(subDir); + moduleNames.append(subDirModules); + } + } + else { + QString moduleName = generateModuleCmake(dir); + if (!moduleName.isEmpty()) { + moduleNames.append(moduleName); + } + } + + return moduleNames; +} + +const char MAINFILE_REQUIRED_VERSION[] = "cmake_minimum_required(VERSION 3.18)\n\n"; +const char MAINFILE_PROJECT[] = "project(%1 LANGUAGES CXX)\n\n"; +const char MAINFILE_CMAKE_OPTIONS[] = "set(CMAKE_INCLUDE_CURRENT_DIR ON)\nset(CMAKE_AUTOMOC ON)\n\n"; +const char MAINFILE_PACKAGES[] = "find_package(Qt6 COMPONENTS Gui Qml Quick)\n"; +const char MAINFILE_LIBRARIES[] = "set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml)\n\n"; +const char MAINFILE_CPP[] = "add_executable(%1 main.cpp)\n\n"; +const char MAINFILE_MAINMODULE[] = "qt6_add_qml_module(%1\n\tURI \"Main\"\n\tVERSION 1.0\n\tNO_PLUGIN\n\tQML_FILES main.qml\n)\n\n"; +const char MAINFILE_LINK_LIBRARIES[] = "target_link_libraries(%1 PRIVATE\n\tQt${QT_VERSION_MAJOR}::Core\n\tQt${QT_VERSION_MAJOR}::Gui\n\tQt${QT_VERSION_MAJOR}::Quick\n\tQt${QT_VERSION_MAJOR}::Qml\n)\n\n"; + +const char ADD_SUBDIR[] = "add_subdirectory(%1)\n"; + +void generateMainCmake(const FilePath &rootDir) +{ + //TODO startupProject() may be a terrible way to try to get "current project". It's not necessarily the same thing at all. + QString projectName = ProjectExplorer::SessionManager::startupProject()->displayName(); + + FilePaths subDirs = rootDir.dirEntries(DIRS_ONLY); + + QString fileContent; + fileContent.append(MAINFILE_REQUIRED_VERSION); + fileContent.append(QString(MAINFILE_PROJECT).arg(projectName)); + fileContent.append(MAINFILE_CMAKE_OPTIONS); + fileContent.append(MAINFILE_PACKAGES); + fileContent.append(QString(MAINFILE_CPP).arg(projectName)); + fileContent.append(QString(MAINFILE_MAINMODULE).arg(projectName)); + fileContent.append(MAINFILE_LIBRARIES); + + for (FilePath &subDir : subDirs) { + QStringList subDirModules = processDirectory(subDir); + if (!subDirModules.isEmpty()) + fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName())); + } + fileContent.append("\n"); + + fileContent.append(QString(MAINFILE_LINK_LIBRARIES).arg(projectName)); + + createCmakeFile(rootDir, fileContent); +} + +const char MODULEFILE_PROPERTY_SINGLETON[] = "QT_QML_SINGLETON_TYPE"; +const char MODULEFILE_PROPERTY_SET[] = "set_source_files_properties(%1\n\tPROPERTIES\n\t\t%2 %3\n)\n\n"; +const char MODULEFILE_CREATE_MODULE[] = "qt6_add_qml_module(%1\n\tURI \"%1\"\n\tVERSION 1.0\n%2)\n\n"; + + +QString generateModuleCmake(const FilePath &dir) +{ + QString fileContent; + const QStringList qmlFilesOnly("*.qml"); + const QStringList qmldirFilesOnly(QMLDIRFILENAME); + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + + FilePaths qmldirFileList = dir.dirEntries(qmldirFilesOnly, FILES_ONLY); + if (!qmldirFileList.isEmpty()) { + QStringList singletons = getSingletonsFromQmldirFile(qmldirFileList.first()); + for (QString &singleton : singletons) { + fileContent.append(QString(MODULEFILE_PROPERTY_SET).arg(singleton).arg(MODULEFILE_PROPERTY_SINGLETON).arg("true")); + } + } + + FilePaths qmlFileList = dir.dirEntries(qmlFilesOnly, FILES_ONLY); + QString qmlFiles; + for (FilePath &qmlFile : qmlFileList) { + if (project->isKnownFile(qmlFile)) + qmlFiles.append(QString("\t\t%1\n").arg(qmlFile.fileName())); + } + + QStringList resourceFileList = getDirectoryTreeResources(dir); + QString resourceFiles; + for (QString &resourceFile : resourceFileList) { + resourceFiles.append(QString("\t\t%1\n").arg(resourceFile)); + } + + QString moduleContent; + if (!qmlFiles.isEmpty()) { + moduleContent.append(QString("\tQML_FILES\n%1").arg(qmlFiles)); + } + if (!resourceFiles.isEmpty()) { + moduleContent.append(QString("\tRESOURCES\n%1").arg(resourceFiles)); + } + + QString moduleName = dir.fileName(); + + fileContent.append(QString(MODULEFILE_CREATE_MODULE).arg(moduleName).arg(moduleContent)); + + createCmakeFile(dir, fileContent); + + return moduleName; +} + +void generateSubdirCmake(const FilePath &dir) +{ + QString fileContent; + FilePaths subDirs = dir.dirEntries(DIRS_ONLY); + + for (FilePath &subDir : subDirs) { + fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName())); + } + + createCmakeFile(dir, fileContent); +} + +QStringList getSingletonsFromQmldirFile(const FilePath &filePath) +{ + QStringList singletons; + QFile f(filePath.toString()); + f.open(QIODevice::ReadOnly); + QTextStream stream(&f); + + while (!stream.atEnd()) { + QString line = stream.readLine(); + if (line.startsWith("singleton", Qt::CaseInsensitive)) { + QStringList tokenizedLine = line.split(QRegularExpression("\\s+")); + QString fileName = tokenizedLine.last(); + if (fileName.endsWith(".qml", Qt::CaseInsensitive)) { + singletons.append(fileName); + } + } + } + + f.close(); + + return singletons; +} + +QStringList getDirectoryTreeResources(const FilePath &dir) +{ + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + QStringList resourceFileList; + + FilePaths thisDirFiles = dir.dirEntries(FILES_ONLY); + for (FilePath &file : thisDirFiles) { + if (!isFileBlacklisted(file.fileName()) && + !file.fileName().endsWith(".qml", Qt::CaseInsensitive) && + project->isKnownFile(file)) { + resourceFileList.append(file.fileName()); + } + } + + FilePaths subDirsList = dir.dirEntries(DIRS_ONLY); + for (FilePath &subDir : subDirsList) { + QStringList subDirResources = getDirectoryTreeResources(subDir); + for (QString &resource : subDirResources) { + resourceFileList.append(subDir.fileName().append('/').append(resource)); + } + + } + + return resourceFileList; +} + +void createCmakeFile(const FilePath &dir, const QString &content) +{ + FilePath filePath = dir.pathAppended(CMAKEFILENAME); + QFile cmakeFile(filePath.toString()); + cmakeFile.open(QIODevice::WriteOnly); + QTextStream stream(&cmakeFile); + stream << content; + cmakeFile.close(); +} + +bool isFileBlacklisted(const QString &fileName) +{ + return (!fileName.compare(QMLDIRFILENAME) || + !fileName.compare(CMAKEFILENAME)); +} + +} +} diff --git a/src/plugins/qmldesigner/generatecmakelists.h b/src/plugins/qmldesigner/generatecmakelists.h new file mode 100644 index 0000000000..55b0f6958d --- /dev/null +++ b/src/plugins/qmldesigner/generatecmakelists.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <projectexplorer/project.h> + +#include <utils/fileutils.h> + +namespace QmlDesigner { +namespace GenerateCmakeLists { +void generateMenuEntry(); +void onGenerateCmakeLists(); +void generateMainCmake(const Utils::FilePath &rootDir); +void generateSubdirCmake(const Utils::FilePath &dir); +QString generateModuleCmake(const Utils::FilePath &dir); +QStringList processDirectory(const Utils::FilePath &dir); +QStringList getSingletonsFromQmldirFile(const Utils::FilePath &filePath); +QStringList getDirectoryTreeResources(const Utils::FilePath &dir); +void createCmakeFile(const Utils::FilePath &filePath, const QString &content); +bool isFileBlacklisted(const QString &fileName); +} +} diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 77c4715f17..014c79b59d 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -31,6 +31,7 @@ #include "designmodecontext.h" #include "openuiqmlfiledialog.h" #include "generateresource.h" +#include "generatecmakelists.h" #include "nodeinstanceview.h" #include "gestures.h" @@ -222,6 +223,8 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool()) GenerateResource::generateMenuEntry(); + GenerateCmakeLists::generateMenuEntry(); + const QString fontPath = Core::ICore::resourcePath( "qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf") diff --git a/src/plugins/qmldesigner/qmldesignerplugin.pri b/src/plugins/qmldesigner/qmldesignerplugin.pri index 58fb55788f..4cf7edf4ba 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.pri +++ b/src/plugins/qmldesigner/qmldesignerplugin.pri @@ -5,6 +5,7 @@ HEADERS += $$PWD/qmldesignerconstants.h \ $$PWD/designersettings.h \ $$PWD/editorproxy.h \ $$PWD/generateresource.h \ + $$PWD/generatecmakelists.h \ $$PWD/settingspage.h \ $$PWD/designmodecontext.h \ $$PWD/documentmanager.h \ @@ -20,6 +21,7 @@ SOURCES += $$PWD/qmldesignerplugin.cpp \ $$PWD/designersettings.cpp \ $$PWD/editorproxy.cpp \ $$PWD/generateresource.cpp \ + $$PWD/generatecmakelists.cpp \ $$PWD/settingspage.cpp \ $$PWD/designmodecontext.cpp \ $$PWD/documentmanager.cpp \ diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index a1cf95c0e8..a3b70ec970 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -1007,6 +1007,8 @@ Project { files: [ "generateresource.cpp", "generateresource.h", + "generatecmakelists.cpp", + "generatecmakelists.h", "designersettings.cpp", "designersettings.h", "designmodecontext.cpp", diff --git a/src/plugins/qmldesigner/qtquickplugin/images/component-icon.png b/src/plugins/qmldesigner/qtquickplugin/images/component-icon.png Binary files differnew file mode 100644 index 0000000000..9c7df42bc7 --- /dev/null +++ b/src/plugins/qmldesigner/qtquickplugin/images/component-icon.png diff --git a/src/plugins/qmldesigner/qtquickplugin/images/component-icon16.png b/src/plugins/qmldesigner/qtquickplugin/images/component-icon16.png Binary files differnew file mode 100644 index 0000000000..99941541c6 --- /dev/null +++ b/src/plugins/qmldesigner/qtquickplugin/images/component-icon16.png diff --git a/src/plugins/qmldesigner/qtquickplugin/images/component-icon@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/component-icon@2x.png Binary files differnew file mode 100644 index 0000000000..f66349a63b --- /dev/null +++ b/src/plugins/qmldesigner/qtquickplugin/images/component-icon@2x.png diff --git a/src/plugins/qmldesigner/qtquickplugin/images/loader-icon.png b/src/plugins/qmldesigner/qtquickplugin/images/loader-icon.png Binary files differnew file mode 100644 index 0000000000..29082eacf1 --- /dev/null +++ b/src/plugins/qmldesigner/qtquickplugin/images/loader-icon.png diff --git a/src/plugins/qmldesigner/qtquickplugin/images/loader-icon16.png b/src/plugins/qmldesigner/qtquickplugin/images/loader-icon16.png Binary files differnew file mode 100644 index 0000000000..4a2b093259 --- /dev/null +++ b/src/plugins/qmldesigner/qtquickplugin/images/loader-icon16.png diff --git a/src/plugins/qmldesigner/qtquickplugin/images/loader-icon@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/loader-icon@2x.png Binary files differnew file mode 100644 index 0000000000..750b13bd02 --- /dev/null +++ b/src/plugins/qmldesigner/qtquickplugin/images/loader-icon@2x.png diff --git a/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon.png b/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon.png Binary files differnew file mode 100644 index 0000000000..efe3ca80b4 --- /dev/null +++ b/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon.png diff --git a/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon16.png b/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon16.png Binary files differnew file mode 100644 index 0000000000..775a57a38c --- /dev/null +++ b/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon16.png diff --git a/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon@2x.png Binary files differnew file mode 100644 index 0000000000..bb541b6711 --- /dev/null +++ b/src/plugins/qmldesigner/qtquickplugin/images/repeater-icon@2x.png diff --git a/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc b/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc index be1770378b..8adfb84baf 100644 --- a/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc +++ b/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc @@ -72,5 +72,14 @@ <file>images/animated-image-icon.png</file> <file>images/animated-image-icon@2x.png</file> <file>images/animated-image-icon16.png</file> + <file>images/component-icon.png</file> + <file>images/component-icon@2x.png</file> + <file>images/component-icon16.png</file> + <file>images/repeater-icon.png</file> + <file>images/repeater-icon@2x.png</file> + <file>images/repeater-icon16.png</file> + <file>images/loader-icon.png</file> + <file>images/loader-icon@2x.png</file> + <file>images/loader-icon16.png</file> </qresource> </RCC> diff --git a/src/plugins/qmldesigner/qtquickplugin/quick.metainfo b/src/plugins/qmldesigner/qtquickplugin/quick.metainfo index 019be09973..851d457cdc 100644 --- a/src/plugins/qmldesigner/qtquickplugin/quick.metainfo +++ b/src/plugins/qmldesigner/qtquickplugin/quick.metainfo @@ -434,7 +434,7 @@ MetaInfo { Type { name: "QtQml.Component" - icon: ":/qtquickplugin/images/item-icon16.png" + icon: ":/qtquickplugin/images/component-icon16.png" Hints { canBeDroppedInNavigator: true @@ -444,19 +444,19 @@ MetaInfo { ItemLibraryEntry { name: "Component" category: "e.Qt Quick - Component" - libraryIcon: ":/qtquickplugin/images/item-icon.png" + libraryIcon: ":/qtquickplugin/images/component-icon.png" version: "2.0" } } Type { name: "QtQuick.Loader" - icon: ":/qtquickplugin/images/item-icon16.png" + icon: ":/qtquickplugin/images/loader-icon16.png" ItemLibraryEntry { name: "Loader" category: "e.Qt Quick - Component" - libraryIcon: ":/qtquickplugin/images/item-icon.png" + libraryIcon: ":/qtquickplugin/images/loader-icon.png" version: "2.0" Property { name: "width"; type: "int"; value: 200; } Property { name: "height"; type: "int"; value: 200; } @@ -465,7 +465,7 @@ MetaInfo { Type { name: "QtQuick.Repeater" - icon: ":/qtquickplugin/images/item-icon16.png" + icon: ":/qtquickplugin/images/repeater-icon16.png" Hints { canBeDroppedInFormEditor: false @@ -475,7 +475,7 @@ MetaInfo { ItemLibraryEntry { name: "Repeater" category: "e.Qt Quick - Component" - libraryIcon: ":/qtquickplugin/images/item-icon.png" + libraryIcon: ":/qtquickplugin/images/repeater-icon.png" version: "2.0" } } diff --git a/src/plugins/qmlpreview/qmldebugtranslationclient.cpp b/src/plugins/qmlpreview/qmldebugtranslationclient.cpp index e383784ef5..5d48877265 100644 --- a/src/plugins/qmlpreview/qmldebugtranslationclient.cpp +++ b/src/plugins/qmlpreview/qmldebugtranslationclient.cpp @@ -52,14 +52,6 @@ void QmlDebugTranslationClient::changeLanguage(const QUrl &url, const QString &l } -void QmlDebugTranslationClient::messageReceived(const QByteArray &data) -{ - QmlDebug::QPacket packet(dataStreamVersion(), data); - qint8 command; - packet >> command; - qDebug() << Q_FUNC_INFO << "invalid command" << command; -} - void QmlDebugTranslationClient::stateChanged(QmlDebug::QmlDebugClient::State state) { if (state == Unavailable) diff --git a/src/plugins/qmlpreview/qmldebugtranslationclient.h b/src/plugins/qmlpreview/qmldebugtranslationclient.h index 0b9e3594b2..8a6bc1478f 100644 --- a/src/plugins/qmlpreview/qmldebugtranslationclient.h +++ b/src/plugins/qmlpreview/qmldebugtranslationclient.h @@ -37,8 +37,6 @@ public: explicit QmlDebugTranslationClient(QmlDebug::QmlDebugConnection *connection); void changeLanguage(const QUrl &url, const QString &localeIsoCode); - - void messageReceived(const QByteArray &message) override; void stateChanged(State state) override; signals: diff --git a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp index 054cc31eae..8dcd41cbb4 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp @@ -36,7 +36,7 @@ namespace QmlProfiler { -inline uint qHash(const QmlEventType &type) +inline auto qHash(const QmlEventType &type) { return qHash(type.location()) ^ (((type.message() << 12) & 0xf000) // 4 bits of message diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp index 53c76263a2..962b403492 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp @@ -99,6 +99,14 @@ QmlProjectItem *QmlProjectFileFormat::parseProjectFile(const Utils::FilePath &fi if (fileSelectorsProperty.isValid()) projectItem->setFileSelectors(fileSelectorsProperty.value.toStringList()); + const auto languagesProperty = rootNode->property(QLatin1String("supportedLanguages")); + if (languagesProperty.isValid()) + projectItem->setSupportedLanguages(languagesProperty.value.toStringList()); + + const auto primaryLanguageProperty = rootNode->property(QLatin1String("primaryLanguage")); + if (primaryLanguageProperty.isValid()) + projectItem->setPrimaryLanguage(primaryLanguageProperty.value.toString()); + const auto forceFreeTypeProperty = rootNode->property("forceFreeType"); if (forceFreeTypeProperty.isValid()) projectItem->setForceFreeType(forceFreeTypeProperty.value.toBool()); diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp index b7aa7ec434..249474a224 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp @@ -77,6 +77,18 @@ void QmlProjectItem::setFileSelectors(const QStringList &selectors) m_fileSelectors = selectors; } +void QmlProjectItem::setSupportedLanguages(const QStringList &languages) +{ + if (m_supportedLanguages != languages) + m_supportedLanguages = languages; +} + +void QmlProjectItem::setPrimaryLanguage(const QString &language) +{ + if (m_primaryLanguage != language) + m_primaryLanguage = language; +} + /* Returns list of absolute paths */ QStringList QmlProjectItem::files() const { diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h index 2f0f8786ef..90d17e4859 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h @@ -63,6 +63,12 @@ public: QStringList fileSelectors() const { return m_fileSelectors; } void setFileSelectors(const QStringList &selectors); + QStringList supportedLanguages() const { return m_supportedLanguages; } + void setSupportedLanguages(const QStringList &languages); + + QString primaryLanguage() const { return m_primaryLanguage; } + void setPrimaryLanguage(const QString &language); + QStringList files() const; bool matchesFile(const QString &filePath) const; @@ -85,6 +91,8 @@ protected: QString m_targetDirectory; QStringList m_importPaths; QStringList m_fileSelectors; + QStringList m_supportedLanguages; + QString m_primaryLanguage; QString m_mainFile; Utils::EnvironmentItems m_environment; QVector<QmlProjectContentItem *> m_content; // content property diff --git a/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp b/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp index dc8940844b..662e904974 100644 --- a/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp +++ b/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp @@ -46,8 +46,7 @@ static bool isMultilanguagePresent() static Utils::FilePath getMultilanguageDatabaseFilePath(ProjectExplorer::Target *target) { if (target) { - auto filePath = target->project()->projectDirectory().pathAppended( - "multilanguage-experimental-v6.db"); + auto filePath = target->project()->projectDirectory().pathAppended("translations.db"); if (filePath.exists()) return filePath; } diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index c1b8c6dc43..876fa4e188 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -340,6 +340,20 @@ QStringList QmlBuildSystem::customFileSelectors() const return {}; } +QStringList QmlBuildSystem::supportedLanguages() const +{ + if (m_projectItem) + return m_projectItem.data()->supportedLanguages(); + return {}; +} + +QString QmlBuildSystem::primaryLanguage() const +{ + if (m_projectItem) + return m_projectItem.data()->primaryLanguage(); + return {}; +} + void QmlBuildSystem::refreshProjectFile() { refresh(QmlBuildSystem::ProjectFile | Files); @@ -509,6 +523,10 @@ QVariant QmlBuildSystem::additionalData(Id id) const { if (id == Constants::customFileSelectorsData) return customFileSelectors(); + if (id == Constants::supportedLanguagesData) + return supportedLanguages(); + if (id == Constants::primaryLanguageData) + return primaryLanguage(); if (id == Constants::customForceFreeTypeData) return forceFreeType(); if (id == Constants::customQtForMCUs) diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h index 51028b0d54..64c0cc90ec 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.h +++ b/src/plugins/qmlprojectmanager/qmlproject.h @@ -88,6 +88,8 @@ public: Utils::EnvironmentItems environment() const; QStringList customImportPaths() const; QStringList customFileSelectors() const; + QStringList supportedLanguages() const; + QString primaryLanguage() const; bool forceFreeType() const; bool addFiles(const QStringList &filePaths); diff --git a/src/plugins/qmlprojectmanager/qmlprojectconstants.h b/src/plugins/qmlprojectmanager/qmlprojectconstants.h index 7a8df1f4f8..184469f243 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectconstants.h +++ b/src/plugins/qmlprojectmanager/qmlprojectconstants.h @@ -32,6 +32,8 @@ namespace Constants { const char * const QMLPROJECT_MIMETYPE = QmlJSTools::Constants::QMLPROJECT_MIMETYPE; const char customFileSelectorsData[] = "CustomFileSelectorsData"; +const char supportedLanguagesData[] = "SupportedLanguagesData"; +const char primaryLanguageData[] = "PrimaryLanguageData"; const char customForceFreeTypeData[] = "CustomForceFreeType"; const char customQtForMCUs[] = "CustomQtForMCUs"; const char customQt6Project[] = "CustomQt6Project"; diff --git a/src/plugins/remotelinux/deploymenttimeinfo.cpp b/src/plugins/remotelinux/deploymenttimeinfo.cpp index 3130aadf20..81eb9417e3 100644 --- a/src/plugins/remotelinux/deploymenttimeinfo.cpp +++ b/src/plugins/remotelinux/deploymenttimeinfo.cpp @@ -61,7 +61,7 @@ public: QString sysroot; }; -uint qHash(const DeployParameters &p) { +auto qHash(const DeployParameters &p) { return qHash(qMakePair(qMakePair(p.file, p.host), p.sysroot)); } diff --git a/src/plugins/resourceeditor/resourceeditorplugin.cpp b/src/plugins/resourceeditor/resourceeditorplugin.cpp index 62a4d75245..36de99ca39 100644 --- a/src/plugins/resourceeditor/resourceeditorplugin.cpp +++ b/src/plugins/resourceeditor/resourceeditorplugin.cpp @@ -46,6 +46,7 @@ #include <utils/algorithm.h> #include <utils/parameteraction.h> #include <utils/qtcassert.h> +#include <utils/threadutils.h> #include <QCoreApplication> #include <QAction> @@ -247,21 +248,35 @@ ResourceEditorPluginPrivate::ResourceEditorPluginPrivate(ResourceEditorPlugin *q void ResourceEditorPlugin::extensionsInitialized() { - ProjectTree::registerTreeManager([](FolderNode *folder) { - QList<FileNode *> toReplace; - folder->forEachNode([&toReplace](FileNode *fn) { - if (fn->fileType() == FileType::Resource) - toReplace.append(fn); - }); - - for (FileNode *file : qAsConst(toReplace)) { - FolderNode *const pn = file->parentFolderNode(); - QTC_ASSERT(pn, continue); - const Utils::FilePath path = file->filePath(); - auto topLevel = std::make_unique<ResourceTopLevelNode>(path, pn->filePath()); - topLevel->setEnabled(file->isEnabled()); - topLevel->setIsGenerated(file->isGenerated()); - pn->replaceSubtree(file, std::move(topLevel)); + ProjectTree::registerTreeManager([](FolderNode *folder, ProjectTree::ConstructionPhase phase) { + switch (phase) { + case ProjectTree::AsyncPhase: { + QList<FileNode *> toReplace; + folder->forEachNode([&toReplace](FileNode *fn) { + if (fn->fileType() == FileType::Resource) + toReplace.append(fn); + }, {}, [](const FolderNode *fn) { + return dynamic_cast<const ResourceTopLevelNode *>(fn) == nullptr; + }); + for (FileNode *file : qAsConst(toReplace)) { + FolderNode *const pn = file->parentFolderNode(); + QTC_ASSERT(pn, continue); + const Utils::FilePath path = file->filePath(); + auto topLevel = std::make_unique<ResourceTopLevelNode>(path, pn->filePath()); + topLevel->setEnabled(file->isEnabled()); + topLevel->setIsGenerated(file->isGenerated()); + pn->replaceSubtree(file, std::move(topLevel)); + } + break; + } + case ProjectTree::FinalPhase: { + folder->forEachNode({}, [](FolderNode *fn) { + auto *topLevel = dynamic_cast<ResourceTopLevelNode *>(fn); + if (topLevel) + topLevel->setupWatcherIfNeeded(); + }); + break; + } } }); } diff --git a/src/plugins/resourceeditor/resourcenode.cpp b/src/plugins/resourceeditor/resourcenode.cpp index 30be6b0c0a..75f35da4d8 100644 --- a/src/plugins/resourceeditor/resourcenode.cpp +++ b/src/plugins/resourceeditor/resourcenode.cpp @@ -36,6 +36,7 @@ #include <utils/fileutils.h> #include <utils/mimetypes/mimedatabase.h> #include <utils/qtcassert.h> +#include <utils/threadutils.h> #include <QCoreApplication> #include <QDir> @@ -251,10 +252,8 @@ ResourceTopLevelNode::ResourceTopLevelNode(const FilePath &filePath, setShowWhenEmpty(true); if (!filePath.isEmpty()) { - if (filePath.isReadableFile()) { - m_document = new ResourceFileWatcher(this); - DocumentManager::addDocument(m_document); - } + if (filePath.isReadableFile()) + setupWatcherIfNeeded(); } else { m_contents = contents; } @@ -267,6 +266,15 @@ ResourceTopLevelNode::ResourceTopLevelNode(const FilePath &filePath, addInternalNodes(); } +void ResourceTopLevelNode::setupWatcherIfNeeded() +{ + if (m_document || !isMainThread()) + return; + + m_document = new ResourceFileWatcher(this); + DocumentManager::addDocument(m_document); +} + ResourceTopLevelNode::~ResourceTopLevelNode() { if (m_document) diff --git a/src/plugins/resourceeditor/resourcenode.h b/src/plugins/resourceeditor/resourcenode.h index a992e267dc..03ae8039f0 100644 --- a/src/plugins/resourceeditor/resourcenode.h +++ b/src/plugins/resourceeditor/resourcenode.h @@ -39,6 +39,7 @@ public: const QString &contents = {}); ~ResourceTopLevelNode() override; + void setupWatcherIfNeeded(); void addInternalNodes(); bool supportsAction(ProjectExplorer::ProjectAction action, const Node *node) const override; diff --git a/src/plugins/scxmleditor/scxmleditordocument.cpp b/src/plugins/scxmleditor/scxmleditordocument.cpp index 22cf828589..2ce6669e68 100644 --- a/src/plugins/scxmleditor/scxmleditordocument.cpp +++ b/src/plugins/scxmleditor/scxmleditordocument.cpp @@ -147,6 +147,11 @@ bool ScxmlEditorDocument::reload(QString *errorString, ReloadFlag flag, ChangeTy return success; } +bool ScxmlEditorDocument::supportsCodec(const QTextCodec *codec) const +{ + return codec == QTextCodec::codecForName("UTF-8"); +} + QString ScxmlEditorDocument::designWidgetContents() const { return m_designWidget->contents(); diff --git a/src/plugins/scxmleditor/scxmleditordocument.h b/src/plugins/scxmleditor/scxmleditordocument.h index 587343a70b..f46d03f0a2 100644 --- a/src/plugins/scxmleditor/scxmleditordocument.h +++ b/src/plugins/scxmleditor/scxmleditordocument.h @@ -57,6 +57,7 @@ public: bool isSaveAsAllowed() const override; bool isModified() const override; bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override; + bool supportsCodec(const QTextCodec *codec) const override; // Internal Common::MainWidget *designWidget() const; diff --git a/src/plugins/studiowelcome/CMakeLists.txt b/src/plugins/studiowelcome/CMakeLists.txt index d22625e7c7..2ae3bdcc9a 100644 --- a/src/plugins/studiowelcome/CMakeLists.txt +++ b/src/plugins/studiowelcome/CMakeLists.txt @@ -1,4 +1,5 @@ add_qtc_plugin(StudioWelcome + CONDITION TARGET Qt5::QuickWidgets DEPENDS Qt5::QuickWidgets PLUGIN_DEPENDS Core ProjectExplorer QtSupport DEFINES STUDIO_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/qml/" diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 52957d7192..d119567562 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -342,10 +342,6 @@ bool StudioWelcomePlugin::initialize(const QStringList &arguments, QString *erro m_welcomeMode = new WelcomeMode; - QFontDatabase::addApplicationFont(":/studiofonts/TitilliumWeb-Regular.ttf"); - QFont systemFont("Titillium Web", QApplication::font().pointSize()); - QApplication::setFont(systemFont); - m_removeSplashTimer.setSingleShot(true); m_removeSplashTimer.setInterval(15000); connect(&m_removeSplashTimer, &QTimer::timeout, this, [this] { closeSplashScreen(); }); diff --git a/src/plugins/texteditor/codeassist/genericproposalmodel.cpp b/src/plugins/texteditor/codeassist/genericproposalmodel.cpp index 96492caadb..d0343b11bf 100644 --- a/src/plugins/texteditor/codeassist/genericproposalmodel.cpp +++ b/src/plugins/texteditor/codeassist/genericproposalmodel.cpp @@ -41,7 +41,7 @@ using namespace TextEditor; QT_BEGIN_NAMESPACE -uint qHash(const AssistProposalItem &item) +auto qHash(const AssistProposalItem &item) { return qHash(item.text()); } diff --git a/src/plugins/texteditor/fontsettings.cpp b/src/plugins/texteditor/fontsettings.cpp index e35ed5c3b2..4c6df391ce 100644 --- a/src/plugins/texteditor/fontsettings.cpp +++ b/src/plugins/texteditor/fontsettings.cpp @@ -141,7 +141,7 @@ bool FontSettings::equals(const FontSettings &f) const && m_scheme == f.m_scheme; } -uint qHash(const TextStyle &textStyle) +auto qHash(const TextStyle &textStyle) { return ::qHash(quint8(textStyle)); } @@ -202,7 +202,7 @@ QTextCharFormat FontSettings::toTextCharFormat(TextStyle category) const return tf; } -uint qHash(TextStyles textStyles) +auto qHash(TextStyles textStyles) { return ::qHash(reinterpret_cast<quint64&>(textStyles)); } diff --git a/src/plugins/texteditor/snippets/snippetoverlay.cpp b/src/plugins/texteditor/snippets/snippetoverlay.cpp index 568470b90e..287d0d7531 100644 --- a/src/plugins/texteditor/snippets/snippetoverlay.cpp +++ b/src/plugins/texteditor/snippets/snippetoverlay.cpp @@ -114,10 +114,10 @@ QTextCursor SnippetOverlay::nextSelectionCursor(const QTextCursor &cursor) const const SnippetSelection ¤tSelection = selectionForCursor(cursor); if (currentSelection.variableIndex >= 0) { int nextVariableIndex = currentSelection.variableIndex + 1; - if (nextVariableIndex >= m_variables.size()) { + if (!m_variables.contains(nextVariableIndex)) { if (m_finalSelectionIndex >= 0) return cursorForIndex(m_finalSelectionIndex); - nextVariableIndex = 0; + nextVariableIndex = m_variables.firstKey(); } for (int selectionIndex : m_variables[nextVariableIndex]) { @@ -142,8 +142,8 @@ QTextCursor SnippetOverlay::previousSelectionCursor(const QTextCursor &cursor) c const SnippetSelection ¤tSelection = selectionForCursor(cursor); if (currentSelection.variableIndex >= 0) { int previousVariableIndex = currentSelection.variableIndex - 1; - if (previousVariableIndex < 0) - previousVariableIndex = m_variables.size() - 1; + if (!m_variables.contains(previousVariableIndex)) + previousVariableIndex = m_variables.lastKey(); const QList<int> &equivalents = m_variables[previousVariableIndex]; for (int i = equivalents.size() - 1; i >= 0; --i) { diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index d7643af772..90d141808a 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -1966,7 +1966,7 @@ void TextEditorWidget::indent() void TextEditorWidget::unindent() { - setMultiTextCursor(textDocument()->indent(multiTextCursor())); + setMultiTextCursor(textDocument()->unindent(multiTextCursor())); } void TextEditorWidget::undo() @@ -8255,7 +8255,7 @@ IEditor *BaseTextEditor::duplicate() QT_BEGIN_NAMESPACE -uint qHash(const QColor &color) +Utils::QHashValueType qHash(const QColor &color) { return color.rgba(); } diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index 38cbdd01d3..5811f466e4 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -41,6 +41,7 @@ #include <utils/elidinglabel.h> #include <utils/link.h> #include <utils/multitextcursor.h> +#include <utils/porting.h> #include <utils/uncommentselection.h> #include <QPlainTextEdit> @@ -685,6 +686,6 @@ private: QT_BEGIN_NAMESPACE -uint qHash(const QColor &color); +Utils::QHashValueType qHash(const QColor &color); QT_END_NAMESPACE diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index d24b96dd5f..c2f4d4a0c9 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -958,18 +958,19 @@ void VcsBaseEditorWidget::slotCursorPositionChanged() // Adapt entries combo to new position // if the cursor goes across a file line. const int newCursorLine = textCursor().blockNumber(); - if (newCursorLine == d->m_cursorLine) - return; - // Which section does it belong to? - d->m_cursorLine = newCursorLine; - const int section = sectionOfLine(d->m_cursorLine, d->m_entrySections); - if (section != -1) { - QComboBox *entriesComboBox = d->entriesComboBox(); - if (entriesComboBox->currentIndex() != section) { - QSignalBlocker blocker(entriesComboBox); - entriesComboBox->setCurrentIndex(section); + if (newCursorLine != d->m_cursorLine) { + // Which section does it belong to? + d->m_cursorLine = newCursorLine; + const int section = sectionOfLine(d->m_cursorLine, d->m_entrySections); + if (section != -1) { + QComboBox *entriesComboBox = d->entriesComboBox(); + if (entriesComboBox->currentIndex() != section) { + QSignalBlocker blocker(entriesComboBox); + entriesComboBox->setCurrentIndex(section); + } } } + TextEditorWidget::slotCursorPositionChanged(); } void VcsBaseEditorWidget::contextMenuEvent(QContextMenuEvent *e) @@ -983,8 +984,10 @@ void VcsBaseEditorWidget::contextMenuEvent(QContextMenuEvent *e) handler->fillContextMenu(menu, d->m_parameters->type); } } - if (!menu) - menu = createStandardContextMenu(); + if (!menu) { + menu = new QMenu; + appendStandardContextMenuActions(menu); + } switch (d->m_parameters->type) { case LogOutput: // log might have diff case DiffOutput: { diff --git a/src/plugins/webassembly/webassemblyrunconfiguration.cpp b/src/plugins/webassembly/webassemblyrunconfiguration.cpp index 82d7f8d9a5..123887caf7 100644 --- a/src/plugins/webassembly/webassemblyrunconfiguration.cpp +++ b/src/plugins/webassembly/webassemblyrunconfiguration.cpp @@ -40,25 +40,32 @@ using namespace Utils; namespace WebAssembly { namespace Internal { +static FilePath pythonInterpreter(const Environment &env) +{ + const QString emsdkPythonEnvVarKey("EMSDK_PYTHON"); + if (env.hasKey(emsdkPythonEnvVarKey)) + return FilePath::fromUserInput(env.value(emsdkPythonEnvVarKey)); + + // FIXME: Centralize addPythonsFromPath() from the Python plugin and use that + for (const char *interpreterCandidate : {"python3", "python", "python2"}) { + const FilePath interpereter = env.searchInPath(QLatin1String(interpreterCandidate)); + if (interpereter.isExecutableFile()) + return interpereter; + } + return {}; +} + static CommandLine emrunCommand(Target *target, const QString &browser, const QString &port) { if (BuildConfiguration *bc = target->activeBuildConfiguration()) { - const QFileInfo emrun = bc->environment().searchInPath("emrun").toFileInfo(); - auto html = bc->buildDirectory().pathAppended(target->project()->displayName() + ".html"); - - // On Windows, we need to use the python interpreter (it comes with the emsdk) to ensure - // that the web server is killed when the application is stopped in Qt Creator. - // On Non-windows, we prefer using the shell script, because that knows how to find the - // right python (not part of emsdk). The shell script stays attached to the server process. - const FilePath interpreter = HostOsInfo::isWindowsHost() - ? FilePath::fromUserInput(bc->environment().value("EMSDK_PYTHON")) - : bc->environment().searchInPath("sh"); - const QString emrunLaunchScript = HostOsInfo::isWindowsHost() - ? emrun.absolutePath() + "/" + emrun.baseName() + ".py" - : emrun.absoluteFilePath(); - - return CommandLine(interpreter, { - emrunLaunchScript, + const Environment env = bc->environment(); + const FilePath emrun = env.searchInPath("emrun"); + const FilePath emrunPy = emrun.absolutePath().pathAppended(emrun.baseName() + ".py"); + const FilePath html = + bc->buildDirectory().pathAppended(target->project()->displayName() + ".html"); + + return CommandLine(pythonInterpreter(env), { + emrunPy.path(), "--browser", browser, "--port", port, "--no_emrun_detect", diff --git a/src/shared/proparser/proitems.cpp b/src/shared/proparser/proitems.cpp index 1f4a436115..8980e4c216 100644 --- a/src/shared/proparser/proitems.cpp +++ b/src/shared/proparser/proitems.cpp @@ -114,7 +114,7 @@ uint ProString::updatedHash() const return (m_hash = hash(m_string.constData() + m_offset, m_length)); } -uint qHash(const ProString &str) +Utils::QHashValueType qHash(const ProString &str) { if (!(str.m_hash & 0x80000000)) return str.m_hash; diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h index a16e0399d1..4da7e5444b 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -182,7 +182,7 @@ private: int m_file; mutable uint m_hash; uint updatedHash() const; - friend uint qHash(const ProString &str); + friend Utils::QHashValueType qHash(const ProString &str); friend QString operator+(const ProString &one, const ProString &two); friend class ProKey; }; @@ -253,7 +253,7 @@ template <> struct QConcatenable<ProKey> : private QAbstractConcatenable }; -uint qHash(const ProString &str); +Utils::QHashValueType qHash(const ProString &str); inline QString &operator+=(QString &that, const ProString &other) { return that += other.toStringView(); } diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index ff87a1b8f4..b937037b1e 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -104,7 +104,7 @@ QMakeBaseKey::QMakeBaseKey(const QString &_root, const QString &_stash, bool _ho { } -uint qHash(const QMakeBaseKey &key) +Utils::QHashValueType qHash(const QMakeBaseKey &key) { return qHash(key.root) ^ qHash(key.stash) ^ (uint)key.hostBuild; } diff --git a/src/shared/proparser/qmakeglobals.h b/src/shared/proparser/qmakeglobals.h index 2baeab4bf5..36b1c08c41 100644 --- a/src/shared/proparser/qmakeglobals.h +++ b/src/shared/proparser/qmakeglobals.h @@ -27,6 +27,7 @@ #include "qmake_global.h" #include "proitems.h" +#include <utils/porting.h> #ifdef QT_BUILD_QMAKE # include <property.h> @@ -58,7 +59,7 @@ public: bool hostBuild; }; -uint qHash(const QMakeBaseKey &key); +Utils::QHashValueType qHash(const QMakeBaseKey &key); bool operator==(const QMakeBaseKey &one, const QMakeBaseKey &two); class QMakeBaseEnv diff --git a/src/shared/qbs b/src/shared/qbs -Subproject a35ff56175cc8c993b54bb1d92ff71ba4532fc8 +Subproject 966689ab499725cb7e7ab1157043b968a1a39e6 diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt index 924e3a838c..4606ee5708 100644 --- a/src/tools/qml2puppet/CMakeLists.txt +++ b/src/tools/qml2puppet/CMakeLists.txt @@ -97,6 +97,7 @@ extend_qtc_library(qml2puppet_static ) add_qtc_executable(qml2puppet + CONDITION TARGET Qt5::QuickPrivate DEPENDS Qt5::CorePrivate Qt5::Widgets Qt5::QmlPrivate Qt5::QuickPrivate Qt5::Network Qt5::GuiPrivate |