forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/11.0'
Change-Id: I8d1c9720a868da02b3157a48954eb4e262539c84
This commit is contained in:
76
dist/changelog/changes-10.0.2.md
vendored
Normal file
76
dist/changelog/changes-10.0.2.md
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
Qt Creator 10.0.2
|
||||||
|
=================
|
||||||
|
|
||||||
|
Qt Creator version 10.0.2 contains bug fixes.
|
||||||
|
|
||||||
|
The most important changes are listed in this document. For a complete list of
|
||||||
|
changes, see the Git log for the Qt Creator sources that you can check out from
|
||||||
|
the public Git repository. For example:
|
||||||
|
|
||||||
|
git clone git://code.qt.io/qt-creator/qt-creator.git
|
||||||
|
git log --cherry-pick --pretty=oneline origin/v10.0.1..v10.0.2
|
||||||
|
|
||||||
|
General
|
||||||
|
-------
|
||||||
|
|
||||||
|
* Fixed freezes due to excessive file watching (QTCREATORBUG-28957)
|
||||||
|
|
||||||
|
Editing
|
||||||
|
-------
|
||||||
|
|
||||||
|
### C++
|
||||||
|
|
||||||
|
* Fixed a crash when following symbols (QTCREATORBUG-28989)
|
||||||
|
* Fixed the highlighting of raw string literals with empty lines
|
||||||
|
(QTCREATORBUG-29200)
|
||||||
|
* Clang Format
|
||||||
|
* Fixed the editing of custom code styles (QTCREATORBUG-29129)
|
||||||
|
* Fixed that the wrong code style could be used (QTCREATORBUG-29145)
|
||||||
|
|
||||||
|
Projects
|
||||||
|
--------
|
||||||
|
|
||||||
|
* Fixed a crash when triggering a build with unconfigured projects present
|
||||||
|
(QTCREATORBUG-29207)
|
||||||
|
|
||||||
|
### CMake
|
||||||
|
|
||||||
|
* Fixed that the global `Autorun CMake` option could be overridden by old
|
||||||
|
settings
|
||||||
|
* Fixed the `Build CMake Target` locator filter in case a build is already
|
||||||
|
running (QTCREATORBUG-26699)
|
||||||
|
* Presets
|
||||||
|
* Added the expansion of `${hostSystemName}` (QTCREATORBUG-28935)
|
||||||
|
* Fixed the Qt detection when `CMAKE_TOOLCHAIN_FILE` and `CMAKE_PREFIX_PATH`
|
||||||
|
are set
|
||||||
|
|
||||||
|
Debugging
|
||||||
|
---------
|
||||||
|
|
||||||
|
* Fixed that debugger tooltips in the editor vanished after expanding
|
||||||
|
(QTCREATORBUG-29083)
|
||||||
|
|
||||||
|
Test Integration
|
||||||
|
----------------
|
||||||
|
|
||||||
|
* GoogleTest
|
||||||
|
* Fixed the reporting of failed tests (QTCREATORBUG-29146)
|
||||||
|
|
||||||
|
Credits for these changes go to:
|
||||||
|
--------------------------------
|
||||||
|
Alessandro Portale
|
||||||
|
André Pönitz
|
||||||
|
Artem Sokolovskii
|
||||||
|
Björn Schäpers
|
||||||
|
Christian Kandeler
|
||||||
|
Christian Stenger
|
||||||
|
Cristian Adam
|
||||||
|
David Schulz
|
||||||
|
Eike Ziller
|
||||||
|
Jaroslaw Kobus
|
||||||
|
Karim Abdelrahman
|
||||||
|
Leena Miettinen
|
||||||
|
Miikka Heikkinen
|
||||||
|
Patrik Teivonen
|
||||||
|
Robert Löhning
|
||||||
|
Sivert Krøvel
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\previouspage creator-build-settings.html
|
\previouspage creator-build-settings.html
|
||||||
\page creator-build-settings-cmake.html
|
\page creator-build-settings-cmake.html
|
||||||
\nextpage creator-build-settings-qmake.html
|
\nextpage creator-build-settings-cmake-presets.html
|
||||||
|
|
||||||
\title CMake Build Configuration
|
\title CMake Build Configuration
|
||||||
|
|
||||||
@@ -30,6 +30,9 @@
|
|||||||
Select \uicontrol {Kit Configuration} to edit the CMake settings for the
|
Select \uicontrol {Kit Configuration} to edit the CMake settings for the
|
||||||
build and run kit selected for the project.
|
build and run kit selected for the project.
|
||||||
|
|
||||||
|
You can use \l{CMake Presets}{CMake presets} files to specify common
|
||||||
|
configure, build, and test options and share them with others.
|
||||||
|
|
||||||
\section1 Initial Configuration
|
\section1 Initial Configuration
|
||||||
|
|
||||||
\image qtcreator-build-settings-cmake-initial.webp {Initial CMake configuration}
|
\image qtcreator-build-settings-cmake-initial.webp {Initial CMake configuration}
|
||||||
@@ -57,224 +60,6 @@
|
|||||||
\l{CMake: cmake-variables(7)}. For more information about Qt-specific
|
\l{CMake: cmake-variables(7)}. For more information about Qt-specific
|
||||||
variables, see \l{CMake Variable Reference}.
|
variables, see \l{CMake Variable Reference}.
|
||||||
|
|
||||||
\section1 CMake Presets
|
|
||||||
|
|
||||||
You can use CMake presets files to specify common configure, build, and test
|
|
||||||
options and share them with others. \c CMakePresets.json has options for
|
|
||||||
project-wide builds, whereas \c CMakeUserPresets.json has options for
|
|
||||||
your local builds.
|
|
||||||
|
|
||||||
Create the presets files in the format described in
|
|
||||||
\l{https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html}
|
|
||||||
{cmake-presets(7)} and store them in project's root directory.
|
|
||||||
|
|
||||||
\QC supports presets up to version 3 (introduced in CMake 3.21), but does not
|
|
||||||
enforce version checking. It reads and uses all the fields from version 3 if
|
|
||||||
present. It does not support test presets.
|
|
||||||
|
|
||||||
You can import the presets the first time you \l {Opening Projects}
|
|
||||||
{open a project}, when no \c CMakeLists.txt.user file exists or you have
|
|
||||||
disabled all kits in the project. To update changes to the
|
|
||||||
\c CMakePresets.json file, delete the \c CMakeLists.txt.user file.
|
|
||||||
|
|
||||||
\image qtcreator-cmake-presets-configure.webp {Opening a project that has CMake presets}
|
|
||||||
|
|
||||||
You can view the presets in the \uicontrol {Initial Configuration} field and
|
|
||||||
in the environment configuration field below it.
|
|
||||||
|
|
||||||
\image qtcreator-cmake-presets-environment.webp {CMake environment configuration}
|
|
||||||
|
|
||||||
\section2 Configure Presets
|
|
||||||
|
|
||||||
The following configure presets instruct CMake to use the default generator
|
|
||||||
on the platform and specify the build directory for all build types.
|
|
||||||
\c NOT_COMMON_VALUE is displayed in \uicontrol {Initial Parameters}
|
|
||||||
and \c AN_ENVIRONMENT_FLAG in the environment configuration field.
|
|
||||||
|
|
||||||
\badcode
|
|
||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"configurePresets": [
|
|
||||||
{
|
|
||||||
"name": "preset",
|
|
||||||
"displayName": "preset",
|
|
||||||
"binaryDir": "${sourceDir}/build/preset",
|
|
||||||
"cacheVariables": {
|
|
||||||
"NOT_COMMON_VALUE": "NOT_COMMON_VALUE"
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"AN_ENVIRONMENT_FLAG": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
\section2 MinGW Example
|
|
||||||
|
|
||||||
The following example configures a Qt project with:
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li MinGW compiler
|
|
||||||
\li build directory – \c <sourceDir>/build-release
|
|
||||||
\li build type – \c CMAKE_BUILD_TYPE as \c Release
|
|
||||||
\li generator – MinGW Makefiles
|
|
||||||
\li path to a CMake executable
|
|
||||||
\li path to the Qt installation via \c CMAKE_PREFIX_PATH
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
\badcode
|
|
||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"configurePresets": [
|
|
||||||
{
|
|
||||||
"name": "mingw",
|
|
||||||
"displayName": "MinGW 11.2.0",
|
|
||||||
"generator": "MinGW Makefiles",
|
|
||||||
"binaryDir": "${sourceDir}/build-release",
|
|
||||||
"cmakeExecutable": "C:/Qt/Tools/CMake_64/bin/cmake.exe",
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_BUILD_TYPE": "Release",
|
|
||||||
"CMAKE_PREFIX_PATH": "C:/Qt/6.4.0/mingw_64"
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"PATH": "C:/Qt/Tools/mingw1120_64/bin;$penv{PATH}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
To speed up the process on Windows, specify the \c CMAKE_C_COMPILER and
|
|
||||||
\c CMAKE_CXX_COMPILER in the \c cacheVariables section.
|
|
||||||
|
|
||||||
\section2 Ninja Generator Example
|
|
||||||
|
|
||||||
The following configure and build presets set Ninja Multi-Config as the
|
|
||||||
generator, add \c Debug and \c Release build steps, and specify the path
|
|
||||||
to \c ninja.exe as a value of the \c CMAKE_MAKE_PROGRAM variable:
|
|
||||||
|
|
||||||
\badcode
|
|
||||||
{
|
|
||||||
"version": 2,
|
|
||||||
"configurePresets": [
|
|
||||||
{
|
|
||||||
"name": "ninja-nmc",
|
|
||||||
"displayName": "Ninja Multi-Config MinGW",
|
|
||||||
"generator": "Ninja Multi-Config",
|
|
||||||
"binaryDir": "${sourceDir}/build",
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_BUILD_TYPE": "Debug;Release",
|
|
||||||
"CMAKE_PREFIX_PATH": "C:/Qt/6.4.0/mingw_64"
|
|
||||||
"CMAKE_MAKE_PROGRAM": "C:/Qt/Tools/Ninja/ninja.exe"
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"PATH": "c:/Qt/Tools/mingw1120_64/bin;$penv{PATH}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"buildPresets": [
|
|
||||||
{
|
|
||||||
"name": "release",
|
|
||||||
"displayName": "Ninja Release",
|
|
||||||
"configurePreset": "ninja-nmc",
|
|
||||||
"configuration": "Release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "debug",
|
|
||||||
"displayName": "Ninja Debug",
|
|
||||||
"configurePreset": "ninja-nmc",
|
|
||||||
"configuration": "Debug"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
This example assumes that the CMake executable path is set in
|
|
||||||
\uicontrol Edit > \uicontrol Preferences > \uicontrol CMake >
|
|
||||||
\uicontrol Tools.
|
|
||||||
|
|
||||||
\section2 MSVC Example
|
|
||||||
|
|
||||||
When using MSVC compilers with NMAKE Makefiles, Ninja, or Ninja
|
|
||||||
Multi-Config generators, you can use the \c external strategy for
|
|
||||||
the \c architecture and \c toolset fields. This lets \QC set up
|
|
||||||
the Visual C++ environment before invoking CMake.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
\badcode
|
|
||||||
"generator": "Ninja Multi-Config",
|
|
||||||
"toolset": {
|
|
||||||
"value": "v142,host=x64",
|
|
||||||
"strategy": "external"
|
|
||||||
},
|
|
||||||
"architecture": {
|
|
||||||
"value": "x64",
|
|
||||||
"strategy": "external"
|
|
||||||
},
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
If you use MSVC compilers with non-VS generators and have several compilers
|
|
||||||
in the \c PATH, you might also have to specify the compiler to use in
|
|
||||||
\c cacheVariables or \c environmentVariables:
|
|
||||||
|
|
||||||
\badcode
|
|
||||||
"generator": "Ninja Multi-Config",
|
|
||||||
"toolset": {
|
|
||||||
"value": "v142,host=x64",
|
|
||||||
"strategy": "external"
|
|
||||||
},
|
|
||||||
"architecture": {
|
|
||||||
"value": "x64",
|
|
||||||
"strategy": "external"
|
|
||||||
},
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_C_COMPILER": "cl.exe",
|
|
||||||
"CMAKE_CXX_COMPILER": "cl.exe"
|
|
||||||
}
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
\section2 Using Conditions
|
|
||||||
|
|
||||||
The following configure presets are used if they match \c condition. That is,
|
|
||||||
if the \c hostSystemName equals \c Linux, the \c linux presets are used and
|
|
||||||
if it equals \c Windows, the \c windows presets are used.
|
|
||||||
|
|
||||||
\badcode
|
|
||||||
{
|
|
||||||
"version": 3,
|
|
||||||
"configurePresets": [
|
|
||||||
{
|
|
||||||
"name": "linux",
|
|
||||||
"displayName": "Linux GCC",
|
|
||||||
"binaryDir": "${sourceDir}/build",
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_PREFIX_PATH": "$env{HOME}/Qt/6.4.0/gcc_64"
|
|
||||||
},
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Linux"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows",
|
|
||||||
"displayName": "Windows MSVC",
|
|
||||||
"binaryDir": "${sourceDir}/build",
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_PREFIX_PATH": "$env{SYSTEMDRIVE}/Qt/6.4.0/msvc2019_64"
|
|
||||||
},
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Windows"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
\section1 Multi-Config Support
|
\section1 Multi-Config Support
|
||||||
|
|
||||||
\QC supports
|
\QC supports
|
||||||
|
|||||||
227
doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc
Normal file
227
doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\previouspage creator-build-settings-cmake.html
|
||||||
|
\page creator-build-settings-cmake-presets.html
|
||||||
|
\nextpage creator-build-settings-qmake.html
|
||||||
|
|
||||||
|
\title CMake Presets
|
||||||
|
|
||||||
|
\c CMakePresets.json has options for project-wide builds, whereas
|
||||||
|
\c CMakeUserPresets.json has options for your local builds.
|
||||||
|
|
||||||
|
Create the presets files in the format described in
|
||||||
|
\l{https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html}
|
||||||
|
{cmake-presets(7)} and store them in the project's root directory.
|
||||||
|
You can then see them in the \l {Projects} view.
|
||||||
|
|
||||||
|
\QC supports presets up to version 3 (introduced in CMake 3.21), but does not
|
||||||
|
enforce version checking. It reads and uses all the fields from version 3 if
|
||||||
|
present. It does not support test presets.
|
||||||
|
|
||||||
|
You can import the presets the first time you \l {Opening Projects}
|
||||||
|
{open a project}, when no \c CMakeLists.txt.user file exists or you have
|
||||||
|
disabled all kits in the project.
|
||||||
|
|
||||||
|
\image qtcreator-cmake-presets-configure.webp {Opening a project that has CMake presets}
|
||||||
|
|
||||||
|
You can view the presets in the \uicontrol {Initial Configuration} field and
|
||||||
|
in the environment configuration field below it.
|
||||||
|
|
||||||
|
\image qtcreator-cmake-presets-environment.webp {CMake environment configuration}
|
||||||
|
|
||||||
|
To update changes to the \c CMakePresets.json file, select \uicontrol Build >
|
||||||
|
\uicontrol {Reload CMake Presets}, and then select the presets file to load.
|
||||||
|
|
||||||
|
\section1 Configure Presets
|
||||||
|
|
||||||
|
The following configure presets instruct CMake to use the default generator
|
||||||
|
on the platform and specify the build directory for all build types.
|
||||||
|
\c NOT_COMMON_VALUE is displayed in \uicontrol {Initial Parameters}
|
||||||
|
and \c AN_ENVIRONMENT_FLAG in the environment configuration field.
|
||||||
|
|
||||||
|
\badcode
|
||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "preset",
|
||||||
|
"displayName": "preset",
|
||||||
|
"binaryDir": "${sourceDir}/build/preset",
|
||||||
|
"cacheVariables": {
|
||||||
|
"NOT_COMMON_VALUE": "NOT_COMMON_VALUE"
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"AN_ENVIRONMENT_FLAG": "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\section1 MinGW Example
|
||||||
|
|
||||||
|
The following example configures a Qt project with:
|
||||||
|
|
||||||
|
\list
|
||||||
|
\li MinGW compiler
|
||||||
|
\li build directory – \c <sourceDir>/build-release
|
||||||
|
\li build type – \c CMAKE_BUILD_TYPE as \c Release
|
||||||
|
\li generator – MinGW Makefiles
|
||||||
|
\li path to a CMake executable
|
||||||
|
\li path to the Qt installation via \c CMAKE_PREFIX_PATH
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\badcode
|
||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "mingw",
|
||||||
|
"displayName": "MinGW 11.2.0",
|
||||||
|
"generator": "MinGW Makefiles",
|
||||||
|
"binaryDir": "${sourceDir}/build-release",
|
||||||
|
"cmakeExecutable": "C:/Qt/Tools/CMake_64/bin/cmake.exe",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Release",
|
||||||
|
"CMAKE_PREFIX_PATH": "C:/Qt/6.4.0/mingw_64"
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"PATH": "C:/Qt/Tools/mingw1120_64/bin;$penv{PATH}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
To speed up the process on Windows, specify the \c CMAKE_C_COMPILER and
|
||||||
|
\c CMAKE_CXX_COMPILER in the \c cacheVariables section.
|
||||||
|
|
||||||
|
\section1 Ninja Generator Example
|
||||||
|
|
||||||
|
The following configure and build presets set Ninja Multi-Config as the
|
||||||
|
generator, add \c Debug and \c Release build steps, and specify the path
|
||||||
|
to \c ninja.exe as a value of the \c CMAKE_MAKE_PROGRAM variable:
|
||||||
|
|
||||||
|
\badcode
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "ninja-nmc",
|
||||||
|
"displayName": "Ninja Multi-Config MinGW",
|
||||||
|
"generator": "Ninja Multi-Config",
|
||||||
|
"binaryDir": "${sourceDir}/build",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Debug;Release",
|
||||||
|
"CMAKE_PREFIX_PATH": "C:/Qt/6.4.0/mingw_64"
|
||||||
|
"CMAKE_MAKE_PROGRAM": "C:/Qt/Tools/Ninja/ninja.exe"
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"PATH": "c:/Qt/Tools/mingw1120_64/bin;$penv{PATH}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buildPresets": [
|
||||||
|
{
|
||||||
|
"name": "release",
|
||||||
|
"displayName": "Ninja Release",
|
||||||
|
"configurePreset": "ninja-nmc",
|
||||||
|
"configuration": "Release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "debug",
|
||||||
|
"displayName": "Ninja Debug",
|
||||||
|
"configurePreset": "ninja-nmc",
|
||||||
|
"configuration": "Debug"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
This example assumes that the CMake executable path is set in
|
||||||
|
\uicontrol Edit > \uicontrol Preferences > \uicontrol CMake >
|
||||||
|
\uicontrol Tools.
|
||||||
|
|
||||||
|
\section1 MSVC Example
|
||||||
|
|
||||||
|
When using MSVC compilers with NMAKE Makefiles, Ninja, or Ninja
|
||||||
|
Multi-Config generators, you can use the \c external strategy for
|
||||||
|
the \c architecture and \c toolset fields. This lets \QC set up
|
||||||
|
the Visual C++ environment before invoking CMake.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
\badcode
|
||||||
|
"generator": "Ninja Multi-Config",
|
||||||
|
"toolset": {
|
||||||
|
"value": "v142,host=x64",
|
||||||
|
"strategy": "external"
|
||||||
|
},
|
||||||
|
"architecture": {
|
||||||
|
"value": "x64",
|
||||||
|
"strategy": "external"
|
||||||
|
},
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
If you use MSVC compilers with non-VS generators and have several compilers
|
||||||
|
in the \c PATH, you might also have to specify the compiler to use in
|
||||||
|
\c cacheVariables or \c environmentVariables:
|
||||||
|
|
||||||
|
\badcode
|
||||||
|
"generator": "Ninja Multi-Config",
|
||||||
|
"toolset": {
|
||||||
|
"value": "v142,host=x64",
|
||||||
|
"strategy": "external"
|
||||||
|
},
|
||||||
|
"architecture": {
|
||||||
|
"value": "x64",
|
||||||
|
"strategy": "external"
|
||||||
|
},
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_C_COMPILER": "cl.exe",
|
||||||
|
"CMAKE_CXX_COMPILER": "cl.exe"
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\section1 Using Conditions
|
||||||
|
|
||||||
|
The following configure presets are used if they match \c condition. That is,
|
||||||
|
if the \c hostSystemName equals \c Linux, the \c linux presets are used and
|
||||||
|
if it equals \c Windows, the \c windows presets are used.
|
||||||
|
|
||||||
|
\badcode
|
||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "linux",
|
||||||
|
"displayName": "Linux GCC",
|
||||||
|
"binaryDir": "${sourceDir}/build",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_PREFIX_PATH": "$env{HOME}/Qt/6.4.0/gcc_64"
|
||||||
|
},
|
||||||
|
"condition": {
|
||||||
|
"type": "equals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Linux"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows",
|
||||||
|
"displayName": "Windows MSVC",
|
||||||
|
"binaryDir": "${sourceDir}/build",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_PREFIX_PATH": "$env{SYSTEMDRIVE}/Qt/6.4.0/msvc2019_64"
|
||||||
|
},
|
||||||
|
"condition": {
|
||||||
|
"type": "equals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Windows"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
@@ -181,6 +181,18 @@
|
|||||||
current project.
|
current project.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
|
\section1 Managing Files
|
||||||
|
|
||||||
|
When you use project wizard templates to \l{Creating Files}{add files} to
|
||||||
|
a project, \QC automatically adds them to the \c {qt_add_executable()},
|
||||||
|
\c {add_executable()}, or \c {qt_add_library()} function in the
|
||||||
|
CMakeLists.txt file.
|
||||||
|
|
||||||
|
If you use custom API, \QC uses \c {target_sources()} to add the files.
|
||||||
|
|
||||||
|
When you rename or remove files in the \l {Projects} or \l {File System}
|
||||||
|
view, \QC renames them in the CMakeLists.txt file or removes them from it.
|
||||||
|
|
||||||
\section1 Adding External Libraries to CMake Projects
|
\section1 Adding External Libraries to CMake Projects
|
||||||
|
|
||||||
Through external libraries, \QC can support code completion and syntax
|
Through external libraries, \QC can support code completion and syntax
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
container operates like a virtual machine but uses less system resources at
|
container operates like a virtual machine but uses less system resources at
|
||||||
the cost of being less flexible.
|
the cost of being less flexible.
|
||||||
|
|
||||||
Docker support is experimental. While Linux, \macos, and Windows hosts are
|
While Linux, \macos, and Windows hosts are supported in principle, Linux is
|
||||||
supported in principle, Linux is the recommended platform.
|
the recommended platform.
|
||||||
|
|
||||||
Currently, only CMake is supported for building applications in the Docker
|
Currently, only CMake is supported for building applications in the Docker
|
||||||
container.
|
container.
|
||||||
@@ -29,16 +29,6 @@
|
|||||||
\l{https://docs.docker.com/engine/reference/commandline/pull/}{docker pull}
|
\l{https://docs.docker.com/engine/reference/commandline/pull/}{docker pull}
|
||||||
command.
|
command.
|
||||||
|
|
||||||
\section1 Enabling Docker Plugin
|
|
||||||
|
|
||||||
To enable the experimental Docker plugin:
|
|
||||||
|
|
||||||
\list 1
|
|
||||||
\li In \QC, select \uicontrol Help > \uicontrol {About Plugins} >
|
|
||||||
\uicontrol Utilities > \uicontrol {Docker (experimental)}.
|
|
||||||
\li Select \uicontrol {Restart Now} to restart \QC and load the plugin.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
\section1 Adding Docker Images as Devices
|
\section1 Adding Docker Images as Devices
|
||||||
|
|
||||||
To add a Docker image as a device:
|
To add a Docker image as a device:
|
||||||
|
|||||||
@@ -433,15 +433,19 @@
|
|||||||
\row
|
\row
|
||||||
\li Find references to symbol under cursor
|
\li Find references to symbol under cursor
|
||||||
\li Ctrl+Shift+U
|
\li Ctrl+Shift+U
|
||||||
|
\if defined(qtcreator)
|
||||||
\note If this keyboard shortcut does not work on Linux, see
|
\note If this keyboard shortcut does not work on Linux, see
|
||||||
\l {Editing Issues}.
|
\l {Editing Issues}.
|
||||||
|
\endif
|
||||||
\row
|
\row
|
||||||
\li Follow symbol under cursor
|
\li Follow symbol under cursor
|
||||||
|
|
||||||
Works with namespaces, classes, functions, variables, include
|
Works with namespaces, classes, functions, variables, include
|
||||||
statements, and macros. Also, opens URLs in the default browser
|
statements, and macros. Also, opens URLs in the default browser
|
||||||
|
\if defined(qtcreator)
|
||||||
and Qt resource files (.qrc) in the \l{Resource Files}
|
and Qt resource files (.qrc) in the \l{Resource Files}
|
||||||
{resource editor}
|
{resource editor}
|
||||||
|
\endif
|
||||||
\li F2
|
\li F2
|
||||||
\row
|
\row
|
||||||
\li Rename symbol under cursor
|
\li Rename symbol under cursor
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\previouspage creator-build-settings-cmake.html
|
\previouspage creator-build-settings-cmake-presets.html
|
||||||
\page creator-build-settings-qmake.html
|
\page creator-build-settings-qmake.html
|
||||||
\nextpage creator-build-settings-qbs.html
|
\nextpage creator-build-settings-qbs.html
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,9 @@
|
|||||||
\li \l{Specifying Build Settings}
|
\li \l{Specifying Build Settings}
|
||||||
\list
|
\list
|
||||||
\li \l{Cmake Build Configuration}
|
\li \l{Cmake Build Configuration}
|
||||||
|
\list
|
||||||
|
\li \l{CMake Presets}
|
||||||
|
\endlist
|
||||||
\li \l{qmake Build Configuration}
|
\li \l{qmake Build Configuration}
|
||||||
\li \l{Qbs Build Configuration}
|
\li \l{Qbs Build Configuration}
|
||||||
\li \l{Meson Build Configuration}
|
\li \l{Meson Build Configuration}
|
||||||
|
|||||||
@@ -60,9 +60,12 @@
|
|||||||
\li Open a terminal window in the selected directory or in the directory
|
\li Open a terminal window in the selected directory or in the directory
|
||||||
that has the file. To specify the terminal to use on Linux and
|
that has the file. To specify the terminal to use on Linux and
|
||||||
\macos, select \uicontrol Edit > \uicontrol Preferences >
|
\macos, select \uicontrol Edit > \uicontrol Preferences >
|
||||||
\uicontrol Environment > \uicontrol System. To use an \l{Terminal}
|
\uicontrol Environment > \uicontrol System.
|
||||||
{internal terminal}, select \uicontrol Edit > \uicontrol Preferences
|
\if defined(qtcreator)
|
||||||
> \uicontrol Terminal > \uicontrol {Use internal terminal}.
|
To use an \l{Terminal} {internal terminal}, select \uicontrol Edit >
|
||||||
|
\uicontrol Preferences > \uicontrol Terminal >
|
||||||
|
\uicontrol {Use internal terminal}.
|
||||||
|
\endif
|
||||||
\li Search from the selected directory.
|
\li Search from the selected directory.
|
||||||
\li View file properties, such as name, path, MIME type, default editor,
|
\li View file properties, such as name, path, MIME type, default editor,
|
||||||
line endings, indentation, owner, size, last read and modified
|
line endings, indentation, owner, size, last read and modified
|
||||||
@@ -73,7 +76,10 @@
|
|||||||
\else
|
\else
|
||||||
\l{Creating Files}.
|
\l{Creating Files}.
|
||||||
\endif
|
\endif
|
||||||
\li Rename or remove existing files.
|
\li Rename existing files. To move the file to another directory, enter
|
||||||
|
the relative or absolute path to its new location in addition to the
|
||||||
|
new filename.
|
||||||
|
\li Remove existing files.
|
||||||
\li Create new folders.
|
\li Create new folders.
|
||||||
\li Compare the selected file with the currently open file in the diff
|
\li Compare the selected file with the currently open file in the diff
|
||||||
editor. For more information, see \l{Comparing Files}.
|
editor. For more information, see \l{Comparing Files}.
|
||||||
|
|||||||
@@ -66,10 +66,11 @@
|
|||||||
\else
|
\else
|
||||||
\l{Creating Files}.
|
\l{Creating Files}.
|
||||||
\endif
|
\endif
|
||||||
\li Rename or remove existing files. If you change the base name of a
|
\li Rename existing files. If you change the base name of a
|
||||||
file, \QC displays a list of other files with the same base name
|
file, \QC displays a list of other files with the same base name
|
||||||
and offers to rename them as well. If you rename a UI file (.ui),
|
and offers to rename them as well. If you rename a UI file (.ui),
|
||||||
\QC also changes corresponding include statements accordingly.
|
\QC also changes corresponding include statements accordingly.
|
||||||
|
\li Remove existing files.
|
||||||
\if defined(qtcreator)
|
\if defined(qtcreator)
|
||||||
\li Remove existing directories from \l{Setting Up a Generic Project}
|
\li Remove existing directories from \l{Setting Up a Generic Project}
|
||||||
{generic projects}.
|
{generic projects}.
|
||||||
@@ -79,14 +80,16 @@
|
|||||||
\li Add and remove subprojects.
|
\li Add and remove subprojects.
|
||||||
\li Find unused functions.
|
\li Find unused functions.
|
||||||
\endif
|
\endif
|
||||||
|
|
||||||
\li Search from the selected directory.
|
\li Search from the selected directory.
|
||||||
|
|
||||||
\li Open a terminal window in the project directory. To specify the
|
\li Open a terminal window in the project directory. To specify the
|
||||||
terminal to use on Linux and \macos, select \uicontrol Edit >
|
terminal to use on Linux and \macos, select \uicontrol Edit >
|
||||||
\uicontrol Preferences > \uicontrol Environment > \uicontrol System.
|
\uicontrol Preferences > \uicontrol Environment > \uicontrol System.
|
||||||
|
\if defined(qtcreator)
|
||||||
To use an \l{Terminal}{internal terminal}, select \uicontrol Edit >
|
To use an \l{Terminal}{internal terminal}, select \uicontrol Edit >
|
||||||
\uicontrol Preferences > \uicontrol Terminal >
|
\uicontrol Preferences > \uicontrol Terminal >
|
||||||
\uicontrol {Use internal terminal}.
|
\uicontrol {Use internal terminal}.
|
||||||
|
\endif
|
||||||
\li Open a terminal window in the project directory that you configured
|
\li Open a terminal window in the project directory that you configured
|
||||||
for building or running the project.
|
for building or running the project.
|
||||||
\li Expand or collapse the tree view to show or hide all files and
|
\li Expand or collapse the tree view to show or hide all files and
|
||||||
|
|||||||
@@ -278,7 +278,6 @@ static Utils::QtcSettings *createUserSettings()
|
|||||||
|
|
||||||
static void setHighDpiEnvironmentVariable()
|
static void setHighDpiEnvironmentVariable()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (Utils::HostOsInfo::isMacHost())
|
if (Utils::HostOsInfo::isMacHost())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -293,10 +292,12 @@ static void setHighDpiEnvironmentVariable()
|
|||||||
&& !qEnvironmentVariableIsSet("QT_AUTO_SCREEN_SCALE_FACTOR")
|
&& !qEnvironmentVariableIsSet("QT_AUTO_SCREEN_SCALE_FACTOR")
|
||||||
&& !qEnvironmentVariableIsSet("QT_SCALE_FACTOR")
|
&& !qEnvironmentVariableIsSet("QT_SCALE_FACTOR")
|
||||||
&& !qEnvironmentVariableIsSet("QT_SCREEN_SCALE_FACTORS")) {
|
&& !qEnvironmentVariableIsSet("QT_SCREEN_SCALE_FACTORS")) {
|
||||||
} else {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!qEnvironmentVariableIsSet("QT_SCALE_FACTOR_ROUNDING_POLICY"))
|
||||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
|
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
|
||||||
Qt::HighDpiScaleFactorRoundingPolicy::Floor);
|
Qt::HighDpiScaleFactorRoundingPolicy::Floor);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPixmapCacheLimit()
|
void setPixmapCacheLimit()
|
||||||
|
|||||||
@@ -1284,7 +1284,7 @@ void TaskNode::invokeEndHandler(bool success)
|
|||||||
\li Starts asynchronous task, runs in separate thread.
|
\li Starts asynchronous task, runs in separate thread.
|
||||||
\row
|
\row
|
||||||
\li TaskTreeTask
|
\li TaskTreeTask
|
||||||
\li Utils::TaskTree
|
\li Tasking::TaskTree
|
||||||
\li Starts a nested task tree.
|
\li Starts a nested task tree.
|
||||||
\row
|
\row
|
||||||
\li FileTransferTask
|
\li FileTransferTask
|
||||||
@@ -1513,7 +1513,7 @@ void TaskNode::invokeEndHandler(bool success)
|
|||||||
The execution mode element in a Group specifies how the direct child tasks of
|
The execution mode element in a Group specifies how the direct child tasks of
|
||||||
the Group are started. The most common execution modes are \l sequential and
|
the Group are started. The most common execution modes are \l sequential and
|
||||||
\l parallel. It's also possible to specify the limit of tasks running
|
\l parallel. It's also possible to specify the limit of tasks running
|
||||||
in parallel by using the parallelLimit function.
|
in parallel by using the parallelLimit() function.
|
||||||
|
|
||||||
In all execution modes, a group starts tasks in the oder in which they appear.
|
In all execution modes, a group starts tasks in the oder in which they appear.
|
||||||
|
|
||||||
@@ -1745,16 +1745,50 @@ void TaskNode::invokeEndHandler(bool success)
|
|||||||
to finish (that is, safe non-blocking destructor of a running task).
|
to finish (that is, safe non-blocking destructor of a running task).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructs an empty task tree. Use setRecipe() to pass a declarative description
|
||||||
|
on how the task tree should execute the tasks and how it should handle the finished tasks.
|
||||||
|
|
||||||
|
Starting an empty task tree is no-op and the relevant warning message is issued.
|
||||||
|
|
||||||
|
\sa setRecipe(), start()
|
||||||
|
*/
|
||||||
TaskTree::TaskTree()
|
TaskTree::TaskTree()
|
||||||
: d(new TaskTreePrivate(this))
|
: d(new TaskTreePrivate(this))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructs a task tree with a given \a recipe. After the task tree is started,
|
||||||
|
it executes the tasks contained inside the \a recipe and
|
||||||
|
handles finished tasks according to the passed description.
|
||||||
|
|
||||||
|
\sa setRecipe(), start()
|
||||||
|
*/
|
||||||
TaskTree::TaskTree(const Group &recipe) : TaskTree()
|
TaskTree::TaskTree(const Group &recipe) : TaskTree()
|
||||||
{
|
{
|
||||||
setRecipe(recipe);
|
setRecipe(recipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Destroys the task tree.
|
||||||
|
|
||||||
|
When the task tree is running while being destructed, it stops all the running tasks
|
||||||
|
immediately. In this case, no handlers are called, not even the groups' and
|
||||||
|
tasks' error handlers or onStorageDone() handlers. The task tree also doesn't emit any
|
||||||
|
signals from the destructor, not even errorOccurred() or progressValueChanged() signals.
|
||||||
|
This behavior may always be relied on.
|
||||||
|
It is completely safe to destruct the running task tree.
|
||||||
|
|
||||||
|
It's a usual pattern to destruct the running task tree, even from the main thread.
|
||||||
|
It's guaranteed that the destruction will run quickly, without having to wait for
|
||||||
|
the currently running tasks to finish, provided that the used tasks implement
|
||||||
|
their destructors in a non-blocking way.
|
||||||
|
|
||||||
|
\note Do not call the destructor directly from any of the running task's handlers
|
||||||
|
or task tree's signals. In these cases, use \l deleteLater() instead.
|
||||||
|
|
||||||
|
\sa stop()
|
||||||
|
*/
|
||||||
TaskTree::~TaskTree()
|
TaskTree::~TaskTree()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!d->m_guard.isLocked(), qWarning("Deleting TaskTree instance directly from "
|
QTC_ASSERT(!d->m_guard.isLocked(), qWarning("Deleting TaskTree instance directly from "
|
||||||
@@ -1763,6 +1797,15 @@ TaskTree::~TaskTree()
|
|||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets a given \a recipe for the task tree. After the task tree is started,
|
||||||
|
it executes the tasks contained inside the \a recipe and
|
||||||
|
handles finished tasks according to the passed description.
|
||||||
|
|
||||||
|
\note When called for a running task tree, the call is ignored.
|
||||||
|
|
||||||
|
\sa TaskTree(const Tasking::Group &recipe), start()
|
||||||
|
*/
|
||||||
void TaskTree::setRecipe(const Group &recipe)
|
void TaskTree::setRecipe(const Group &recipe)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!isRunning(), qWarning("The TaskTree is already running, ignoring..."); return);
|
QTC_ASSERT(!isRunning(), qWarning("The TaskTree is already running, ignoring..."); return);
|
||||||
@@ -1772,6 +1815,32 @@ void TaskTree::setRecipe(const Group &recipe)
|
|||||||
d->m_root.reset(new TaskNode(d, recipe, nullptr));
|
d->m_root.reset(new TaskNode(d, recipe, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Starts the task tree.
|
||||||
|
|
||||||
|
Use setRecipe() or the constructor to set the declarative description according to which
|
||||||
|
the task tree will execute the contained tasks and handle finished tasks.
|
||||||
|
|
||||||
|
When the task tree is empty, that is, constructed with a default constructor,
|
||||||
|
a call to \e start is no-op and the relevant warning message is issued.
|
||||||
|
|
||||||
|
Otherwise, when the task tree is already running, a call to \e start is ignored and the
|
||||||
|
relevant warning message is issued.
|
||||||
|
|
||||||
|
Otherwise, the task tree is started.
|
||||||
|
|
||||||
|
The started task tree may finish synchronously,
|
||||||
|
for example when the main group's start handler returns TaskAction::StopWithError.
|
||||||
|
For this reason, the connections to the done and errorOccurred signals should be
|
||||||
|
established before calling start. Use isRunning() in order to detect whether
|
||||||
|
the task tree is still running after a call to start().
|
||||||
|
|
||||||
|
The task tree implementation relies on the running event loop for listening to the tasks'
|
||||||
|
done signals. Make sure you have a QEventLoop or QCoreApplication or one of its
|
||||||
|
subclasses running (or about to be run) when calling this method.
|
||||||
|
|
||||||
|
\sa TaskTree(const Tasking::Group &recipe), setRecipe(), isRunning(), stop()
|
||||||
|
*/
|
||||||
void TaskTree::start()
|
void TaskTree::start()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!isRunning(), qWarning("The TaskTree is already running, ignoring..."); return);
|
QTC_ASSERT(!isRunning(), qWarning("The TaskTree is already running, ignoring..."); return);
|
||||||
@@ -1780,6 +1849,65 @@ void TaskTree::start()
|
|||||||
d->start();
|
d->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void TaskTree::started()
|
||||||
|
|
||||||
|
This signal is emitted when the task tree is started. The emission of this signal is
|
||||||
|
followed synchronously by the progressValueChanged() signal with an initial \c 0 value.
|
||||||
|
|
||||||
|
\sa start(), done(), errorOccurred()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void TaskTree::done()
|
||||||
|
|
||||||
|
This signal is emitted when the task tree finished with success.
|
||||||
|
The task tree neither calls any handler, nor emits any signal anymore after this signal
|
||||||
|
was emitted.
|
||||||
|
|
||||||
|
Don't delete the task tree directly from this signal's handler. Use deleteLater() instead.
|
||||||
|
|
||||||
|
\sa started(), errorOccurred()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void TaskTree::errorOccurred()
|
||||||
|
|
||||||
|
This signal is emitted when the task tree finished with an error.
|
||||||
|
The task tree neither calls any handler, nor emits any signal anymore after this signal
|
||||||
|
was emitted.
|
||||||
|
|
||||||
|
Don't delete the task tree directly from this signal's handler. Use deleteLater() instead.
|
||||||
|
|
||||||
|
\sa started(), done()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Stops the running task tree.
|
||||||
|
|
||||||
|
Stops all the running tasks immediately.
|
||||||
|
All running tasks finish with an error, invoking their error handlers.
|
||||||
|
All running groups dispatch their handlers according to their workflow policies,
|
||||||
|
invoking one of their end handlers. The storages' onStorageDone() handlers are invoked, too.
|
||||||
|
The \l progressValueChanged signals are also being sent.
|
||||||
|
This behavior may always be relied on.
|
||||||
|
|
||||||
|
The \l stop is executed synchronously, so that after a call to \e stop
|
||||||
|
all running tasks are finished and the tree is already stopped.
|
||||||
|
It's guaranteed that the stop will run quickly, without any blocking wait for
|
||||||
|
the currently running tasks to finish, provided the used tasks implement their destructors
|
||||||
|
in a non-blocking way.
|
||||||
|
|
||||||
|
When the task tree is empty, that is, constructed with a default constructor,
|
||||||
|
a call to \e stop is no-op and the relevant warning message is issued.
|
||||||
|
|
||||||
|
Otherwise, when the task tree wasn't started, a call to stop is ignored.
|
||||||
|
|
||||||
|
\note Do not call this function directly from any of the running task's handlers
|
||||||
|
or task tree's signals.
|
||||||
|
|
||||||
|
\sa ~TaskTree()
|
||||||
|
*/
|
||||||
void TaskTree::stop()
|
void TaskTree::stop()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!d->m_guard.isLocked(), qWarning("The stop() is called from one of the"
|
QTC_ASSERT(!d->m_guard.isLocked(), qWarning("The stop() is called from one of the"
|
||||||
@@ -1787,11 +1915,26 @@ void TaskTree::stop()
|
|||||||
d->stop();
|
d->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns \c true if the task tree is currently running; otherwise returns \c false.
|
||||||
|
|
||||||
|
\sa start(), stop()
|
||||||
|
*/
|
||||||
bool TaskTree::isRunning() const
|
bool TaskTree::isRunning() const
|
||||||
{
|
{
|
||||||
return d->m_root && d->m_root->isRunning();
|
return d->m_root && d->m_root->isRunning();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Executes a local event loop with QEventLoop::ExcludeUserInputEvents and starts the task tree.
|
||||||
|
|
||||||
|
Returns \c true if the task tree finished successfully; otherwise returns \c false.
|
||||||
|
|
||||||
|
\note Avoid using this method from the main thread. Use asynchronous start() instead.
|
||||||
|
This method is to be used in non-main threads or in auto tests.
|
||||||
|
|
||||||
|
\sa start()
|
||||||
|
*/
|
||||||
bool TaskTree::runBlocking()
|
bool TaskTree::runBlocking()
|
||||||
{
|
{
|
||||||
QPromise<void> dummy;
|
QPromise<void> dummy;
|
||||||
@@ -1799,6 +1942,12 @@ bool TaskTree::runBlocking()
|
|||||||
return runBlocking(dummy.future());
|
return runBlocking(dummy.future());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\overload runBlocking()
|
||||||
|
|
||||||
|
The passed \a future is used for listening to the cancel event.
|
||||||
|
When the task tree finishes with an error, this method cancels the passed \a future.
|
||||||
|
*/
|
||||||
bool TaskTree::runBlocking(const QFuture<void> &future)
|
bool TaskTree::runBlocking(const QFuture<void> &future)
|
||||||
{
|
{
|
||||||
if (future.isCanceled())
|
if (future.isCanceled())
|
||||||
@@ -1830,6 +1979,19 @@ bool TaskTree::runBlocking(const QFuture<void> &future)
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructs a temporary task tree using the passed \a recipe and runs it blocking.
|
||||||
|
|
||||||
|
The optionally provided \a timeout is used to stop the tree automatically after
|
||||||
|
\a timeout milliseconds have passed.
|
||||||
|
|
||||||
|
Returns \c true if the task tree finished successfully; otherwise returns \c false.
|
||||||
|
|
||||||
|
\note Avoid using this method from the main thread. Use asynchronous start() instead.
|
||||||
|
This method is to be used in non-main threads or in auto tests.
|
||||||
|
|
||||||
|
\sa start()
|
||||||
|
*/
|
||||||
bool TaskTree::runBlocking(const Group &recipe, milliseconds timeout)
|
bool TaskTree::runBlocking(const Group &recipe, milliseconds timeout)
|
||||||
{
|
{
|
||||||
QPromise<void> dummy;
|
QPromise<void> dummy;
|
||||||
@@ -1837,6 +1999,12 @@ bool TaskTree::runBlocking(const Group &recipe, milliseconds timeout)
|
|||||||
return TaskTree::runBlocking(recipe, dummy.future(), timeout);
|
return TaskTree::runBlocking(recipe, dummy.future(), timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\overload runBlocking(const Group &recipe, milliseconds timeout)
|
||||||
|
|
||||||
|
The passed \a future is used for listening to the cancel event.
|
||||||
|
When the task tree finishes with an error, this method cancels the passed \a future.
|
||||||
|
*/
|
||||||
bool TaskTree::runBlocking(const Group &recipe, const QFuture<void> &future, milliseconds timeout)
|
bool TaskTree::runBlocking(const Group &recipe, const QFuture<void> &future, milliseconds timeout)
|
||||||
{
|
{
|
||||||
const Group root = timeout == milliseconds::max() ? recipe
|
const Group root = timeout == milliseconds::max() ? recipe
|
||||||
@@ -1845,16 +2013,145 @@ bool TaskTree::runBlocking(const Group &recipe, const QFuture<void> &future, mil
|
|||||||
return taskTree.runBlocking(future);
|
return taskTree.runBlocking(future);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the number of asynchronous tasks contained in the stored recipe.
|
||||||
|
|
||||||
|
\note The returned number doesn't include Sync tasks.
|
||||||
|
\note Any task or group that was set up using withTimeout() increases the total number of
|
||||||
|
tasks by \c 1.
|
||||||
|
|
||||||
|
\sa setRecipe(), progressMaximum()
|
||||||
|
*/
|
||||||
int TaskTree::taskCount() const
|
int TaskTree::taskCount() const
|
||||||
{
|
{
|
||||||
return d->m_root ? d->m_root->taskCount() : 0;
|
return d->m_root ? d->m_root->taskCount() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void TaskTree::progressValueChanged(int value)
|
||||||
|
|
||||||
|
This signal is emitted when the running task tree finished, stopped, or skipped some tasks.
|
||||||
|
The \a value gives the current total number of finished, stopped or skipped tasks.
|
||||||
|
When the task tree is started, and after the started() signal was emitted,
|
||||||
|
this signal is emitted with an initial \a value of \c 0.
|
||||||
|
When the task tree is about to finish, and before the done() or errorOccurred() signal
|
||||||
|
is emitted, this signal is emitted with the final \a value of progressMaximum().
|
||||||
|
|
||||||
|
\sa progressValue(), progressMaximum()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn int TaskTree::progressMaximum() const
|
||||||
|
|
||||||
|
Returns the maximum progressValue().
|
||||||
|
|
||||||
|
\note Currently, it's the same as taskCount(). This might change in the future.
|
||||||
|
|
||||||
|
\sa progressValue()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the current progress value, which is between the \c 0 and progressMaximum().
|
||||||
|
|
||||||
|
The returned number indicates how many tasks have been already finished, stopped, or skipped
|
||||||
|
while the task tree is running.
|
||||||
|
When the task tree is started, this number is set to \c 0.
|
||||||
|
When the task tree is finished, this number always equals progressMaximum().
|
||||||
|
|
||||||
|
\sa progressMaximum()
|
||||||
|
*/
|
||||||
int TaskTree::progressValue() const
|
int TaskTree::progressValue() const
|
||||||
{
|
{
|
||||||
return d->m_progressValue;
|
return d->m_progressValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn template <typename StorageStruct, typename StorageHandler> void TaskTree::onStorageSetup(const TreeStorage<StorageStruct> &storage, StorageHandler &&handler)
|
||||||
|
|
||||||
|
Installs a storage setup \a handler for the \a storage to pass the initial data
|
||||||
|
dynamically to the running task tree.
|
||||||
|
|
||||||
|
The \c StorageHandler takes the pointer to the \c StorageStruct instance:
|
||||||
|
|
||||||
|
\code
|
||||||
|
static void save(const QString &fileName, const QByteArray &array) { ... }
|
||||||
|
|
||||||
|
TreeStorage<QByteArray> storage;
|
||||||
|
|
||||||
|
const auto onSaverSetup = [storage](ConcurrentCall<void> &concurrent) {
|
||||||
|
concurrent.setConcurrentCallData(&save, "foo.txt", *storage);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Group root {
|
||||||
|
Storage(storage),
|
||||||
|
ConcurrentCallTask(onSaverSetup)
|
||||||
|
};
|
||||||
|
|
||||||
|
TaskTree taskTree(root);
|
||||||
|
auto initStorage = [](QByteArray *storage){
|
||||||
|
*storage = "initial content";
|
||||||
|
};
|
||||||
|
taskTree.onStorageSetup(storage, initStorage);
|
||||||
|
taskTree.start();
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
When the running task tree enters a Group where the \a storage is placed in,
|
||||||
|
it creates a \c StorageStruct instance, ready to be used inside this group.
|
||||||
|
Just after the \c StorageStruct instance is created, and before any handler of this group
|
||||||
|
is called, the task tree invokes the passed \a handler. This enables setting up
|
||||||
|
initial content for the given storage dynamically. Later, when any group's handler is invoked,
|
||||||
|
the task tree activates the created and initialized storage, so that it's available inside
|
||||||
|
any group's handler.
|
||||||
|
|
||||||
|
\sa onStorageDone()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn template <typename StorageStruct, typename StorageHandler> void TaskTree::onStorageDone(const TreeStorage<StorageStruct> &storage, StorageHandler &&handler)
|
||||||
|
|
||||||
|
Installs a storage done \a handler for the \a storage to retrie the final data
|
||||||
|
dynamically from the running task tree.
|
||||||
|
|
||||||
|
The \c StorageHandler takes the pointer to the \c StorageStruct instance:
|
||||||
|
|
||||||
|
\code
|
||||||
|
static QByteArray load(const QString &fileName) { ... }
|
||||||
|
|
||||||
|
TreeStorage<QByteArray> storage;
|
||||||
|
|
||||||
|
const auto onLoaderSetup = [storage](ConcurrentCall<void> &concurrent) {
|
||||||
|
concurrent.setConcurrentCallData(&load, "foo.txt");
|
||||||
|
};
|
||||||
|
const auto onLoaderDone = [storage](const ConcurrentCall<void> &concurrent) {
|
||||||
|
*storage = concurrent.result();
|
||||||
|
};
|
||||||
|
|
||||||
|
const Group root {
|
||||||
|
Storage(storage),
|
||||||
|
ConcurrentCallTask(onLoaderDone, onLoaderDone)
|
||||||
|
};
|
||||||
|
|
||||||
|
TaskTree taskTree(root);
|
||||||
|
auto collectStorage = [](QByteArray *storage){
|
||||||
|
qDebug() << "final content" << *storage;
|
||||||
|
};
|
||||||
|
taskTree.onStorageDone(storage, collectStorage);
|
||||||
|
taskTree.start();
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
When the running task tree is about to leave a Group where the \a storage is placed in,
|
||||||
|
it destructs a \c StorageStruct instance.
|
||||||
|
Just before the \c StorageStruct instance is destructed, and after all possible handlers from
|
||||||
|
this group were called, the task tree invokes the passed \a handler. This enables reading
|
||||||
|
the final content of the given storage dynamically and processing it further outside of
|
||||||
|
the task tree.
|
||||||
|
|
||||||
|
This handler is called also when the running tree is stopped. However, it's not called
|
||||||
|
when the running tree is destructed.
|
||||||
|
|
||||||
|
\sa onStorageSetup()
|
||||||
|
*/
|
||||||
|
|
||||||
void TaskTree::setupStorageHandler(const TreeStorageBase &storage,
|
void TaskTree::setupStorageHandler(const TreeStorageBase &storage,
|
||||||
StorageVoidHandler setupHandler,
|
StorageVoidHandler setupHandler,
|
||||||
StorageVoidHandler doneHandler)
|
StorageVoidHandler doneHandler)
|
||||||
|
|||||||
@@ -108,6 +108,8 @@ expected_str<qint64> ProcessStubCreator::startStubProcess(const ProcessSetupData
|
|||||||
cmdLine.addCommandLineAsArgs(setupData.m_commandLine, CommandLine::Raw);
|
cmdLine.addCommandLineAsArgs(setupData.m_commandLine, CommandLine::Raw);
|
||||||
process->setCommand(cmdLine);
|
process->setCommand(cmdLine);
|
||||||
}
|
}
|
||||||
|
process->setEnvironment(
|
||||||
|
setupData.m_environment.appliedToEnvironment(Environment::systemEnvironment()));
|
||||||
|
|
||||||
process->setEnvironment(setupData.m_environment);
|
process->setEnvironment(setupData.m_environment);
|
||||||
|
|
||||||
|
|||||||
@@ -384,9 +384,13 @@ void TerminalInterface::start()
|
|||||||
|
|
||||||
QTC_ASSERT(d->stubCreator, return);
|
QTC_ASSERT(d->stubCreator, return);
|
||||||
|
|
||||||
ProcessSetupData stubSetupData = m_setup;
|
ProcessSetupData stubSetupData;
|
||||||
stubSetupData.m_commandLine = cmd;
|
stubSetupData.m_commandLine = cmd;
|
||||||
|
|
||||||
|
stubSetupData.m_extraData[TERMINAL_SHELL_NAME]
|
||||||
|
= m_setup.m_extraData.value(TERMINAL_SHELL_NAME,
|
||||||
|
m_setup.m_commandLine.executable().fileName());
|
||||||
|
|
||||||
if (m_setup.m_runAsRoot && !HostOsInfo::isWindowsHost()) {
|
if (m_setup.m_runAsRoot && !HostOsInfo::isWindowsHost()) {
|
||||||
CommandLine rootCommand(FilePath("sudo").searchInPath(), {"-A"});
|
CommandLine rootCommand(FilePath("sudo").searchInPath(), {"-A"});
|
||||||
rootCommand.addCommandLineAsArgs(cmd);
|
rootCommand.addCommandLineAsArgs(cmd);
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ namespace Utils {
|
|||||||
|
|
||||||
class TerminalInterfacePrivate;
|
class TerminalInterfacePrivate;
|
||||||
|
|
||||||
|
const char TERMINAL_SHELL_NAME[] = "Terminal.ShellName";
|
||||||
|
|
||||||
class StubCreator : public QObject
|
class StubCreator : public QObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -25,10 +25,12 @@ AndroidManifestDocument::AndroidManifestDocument(AndroidManifestEditorWidget *ed
|
|||||||
this, &Core::IDocument::changed);
|
this, &Core::IDocument::changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidManifestDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
|
bool AndroidManifestDocument::saveImpl(QString *errorString,
|
||||||
|
const Utils::FilePath &filePath,
|
||||||
|
bool autoSave)
|
||||||
{
|
{
|
||||||
m_editorWidget->preSave();
|
m_editorWidget->preSave();
|
||||||
bool result = TextDocument::save(errorString, filePath, autoSave);
|
bool result = TextDocument::saveImpl(errorString, filePath, autoSave);
|
||||||
m_editorWidget->postSave();
|
m_editorWidget->postSave();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,15 @@ class AndroidManifestDocument : public TextEditor::TextDocument
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit AndroidManifestDocument(AndroidManifestEditorWidget *editorWidget);
|
explicit AndroidManifestDocument(AndroidManifestEditorWidget *editorWidget);
|
||||||
bool save(QString *errorString, const Utils::FilePath &filePath,
|
|
||||||
bool autoSave = false) override;
|
|
||||||
|
|
||||||
bool isModified() const override;
|
bool isModified() const override;
|
||||||
bool isSaveAsAllowed() const override;
|
bool isSaveAsAllowed() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool saveImpl(QString *errorString,
|
||||||
|
const Utils::FilePath &filePath,
|
||||||
|
bool autoSave = false) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AndroidManifestEditorWidget *m_editorWidget;
|
AndroidManifestEditorWidget *m_editorWidget;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -217,17 +217,6 @@ public:
|
|||||||
return type == TypeRemoved ? BehaviorSilent : IDocument::reloadBehavior(state, type);
|
return type == TypeRemoved ? BehaviorSilent : IDocument::reloadBehavior(state, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override
|
|
||||||
{
|
|
||||||
QTC_ASSERT(!autoSave, return true); // bineditor does not support autosave - it would be a bit expensive
|
|
||||||
const FilePath &fileNameToUse = filePath.isEmpty() ? this->filePath() : filePath;
|
|
||||||
if (m_widget->save(errorString, this->filePath(), fileNameToUse)) {
|
|
||||||
setFilePath(fileNameToUse);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenResult open(QString *errorString, const FilePath &filePath,
|
OpenResult open(QString *errorString, const FilePath &filePath,
|
||||||
const FilePath &realFilePath) override
|
const FilePath &realFilePath) override
|
||||||
{
|
{
|
||||||
@@ -320,6 +309,18 @@ public:
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!autoSave, return true); // bineditor does not support autosave - it would be a bit expensive
|
||||||
|
const FilePath &fileNameToUse = filePath.isEmpty() ? this->filePath() : filePath;
|
||||||
|
if (m_widget->save(errorString, this->filePath(), fileNameToUse)) {
|
||||||
|
setFilePath(fileNameToUse);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BinEditorWidget *m_widget;
|
BinEditorWidget *m_widget;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -711,11 +711,11 @@ class ClangdDiagnosticManager : public LanguageClient::DiagnosticManager
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
TextMark *createTextMark(const Utils::FilePath &filePath,
|
TextMark *createTextMark(TextDocument *doc,
|
||||||
const Diagnostic &diagnostic,
|
const Diagnostic &diagnostic,
|
||||||
bool isProjectFile) const override
|
bool isProjectFile) const override
|
||||||
{
|
{
|
||||||
return new ClangdTextMark(filePath, diagnostic, isProjectFile, getClient());
|
return new ClangdTextMark(doc, diagnostic, isProjectFile, getClient());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -263,16 +263,16 @@ Task createTask(const ClangDiagnostic &diagnostic)
|
|||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
ClangdTextMark::ClangdTextMark(const FilePath &filePath,
|
ClangdTextMark::ClangdTextMark(TextEditor::TextDocument *doc,
|
||||||
const Diagnostic &diagnostic,
|
const Diagnostic &diagnostic,
|
||||||
bool isProjectFile,
|
bool isProjectFile,
|
||||||
ClangdClient *client)
|
ClangdClient *client)
|
||||||
: TextEditor::TextMark(filePath,
|
: TextEditor::TextMark(doc,
|
||||||
int(diagnostic.range().start().line() + 1),
|
int(diagnostic.range().start().line() + 1),
|
||||||
{client->name(), client->id()})
|
{client->name(), client->id()})
|
||||||
, m_lspDiagnostic(diagnostic)
|
, m_lspDiagnostic(diagnostic)
|
||||||
, m_diagnostic(
|
, m_diagnostic(
|
||||||
convertDiagnostic(ClangdDiagnostic(diagnostic), filePath, client->hostPathMapper()))
|
convertDiagnostic(ClangdDiagnostic(diagnostic), doc->filePath(), client->hostPathMapper()))
|
||||||
, m_client(client)
|
, m_client(client)
|
||||||
{
|
{
|
||||||
setSettingsPage(CppEditor::Constants::CPP_CLANGD_SETTINGS_ID);
|
setSettingsPage(CppEditor::Constants::CPP_CLANGD_SETTINGS_ID);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class ClangdClient;
|
|||||||
class ClangdTextMark : public TextEditor::TextMark
|
class ClangdTextMark : public TextEditor::TextMark
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ClangdTextMark(const ::Utils::FilePath &filePath,
|
ClangdTextMark(TextEditor::TextDocument *doc,
|
||||||
const LanguageServerProtocol::Diagnostic &diagnostic,
|
const LanguageServerProtocol::Diagnostic &diagnostic,
|
||||||
bool isProjectFile,
|
bool isProjectFile,
|
||||||
ClangdClient *client);
|
ClangdClient *client);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ static bool isBeautifierPluginActivated()
|
|||||||
return std::find_if(specs.begin(),
|
return std::find_if(specs.begin(),
|
||||||
specs.end(),
|
specs.end(),
|
||||||
[](ExtensionSystem::PluginSpec *spec) {
|
[](ExtensionSystem::PluginSpec *spec) {
|
||||||
return spec->name() == "Beautifier";
|
return spec->name() == "Beautifier" && spec->isEffectivelyEnabled();
|
||||||
})
|
})
|
||||||
!= specs.end();
|
!= specs.end();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public:
|
|||||||
Q_UNUSED(RequiresNullTerminator);
|
Q_UNUSED(RequiresNullTerminator);
|
||||||
Q_UNUSED(IsVolatile);
|
Q_UNUSED(IsVolatile);
|
||||||
|
|
||||||
const FilePath path = FilePath::fromString(QString::fromStdString(Name.str()));
|
const FilePath path = FilePath::fromUserInput(QString::fromStdString(Name.str()));
|
||||||
const expected_str<QByteArray> contents = path.fileContents(FileSize, 0);
|
const expected_str<QByteArray> contents = path.fileContents(FileSize, 0);
|
||||||
QTC_ASSERT_EXPECTED(contents, return std::error_code());
|
QTC_ASSERT_EXPECTED(contents, return std::error_code());
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ public:
|
|||||||
|
|
||||||
ErrorOr<Status> status(const Twine &Path) override
|
ErrorOr<Status> status(const Twine &Path) override
|
||||||
{
|
{
|
||||||
const Utils::FilePath path = FilePath::fromString(QString::fromStdString(Path.str()));
|
const FilePath path = FilePath::fromUserInput(QString::fromStdString(Path.str()));
|
||||||
|
|
||||||
QFileInfo fInfo(QString::fromStdString(Path.str()));
|
QFileInfo fInfo(QString::fromStdString(Path.str()));
|
||||||
if (!fInfo.exists())
|
if (!fInfo.exists())
|
||||||
|
|||||||
@@ -426,8 +426,10 @@ CommandLine CMakeBuildStep::cmakeCommand() const
|
|||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}));
|
}));
|
||||||
|
if (m_useStaging->value())
|
||||||
|
cmd.addArg("install");
|
||||||
|
|
||||||
auto bs = qobject_cast<CMakeBuildSystem*>(buildSystem());
|
auto bs = qobject_cast<CMakeBuildSystem *>(buildSystem());
|
||||||
if (bs && bs->isMultiConfigReader()) {
|
if (bs && bs->isMultiConfigReader()) {
|
||||||
cmd.addArg("--config");
|
cmd.addArg("--config");
|
||||||
if (m_configuration)
|
if (m_configuration)
|
||||||
@@ -439,9 +441,6 @@ CommandLine CMakeBuildStep::cmakeCommand() const
|
|||||||
if (!m_cmakeArguments->value().isEmpty())
|
if (!m_cmakeArguments->value().isEmpty())
|
||||||
cmd.addArgs(m_cmakeArguments->value(), CommandLine::Raw);
|
cmd.addArgs(m_cmakeArguments->value(), CommandLine::Raw);
|
||||||
|
|
||||||
if (m_useStaging->value())
|
|
||||||
cmd.addArg("install");
|
|
||||||
|
|
||||||
bool toolArgumentsSpecified = false;
|
bool toolArgumentsSpecified = false;
|
||||||
if (!m_toolArguments->value().isEmpty()) {
|
if (!m_toolArguments->value().isEmpty()) {
|
||||||
cmd.addArg("--");
|
cmd.addArg("--");
|
||||||
|
|||||||
@@ -130,8 +130,8 @@ public:
|
|||||||
class CocoTextMark : public TextEditor::TextMark
|
class CocoTextMark : public TextEditor::TextMark
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CocoTextMark(const FilePath &fileName, const CocoDiagnostic &diag, const Id &clientId)
|
CocoTextMark(TextEditor::TextDocument *doc, const CocoDiagnostic &diag, const Id &clientId)
|
||||||
: TextEditor::TextMark(fileName, diag.range().start().line() + 1, {"Coco", clientId})
|
: TextEditor::TextMark(doc, diag.range().start().line() + 1, {"Coco", clientId})
|
||||||
, m_severity(diag.cocoSeverity())
|
, m_severity(diag.cocoSeverity())
|
||||||
{
|
{
|
||||||
setLineAnnotation(diag.message());
|
setLineAnnotation(diag.message());
|
||||||
@@ -180,13 +180,13 @@ private:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEditor::TextMark *createTextMark(const FilePath &filePath,
|
TextEditor::TextMark *createTextMark(TextEditor::TextDocument *doc,
|
||||||
const Diagnostic &diagnostic,
|
const Diagnostic &diagnostic,
|
||||||
bool /*isProjectFile*/) const override
|
bool /*isProjectFile*/) const override
|
||||||
{
|
{
|
||||||
const CocoDiagnostic cocoDiagnostic(diagnostic);
|
const CocoDiagnostic cocoDiagnostic(diagnostic);
|
||||||
if (std::optional<CocoDiagnosticSeverity> severity = cocoDiagnostic.cocoSeverity())
|
if (std::optional<CocoDiagnosticSeverity> severity = cocoDiagnostic.cocoSeverity())
|
||||||
return new CocoTextMark(filePath, cocoDiagnostic, client()->id());
|
return new CocoTextMark(doc, cocoDiagnostic, client()->id());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,8 +183,24 @@ void CopilotClient::handleCompletions(const GetCompletionRequest::Response &resp
|
|||||||
auto isValidCompletion = [](const Completion &completion) {
|
auto isValidCompletion = [](const Completion &completion) {
|
||||||
return completion.isValid() && !completion.text().trimmed().isEmpty();
|
return completion.isValid() && !completion.text().trimmed().isEmpty();
|
||||||
};
|
};
|
||||||
const QList<Completion> completions = Utils::filtered(result->completions().toListOrEmpty(),
|
QList<Completion> completions = Utils::filtered(result->completions().toListOrEmpty(),
|
||||||
isValidCompletion);
|
isValidCompletion);
|
||||||
|
|
||||||
|
// remove trailing whitespaces from the end of the completions
|
||||||
|
for (Completion &completion : completions) {
|
||||||
|
const LanguageServerProtocol::Range range = completion.range();
|
||||||
|
if (range.start().line() != range.end().line())
|
||||||
|
continue; // do not remove trailing whitespaces for multi-line replacements
|
||||||
|
|
||||||
|
const QString completionText = completion.text();
|
||||||
|
const int end = int(completionText.size()) - 1; // empty strings have been removed above
|
||||||
|
int delta = 0;
|
||||||
|
while (delta <= end && completionText[end - delta].isSpace())
|
||||||
|
++delta;
|
||||||
|
|
||||||
|
if (delta > 0)
|
||||||
|
completion.setText(completionText.chopped(delta));
|
||||||
|
}
|
||||||
if (completions.isEmpty())
|
if (completions.isEmpty())
|
||||||
return;
|
return;
|
||||||
editor->insertSuggestion(
|
editor->insertSuggestion(
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public:
|
|||||||
return typedValue<LanguageServerProtocol::Range>(LanguageServerProtocol::rangeKey);
|
return typedValue<LanguageServerProtocol::Range>(LanguageServerProtocol::rangeKey);
|
||||||
}
|
}
|
||||||
QString text() const { return typedValue<QString>(LanguageServerProtocol::textKey); }
|
QString text() const { return typedValue<QString>(LanguageServerProtocol::textKey); }
|
||||||
|
void setText(const QString &text) { insert(LanguageServerProtocol::textKey, text); }
|
||||||
QString uuid() const { return typedValue<QString>(uuidKey); }
|
QString uuid() const { return typedValue<QString>(uuidKey); }
|
||||||
|
|
||||||
bool isValid() const override
|
bool isValid() const override
|
||||||
|
|||||||
@@ -181,6 +181,26 @@
|
|||||||
\sa reload()
|
\sa reload()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn Core::IDocument::aboutToSave(const Utils::FilePath &filePath, bool autoSave)
|
||||||
|
|
||||||
|
This signal is emitted before the document is saved to \a filePath.
|
||||||
|
|
||||||
|
\a autoSave indicates whether this save was triggered by the auto save timer.
|
||||||
|
|
||||||
|
\sa save()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn Core::IDocument::saved(const Utils::FilePath &filePath, bool autoSave)
|
||||||
|
|
||||||
|
This signal is emitted after the document was saved to \a filePath.
|
||||||
|
|
||||||
|
\a autoSave indicates whether this save was triggered by the auto save timer.
|
||||||
|
|
||||||
|
\sa save()
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn Core::IDocument::filePathChanged(const Utils::FilePath &oldName, const Utils::FilePath &newName)
|
\fn Core::IDocument::filePathChanged(const Utils::FilePath &oldName, const Utils::FilePath &newName)
|
||||||
|
|
||||||
@@ -315,11 +335,35 @@ IDocument::OpenResult IDocument::open(QString *errorString, const Utils::FilePat
|
|||||||
|
|
||||||
Returns whether saving was successful.
|
Returns whether saving was successful.
|
||||||
|
|
||||||
The default implementation does nothing and returns \c false.
|
If saving was successful saved is emitted.
|
||||||
|
|
||||||
\sa shouldAutoSave()
|
\sa shouldAutoSave()
|
||||||
|
\sa aboutToSave()
|
||||||
|
\sa saved()
|
||||||
*/
|
*/
|
||||||
bool IDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
|
bool IDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
|
||||||
|
{
|
||||||
|
emit aboutToSave(filePath, autoSave);
|
||||||
|
const bool success = saveImpl(errorString, filePath, autoSave);
|
||||||
|
if (success)
|
||||||
|
emit saved(filePath, autoSave);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Implementation of saving the contents of the document to the \a filePath on disk.
|
||||||
|
|
||||||
|
If \a autoSave is \c true, the saving is done for an auto-save, so the
|
||||||
|
document should avoid cleanups or other operations that it does for
|
||||||
|
user-requested saves.
|
||||||
|
|
||||||
|
Use \a errorString to return an error message if saving failed.
|
||||||
|
|
||||||
|
Returns whether saving was successful.
|
||||||
|
|
||||||
|
The default implementation does nothing and returns \c false.
|
||||||
|
*/
|
||||||
|
bool IDocument::saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
|
||||||
{
|
{
|
||||||
Q_UNUSED(errorString)
|
Q_UNUSED(errorString)
|
||||||
Q_UNUSED(filePath)
|
Q_UNUSED(filePath)
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ public:
|
|||||||
|
|
||||||
virtual OpenResult open(QString *errorString, const Utils::FilePath &filePath, const Utils::FilePath &realFilePath);
|
virtual OpenResult open(QString *errorString, const Utils::FilePath &filePath, const Utils::FilePath &realFilePath);
|
||||||
|
|
||||||
virtual bool save(QString *errorString, const Utils::FilePath &filePath = Utils::FilePath(), bool autoSave = false);
|
bool save(QString *errorString, const Utils::FilePath &filePath = Utils::FilePath(), bool autoSave = false);
|
||||||
|
|
||||||
virtual QByteArray contents() const;
|
virtual QByteArray contents() const;
|
||||||
virtual bool setContents(const QByteArray &contents);
|
virtual bool setContents(const QByteArray &contents);
|
||||||
@@ -124,9 +124,16 @@ signals:
|
|||||||
|
|
||||||
void aboutToReload();
|
void aboutToReload();
|
||||||
void reloadFinished(bool success);
|
void reloadFinished(bool success);
|
||||||
|
void aboutToSave(const Utils::FilePath &filePath, bool autoSave);
|
||||||
|
void saved(const Utils::FilePath &filePath, bool autoSave);
|
||||||
|
|
||||||
void filePathChanged(const Utils::FilePath &oldName, const Utils::FilePath &newName);
|
void filePathChanged(const Utils::FilePath &oldName, const Utils::FilePath &newName);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool saveImpl(QString *errorString,
|
||||||
|
const Utils::FilePath &filePath = Utils::FilePath(),
|
||||||
|
bool autoSave = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Internal::IDocumentPrivate *d;
|
Internal::IDocumentPrivate *d;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -435,10 +435,10 @@ TextEditor::TabSettings CppEditorDocument::tabSettings() const
|
|||||||
return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings());
|
return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CppEditorDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
|
bool CppEditorDocument::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
|
||||||
{
|
{
|
||||||
if (!indenter()->formatOnSave() || autoSave)
|
if (!indenter()->formatOnSave() || autoSave)
|
||||||
return TextEditor::TextDocument::save(errorString, filePath, autoSave);
|
return TextEditor::TextDocument::saveImpl(errorString, filePath, autoSave);
|
||||||
|
|
||||||
auto *layout = qobject_cast<TextEditor::TextDocumentLayout *>(document()->documentLayout());
|
auto *layout = qobject_cast<TextEditor::TextDocumentLayout *>(document()->documentLayout());
|
||||||
const int documentRevision = layout->lastSaveRevision;
|
const int documentRevision = layout->lastSaveRevision;
|
||||||
@@ -476,7 +476,7 @@ bool CppEditorDocument::save(QString *errorString, const FilePath &filePath, boo
|
|||||||
settings.m_cleanWhitespace = false;
|
settings.m_cleanWhitespace = false;
|
||||||
setStorageSettings(settings);
|
setStorageSettings(settings);
|
||||||
|
|
||||||
return TextEditor::TextDocument::save(errorString, filePath, autoSave);
|
return TextEditor::TextDocument::saveImpl(errorString, filePath, autoSave);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CppEditorDocument::usesClangd() const
|
bool CppEditorDocument::usesClangd() const
|
||||||
|
|||||||
@@ -47,10 +47,6 @@ public:
|
|||||||
QFuture<CursorInfo> cursorInfo(const CursorInfoParams ¶ms);
|
QFuture<CursorInfo> cursorInfo(const CursorInfoParams ¶ms);
|
||||||
TextEditor::TabSettings tabSettings() const override;
|
TextEditor::TabSettings tabSettings() const override;
|
||||||
|
|
||||||
bool save(QString *errorString,
|
|
||||||
const Utils::FilePath &filePath = Utils::FilePath(),
|
|
||||||
bool autoSave = false) override;
|
|
||||||
|
|
||||||
bool usesClangd() const;
|
bool usesClangd() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -68,8 +64,12 @@ signals:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void applyFontSettings() override;
|
void applyFontSettings() override;
|
||||||
|
bool saveImpl(QString *errorString,
|
||||||
|
const Utils::FilePath &filePath = Utils::FilePath(),
|
||||||
|
bool autoSave = false) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void invalidateFormatterCache();
|
void invalidateFormatterCache();
|
||||||
void onFilePathChanged(const Utils::FilePath &oldPath, const Utils::FilePath &newPath);
|
void onFilePathChanged(const Utils::FilePath &oldPath, const Utils::FilePath &newPath);
|
||||||
void onMimeTypeChanged();
|
void onMimeTypeChanged();
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ Core::IDocument::OpenResult FormWindowFile::open(QString *errorString,
|
|||||||
return OpenResult::Success;
|
return OpenResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FormWindowFile::save(QString *errorString, const FilePath &filePath, bool autoSave)
|
bool FormWindowFile::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
|
||||||
{
|
{
|
||||||
const FilePath &actualName = filePath.isEmpty() ? this->filePath() : filePath;
|
const FilePath &actualName = filePath.isEmpty() ? this->filePath() : filePath;
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ public:
|
|||||||
// IDocument
|
// IDocument
|
||||||
OpenResult open(QString *errorString, const Utils::FilePath &filePath,
|
OpenResult open(QString *errorString, const Utils::FilePath &filePath,
|
||||||
const Utils::FilePath &realFilePath) override;
|
const Utils::FilePath &realFilePath) override;
|
||||||
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
|
||||||
QByteArray contents() const override;
|
QByteArray contents() const override;
|
||||||
bool setContents(const QByteArray &contents) override;
|
bool setContents(const QByteArray &contents) override;
|
||||||
bool shouldAutoSave() const override;
|
bool shouldAutoSave() const override;
|
||||||
@@ -52,6 +51,9 @@ public:
|
|||||||
void setShouldAutoSave(bool sad = true) { m_shouldAutoSave = sad; }
|
void setShouldAutoSave(bool sad = true) { m_shouldAutoSave = sad; }
|
||||||
void updateIsModified();
|
void updateIsModified();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void slotFormWindowRemoved(QDesignerFormWindowInterface *w);
|
void slotFormWindowRemoved(QDesignerFormWindowInterface *w);
|
||||||
|
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ bool DiffEditorDocument::isSaveAsAllowed() const
|
|||||||
return state() == LoadOK;
|
return state() == LoadOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiffEditorDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
|
bool DiffEditorDocument::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
|
||||||
{
|
{
|
||||||
Q_UNUSED(errorString)
|
Q_UNUSED(errorString)
|
||||||
Q_UNUSED(autoSave)
|
Q_UNUSED(autoSave)
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ public:
|
|||||||
QString fallbackSaveAsFileName() const override;
|
QString fallbackSaveAsFileName() const override;
|
||||||
|
|
||||||
bool isSaveAsAllowed() const override;
|
bool isSaveAsAllowed() const override;
|
||||||
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
|
||||||
void reload();
|
void reload();
|
||||||
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
|
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
|
||||||
OpenResult open(QString *errorString, const Utils::FilePath &filePath,
|
OpenResult open(QString *errorString, const Utils::FilePath &filePath,
|
||||||
@@ -75,6 +74,9 @@ signals:
|
|||||||
void documentChanged();
|
void documentChanged();
|
||||||
void descriptionChanged();
|
void descriptionChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void beginReload();
|
void beginReload();
|
||||||
void endReload(bool success);
|
void endReload(bool success);
|
||||||
|
|||||||
@@ -277,10 +277,14 @@ public:
|
|||||||
{
|
{
|
||||||
QObject::disconnect(contentsChangedConnection);
|
QObject::disconnect(contentsChangedConnection);
|
||||||
QObject::disconnect(filePathChangedConnection);
|
QObject::disconnect(filePathChangedConnection);
|
||||||
|
QObject::disconnect(aboutToSaveConnection);
|
||||||
|
QObject::disconnect(savedConnection);
|
||||||
delete document;
|
delete document;
|
||||||
}
|
}
|
||||||
QMetaObject::Connection contentsChangedConnection;
|
QMetaObject::Connection contentsChangedConnection;
|
||||||
QMetaObject::Connection filePathChangedConnection;
|
QMetaObject::Connection filePathChangedConnection;
|
||||||
|
QMetaObject::Connection aboutToSaveConnection;
|
||||||
|
QMetaObject::Connection savedConnection;
|
||||||
QTextDocument *document = nullptr;
|
QTextDocument *document = nullptr;
|
||||||
};
|
};
|
||||||
QMap<TextEditor::TextDocument *, OpenedDocument> m_openedDocument;
|
QMap<TextEditor::TextDocument *, OpenedDocument> m_openedDocument;
|
||||||
@@ -648,6 +652,22 @@ void Client::openDocument(TextEditor::TextDocument *document)
|
|||||||
if (isSupportedDocument(document))
|
if (isSupportedDocument(document))
|
||||||
openDocument(document);
|
openDocument(document);
|
||||||
});
|
});
|
||||||
|
d->m_openedDocument[document].savedConnection
|
||||||
|
= connect(document,
|
||||||
|
&TextDocument::saved,
|
||||||
|
this,
|
||||||
|
[this, document](const FilePath &saveFilePath) {
|
||||||
|
if (saveFilePath == document->filePath())
|
||||||
|
documentContentsSaved(document);
|
||||||
|
});
|
||||||
|
d->m_openedDocument[document].aboutToSaveConnection
|
||||||
|
= connect(document,
|
||||||
|
&TextDocument::aboutToSave,
|
||||||
|
this,
|
||||||
|
[this, document](const FilePath &saveFilePath) {
|
||||||
|
if (saveFilePath == document->filePath())
|
||||||
|
documentWillSave(document);
|
||||||
|
});
|
||||||
if (!d->m_documentVersions.contains(filePath))
|
if (!d->m_documentVersions.contains(filePath))
|
||||||
d->m_documentVersions[filePath] = 0;
|
d->m_documentVersions[filePath] = 0;
|
||||||
d->sendOpenNotification(filePath, document->mimeType(), document->plainText(),
|
d->sendOpenNotification(filePath, document->mimeType(), document->plainText(),
|
||||||
|
|||||||
@@ -31,10 +31,8 @@ namespace LanguageClient {
|
|||||||
class TextMark : public TextEditor::TextMark
|
class TextMark : public TextEditor::TextMark
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TextMark(const FilePath &fileName, const Diagnostic &diag, const Client *client)
|
TextMark(TextDocument *doc, const Diagnostic &diag, const Client *client)
|
||||||
: TextEditor::TextMark(fileName,
|
: TextEditor::TextMark(doc, diag.range().start().line() + 1, {client->name(), client->id()})
|
||||||
diag.range().start().line() + 1,
|
|
||||||
{client->name(), client->id()})
|
|
||||||
{
|
{
|
||||||
setLineAnnotation(diag.message());
|
setLineAnnotation(diag.message());
|
||||||
setToolTip(diag.message());
|
setToolTip(diag.message());
|
||||||
@@ -106,7 +104,7 @@ void DiagnosticManager::showDiagnostics(const FilePath &filePath, int version)
|
|||||||
= createDiagnosticSelection(diagnostic, doc->document());
|
= createDiagnosticSelection(diagnostic, doc->document());
|
||||||
if (!selection.cursor.isNull())
|
if (!selection.cursor.isNull())
|
||||||
extraSelections << selection;
|
extraSelections << selection;
|
||||||
if (TextEditor::TextMark *mark = createTextMark(filePath, diagnostic, isProjectFile))
|
if (TextEditor::TextMark *mark = createTextMark(doc, diagnostic, isProjectFile))
|
||||||
marks.marks.append(mark);
|
marks.marks.append(mark);
|
||||||
}
|
}
|
||||||
if (!marks.marks.isEmpty())
|
if (!marks.marks.isEmpty())
|
||||||
@@ -118,13 +116,13 @@ void DiagnosticManager::showDiagnostics(const FilePath &filePath, int version)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEditor::TextMark *DiagnosticManager::createTextMark(const FilePath &filePath,
|
TextEditor::TextMark *DiagnosticManager::createTextMark(TextDocument *doc,
|
||||||
const Diagnostic &diagnostic,
|
const Diagnostic &diagnostic,
|
||||||
bool /*isProjectFile*/) const
|
bool /*isProjectFile*/) const
|
||||||
{
|
{
|
||||||
static const auto icon = QIcon::fromTheme("edit-copy", Utils::Icons::COPY.icon());
|
static const auto icon = QIcon::fromTheme("edit-copy", Utils::Icons::COPY.icon());
|
||||||
static const QString tooltip = Tr::tr("Copy to Clipboard");
|
static const QString tooltip = Tr::tr("Copy to Clipboard");
|
||||||
auto mark = new TextMark(filePath, diagnostic, m_client);
|
auto mark = new TextMark(doc, diagnostic, m_client);
|
||||||
mark->setActionsProvider([text = diagnostic.message()] {
|
mark->setActionsProvider([text = diagnostic.message()] {
|
||||||
QAction *action = new QAction();
|
QAction *action = new QAction();
|
||||||
action->setIcon(icon);
|
action->setIcon(icon);
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ signals:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
Client *client() const { return m_client; }
|
Client *client() const { return m_client; }
|
||||||
virtual TextEditor::TextMark *createTextMark(const Utils::FilePath &filePath,
|
virtual TextEditor::TextMark *createTextMark(TextEditor::TextDocument *doc,
|
||||||
const LanguageServerProtocol::Diagnostic &diagnostic,
|
const LanguageServerProtocol::Diagnostic &diagnostic,
|
||||||
bool isProjectFile) const;
|
bool isProjectFile) const;
|
||||||
virtual QTextEdit::ExtraSelection createDiagnosticSelection(
|
virtual QTextEdit::ExtraSelection createDiagnosticSelection(
|
||||||
|
|||||||
@@ -63,10 +63,6 @@ LanguageClientManager::LanguageClientManager(QObject *parent)
|
|||||||
this, &LanguageClientManager::documentOpened);
|
this, &LanguageClientManager::documentOpened);
|
||||||
connect(EditorManager::instance(), &EditorManager::documentClosed,
|
connect(EditorManager::instance(), &EditorManager::documentClosed,
|
||||||
this, &LanguageClientManager::documentClosed);
|
this, &LanguageClientManager::documentClosed);
|
||||||
connect(EditorManager::instance(), &EditorManager::saved,
|
|
||||||
this, &LanguageClientManager::documentContentsSaved);
|
|
||||||
connect(EditorManager::instance(), &EditorManager::aboutToSave,
|
|
||||||
this, &LanguageClientManager::documentWillSave);
|
|
||||||
connect(ProjectManager::instance(), &ProjectManager::projectAdded,
|
connect(ProjectManager::instance(), &ProjectManager::projectAdded,
|
||||||
this, &LanguageClientManager::projectAdded);
|
this, &LanguageClientManager::projectAdded);
|
||||||
connect(ProjectManager::instance(), &ProjectManager::projectRemoved,
|
connect(ProjectManager::instance(), &ProjectManager::projectRemoved,
|
||||||
@@ -550,24 +546,6 @@ void LanguageClientManager::documentClosed(Core::IDocument *document)
|
|||||||
m_clientForDocument.remove(textDocument);
|
m_clientForDocument.remove(textDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanguageClientManager::documentContentsSaved(Core::IDocument *document)
|
|
||||||
{
|
|
||||||
if (auto textDocument = qobject_cast<TextEditor::TextDocument *>(document)) {
|
|
||||||
const QList<Client *> &clients = reachableClients();
|
|
||||||
for (Client *client : clients)
|
|
||||||
client->documentContentsSaved(textDocument);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LanguageClientManager::documentWillSave(Core::IDocument *document)
|
|
||||||
{
|
|
||||||
if (auto textDocument = qobject_cast<TextEditor::TextDocument *>(document)) {
|
|
||||||
const QList<Client *> &clients = reachableClients();
|
|
||||||
for (Client *client : clients)
|
|
||||||
client->documentWillSave(textDocument);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LanguageClientManager::updateProject(ProjectExplorer::Project *project)
|
void LanguageClientManager::updateProject(ProjectExplorer::Project *project)
|
||||||
{
|
{
|
||||||
for (BaseSettings *setting : std::as_const(m_currentSettings)) {
|
for (BaseSettings *setting : std::as_const(m_currentSettings)) {
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ private:
|
|||||||
void editorOpened(Core::IEditor *editor);
|
void editorOpened(Core::IEditor *editor);
|
||||||
void documentOpened(Core::IDocument *document);
|
void documentOpened(Core::IDocument *document);
|
||||||
void documentClosed(Core::IDocument *document);
|
void documentClosed(Core::IDocument *document);
|
||||||
void documentContentsSaved(Core::IDocument *document);
|
|
||||||
void documentWillSave(Core::IDocument *document);
|
|
||||||
|
|
||||||
void updateProject(ProjectExplorer::Project *project);
|
void updateProject(ProjectExplorer::Project *project);
|
||||||
void projectAdded(ProjectExplorer::Project *project);
|
void projectAdded(ProjectExplorer::Project *project);
|
||||||
|
|||||||
@@ -146,9 +146,9 @@ const QString stmCubeProgrammerDetectionPath{HostOsInfo::isWindowsHost()
|
|||||||
? QString("bin/STM32_Programmer_CLI.exe")
|
? QString("bin/STM32_Programmer_CLI.exe")
|
||||||
: QString("bin/STM32_Programmer.sh")};
|
: QString("bin/STM32_Programmer.sh")};
|
||||||
|
|
||||||
const char renesasProgrammerSetting[]{"FlashProgrammerPath"};
|
const char renesasProgrammerSetting[]{"RenesasFlashProgrammer"};
|
||||||
const char renesasProgrammerCmakeVar[]{"RENESAS_FLASH_PROGRAMMER_PATH"};
|
const char renesasProgrammerCmakeVar[]{"RENESAS_FLASH_PROGRAMMER_PATH"};
|
||||||
const QString renesasProgrammerEnvVar{"RenesasFlashProgrammer_PATH"};
|
const char renesasProgrammerEnvVar[]{"RENESAS_FLASH_PROGRAMMER_PATH"};
|
||||||
const char renesasProgrammerLabel[]{"Renesas Flash Programmer"};
|
const char renesasProgrammerLabel[]{"Renesas Flash Programmer"};
|
||||||
const QString renesasProgrammerDetectionPath{HostOsInfo::withExecutableSuffix("rfp-cli")};
|
const QString renesasProgrammerDetectionPath{HostOsInfo::withExecutableSuffix("rfp-cli")};
|
||||||
|
|
||||||
@@ -1539,9 +1539,9 @@ void McuSupportTest::test_legacy_createThirdPartyPackage_data()
|
|||||||
<< PackageCreator{[this]() {
|
<< PackageCreator{[this]() {
|
||||||
return Legacy::createRenesasProgrammerPackage(settingsMockPtr);
|
return Legacy::createRenesasProgrammerPackage(settingsMockPtr);
|
||||||
}}
|
}}
|
||||||
<< ghs_rh850_d1m1a_baremetal_json << defaultToolPath << defaultToolPath
|
<< ghs_rh850_d1m1a_baremetal_json << empty << empty << renesasProgrammerSetting
|
||||||
<< renesasProgrammerSetting << renesasProgrammerCmakeVar << renesasProgrammerEnvVar
|
<< renesasProgrammerCmakeVar << renesasProgrammerEnvVar << renesasProgrammerLabel
|
||||||
<< renesasProgrammerLabel << renesasProgrammerDetectionPath;
|
<< renesasProgrammerDetectionPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void McuSupportTest::test_legacy_createThirdPartyPackage()
|
void McuSupportTest::test_legacy_createThirdPartyPackage()
|
||||||
@@ -1574,7 +1574,53 @@ void McuSupportTest::test_legacy_createThirdPartyPackage()
|
|||||||
|
|
||||||
void McuSupportTest::test_createThirdPartyPackage_data()
|
void McuSupportTest::test_createThirdPartyPackage_data()
|
||||||
{
|
{
|
||||||
test_legacy_createThirdPartyPackage_data();
|
QTest::addColumn<QString>("json");
|
||||||
|
QTest::addColumn<QString>("path");
|
||||||
|
QTest::addColumn<QString>("defaultPath");
|
||||||
|
QTest::addColumn<QString>("setting");
|
||||||
|
QTest::addColumn<QString>("cmakeVar");
|
||||||
|
QTest::addColumn<QString>("envVar");
|
||||||
|
QTest::addColumn<QString>("label");
|
||||||
|
QTest::addColumn<QString>("detectionPath");
|
||||||
|
|
||||||
|
// Sometimes the jsons have different values than the legacy packages
|
||||||
|
// Enter the expected values from the jsons here when they diverge from legacy values
|
||||||
|
QString programFiles = qtcEnvironmentVariable("Env:PROGRAMFILES(x86)");
|
||||||
|
const QString renesasProgrammerDefaultPath = {
|
||||||
|
HostOsInfo::isWindowsHost()
|
||||||
|
? QString("%1/Renesas Electronics/Programming Tools/Renesas "
|
||||||
|
"Flash Programmer V3.09").arg(programFiles)
|
||||||
|
: QString("")};
|
||||||
|
|
||||||
|
QTest::newRow("armgcc_mimxrt1050_evk_freertos_json mcuXpresso")
|
||||||
|
<< armgcc_mimxrt1050_evk_freertos_json << xpressoIdePath << xpressoIdePath
|
||||||
|
<< xpressoIdeSetting << xpressoIdeCmakeVar << xpressoIdeEnvVar << xpressoIdeLabel
|
||||||
|
<< xpressoIdeDetectionPath;
|
||||||
|
|
||||||
|
QTest::newRow("armgcc_mimxrt1064_evk_freertos_json mcuXpresso")
|
||||||
|
<< armgcc_mimxrt1064_evk_freertos_json << xpressoIdePath << xpressoIdePath
|
||||||
|
<< xpressoIdeSetting << xpressoIdeCmakeVar << xpressoIdeEnvVar << xpressoIdeLabel
|
||||||
|
<< xpressoIdeDetectionPath;
|
||||||
|
|
||||||
|
QTest::newRow("armgcc_mimxrt1170_evk_freertos_json mcuXpresso")
|
||||||
|
<< armgcc_mimxrt1170_evk_freertos_json << xpressoIdePath << xpressoIdePath
|
||||||
|
<< xpressoIdeSetting << xpressoIdeCmakeVar << xpressoIdeEnvVar << xpressoIdeLabel
|
||||||
|
<< xpressoIdeDetectionPath;
|
||||||
|
|
||||||
|
QTest::newRow("armgcc_stm32h750b_discovery_baremetal_json stmCubeProgrammer")
|
||||||
|
<< armgcc_stm32h750b_discovery_baremetal_json << stmCubeProgrammerPath
|
||||||
|
<< stmCubeProgrammerPath << stmCubeProgrammerSetting << empty << empty
|
||||||
|
<< stmCubeProgrammerLabel << stmCubeProgrammerDetectionPath;
|
||||||
|
|
||||||
|
QTest::newRow("armgcc_stm32f769i_discovery_freertos_json stmCubeProgrammer")
|
||||||
|
<< armgcc_stm32f769i_discovery_freertos_json << stmCubeProgrammerPath
|
||||||
|
<< stmCubeProgrammerPath << stmCubeProgrammerSetting << empty << empty
|
||||||
|
<< stmCubeProgrammerLabel << stmCubeProgrammerDetectionPath;
|
||||||
|
|
||||||
|
QTest::newRow("ghs_rh850_d1m1a_baremetal_json renesasProgrammer")
|
||||||
|
<< ghs_rh850_d1m1a_baremetal_json << renesasProgrammerDefaultPath << empty
|
||||||
|
<< "FlashProgrammerPath" << renesasProgrammerCmakeVar << "RenesasFlashProgrammer_PATH"
|
||||||
|
<< renesasProgrammerLabel << renesasProgrammerDetectionPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void McuSupportTest::test_createThirdPartyPackage()
|
void McuSupportTest::test_createThirdPartyPackage()
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ Core::IDocument::OpenResult ModelDocument::open(QString *errorString,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
|
bool ModelDocument::saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
|
||||||
{
|
{
|
||||||
if (!d->documentController) {
|
if (!d->documentController) {
|
||||||
*errorString = Tr::tr("No model loaded. Cannot save.");
|
*errorString = Tr::tr("No model loaded. Cannot save.");
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ public:
|
|||||||
OpenResult open(QString *errorString,
|
OpenResult open(QString *errorString,
|
||||||
const Utils::FilePath &filePath,
|
const Utils::FilePath &filePath,
|
||||||
const Utils::FilePath &realFilePath) override;
|
const Utils::FilePath &realFilePath) override;
|
||||||
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
|
||||||
bool shouldAutoSave() const override;
|
bool shouldAutoSave() const override;
|
||||||
bool isModified() const override;
|
bool isModified() const override;
|
||||||
bool isSaveAsAllowed() const override;
|
bool isSaveAsAllowed() const override;
|
||||||
@@ -39,6 +38,9 @@ public:
|
|||||||
|
|
||||||
OpenResult load(QString *errorString, const QString &fileName);
|
OpenResult load(QString *errorString, const QString &fileName);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ModelDocumentPrivate *d;
|
ModelDocumentPrivate *d;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -61,7 +61,9 @@ static const QList<Target *> targetsForSelection(const Project *project,
|
|||||||
{
|
{
|
||||||
if (targetSelection == ConfigSelection::All)
|
if (targetSelection == ConfigSelection::All)
|
||||||
return project->targets();
|
return project->targets();
|
||||||
|
if (project->activeTarget())
|
||||||
return {project->activeTarget()};
|
return {project->activeTarget()};
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QList<BuildConfiguration *> buildConfigsForSelection(const Target *target,
|
static const QList<BuildConfiguration *> buildConfigsForSelection(const Target *target,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <utils/process.h>
|
#include <utils/process.h>
|
||||||
#include <utils/processinterface.h>
|
#include <utils/processinterface.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/terminalinterface.h>
|
||||||
#include <utils/utilsicons.h>
|
#include <utils/utilsicons.h>
|
||||||
|
|
||||||
#include <coreplugin/icontext.h>
|
#include <coreplugin/icontext.h>
|
||||||
@@ -1348,9 +1349,12 @@ void SimpleTargetRunnerPrivate::start()
|
|||||||
|
|
||||||
m_stopRequested = false;
|
m_stopRequested = false;
|
||||||
|
|
||||||
|
QVariantHash extraData = m_extraData;
|
||||||
|
extraData[TERMINAL_SHELL_NAME] = m_command.executable().fileName();
|
||||||
|
|
||||||
m_process.setCommand(cmdLine);
|
m_process.setCommand(cmdLine);
|
||||||
m_process.setEnvironment(env);
|
m_process.setEnvironment(env);
|
||||||
m_process.setExtraData(m_extraData);
|
m_process.setExtraData(extraData);
|
||||||
|
|
||||||
m_state = Run;
|
m_state = Run;
|
||||||
m_process.setWorkingDirectory(m_workingDirectory);
|
m_process.setWorkingDirectory(m_workingDirectory);
|
||||||
|
|||||||
@@ -120,9 +120,8 @@ static QJsonObject readObjJson(const FilePath &projectFile, QString *errorMessag
|
|||||||
|
|
||||||
static QStringList readLines(const FilePath &projectFile)
|
static QStringList readLines(const FilePath &projectFile)
|
||||||
{
|
{
|
||||||
const QString projectFileName = projectFile.fileName();
|
QSet<QString> visited;
|
||||||
QSet<QString> visited = { projectFileName };
|
QStringList lines;
|
||||||
QStringList lines = { projectFileName };
|
|
||||||
|
|
||||||
const expected_str<QByteArray> contents = projectFile.fileContents();
|
const expected_str<QByteArray> contents = projectFile.fileContents();
|
||||||
if (contents) {
|
if (contents) {
|
||||||
@@ -144,9 +143,8 @@ static QStringList readLines(const FilePath &projectFile)
|
|||||||
|
|
||||||
static QStringList readLinesJson(const FilePath &projectFile, QString *errorMessage)
|
static QStringList readLinesJson(const FilePath &projectFile, QString *errorMessage)
|
||||||
{
|
{
|
||||||
const QString projectFileName = projectFile.fileName();
|
QSet<QString> visited;
|
||||||
QSet<QString> visited = { projectFileName };
|
QStringList lines;
|
||||||
QStringList lines = { projectFileName };
|
|
||||||
|
|
||||||
const QJsonObject obj = readObjJson(projectFile, errorMessage);
|
const QJsonObject obj = readObjJson(projectFile, errorMessage);
|
||||||
for (const QJsonValue &file : obj.value("files").toArray()) {
|
for (const QJsonValue &file : obj.value("files").toArray()) {
|
||||||
@@ -205,8 +203,6 @@ static FileType getFileType(const FilePath &f)
|
|||||||
{
|
{
|
||||||
if (f.endsWith(".py"))
|
if (f.endsWith(".py"))
|
||||||
return FileType::Source;
|
return FileType::Source;
|
||||||
if (f.endsWith(".pyproject") || f.endsWith(".pyqtc"))
|
|
||||||
return FileType::Project;
|
|
||||||
if (f.endsWith(".qrc"))
|
if (f.endsWith(".qrc"))
|
||||||
return FileType::Resource;
|
return FileType::Resource;
|
||||||
if (f.endsWith(".ui"))
|
if (f.endsWith(".ui"))
|
||||||
@@ -221,11 +217,16 @@ void PythonBuildSystem::triggerParsing()
|
|||||||
ParseGuard guard = guardParsingRun();
|
ParseGuard guard = guardParsingRun();
|
||||||
parse();
|
parse();
|
||||||
|
|
||||||
const QDir baseDir(projectDirectory().toString());
|
|
||||||
QList<BuildTargetInfo> appTargets;
|
QList<BuildTargetInfo> appTargets;
|
||||||
|
|
||||||
auto newRoot = std::make_unique<PythonProjectNode>(projectDirectory());
|
auto newRoot = std::make_unique<PythonProjectNode>(projectDirectory());
|
||||||
for (const FileEntry &entry: std::as_const(m_files)) {
|
|
||||||
|
const FilePath projectFile = projectFilePath();
|
||||||
|
const QString displayName = projectFile.relativePathFrom(projectDirectory()).toUserOutput();
|
||||||
|
newRoot->addNestedNode(
|
||||||
|
std::make_unique<PythonFileNode>(projectFile, displayName, FileType::Project));
|
||||||
|
|
||||||
|
for (const FileEntry &entry : std::as_const(m_files)) {
|
||||||
const QString displayName = entry.filePath.relativePathFrom(projectDirectory()).toUserOutput();
|
const QString displayName = entry.filePath.relativePathFrom(projectDirectory()).toUserOutput();
|
||||||
const FileType fileType = getFileType(entry.filePath);
|
const FileType fileType = getFileType(entry.filePath);
|
||||||
|
|
||||||
@@ -236,7 +237,7 @@ void PythonBuildSystem::triggerParsing()
|
|||||||
bti.displayName = displayName;
|
bti.displayName = displayName;
|
||||||
bti.buildKey = entry.filePath.toString();
|
bti.buildKey = entry.filePath.toString();
|
||||||
bti.targetFilePath = entry.filePath;
|
bti.targetFilePath = entry.filePath;
|
||||||
bti.projectFilePath = projectFilePath();
|
bti.projectFilePath = projectFile;
|
||||||
bti.isQtcRunnable = entry.filePath.fileName() == "main.py";
|
bti.isQtcRunnable = entry.filePath.fileName() == "main.py";
|
||||||
appTargets.append(bti);
|
appTargets.append(bti);
|
||||||
}
|
}
|
||||||
@@ -301,12 +302,21 @@ bool PythonBuildSystem::addFiles(Node *, const FilePaths &filePaths, FilePaths *
|
|||||||
{
|
{
|
||||||
const Utils::FilePath projectDir = projectDirectory();
|
const Utils::FilePath projectDir = projectDirectory();
|
||||||
|
|
||||||
|
auto comp = [](const FileEntry &left, const FileEntry &right) {
|
||||||
|
return left.rawEntry < right.rawEntry;
|
||||||
|
};
|
||||||
|
|
||||||
|
const bool isSorted = std::is_sorted(m_files.begin(), m_files.end(), comp);
|
||||||
|
|
||||||
for (const FilePath &filePath : filePaths) {
|
for (const FilePath &filePath : filePaths) {
|
||||||
if (!projectDir.isSameDevice(filePath))
|
if (!projectDir.isSameDevice(filePath))
|
||||||
return false;
|
return false;
|
||||||
m_files.append(FileEntry{filePath.relativePathFrom(projectDir).toString(), filePath});
|
m_files.append(FileEntry{filePath.relativePathFrom(projectDir).toString(), filePath});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isSorted)
|
||||||
|
std::sort(m_files.begin(), m_files.end(), comp);
|
||||||
|
|
||||||
return save();
|
return save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,10 +120,10 @@ Core::IDocument::OpenResult ResourceEditorDocument::open(QString *errorString,
|
|||||||
return OpenResult::Success;
|
return OpenResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ResourceEditorDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
|
bool ResourceEditorDocument::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
|
||||||
{
|
{
|
||||||
if (debugResourceEditorW)
|
if (debugResourceEditorW)
|
||||||
qDebug() << ">ResourceEditorW::save: " << filePath;
|
qDebug() << ">ResourceEditorW::saveImpl: " << filePath;
|
||||||
|
|
||||||
const FilePath &actualName = filePath.isEmpty() ? this->filePath() : filePath;
|
const FilePath &actualName = filePath.isEmpty() ? this->filePath() : filePath;
|
||||||
if (actualName.isEmpty())
|
if (actualName.isEmpty())
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ public:
|
|||||||
//IDocument
|
//IDocument
|
||||||
OpenResult open(QString *errorString, const Utils::FilePath &filePath,
|
OpenResult open(QString *errorString, const Utils::FilePath &filePath,
|
||||||
const Utils::FilePath &realFilePath) override;
|
const Utils::FilePath &realFilePath) override;
|
||||||
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
|
||||||
QString plainText() const;
|
QString plainText() const;
|
||||||
QByteArray contents() const override;
|
QByteArray contents() const override;
|
||||||
bool setContents(const QByteArray &contents) override;
|
bool setContents(const QByteArray &contents) override;
|
||||||
@@ -47,6 +46,9 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void loaded(bool success);
|
void loaded(bool success);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void dirtyChanged(bool);
|
void dirtyChanged(bool);
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ Core::IDocument::OpenResult ScxmlEditorDocument::open(QString *errorString,
|
|||||||
return OpenResult::Success;
|
return OpenResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScxmlEditorDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
|
bool ScxmlEditorDocument::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
|
||||||
{
|
{
|
||||||
const FilePath oldFileName = this->filePath();
|
const FilePath oldFileName = this->filePath();
|
||||||
const FilePath actualName = filePath.isEmpty() ? oldFileName : filePath;
|
const FilePath actualName = filePath.isEmpty() ? oldFileName : filePath;
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ public:
|
|||||||
OpenResult open(QString *errorString,
|
OpenResult open(QString *errorString,
|
||||||
const Utils::FilePath &filePath,
|
const Utils::FilePath &filePath,
|
||||||
const Utils::FilePath &realFilePath) override;
|
const Utils::FilePath &realFilePath) override;
|
||||||
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
|
||||||
bool shouldAutoSave() const override;
|
bool shouldAutoSave() const override;
|
||||||
bool isSaveAsAllowed() const override;
|
bool isSaveAsAllowed() const override;
|
||||||
bool isModified() const override;
|
bool isModified() const override;
|
||||||
@@ -46,6 +45,9 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void reloadRequested(QString *errorString, const QString &);
|
void reloadRequested(QString *errorString, const QString &);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPointer<Common::MainWidget> m_designWidget;
|
QPointer<Common::MainWidget> m_designWidget;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,7 +41,9 @@ Core::IDocument::OpenResult ObjectsMapDocument::open(QString *errorString,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ObjectsMapDocument::save(QString *errorString, const Utils::FilePath &fileName, bool autoSave)
|
bool ObjectsMapDocument::saveImpl(QString *errorString,
|
||||||
|
const Utils::FilePath &fileName,
|
||||||
|
bool autoSave)
|
||||||
{
|
{
|
||||||
const Utils::FilePath actual = fileName.isEmpty() ? filePath() : fileName;
|
const Utils::FilePath actual = fileName.isEmpty() ? filePath() : fileName;
|
||||||
if (actual.isEmpty())
|
if (actual.isEmpty())
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ public:
|
|||||||
OpenResult open(QString *errorString,
|
OpenResult open(QString *errorString,
|
||||||
const Utils::FilePath &fileName,
|
const Utils::FilePath &fileName,
|
||||||
const Utils::FilePath &realFileName) override;
|
const Utils::FilePath &realFileName) override;
|
||||||
bool save(QString *errorString, const Utils::FilePath &fileName, bool autoSave) override;
|
|
||||||
Utils::FilePath fallbackSaveAsPath() const override;
|
Utils::FilePath fallbackSaveAsPath() const override;
|
||||||
QString fallbackSaveAsFileName() const override;
|
QString fallbackSaveAsFileName() const override;
|
||||||
bool isModified() const override { return m_isModified; }
|
bool isModified() const override { return m_isModified; }
|
||||||
@@ -34,6 +33,9 @@ public:
|
|||||||
QByteArray contents() const override;
|
QByteArray contents() const override;
|
||||||
ObjectsMapModel *model() const { return m_contentModel; }
|
ObjectsMapModel *model() const { return m_contentModel; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool saveImpl(QString *errorString, const Utils::FilePath &fileName, bool autoSave) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OpenResult openImpl(QString *error,
|
OpenResult openImpl(QString *error,
|
||||||
const Utils::FilePath &fileName,
|
const Utils::FilePath &fileName,
|
||||||
|
|||||||
@@ -49,7 +49,11 @@ public:
|
|||||||
if (!terminal) {
|
if (!terminal) {
|
||||||
terminal = new TerminalWidget(nullptr, openParameters);
|
terminal = new TerminalWidget(nullptr, openParameters);
|
||||||
|
|
||||||
terminal->setShellName(setup.m_commandLine.executable().fileName());
|
terminal->setShellName(
|
||||||
|
setup.m_extraData
|
||||||
|
.value(TERMINAL_SHELL_NAME, setup.m_commandLine.executable().fileName())
|
||||||
|
.toString());
|
||||||
|
|
||||||
m_terminalPane->addTerminal(terminal, "App");
|
m_terminalPane->addTerminal(terminal, "App");
|
||||||
} else {
|
} else {
|
||||||
terminal->restart(openParameters);
|
terminal->restart(openParameters);
|
||||||
|
|||||||
@@ -146,8 +146,8 @@ void TerminalWidget::setupPty()
|
|||||||
TerminalSettings::instance().shellArguments.value(),
|
TerminalSettings::instance().shellArguments.value(),
|
||||||
CommandLine::Raw});
|
CommandLine::Raw});
|
||||||
|
|
||||||
Environment env = m_openParameters.environment.value_or(
|
Environment env = m_openParameters.environment.value_or(Environment{})
|
||||||
shellCommand.executable().deviceEnvironment());
|
.appliedToEnvironment(shellCommand.executable().deviceEnvironment());
|
||||||
|
|
||||||
// For git bash on Windows
|
// For git bash on Windows
|
||||||
env.prependOrSetPath(shellCommand.executable().parentDir());
|
env.prependOrSetPath(shellCommand.executable().parentDir());
|
||||||
|
|||||||
@@ -185,6 +185,28 @@ void GenerigHighlighterTests::testChange()
|
|||||||
compareFormats(actualFormats.at(i), formatRanges.at(i));
|
compareFormats(actualFormats.at(i), formatRanges.at(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GenerigHighlighterTests::testPreeditText()
|
||||||
|
{
|
||||||
|
QTextBlock block = m_editor->textDocument()->document()->findBlockByNumber(2);
|
||||||
|
QVERIFY(block.isValid());
|
||||||
|
|
||||||
|
block.layout()->setPreeditArea(7, "uaf");
|
||||||
|
m_editor->textDocument()->syntaxHighlighter()->rehighlight();
|
||||||
|
|
||||||
|
const FormatRanges formatRanges = {{0, 4, toFormat(C_VISUAL_WHITESPACE)},
|
||||||
|
{4, 3, toFormat(C_TYPE)},
|
||||||
|
{10, 3, toFormat(C_TYPE)},
|
||||||
|
{13, 1, toFormat(C_FUNCTION)},
|
||||||
|
{14, 1, toFormat(C_VISUAL_WHITESPACE)},
|
||||||
|
{15, 6, toFormat(C_STRING)},
|
||||||
|
{21, 1, toFormat(C_FUNCTION)}};
|
||||||
|
const QList<QTextLayout::FormatRange> actualFormats = block.layout()->formats();
|
||||||
|
// full hash calculation for QTextCharFormat fails so just check the important entries of format
|
||||||
|
QCOMPARE(actualFormats.size(), formatRanges.size());
|
||||||
|
for (int i = 0; i < formatRanges.size(); ++i)
|
||||||
|
compareFormats(actualFormats.at(i), formatRanges.at(i));
|
||||||
|
}
|
||||||
|
|
||||||
void GenerigHighlighterTests::cleanupTestCase()
|
void GenerigHighlighterTests::cleanupTestCase()
|
||||||
{
|
{
|
||||||
if (m_editor)
|
if (m_editor)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ private slots:
|
|||||||
void testHighlight_data();
|
void testHighlight_data();
|
||||||
void testHighlight();
|
void testHighlight();
|
||||||
void testChange();
|
void testChange();
|
||||||
|
void testPreeditText();
|
||||||
void cleanupTestCase();
|
void cleanupTestCase();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -17,6 +17,12 @@
|
|||||||
|
|
||||||
namespace TextEditor {
|
namespace TextEditor {
|
||||||
|
|
||||||
|
enum HighlighterTypeProperty
|
||||||
|
{
|
||||||
|
SyntaxHighlight = QTextFormat::UserProperty + 1,
|
||||||
|
SemanticHighlight = QTextFormat::UserProperty + 2
|
||||||
|
};
|
||||||
|
|
||||||
class SyntaxHighlighterPrivate
|
class SyntaxHighlighterPrivate
|
||||||
{
|
{
|
||||||
SyntaxHighlighter *q_ptr = nullptr;
|
SyntaxHighlighter *q_ptr = nullptr;
|
||||||
@@ -98,9 +104,9 @@ void SyntaxHighlighterPrivate::applyFormatChanges(int from, int charsRemoved, in
|
|||||||
|
|
||||||
QVector<QTextLayout::FormatRange> ranges;
|
QVector<QTextLayout::FormatRange> ranges;
|
||||||
QVector<QTextLayout::FormatRange> oldRanges;
|
QVector<QTextLayout::FormatRange> oldRanges;
|
||||||
std::tie(ranges, oldRanges)
|
std::tie(oldRanges, ranges)
|
||||||
= Utils::partition(layout->formats(), [](const QTextLayout::FormatRange &range) {
|
= Utils::partition(layout->formats(), [](const QTextLayout::FormatRange &range) {
|
||||||
return range.format.property(QTextFormat::UserProperty).toBool();
|
return range.format.property(SyntaxHighlight).toBool();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (currentBlock.contains(from)) {
|
if (currentBlock.contains(from)) {
|
||||||
@@ -129,8 +135,23 @@ void SyntaxHighlighterPrivate::applyFormatChanges(int from, int charsRemoved, in
|
|||||||
while (i < formatChanges.count() && formatChanges.at(i) == r.format)
|
while (i < formatChanges.count() && formatChanges.at(i) == r.format)
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
|
r.format.setProperty(SyntaxHighlight, true);
|
||||||
r.length = i - r.start;
|
r.length = i - r.start;
|
||||||
|
|
||||||
|
const QString preeditText = currentBlock.layout()->preeditAreaText();
|
||||||
|
if (!preeditText.isEmpty()) {
|
||||||
|
const int preeditPosition = currentBlock.layout()->preeditAreaPosition();
|
||||||
|
if (r.start >= preeditPosition) {
|
||||||
|
r.start += preeditText.length();
|
||||||
|
} else if (r.start + r.length > preeditPosition) {
|
||||||
|
QTextLayout::FormatRange beforePreeditRange = r;
|
||||||
|
r.start = preeditPosition + preeditText.length();
|
||||||
|
r.length = r.length - (r.start - preeditPosition);
|
||||||
|
beforePreeditRange.length = preeditPosition - beforePreeditRange.start;
|
||||||
|
newRanges << beforePreeditRange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
newRanges << r;
|
newRanges << r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,6 +677,24 @@ void SyntaxHighlighter::setExtraFormats(const QTextBlock &block,
|
|||||||
if (block.layout() == nullptr || blockLength == 0)
|
if (block.layout() == nullptr || blockLength == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const QString preeditText = block.layout()->preeditAreaText();
|
||||||
|
if (!preeditText.isEmpty()) {
|
||||||
|
QVector<QTextLayout::FormatRange> additionalRanges;
|
||||||
|
const int preeditPosition = block.layout()->preeditAreaPosition();
|
||||||
|
for (QTextLayout::FormatRange &r : formats) {
|
||||||
|
if (r.start >= preeditPosition) {
|
||||||
|
r.start += preeditText.length();
|
||||||
|
} else if (r.start + r.length > preeditPosition) {
|
||||||
|
QTextLayout::FormatRange afterPreeditRange = r;
|
||||||
|
afterPreeditRange.start = preeditPosition + preeditText.length();
|
||||||
|
afterPreeditRange.length = r.length - (preeditPosition - r.start);
|
||||||
|
additionalRanges << afterPreeditRange;
|
||||||
|
r.length = preeditPosition - r.start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formats << additionalRanges;
|
||||||
|
}
|
||||||
|
|
||||||
Utils::sort(formats, byStartOfRange);
|
Utils::sort(formats, byStartOfRange);
|
||||||
|
|
||||||
const QVector<QTextLayout::FormatRange> all = block.layout()->formats();
|
const QVector<QTextLayout::FormatRange> all = block.layout()->formats();
|
||||||
@@ -663,11 +702,11 @@ void SyntaxHighlighter::setExtraFormats(const QTextBlock &block,
|
|||||||
QVector<QTextLayout::FormatRange> formatsToApply;
|
QVector<QTextLayout::FormatRange> formatsToApply;
|
||||||
std::tie(previousSemanticFormats, formatsToApply)
|
std::tie(previousSemanticFormats, formatsToApply)
|
||||||
= Utils::partition(all, [](const QTextLayout::FormatRange &r) {
|
= Utils::partition(all, [](const QTextLayout::FormatRange &r) {
|
||||||
return r.format.hasProperty(QTextFormat::UserProperty);
|
return r.format.property(SemanticHighlight).toBool();
|
||||||
});
|
});
|
||||||
|
|
||||||
for (auto &format : formats)
|
for (auto &format : formats)
|
||||||
format.format.setProperty(QTextFormat::UserProperty, true);
|
format.format.setProperty(SemanticHighlight, true);
|
||||||
|
|
||||||
if (formats.size() == previousSemanticFormats.size()) {
|
if (formats.size() == previousSemanticFormats.size()) {
|
||||||
Utils::sort(previousSemanticFormats, byStartOfRange);
|
Utils::sort(previousSemanticFormats, byStartOfRange);
|
||||||
@@ -694,7 +733,7 @@ void SyntaxHighlighter::clearExtraFormats(const QTextBlock &block)
|
|||||||
|
|
||||||
const QVector<QTextLayout::FormatRange> formatsToApply
|
const QVector<QTextLayout::FormatRange> formatsToApply
|
||||||
= Utils::filtered(block.layout()->formats(), [](const QTextLayout::FormatRange &r) {
|
= Utils::filtered(block.layout()->formats(), [](const QTextLayout::FormatRange &r) {
|
||||||
return !r.format.hasProperty(QTextFormat::UserProperty);
|
return !r.format.property(SemanticHighlight).toBool();
|
||||||
});
|
});
|
||||||
|
|
||||||
bool wasInReformatBlocks = d->inReformatBlocks;
|
bool wasInReformatBlocks = d->inReformatBlocks;
|
||||||
|
|||||||
@@ -622,7 +622,7 @@ SyntaxHighlighter *TextDocument::syntaxHighlighter() const
|
|||||||
* If \a autoSave is true, the cursor will be restored and some signals suppressed
|
* If \a autoSave is true, the cursor will be restored and some signals suppressed
|
||||||
* and we do not clean up the text file (cleanWhitespace(), ensureFinalNewLine()).
|
* and we do not clean up the text file (cleanWhitespace(), ensureFinalNewLine()).
|
||||||
*/
|
*/
|
||||||
bool TextDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
|
bool TextDocument::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
|
||||||
{
|
{
|
||||||
QTextCursor cursor(&d->m_document);
|
QTextCursor cursor(&d->m_document);
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ public:
|
|||||||
static bool marksAnnotationHidden(const Utils::Id &category);
|
static bool marksAnnotationHidden(const Utils::Id &category);
|
||||||
|
|
||||||
// IDocument implementation.
|
// IDocument implementation.
|
||||||
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
|
||||||
QByteArray contents() const override;
|
QByteArray contents() const override;
|
||||||
bool setContents(const QByteArray &contents) override;
|
bool setContents(const QByteArray &contents) override;
|
||||||
bool shouldAutoSave() const override;
|
bool shouldAutoSave() const override;
|
||||||
@@ -166,6 +165,7 @@ signals:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void applyFontSettings();
|
virtual void applyFontSettings();
|
||||||
|
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OpenResult openImpl(QString *errorString,
|
OpenResult openImpl(QString *errorString,
|
||||||
|
|||||||
@@ -4947,15 +4947,15 @@ void TextEditorWidget::paintEvent(QPaintEvent *e)
|
|||||||
|
|
||||||
paintBlock(&painter, data.block, data.offset, blockData.selections, data.eventRect);
|
paintBlock(&painter, data.block, data.offset, blockData.selections, data.eventRect);
|
||||||
|
|
||||||
if (data.isEditable && data.context.cursorPosition < -1
|
if (data.isEditable && !blockData.layout->preeditAreaText().isEmpty()) {
|
||||||
&& !blockData.layout->preeditAreaText().isEmpty()) {
|
if (data.context.cursorPosition < -1) {
|
||||||
const int cursorPos = blockData.layout->preeditAreaPosition()
|
const int cursorPos = blockData.layout->preeditAreaPosition()
|
||||||
- (data.context.cursorPosition + 2);
|
- (data.context.cursorPosition + 2);
|
||||||
data.cursors.append(generateCursorData(cursorPos, data, blockData, painter));
|
data.cursors = {generateCursorData(cursorPos, data, blockData, painter)};
|
||||||
}
|
}
|
||||||
|
} else if (drawCursor && !drawCursorAsBlock) {
|
||||||
if (drawCursor && !drawCursorAsBlock)
|
|
||||||
d->addCursorsPosition(data, painter, blockData);
|
d->addCursorsPosition(data, painter, blockData);
|
||||||
|
}
|
||||||
d->paintIndentDepth(data, painter, blockData);
|
d->paintIndentDepth(data, painter, blockData);
|
||||||
d->paintAdditionalVisualWhitespaces(data, painter, blockData.boundingRect.top());
|
d->paintAdditionalVisualWhitespaces(data, painter, blockData.boundingRect.top());
|
||||||
d->paintReplacement(data, painter, blockData.boundingRect.top());
|
d->paintReplacement(data, painter, blockData.boundingRect.top());
|
||||||
|
|||||||
@@ -159,6 +159,9 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co
|
|||||||
int beginChar = 0;
|
int beginChar = 0;
|
||||||
if (block == begin.block()) {
|
if (block == begin.block()) {
|
||||||
beginChar = begin.positionInBlock();
|
beginChar = begin.positionInBlock();
|
||||||
|
const QString preeditAreaText = begin.block().layout()->preeditAreaText();
|
||||||
|
if (!preeditAreaText.isEmpty() && beginChar >= begin.block().layout()->preeditAreaPosition())
|
||||||
|
beginChar += preeditAreaText.length();
|
||||||
QTextLine line = blockLayout->lineForTextPosition(beginChar);
|
QTextLine line = blockLayout->lineForTextPosition(beginChar);
|
||||||
QTC_ASSERT(line.isValid(), return {});
|
QTC_ASSERT(line.isValid(), return {});
|
||||||
firstLine = line.lineNumber();
|
firstLine = line.lineNumber();
|
||||||
@@ -171,6 +174,9 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co
|
|||||||
int endChar = -1;
|
int endChar = -1;
|
||||||
if (block == end.block()) {
|
if (block == end.block()) {
|
||||||
endChar = end.positionInBlock();
|
endChar = end.positionInBlock();
|
||||||
|
const QString preeditAreaText = end.block().layout()->preeditAreaText();
|
||||||
|
if (!preeditAreaText.isEmpty() && endChar >= end.block().layout()->preeditAreaPosition())
|
||||||
|
endChar += preeditAreaText.length();
|
||||||
QTextLine line = blockLayout->lineForTextPosition(endChar);
|
QTextLine line = blockLayout->lineForTextPosition(endChar);
|
||||||
QTC_ASSERT(line.isValid(), return {});
|
QTC_ASSERT(line.isValid(), return {});
|
||||||
lastLine = line.lineNumber();
|
lastLine = line.lineNumber();
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ class TextMarkRegistry : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
static void add(TextMark *mark);
|
static void add(TextMark *mark);
|
||||||
|
static void add(TextMark *mark, TextDocument *document);
|
||||||
static bool remove(TextMark *mark);
|
static bool remove(TextMark *mark);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -75,6 +76,16 @@ TextMark::TextMark(const FilePath &filePath, int lineNumber, TextMarkCategory ca
|
|||||||
TextMarkRegistry::add(this);
|
TextMarkRegistry::add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextMark::TextMark(TextDocument *document, int lineNumber, TextMarkCategory category)
|
||||||
|
: m_fileName(QTC_GUARD(document) ? document->filePath() : FilePath())
|
||||||
|
, m_lineNumber(lineNumber)
|
||||||
|
, m_visible(true)
|
||||||
|
, m_category(category)
|
||||||
|
{
|
||||||
|
if (!m_fileName.isEmpty())
|
||||||
|
TextMarkRegistry::add(this, document);
|
||||||
|
}
|
||||||
|
|
||||||
TextMark::~TextMark()
|
TextMark::~TextMark()
|
||||||
{
|
{
|
||||||
if (!m_fileName.isEmpty())
|
if (!m_fileName.isEmpty())
|
||||||
@@ -461,9 +472,14 @@ TextMarkRegistry::TextMarkRegistry(QObject *parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextMarkRegistry::add(TextMark *mark)
|
void TextMarkRegistry::add(TextMark *mark)
|
||||||
|
{
|
||||||
|
add(mark, TextDocument::textDocumentForFilePath(mark->filePath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextMarkRegistry::add(TextMark *mark, TextDocument *document)
|
||||||
{
|
{
|
||||||
instance()->m_marks[mark->filePath()].insert(mark);
|
instance()->m_marks[mark->filePath()].insert(mark);
|
||||||
if (TextDocument *document = TextDocument::textDocumentForFilePath(mark->filePath()))
|
if (document)
|
||||||
document->addMark(mark);
|
document->addMark(mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class TEXTEDITOR_EXPORT TextMark
|
|||||||
public:
|
public:
|
||||||
TextMark() = delete;
|
TextMark() = delete;
|
||||||
TextMark(const Utils::FilePath &filePath, int lineNumber, TextMarkCategory category);
|
TextMark(const Utils::FilePath &filePath, int lineNumber, TextMarkCategory category);
|
||||||
|
TextMark(TextDocument *document, int lineNumber, TextMarkCategory category);
|
||||||
virtual ~TextMark();
|
virtual ~TextMark();
|
||||||
|
|
||||||
// determine order on markers on the same line.
|
// determine order on markers on the same line.
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ void SubmitEditorFile::setModified(bool modified)
|
|||||||
emit changed();
|
emit changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SubmitEditorFile::save(QString *errorString, const FilePath &filePath, bool autoSave)
|
bool SubmitEditorFile::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
|
||||||
{
|
{
|
||||||
const FilePath &fName = filePath.isEmpty() ? this->filePath() : filePath;
|
const FilePath &fName = filePath.isEmpty() ? this->filePath() : filePath;
|
||||||
FileSaver saver(fName, QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
|
FileSaver saver(fName, QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
|
||||||
|
|||||||
@@ -23,11 +23,13 @@ public:
|
|||||||
bool setContents(const QByteArray &contents) override;
|
bool setContents(const QByteArray &contents) override;
|
||||||
|
|
||||||
bool isModified() const override { return m_modified; }
|
bool isModified() const override { return m_modified; }
|
||||||
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
|
||||||
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override;
|
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override;
|
||||||
|
|
||||||
void setModified(bool modified = true);
|
void setModified(bool modified = true);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_modified;
|
bool m_modified;
|
||||||
VcsBaseSubmitEditor *m_editor;
|
VcsBaseSubmitEditor *m_editor;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ private slots:
|
|||||||
void test_setExtraAdditionalFormats();
|
void test_setExtraAdditionalFormats();
|
||||||
void test_clearExtraFormats();
|
void test_clearExtraFormats();
|
||||||
void test_incrementalApplyAdditionalFormats();
|
void test_incrementalApplyAdditionalFormats();
|
||||||
|
void test_preeditText();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -235,6 +236,7 @@ void tst_highlighter::test_incrementalApplyAdditionalFormats()
|
|||||||
formatHash);
|
formatHash);
|
||||||
|
|
||||||
formats = firstBlock.layout()->formats();
|
formats = firstBlock.layout()->formats();
|
||||||
|
QCOMPARE(formats.size(), 1);
|
||||||
QCOMPARE(formats.at(0).format.fontItalic(), true);
|
QCOMPARE(formats.at(0).format.fontItalic(), true);
|
||||||
QCOMPARE(formats.at(0).format.fontOverline(), false);
|
QCOMPARE(formats.at(0).format.fontOverline(), false);
|
||||||
QCOMPARE(formats.at(0).start, 0);
|
QCOMPARE(formats.at(0).start, 0);
|
||||||
@@ -338,6 +340,28 @@ void tst_highlighter::test_incrementalApplyAdditionalFormats()
|
|||||||
QCOMPARE(formats.at(1).length, 2);
|
QCOMPARE(formats.at(1).length, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_highlighter::test_preeditText()
|
||||||
|
{
|
||||||
|
QCOMPARE(doc->blockCount(), 4);
|
||||||
|
|
||||||
|
QTextBlock firstBlock = doc->findBlockByNumber(0);
|
||||||
|
firstBlock.layout()->setPreeditArea(2, "uaf");
|
||||||
|
|
||||||
|
SemanticHighlighter::setExtraAdditionalFormats(highlighter, highlightingResults(), formatHash);
|
||||||
|
|
||||||
|
auto formats = firstBlock.layout()->formats();
|
||||||
|
QCOMPARE(formats.size(), 2);
|
||||||
|
QCOMPARE(formats.at(0).format.fontItalic(), true);
|
||||||
|
QCOMPARE(formats.at(0).format.fontOverline(), false);
|
||||||
|
QCOMPARE(formats.at(0).start, 0);
|
||||||
|
QCOMPARE(formats.at(0).length, 2);
|
||||||
|
|
||||||
|
QCOMPARE(formats.at(1).format.fontItalic(), true);
|
||||||
|
QCOMPARE(formats.at(1).format.fontOverline(), false);
|
||||||
|
QCOMPARE(formats.at(1).start, 5);
|
||||||
|
QCOMPARE(formats.at(1).length, 3);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_highlighter::cleanup()
|
void tst_highlighter::cleanup()
|
||||||
{
|
{
|
||||||
delete doc;
|
delete doc;
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ def main():
|
|||||||
test.warning("Parsing project timed out")
|
test.warning("Parsing project timed out")
|
||||||
compareProjectTree(rootNodeTemplate % "Qt Creator", "projecttree_creator.tsv")
|
compareProjectTree(rootNodeTemplate % "Qt Creator", "projecttree_creator.tsv")
|
||||||
buildIssuesTexts = map(lambda i: str(i[0]), getBuildIssues())
|
buildIssuesTexts = map(lambda i: str(i[0]), getBuildIssues())
|
||||||
deprecationWarnings = filter(lambda s: "deprecated" in s, buildIssuesTexts)
|
deprecationWarnings = "\n".join(set(filter(lambda s: "deprecated" in s, buildIssuesTexts)))
|
||||||
if deprecationWarnings:
|
if deprecationWarnings:
|
||||||
test.warning("Creator claims that the .qbs file uses deprecated features.",
|
test.warning("Creator claims that the .qbs file uses deprecated features.",
|
||||||
"\n".join(set(deprecationWarnings)))
|
deprecationWarnings)
|
||||||
invokeMenuItem("File", "Exit")
|
invokeMenuItem("File", "Exit")
|
||||||
|
|||||||
Reference in New Issue
Block a user