Merge "Merge remote-tracking branch 'origin/16.0' into qds/dev" into qds/dev

This commit is contained in:
The Qt Project
2025-03-11 15:58:56 +00:00
152 changed files with 13559 additions and 4532 deletions

View File

@@ -7,7 +7,7 @@ on:
- 'doc/**'
env:
QT_VERSION: 6.8.1
QT_VERSION: 6.8.2
MACOS_DEPLOYMENT_TARGET: 11.0
CLANG_VERSION: 19.1.6
ELFUTILS_VERSION: 0.175

View File

@@ -80,6 +80,18 @@ find_package(Qt6
find_package(Qt6 OPTIONAL_COMPONENTS Quick QuickWidgets Designer DesignerComponentsPrivate
Help SerialPort Svg Tools LinguistTools QUIET)
if (QT_VERSION VERSION_GREATER_EQUAL 6.9.0)
find_package(Qt6 OPTIONAL_COMPONENTS
CorePrivate
Core5CompatPrivate
GuiPrivate
DesignerComponentsPrivate
QmlPrivate
QuickPrivate
QUIET
)
endif()
# depending on Qt version and compiler version enable or disable Qml Designer
# can be overwritten by variable WITH_QMLDESIGNER / QTC_WITH_QMLDESIGNER (env)
configure_qml_designer(${Qt6_VERSION})

70
TESTING.md Normal file
View File

@@ -0,0 +1,70 @@
# Testing Qt Creator
There are four kinds of tests in Qt Creator, you can find some more documentation
[online here](https://doc-snapshots.qt.io/qtcreator-extending/plugin-tests.html).
## Manual Tests
Located in `tests/manual/...`, these need to be run manually as separate executables and require
user interaction for "playing around" with some piece of code.
## Squish-Based Tests
`tests/system/...` are run with [Squish](https://www.qt.io/product/quality-assurance/squish)
at irregular intervals and specifically checked for releases (RTA).
## Auto/Unit Tests
`tests/auto/...` are separate QTest-based executables (tst_...) that are run with tools like
cmake/ctest. They run automatically with the PRECHECK in Gerrit, etc.
## Plugin/Integration Tests
These tests are integrated into the plugins themselves and are executed within
the context of a fully running Qt Creator. They are run with the `-test <plugin>`
command line parameter of the qtcreator executable.
This starts Qt Creator with only that plugin and its dependencies loaded, executes any test
functions that the plugin registers, prints the QTest output, and then closes.
For plugin tests, plugins register test functions if Qt Creator was compiled with WITH_TESTS,
like this:
```c++
void TextEditorPlugin::initialize()
{
#ifdef WITH_TESTS
addTestCreator(createFormatTextTest);
addTestCreator(createTextDocumentTest);
addTestCreator(createTextEditorTest);
addTestCreator(createSnippetParserTest);
#endif
...
}
```
The "test creator" is a factory function that returns a QObject, which functions the same as the
tstSomething QObjects used in standalone unit tests.
```c++
QObject *createFormatTextTest()
{
return new FormatTextTest;
}
```
Slots are executed as QTest tests, and there can be init and cleanup functions, etc.
```c++
class FormatTextTest final : public QObject
{
Q_OBJECT
private slots:
void testFormatting_data();
void testFormatting();
};
```
These tests are executed after Qt Creator plugins have fully initialized and can access the full
Qt Creator state, open files, load projects, etc. (depending on the declared dependencies of
the tested plugin).

View File

@@ -77,7 +77,7 @@ elseif(WIN32)
set(_IDE_CMAKE_INSTALL_PATH "lib/cmake")
else ()
# Small hack to silence a warning in the stable branch - but it means the value is incorrect
if (NOT CMAKE_LIBRARY_ARCHITECTURE)
if (NOT CMAKE_LIBRARY_ARCHITECTURE AND NOT CMAKE_INSTALL_LIBDIR)
set(CMAKE_INSTALL_LIBDIR "lib")
endif()
include(GNUInstallDirs)

View File

@@ -1,6 +1,6 @@
set(IDE_VERSION "15.0.84") # The IDE version.
set(IDE_VERSION_COMPAT "15.0.84") # The IDE Compatibility version.
set(IDE_VERSION_DISPLAY "16.0.0-rc1") # The IDE display version.
set(IDE_VERSION "16.0.0") # The IDE version.
set(IDE_VERSION_COMPAT "16.0.0") # The IDE Compatibility version.
set(IDE_VERSION_DISPLAY "16.0.0") # The IDE display version.
set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation.
set(IDE_DISPLAY_NAME "Qt Creator") # The IDE display name.

View File

@@ -7,7 +7,7 @@ instructions:
instructions:
- type: EnvironmentVariable
variableName: QTC_QT_BASE_URL
variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/qt/6.8.0/release_content/"
variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/qt/6.8.2/release_content/"
- type: EnvironmentVariable
variableName: MACOSX_DEPLOYMENT_TARGET
variableValue: 12.0
@@ -88,7 +88,7 @@ instructions:
instructions:
- type: EnvironmentVariable
variableName: QTC_QT_POSTFIX
variableValue: "-Linux-RHEL_8_8-GCC-Linux-RHEL_8_8-X86_64.7z"
variableValue: "-Linux-RHEL_8_10-GCC-Linux-RHEL_8_10-X86_64.7z"
- type: EnvironmentVariable
variableName: QTC_ICU_URL
variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/development_releases/prebuilt/icu/prebuilt/73.2/icu-linux-g++-Rhel8.6-x64.7z"
@@ -141,7 +141,7 @@ instructions:
instructions:
- type: EnvironmentVariable
variableName: QTC_QT_POSTFIX
variableValue: "-Linux-Debian_11_6-GCC-Linux-Debian_11_6-AARCH64.7z"
variableValue: "-Linux-Ubuntu_24_04-GCC-Linux-Ubuntu_24_04-AARCH64.7z"
- type: EnvironmentVariable
variableName: QTC_SDKTOOL_QT_EXT
variableValue: ".tar.xz"

View File

@@ -36,6 +36,10 @@ Editing
([QTCREATORBUG-32193](https://bugreports.qt.io/browse/QTCREATORBUG-32193))
* Fixed a formatting issue when applying method signature changes
([QTCREATORBUG-31931](https://bugreports.qt.io/browse/QTCREATORBUG-31931))
* Fixed the generation of getters for local enum types
([QTCREATORBUG-32473](https://bugreports.qt.io/browse/QTCREATORBUG-32473))
* Fixed the header guard creation for file names with special characters
([QTCREATORBUG-32539](https://bugreports.qt.io/browse/QTCREATORBUG-32539))
* Built-in
* Added support for init-statements in range-based `for` loops
([QTCREATORBUG-31961](https://bugreports.qt.io/browse/QTCREATORBUG-31961))
@@ -68,6 +72,16 @@ Editing
([QTCREATORBUG-31878](https://bugreports.qt.io/browse/QTCREATORBUG-31878),
[QTCREATORBUG-32163](https://bugreports.qt.io/browse/QTCREATORBUG-32163))
### Copilot
* Fixed issues with newer versions of the language server
([QTCREATORBUG-32536](https://bugreports.qt.io/browse/QTCREATORBUG-32536))
### SCXML
* Fixed the colors of items
([QTCREATORBUG-32477](https://bugreports.qt.io/browse/QTCREATORBUG-32477))
Projects
--------
@@ -101,6 +115,11 @@ Projects
([QTCREATORBUG-32350](https://bugreports.qt.io/browse/QTCREATORBUG-32350))
* Fixed a crash when an application outputs lots of lines
([QTCREATORBUG-32371](https://bugreports.qt.io/browse/QTCREATORBUG-32371))
* Environment Editor
* Fixed the `Disable` button for the first item
([QTCREATORBUG-32495](https://bugreports.qt.io/browse/QTCREATORBUG-32495))
* Fixed the `Edit` button for disabled items
([QTCREATORBUG-32495](https://bugreports.qt.io/browse/QTCREATORBUG-32495))
* Qt
* Improved performance of Qt ABI detection when module `.json` files are
available
@@ -121,6 +140,7 @@ Projects
* Added support for creating run configurations for custom CMake targets
with the `qtc_runnable` `FOLDER` property
([QTCREATORBUG-32324](https://bugreports.qt.io/browse/QTCREATORBUG-32324))
* Improved the performance when CMake reply files change on disk
* Fixed that manually created run configurations could be removed if
`Create suitable run configurations automatically` was turned off
([QTCREATORBUG-32289](https://bugreports.qt.io/browse/QTCREATORBUG-32289))
@@ -130,6 +150,8 @@ Projects
* Fixed that Ninja was not detected even when `CMAKE_MAKE_PROGRAM` was set
to the `ninja` executable
([QTCREATORBUG-32436](https://bugreports.qt.io/browse/QTCREATORBUG-32436))
* Fixed the import of multi-config CMake presets
([QTCREATORBUG-31554](https://bugreports.qt.io/browse/QTCREATORBUG-31554))
* Package Manager Auto Setup
* Changed the default installation directory to `/tmp` to ensure that the
directory is writable
@@ -160,7 +182,9 @@ Debugging
* Pretty printers
* Added `QMultiHash`
([QTCREATORBUG-32313](https://bugreports.qt.io/browse/QTCREATORBUG-32313))
([QTCREATORBUG-32313](https://bugreports.qt.io/browse/QTCREATORBUG-32313))
* Fixed issues with debuggers that use an older Python version
([QTCREATORBUG-32475](https://bugreports.qt.io/browse/QTCREATORBUG-32475))
* CDB
* Disabled heap debugging by default and added the option
`Enable heap debugging`
@@ -180,11 +204,19 @@ Analyzer
([QTCREATORBUG-31372](https://bugreports.qt.io/browse/QTCREATORBUG-31372))
* Fixed that profiling could fail to start
([QTCREATORBUG-32062](https://bugreports.qt.io/browse/QTCREATORBUG-32062))
* Fixed the sorting of statistics
([QTCREATORBUG-32398](https://bugreports.qt.io/browse/QTCREATORBUG-32398))
### Axivion
* Added support for images in the issue details
* Moved Axivion preferences to `Preferences > Analyzer > Axivion`
* Fixed that the display of data in the issues table did not adapt to the
column's data type
([QTCREATORBUG-32023](https://bugreports.qt.io/browse/QTCREATORBUG-32023))
* Fixed that filters were shown even for issue types that do not suppor them
* Fixed that the Filter menus opened at the wrong position
([QTCREATORBUG-32506](https://bugreports.qt.io/browse/QTCREATORBUG-32506))
### Coco
@@ -192,6 +224,23 @@ Analyzer
in `Projects > Project Settings > Coco Code Coverage`
([Documentation]https://doc-snapshots.qt.io/qtcreator-16.0/creator-coco.html)
Terminal
--------
* Fixed that the view didn't jump to the end on input
([QTCREATORBUG-32407](https://bugreports.qt.io/browse/QTCREATORBUG-32407))
* Fixed the title of tabs
([QTCREATORBUG-32197](https://bugreports.qt.io/browse/QTCREATORBUG-32197))
* Fixed killing the shell process
([QTCREATORBUG-32509](https://bugreports.qt.io/browse/QTCREATORBUG-32509))
* Fixed the scrolling behavior
([QTCREATORBUG-32167](https://bugreports.qt.io/browse/QTCREATORBUG-32167),
[QTCREATORBUG-32546](https://bugreports.qt.io/browse/QTCREATORBUG-32546))
* Fixed the title of tabs
([QTCREATORBUG-32197](https://bugreports.qt.io/browse/QTCREATORBUG-32197))
* Fixed the handling of `Home` and `End` keys
([QTCREATORBUG-32545](https://bugreports.qt.io/browse/QTCREATORBUG-32545))
Version Control Systems
-----------------------
@@ -227,10 +276,17 @@ Platforms
* Added support for the `terminator` terminal emulator
([QTCREATORBUG-32111](https://bugreports.qt.io/browse/QTCREATORBUG-32111))
### macOS
* Fixed a crash when MinGW toolchains are detected on macOS hosts
([QTCREATORBUG-32127](https://bugreports.qt.io/browse/QTCREATORBUG-32127))
### Android
* Fixed a performance problem when detecting the Android ABI
([QTCREATORBUG-31068](https://bugreports.qt.io/browse/QTCREATORBUG-31068))
* Fixed that the wrong `lldb-server` could be used
([QTCREATORBUG-32494](https://bugreports.qt.io/browse/QTCREATORBUG-32494))
### iOS
@@ -251,12 +307,20 @@ Platforms
* Fixed an issue with running `pkg-config` in the container
([QTCREATORBUG-32325](https://bugreports.qt.io/browse/QTCREATORBUG-32325))
* Fixed an issue with shutting down the device access
* Fixed soft asserts during container setup
### QNX
* Fixed issues with Clangd 19
([QTCREATORBUG-32529](https://bugreports.qt.io/browse/QTCREATORBUG-32529))
Credits for these changes go to:
--------------------------------
Alessandro Portale
Alexander Drozdov
Alexander Pershin
Alexandre Laurent
Alexis Jeandet
Ali Kianian
Andre Hartmann
@@ -292,6 +356,7 @@ Mats Honkamaa
Miikka Heikkinen
Mitch Curtis
Morteza Jamshidi
Nicholas Bennett
Nikolaus Demmel
Olivier De Cannière
Orgad Shaneh
@@ -311,4 +376,5 @@ Thiago Macieira
Thomas Hartmann
Tim Jenßen
Vikas Pachdha
Ville Lavonius
Xu Jin

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -3,16 +3,16 @@
/*!
\page creator-coco.html
\previouspage creator-reference.html
\previouspage creator-how-tos.html
\ingroup creator-reference-analyzer
\ingroup creator-how-to-analyze
\title Coco
\title Set up code coverage from Coco
\brief Measure and analyze the code coverage of tests.
With Coco, you can measure and analyze the code coverage of tests. You can
set up a project for code coverage and display the coverage in \QC.
With Coco, you can measure and analyze the code coverage of tests. The
following sections describe how to set up a project for code coverage.
For more information about viewing the results in \QC, see
\l{View code coverage reports from Coco}.
To use the plugin, you must download and install Coco version 6.0 or later.
@@ -143,6 +143,9 @@
loading an instrumentation database (a \c .csmes file), which was generated by
Coco CoverageScanner.
For more information about how to set up a project for code coverage in \QC,
see \l{Set up code coverage from Coco}.
To measure and check code coverage:
\list 1
@@ -182,5 +185,6 @@
\li Implicit Manual Coverage Validation
\endlist
\sa {Enable and disable plugins}, {Font & Colors}, {Analyzing Code}, {Coco}
\sa {Enable and disable plugins}, {Set up code coverage from Coco},
{Font & Colors}, {Analyzing Code},
*/

View File

@@ -9,12 +9,13 @@
\title Android Deploy Configuration
\brief Create Application Packages (APK) or Android App Bundles (AAB) to
install and run on devices or to upload to the Google Play store.
\brief Create packages to deploy to devices or to submit to the Google Play
store, or create libraries for Android app modules.
Android applications are packaged as ZIP files called Application Packages
(APK) or Android App Bundles (AAB). You can install and run APK files on a
device. You can upload AAB files to the Google Play store.
(APK), Android App Bundles (AAB), or Android Archives (AAR). You can
install and run APK files on a device. You can upload AAB files to the
Google Play store.
\l{Qt for Android} has binaries for armv7a, arm64-v8a, x86, and x86-64.
To support several different ABIs in your application, build an AAB that
@@ -27,10 +28,14 @@
\list
\li As a stand-alone, distributable application package (APK).
\li As an app bundle (AAB) for distribution in the Google Play store.
\li As an AAR, which fundamentally differs from the APK and AAB formats
in that it is an Android library. You can use it as a dependency for
an Android app module, but you cannot run it alone.
All Qt versions do not support AABs. Qt 6.3.0 and later support
multi-abi builds for applications that you build with CMake. For
more information, see \l{Deploying an Application on Android}.
multi-abi builds for applications when you build with CMake. AARs
are supported from Qt 6.8.0 onwards. For more information, see
\l{Deploying an Application on Android}.
\endlist
\note Since \QC 4.12, Ministro is not supported.
@@ -123,6 +128,12 @@
\image qtcreator-android-build-steps.png {qmake settings for building AABs}
\section3 Building AARs
Select the AAR target in the \uicontrol {Build Steps} section.
\image qt-creator-android-build-aar.webp {Selecting the AAR target}
\section3 Signing Android Packages
To publish your application, you must sign it by using a \e {public-private
@@ -492,8 +503,7 @@
Select the \uicontrol {Include default permissions for Qt modules} and
\uicontrol {Include default features for Qt modules} check boxes to add the
permissions needed by Qt libraries. This can be
\c {android.permission.WRITE_EXTERNAL_STORAGE} for \l{Qt Core} or
permissions needed by Qt libraries, such as
\c {android.permission.ACCESS_BACKGROUND_LOCATION} for \l{Qt Positioning}.
To add a permission, select it from the list, and then select \uicontrol Add.

View File

@@ -20,6 +20,10 @@
\section1 Don't detect indentation settings
When you open a document, the editor tries to automatically detect if it uses tabs or
spaces for indentation and the indentation width, by inspecting its contents.
If the automatic detection fails, the default setting is used.
To turn off the automatic detection of indentation settings, go to
\preferences > \uicontrol {Text Editor} > \uicontrol Behavior
and clear \uicontrol {Auto detect}.
@@ -28,10 +32,14 @@
\section1 Fix indentation in an open file
To fix the indentation settings for the file currently open in the editor, select a
different setting with \uicontrol {Spaces} > \uicontrol {Document Settings} or
\uicontrol {Tabs} > \uicontrol {Document Settings} on the editor toolbar.
To fix the indentation in the file currently open in the editor:
\list
\li On the editor toolbar, select \uicontrol {Spaces}, and then select
\li On the editor toolbar, select \uicontrol {Spaces} or \uicontrol {Tabs}, and then select
\uicontrol {Auto-indent Selection} to automatically indent the
selected text using the current settings.
\li Go to \uicontrol Edit > \uicontrol Advanced, and select an

View File

@@ -137,7 +137,8 @@
Many of the error messages are similar to the ones in Douglas Crockford's
\l{http://www.jslint.com}{JSLint} tool. For more information about JSLint
errors, see \l{http://linterrors.com/js}{JSLint Error Explanations}.
errors, see \l{https://github.com/jamesallardice/jslint-error-explanations}
{JSLint Error Explanations}.
\table
\header
@@ -204,33 +205,30 @@
\li M10
\li Error
\li Duplicate property binding
\li See also: \l{http://linterrors.com/js/duplicate-key-a}
{Duplicate key '{a}'}.
\li For more information, see \e {Duplicate key '{a}'} in
\e {JSLint Error Explanations}.
\row
\li M11
\li Error
\li Id expected
\li See also:
\l{http://linterrors.com/js/expected-an-identifier-and-instead-saw-a-a-reserved-word}
{Expected an identifier and instead saw '{a}' (a reserved word)}.
\li For more information, see
\e {Expected an identifier and instead saw '{a}' (a reserved word)}
in \e {JSLint Error Explanations}.
\row
\li M14
\li Error
\li Invalid id
\li See also:
\l{http://linterrors.com/js/expected-an-identifier-and-instead-saw-a-a-reserved-word}
{Expected an identifier and instead saw '{a}' (a reserved word)}.
\li For more information, see
\e {Expected an identifier and instead saw '{a}' (a reserved word)}.
\row
\li M15
\li Error
\li Duplicate id
\li Ids in a file must be unique.
See also: \l{http://linterrors.com/js/duplicate-key-a}
{Duplicate key '{a}'}.
For more information, see \e {Duplicate key '{a}'}.
\row
\li M16
@@ -270,7 +268,8 @@
\li M23
\li Warning
\li Do not use \c eval
\li See also: \l{http://linterrors.com/js/eval-is-evil}{eval is evil}.
\li For more information, see \e {eval is evil} in
\e {JSLint Error Explanations}.
\row
\li M28
@@ -282,8 +281,8 @@
\li M29
\li Warning
\li Do not use \c with
\li See also: \l{http://linterrors.com/js/unexpected-with}
{Unexpected 'with'}.
\li For more information, see \e {Unexpected 'with'} in
\e {JSLint Error Explanations}.
\row
\li M30
@@ -333,51 +332,48 @@
\li M108
\li Warning
\li Function \c name is used before its declaration
\li See also: \l{http://linterrors.com/js/a-was-used-before-it-was-defined}
{{a} was used before it was defined}.
\li For more information, see \e {{a} was used before it was defined} in
\e {JSLint Error Explanations}.
\row
\li M109
\li Warning
\li Do not use \c Boolean as a constructor
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
{Do not use {a} as a constructor}.
\li For more information, see \e {Do not use {a} as a constructor} in
\e {JSLint Error Explanations}.
\row
\li M110
\li Warning
\li Do not use \c String as a constructor
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
{Do not use {a} as a constructor}.
\li For more information, see \e {Do not use {a} as a constructor}.
\row
\li M111
\li Warning
\li Do not use \c Object as a constructor
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
{Do not use {a} as a constructor}.
\li For more information, see \e {Do not use {a} as a constructor}.
\row
\li M112
\li Warning
\li Do not use \c Array as a constructor
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
{Do not use {a} as a constructor}.
\li For more information, see \e {Do not use {a} as a constructor}.
\row
\li M113
\li Warning
\li Do not use \c Function as a constructor
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
{Do not use {a} as a constructor}.
\li For more information, see \e {Do not use {a} as a constructor}.
\row
\li M114
\li Hint
\li The \c function keyword and the opening parenthesis should be
separated by a single space
\li See also: \l{http://linterrors.com/js/expected-exactly-one-space-between-a-and-b}
{Expected exactly one space between {a} and {b}}.
\li For more information, see
\e {Expected exactly one space between {a} and {b}} in
\e {JSLint Error Explanations}.
\row
\li M115
@@ -397,15 +393,15 @@
\li M117
\li Warning
\li Confusing pluses
\li See also: \l{http://linterrors.com/js/confusing-pluses}
{Confusing pluses}.
\li For more information, see \e {Confusing pluses} in
\e {JSLint Error Explanations}.
\row
\li M119
\li Warning
\li Confusing minuses
\li See also: \l{http://linterrors.com/js/confusing-minuses}
{Confusing minuses}.
\li For more information, see \e {Confusing minuses} in
\e {JSLint Error Explanations}.
\row
\li M121
@@ -453,9 +449,9 @@
\li M201
\li Hint
\li Place var declarations at the start of a function
\li See also:
\l{http://linterrors.com/js/move-var-declarations-to-the-top-of-the-function}
{Move 'var' declarations to the top of the function}.
\li For more information, see
\e {Move 'var' declarations to the top of the function} in
\e {JSLint Error Explanations}.
\row
\li M202
@@ -609,15 +605,14 @@
\li M307
\li Warning
\li Use \c new only with functions that start with an uppercase letter
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
{Do not use {a} as a constructor}.
\li For more information, see \e {Do not use {a} as a constructor} in
\e {JSLint Error Explanations}.
\row
\li M308
\li Warning
\li Do not use \c Number as a constructor
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
{Do not use {a} as a constructor}.
\li For more information, see \e {Do not use {a} as a constructor}.
\row
\li M309
@@ -707,9 +702,9 @@
\li M323
\li Error
\li \c Number elements expected in array value
\li See also:
\l{http://linterrors.com/js/the-array-literal-notation-is-preferrable}
{The array literal notation [] is preferable}.
\li For more information, see
\e {The array literal notation [] is preferable} in
\e {JSLint Error Explanations}.
\row
\li M324

View File

@@ -42,6 +42,53 @@
then select \uicontrol Install.
\endlist
\section1 Enable code syntax highlighting in the inline chat window
To enable code syntax highlighting in the inline chat window, go to
\preferences > \uicontrol {Text Editor} > \uicontrol {Generic Highlighter},
and then select \uicontrol {Download Definitions}.
\image qtcreator-syntax-highlighter.png {Generic Highlighter preferences}
For more information, see \l{Download highlight definitions}.
\section1 Install and use Ollama
To use LLMs running locally on your computer with the Qt AI Assistant extension,
install Ollama. You can run models available from the Ollama selection as well
as custom models added by you to Ollama.
\section2 Run models on Ollama
To run models, enter:
\code
ollama run <model-name>
\endcode
For example:
\code
ollama run codellama:7b-code
\endcode
\section2 Supported models from Ollama
You can use the following models directly from Ollama:
\list
\li \c codellama:7b-code
\li \c deepseek-coder-v2:lite
\li \c starcoder2:7b
\endlist
\section2 Custom models
For custom models, follow the specific installation instructions for that mode.
You can use the following custom models:
\list
\li \l {https://huggingface.co/QtGroup/CodeLlama-13B-QML}{codellama:13b-code-qml}
\endlist
\section1 Connect to an LLM
You can connect to the following LLMs:

View File

@@ -75,7 +75,15 @@
*/
/*!
\externalpage https://doc.qt.io/QtForMCUs/qtul-getting-started-on-nxp.html
\title Getting Started on NXP
\title Getting started on NXP (BareMetal and FreeRTOS)
*/
/*!
\externalpage https://doc.qt.io/QtForMCUs/qtul-getting-started-on-nxp-linux.html
\title Getting started on NXP (Linux)
*/
/*!
\externalpage https://doc.qt.io/QtForMCUs/qtul-getting-started-on-nxp-zephyr.html
\title Getting started on NXP (Zephyr)
*/
/*!
\externalpage https://doc.qt.io/QtForMCUs/qtul-getting-started-on-infineon.html

View File

@@ -11,8 +11,7 @@
\l{https://marketplace.qt.io/}{Qt Marketplace} has links to \QC plugins that
you can download and install either for free or for a price set by their
publisher. Browse the available plugins in the \uicontrol Marketplace tab
in the \uicontrol Welcome mode.
publisher.
You can also install plugins from other sources, such as
\l{https://github.com/}{GitHub}.

View File

@@ -41,7 +41,12 @@
The hardware-specific requirements vary depending on the hardware platform you are developing for.
For more information see:
\list
\li \l{Getting Started on NXP}
\li Getting Started on NXP
\list
\li \l {Getting started on NXP (BareMetal and FreeRTOS)}
\li \l {Getting started on NXP (Linux)}
\li \l {Getting started on NXP (Zephyr)}
\endlist
\li \l{Getting Started on STM}
\li \l{Getting Started on Renesas}
\li \l{Getting Started on Infineon}
@@ -57,8 +62,17 @@
\li \QC version
\li \QMCU SDK version
\row
\li 12.0.2 or later
\li 2.7 or later
\li 16.0.0 or later
\li 2.10 or later
\row
\li 15.0.0
\li 2.9
\row
\li 13.0.2
\li 2.8
\row
\li 12.0.2
\li 2.7
\row
\li 11.0.3
\li 2.6
@@ -91,17 +105,17 @@
\li 1.0
\endtable
\sa {Enable and disable plugins}, {MCUs}{How To: Develop for MCUs},
{Developing for MCUs}, {\QMCU}
\sa {Enable and disable plugins}, {MCUs}{How To: Develop for MCUs}, {\QMCU}
*/
/*!
\page creator-how-to-create-mcu-kits.html
\page creator-how-to-add-mcu-kits.html
\previouspage creator-how-tos.html
\ingroup creator-how-to-mcu
\ingroup creator-how-to-sdks
\title Connect MCU devices
\title Add MCU SDKs
\note Enable the McuSupport plugin to develop for MCUs.
@@ -154,13 +168,25 @@
\li Select \uicontrol Apply to save the preferences.
\endlist
\section1 Add MCU devices
\sa {Enable and disable plugins}, {MCUs}{How To: Develop for MCUs},
{Developing for MCUs}
*/
/*!
\page creator-how-to-add-mcu-devices.html
\previouspage creator-how-tos.html
\ingroup creator-how-to-mcu
\title Add MCU devices
\note Enable the McuSupport plugin to develop for MCUs.
\QC automatically adds a default MCU device when you select
\uicontrol Apply in the \uicontrol MCU tab after configuring the
MCU toolchain.
\uicontrol Apply in \preferences > \uicontrol SDKs > \uicontrol MCU after
adding an SDK.
\image qtcreator-mcu-device.png {MCU devices}
\image qtcreator-mcu-device.webp {MCU devices}
To add MCU devices, select \preferences > \uicontrol Devices > \uicontrol Add
> \uicontrol {MCU Device} > \uicontrol {Start Wizard}:
@@ -175,7 +201,6 @@
{Developing for MCUs}
*/
/*!
\page creator-how-to-manage-mcu-kits.html
\previouspage creator-how-tos.html
@@ -189,9 +214,10 @@
\QC automatically adds kits for all the available MCU targets if you select
\uicontrol {Automatically create kits for all available targets on start}
in \preferences > \uicontrol SDKs > \uicontrol MCU.
in \preferences > \uicontrol SDKs > \uicontrol MCU. This setting is selected
by default.
\image qtcreator-preferences-kits-mcu.webp {MCU kit}
\image qtcreator-mcu-new-kit.webp {Automatically create MCU kits}
\note When you update the \QMCU SDK, \QC asks you whether you want to replace
the existing kits or create additional kits. To do this manually for each
@@ -206,6 +232,8 @@
To change or remove individual kits, go to \preferences > \uicontrol Kits.
\image qtcreator-preferences-kits-mcu.webp {MCU kit}
The \uicontrol {MCU dependencies} field displays paths to 3rd party
software required for MCU development with the current kit.

View File

@@ -4,16 +4,16 @@ import qbs.FileInfo
import qbs.Utilities
Module {
property string qtcreator_display_version: '16.0.0-rc1'
property string ide_version_major: '15'
property string qtcreator_display_version: '16.0.0'
property string ide_version_major: '16'
property string ide_version_minor: '0'
property string ide_version_release: '84'
property string ide_version_release: '0'
property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.'
+ ide_version_release
property string ide_compat_version_major: '15'
property string ide_compat_version_major: '16'
property string ide_compat_version_minor: '0'
property string ide_compat_version_release: '84'
property string ide_compat_version_release: '0'
property string qtcreator_compat_version: ide_compat_version_major + '.'
+ ide_compat_version_minor + '.' + ide_compat_version_release

View File

@@ -78,6 +78,7 @@ local function setup()
end,
})
require 'tst_texteditor'.setup()
require 'tst_markdownbrowser'.setup()
end
return { setup = setup }

View File

@@ -0,0 +1,44 @@
local function tst_markdownBrowser()
G = require 'Gui'
G.Column {
G.MarkdownBrowser {
enableCodeCopyButton = true,
markdown = [[# Markdown Browser Test
## Code Snippets
* Is the following code formatted correctly, and is the syntax highlighting working?
* Can you press the copy button and paste the code into a text editor?
* Is there a copy icon visible for the code snippet?
```c++
#include <print>
int main() {
std::print("Hello World!");
}
```
## Links
* [Is this a link to the Qt website?](https://www.qt.io)
* [Is this an anchor link that scrolls up to the top?](#markdown-browser-test)
]]
}
}:show()
end
local function setup()
Action = require 'Action'
Action.create("LuaTests.markdownBrowserDemo", {
text = "Lua Markdown Browser Test",
onTrigger = tst_markdownBrowser,
})
end
return {
setup = setup,
}

View File

@@ -16,6 +16,8 @@
#include <QMenu>
#include <QMessageBox>
using namespace Core;
namespace %{PluginName}::Internal {
class %{CN} final : public ExtensionSystem::IPlugin
@@ -46,16 +48,15 @@ public:
// bool IPlugin::initialize(const QStringList &arguments, QString *errorString)
// overload.
auto action = new QAction(Tr::tr("%{PluginName} Action"), this);
Core::Command *cmd = Core::ActionManager::registerAction(
action, Constants::ACTION_ID, Core::Context(Core::Constants::C_GLOBAL));
cmd->setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Alt+Meta+A")));
connect(action, &QAction::triggered, this, &%{CN}::triggerAction);
Core::ActionContainer *menu = Core::ActionManager::createMenu(Constants::MENU_ID);
ActionContainer *menu = ActionManager::createMenu(Constants::MENU_ID);
menu->menu()->setTitle(Tr::tr("%{PluginName}"));
menu->addAction(cmd);
Core::ActionManager::actionContainer(Core::Constants::M_TOOLS)->addMenu(menu);
ActionManager::actionContainer(Core::Constants::M_TOOLS)->addMenu(menu);
ActionBuilder(this, Constants::ACTION_ID)
.addToContainer(Constants::MENU_ID)
.setText(Tr::tr("%{PluginName} Action"))
.setDefaultKeySequence(Tr::tr("Ctrl+Alt+Meta+A"))
.addOnTriggered(this, &%{CN}::triggerAction);
}
void extensionsInitialized() final
@@ -77,7 +78,7 @@ public:
private:
void triggerAction()
{
QMessageBox::information(Core::ICore::mainWindow(),
QMessageBox::information(ICore::dialogParent(),
Tr::tr("Action Triggered"),
Tr::tr("This is an action from %{PluginName}."));
}

View File

@@ -15,8 +15,8 @@ CodeModel_Info_TextMarkColor=Token_Notification_Neutral_Default
CodeModel_Warning_TextMarkColor=Token_Notification_Alert_Default
ComboBoxTextColor=Token_Text_Muted
Debugger_Breakpoint_TextMarkColor=Token_Notification_Danger_Default
Debugger_WatchItem_ValueChanged=Token_Notification_Danger_Muted
Debugger_WatchItem_ValueInvalid=Token_Background_Subtle
Debugger_WatchItem_ValueChanged=Token_Notification_Danger_Default
Debugger_WatchItem_ValueInvalid=Token_Text_Muted
Debugger_WatchItem_ValueNormal=Token_Text_Default
DockWidgetResizeHandleColor=Token_Stroke_Subtle
EditorPlaceholderColor=Token_Background_Muted
@@ -66,11 +66,10 @@ PaletteAlternateBase=Token_Background_Muted
PaletteAlternateBaseDisabled=Token_Background_Subtle
PaletteBase=Token_Background_Default
PaletteBaseDisabled=Token_Background_Subtle
PaletteBrightText=Token_Notification_Danger_Default
PaletteBrightText=Token_Text_Default
PaletteBrightTextDisabled=Token_Text_Subtle
PaletteButton=Token_Background_Default
PaletteButtonDisabled=Token_Background_Subtle
PaletteButtonDisabled=Token_Background_Default
PaletteButtonText=Token_Text_Default
PaletteButtonTextDisabled=Token_Text_Subtle
PaletteDark=Token_Background_Default
@@ -118,7 +117,7 @@ TextColorError=Token_Notification_Danger_Default
TextColorLink=Token_Text_Accent
TextColorNormal=Token_Text_Default
TextEditor_CurrentLine_ScrollBarColor=Token_Foreground_Muted
TextEditor_SearchResult_ScrollBarColor=Token_Notification_Alert_Default
TextEditor_SearchResult_ScrollBarColor=Token_Notification_Success_Default
TextEditor_Selection_ScrollBarColor=Token_Foreground_Subtle
Timeline_BackgroundColor1=Token_Background_Default
Timeline_BackgroundColor2=Token_Background_Muted

View File

@@ -337,6 +337,11 @@ TerminalAnsi13=d22dde
TerminalAnsi14=69e2e4
TerminalAnsi15=e5e5e6
;Hack for QTCREATORBUG-32572. Use these two colors from "flat/Hybrid (2016)" theme rather than
;using color tokens. Revert when Red and Yellow tokens are available.
IconsErrorColor=ffdf4f4f
IconsWarningColor=ffecbc1c
[Flags]
ComboBoxDrawTextShadow=false
DerivePaletteFromTheme=true

View File

@@ -25,12 +25,12 @@ Primitive-Neon-100=FFDBFDEC
Primitive-Neon-200=FFB9F9D9
Primitive-Neon-300=FF83F2BA
Primitive-Neon-400=FF2CDE85
Primitive-Neon-500=FF1EC974
Primitive-Neon-600=FF12A75D
Primitive-Neon-500=FF27BF73
Primitive-Neon-600=FF1F9B5D
Primitive-Neon-700=FF12834B
Primitive-Neon-800=FF14673E
Primitive-Neon-900=FF0D4328
Primitive-Neon-1000=FF092C1B
Primitive-Neon-900=FF13432B
Primitive-Neon-1000=FF133122
Primitive-Red-100=FFFACED9
Primitive-Red-200=FFF0A4B7

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -205,7 +205,7 @@ protected:
void visitSymbol0(SymbolVisitor *visitor) override;
private:
FullySpecifiedType _type;
const Name *_conceptName;
const Name *_conceptName = nullptr;
};
class CPLUSPLUS_EXPORT Block final : public Scope

View File

@@ -570,30 +570,21 @@ void _ClosePseudoConsoleMembers(_In_ PseudoConsole* pPty)
{
if (pPty != nullptr)
{
// See MSFT:19918626
// First break the signal pipe - this will trigger conhost to tear itself down
if (_HandleIsValid(pPty->hSignal))
{
CloseHandle(pPty->hSignal);
pPty->hSignal = nullptr;
}
// Then, wait on the conhost process before killing it.
// We do this to make sure the conhost finishes flushing any output it
// has yet to send before we hard kill it.
if (_HandleIsValid(pPty->hConPtyProcess))
{
TerminateProcess(pPty->hConPtyProcess, 0);
CloseHandle(pPty->hConPtyProcess);
pPty->hConPtyProcess = nullptr;
}
// Then take care of the reference handle.
// TODO GH#1810: Closing the reference handle late leaves conhost thinking
// that we have an outstanding connected client.
if (_HandleIsValid(pPty->hPtyReference))
{
CloseHandle(pPty->hPtyReference);
pPty->hPtyReference = nullptr;
}
if (_HandleIsValid(pPty->hConPtyProcess))
{
CloseHandle(pPty->hConPtyProcess);
pPty->hConPtyProcess = nullptr;
}
}
}

View File

@@ -338,7 +338,8 @@ expected_str<QFuture<Environment>> Client::start()
return;
}
// Broken package, search for next magic marker
qCWarning(clientLog) << "Magic marker was not found";
qCWarning(clientLog)
<< "Magic marker was not found, buffer content:" << buffer;
// If we don't find a magic marker, the rest of the buffer is trash.
buffer.clear();
} else {
@@ -445,8 +446,7 @@ static Utils::expected_str<QFuture<R>> createJob(
std::make_exception_ptr(std::system_error(ENOENT, std::generic_category())));
promise->finish();
} else if (errType == "NormalExit") {
promise->setException(
std::make_exception_ptr(std::runtime_error(err.toStdString())));
promise->setException(std::make_exception_ptr(std::runtime_error("NormalExit")));
promise->finish();
} else {
qCWarning(clientLog) << "Error (" << errType << "):" << err;
@@ -857,10 +857,22 @@ Utils::expected_str<QFuture<void>> Client::signalProcess(int pid, Utils::Control
bool Client::exit()
{
try {
createVoidJob(d.get(), QCborMap{{"Type", "exit"}}, "exitres")->waitForFinished();
createVoidJob(d.get(), QCborMap{{"Type", "exit"}}, "exitres").and_then([](auto future) {
future.waitForFinished();
return expected_str<void>();
});
return true;
} catch (const std::runtime_error &e) {
if (e.what() == std::string("NormalExit"))
return true;
qCWarning(clientLog) << "Client::exit() caught exception:" << e.what();
return false;
} catch (const std::exception &e) {
qCWarning(clientLog) << "Client::exit() caught exception:" << e.what();
return false;
} catch (...) {
qCWarning(clientLog) << "Client::exit() caught exception";
qCWarning(clientLog) << "Client::exit() caught unexpected exception";
return false;
}
}

View File

@@ -124,7 +124,7 @@ func readPacket(decoder *cbor.Decoder) (*command, error) {
func sendError(out chan<- []byte, cmd command, err error) {
errMsg := err.Error()
errType := reflect.TypeOf(err).Elem().Name()
errType := reflect.TypeOf(err).Name()
if e, ok := err.(*os.PathError); ok {
errMsg = e.Err.Error()
errType = reflect.TypeOf(e.Err).Name()

View File

@@ -145,6 +145,7 @@ static QHash<Utils::MimeType, QString> mimeTypeLanguageIdMap()
{"application/xml", "xml"},
{"application/xslt+xml", "xsl"},
{"application/x-yaml", "yaml"},
{"text/x-swift", "swift"},
};
for (const QPair<QString, QString> &languageIdForMimeTypeName : languageIdsForMimeTypeNames) {
const Utils::MimeType &mimeType = Utils::mimeTypeForName(languageIdForMimeTypeName.first);

View File

@@ -966,12 +966,6 @@ void TerminalView::keyPressEvent(QKeyEvent *event)
verticalScrollBar()->value() - d->m_surface->liveSize().height(),
verticalScrollBar()->maximum()));
break;
case Qt::Key_End:
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
break;
case Qt::Key_Home:
verticalScrollBar()->setValue(0);
break;
default:
if (event->key() < Qt::Key_Shift || event->key() > Qt::Key_ScrollLock)
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
@@ -1015,8 +1009,10 @@ void TerminalView::applySizeChange()
void TerminalView::updateScrollBars()
{
int scrollSize = d->m_surface->fullSize().height() - d->m_surface->liveSize().height();
const bool shouldScroll = verticalScrollBar()->value() == verticalScrollBar()->maximum();
verticalScrollBar()->setRange(0, scrollSize);
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
if (shouldScroll)
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
updateViewport();
}
@@ -1110,6 +1106,11 @@ void TerminalView::focusOutEvent(QFocusEvent *)
void TerminalView::inputMethodEvent(QInputMethodEvent *event)
{
// Gnome sends empty events when switching virtual desktops, so ignore those.
if (event->commitString().isEmpty() && event->preeditString().isEmpty()
&& event->attributes().empty() && d->m_preEditString.isEmpty())
return;
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
d->m_preEditString = event->preeditString();

View File

@@ -1479,10 +1479,11 @@ expected_str<QByteArray> UnixDeviceFileAccess::fileContents(const FilePath &file
}
#ifndef UTILS_STATIC_LIBRARY
const FilePath dd = filePath.withNewPath("dd");
using namespace std::literals::chrono_literals;
Process p;
p.setCommand({dd, args, OsType::OsTypeLinux});
p.runBlocking();
p.runBlocking(0s); // Run forever
if (p.exitCode() != 0) {
return make_unexpected(Tr::tr("Failed reading file \"%1\": %2")
.arg(filePath.toUserOutput(), p.readAllStandardError()));

View File

@@ -356,7 +356,7 @@ void EnvironmentModel::toggleVariable(const QModelIndex &idx)
{
const QString name = indexToVariable(idx);
const auto newIt = d->m_resultNameValueDictionary.find(name);
QTC_ASSERT(newIt != d->m_resultNameValueDictionary.begin(), return);
QTC_ASSERT(newIt != d->m_resultNameValueDictionary.end(), return);
const auto op = newIt.enabled() ? EnvironmentItem::SetDisabled : EnvironmentItem::SetEnabled;
const int changesPos = d->findInChanges(name);
if (changesPos != -1) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

View File

@@ -820,6 +820,11 @@ void Widget::setMinimumWidth(int minw)
access(this)->setMinimumWidth(minw);
}
void Widget::setMinimumHeight(int height)
{
access(this)->setMinimumHeight(height);
}
void Widget::setSizePolicy(const QSizePolicy &policy)
{
access(this)->setSizePolicy(policy);
@@ -1109,6 +1114,11 @@ MarkdownBrowser::MarkdownBrowser(std::initializer_list<I> ps)
apply(this, ps);
}
QString MarkdownBrowser::toMarkdown() const
{
return access(this)->toMarkdown();
}
void MarkdownBrowser::setMarkdown(const QString &markdown)
{
access(this)->setMarkdown(markdown);
@@ -1119,6 +1129,11 @@ void MarkdownBrowser::setBasePath(const Utils::FilePath &path)
access(this)->setBasePath(path);
}
void MarkdownBrowser::setEnableCodeCopyButton(bool enable)
{
access(this)->setEnableCodeCopyButton(enable);
}
// Special If
If::If(
@@ -1245,11 +1260,6 @@ void LineEdit::setCompleter(QCompleter *completer)
access(this)->setSpecialCompleter(completer);
}
void LineEdit::setMinimumHeight(int height)
{
access(this)->setMinimumHeight(height);
}
void LineEdit::onReturnPressed(QObject *guard, const std::function<void()> &func)
{
static_cast<LineEditImpl *>(access(this))->acceptReturnKeys = true;

View File

@@ -266,6 +266,7 @@ public:
void setContentsMargins(int left, int top, int right, int bottom);
void setCursor(Qt::CursorShape shape);
void setMinimumWidth(int);
void setMinimumHeight(int height);
void activateWindow();
void close();
@@ -357,7 +358,6 @@ public:
void setRightSideIconPath(const Utils::FilePath &path);
void setPlaceHolderText(const QString &text);
void setCompleter(QCompleter *completer);
void setMinimumHeight(int height);
void onReturnPressed(QObject *guard, const std::function<void()> &);
void onRightSideIconClicked(QObject *guard, const std::function<void()> &);
};
@@ -456,8 +456,10 @@ public:
MarkdownBrowser(std::initializer_list<I> items);
QString toMarkdown() const;
void setMarkdown(const QString &);
void setBasePath(const Utils::FilePath &);
void setEnableCodeCopyButton(bool enable);
};
// Special

View File

@@ -8,6 +8,7 @@
#include "mimeutils.h"
#include "movie.h"
#include "networkaccessmanager.h"
#include "stringutils.h"
#include "stylehelper.h"
#include "textutils.h"
#include "theme/theme.h"
@@ -19,8 +20,11 @@
#include <QBuffer>
#include <QCache>
#include <QClipboard>
#include <QDesktopServices>
#include <QGuiApplication>
#include <QPainter>
#include <QScrollBar>
#include <QTextBlock>
#include <QTextBrowser>
#include <QTextDocument>
@@ -81,9 +85,12 @@ static QStringList defaultCodeFontFamilies()
return {"Menlo", "Source Code Pro", "Monospace", "Courier"};
}
static void highlightCodeBlock(QTextDocument *document, QTextBlock &block, const QString &language)
static int registerSnippet(QTextDocument *document, const QString &code);
static void highlightCodeBlock(
QTextDocument *document, QTextBlock &block, const QString &language, bool enableCopy)
{
const int position = block.position();
const int startPos = block.position();
// Find the end of the code block ...
for (block = block.next(); block.isValid(); block = block.next()) {
if (!block.blockFormat().hasProperty(QTextFormat::BlockCodeLanguage))
@@ -91,43 +98,81 @@ static void highlightCodeBlock(QTextDocument *document, QTextBlock &block, const
if (language != block.blockFormat().stringProperty(QTextFormat::BlockCodeLanguage))
break;
}
const int end = (block.isValid() ? block.position() : document->characterCount()) - 1;
const int endPos = (block.isValid() ? block.position() : document->characterCount()) - 1;
// Get the text of the code block and erase it
QTextCursor eraseCursor(document);
eraseCursor.setPosition(position);
eraseCursor.setPosition(end, QTextCursor::KeepAnchor);
eraseCursor.setPosition(startPos);
eraseCursor.setPosition(endPos, QTextCursor::KeepAnchor);
const QString code = eraseCursor.selectedText();
eraseCursor.removeSelectedText();
// Create a new Frame and insert the highlighted code ...
block = document->findBlock(position);
// Reposition the main cursor to startPos, to insert new content
block = document->findBlock(startPos);
QTextCursor cursor(block);
QTextFrameFormat format;
format.setBorderStyle(QTextFrameFormat::BorderStyle_Solid);
format.setBackground(creatorColor(Theme::Token_Background_Muted));
format.setPadding(SpacingTokens::ExPaddingGapM);
format.setLeftMargin(SpacingTokens::VGapM);
format.setRightMargin(SpacingTokens::VGapM);
QTextFrame *frame = cursor.insertFrame(format);
QTextFrameFormat frameFormat;
frameFormat.setBorderStyle(QTextFrameFormat::BorderStyle_Solid);
frameFormat.setBackground(creatorColor(Theme::Token_Background_Muted));
frameFormat.setPadding(SpacingTokens::ExPaddingGapM);
frameFormat.setLeftMargin(SpacingTokens::VGapM);
frameFormat.setRightMargin(SpacingTokens::VGapM);
QTextFrame *frame = cursor.insertFrame(frameFormat);
QTextCursor frameCursor(frame);
std::unique_ptr<QTextDocument> codeDocument(highlightText(code, language));
bool first = true;
if (enableCopy) {
QTextBlockFormat linkBlockFmt;
linkBlockFmt.setAlignment(Qt::AlignRight);
frameCursor.insertBlock(linkBlockFmt);
for (auto block = codeDocument->begin(); block != codeDocument->end(); block = block.next()) {
if (!first)
frameCursor.insertBlock();
const int snippetId = registerSnippet(document, code);
const QString copy_id = QString("copy:%1").arg(snippetId);
QTextCharFormat charFormat = block.charFormat();
charFormat.setFontFamilies(defaultCodeFontFamilies());
frameCursor.setCharFormat(charFormat);
// Insert copy icon
QTextImageFormat imageFormat;
imageFormat.setName("qrc:/markdownbrowser/images/code_copy_square.png");
imageFormat.setAnchor(true);
imageFormat.setAnchorHref(copy_id);
imageFormat.setWidth(16);
imageFormat.setHeight(16);
frameCursor.insertImage(imageFormat);
first = false;
auto formats = block.layout()->formats();
frameCursor.insertText(block.text());
// Create a clickable anchor for the "Copy" text
QTextCharFormat anchorFormat;
anchorFormat.setAnchor(true);
anchorFormat.setAnchorHref(copy_id);
anchorFormat.setForeground(QColor("#888"));
anchorFormat.setFontPointSize(10);
frameCursor.setCharFormat(anchorFormat);
frameCursor.insertText(" Copy");
// Insert a new left-aligned block to start the first line of code
QTextBlockFormat codeBlockFmt;
codeBlockFmt.setAlignment(Qt::AlignLeft);
frameCursor.insertBlock(codeBlockFmt);
}
std::unique_ptr<QTextDocument> codeDoc(highlightText(code, language));
// Iterate each line in codeDoc and copy it out
bool firstLine = true;
for (auto tempBlock = codeDoc->begin(); tempBlock != codeDoc->end();
tempBlock = tempBlock.next()) {
// For each subsequent line, insert another block
if (!firstLine) {
QTextBlockFormat codeBlockFmt;
codeBlockFmt.setAlignment(Qt::AlignLeft);
frameCursor.insertBlock(codeBlockFmt);
}
firstLine = false;
QTextCharFormat lineFormat = tempBlock.charFormat();
lineFormat.setFontFamilies(defaultCodeFontFamilies());
frameCursor.setCharFormat(lineFormat);
auto formats = tempBlock.layout()->formats();
frameCursor.insertText(tempBlock.text());
frameCursor.block().layout()->setFormats(formats);
}
@@ -315,11 +360,18 @@ public:
|| (url.isRelative() && isBaseHttp);
};
QSet<QUrl> remoteUrls = Utils::filtered(m_urlsToLoad, isRemoteUrl);
QSet<QUrl> localUrls = Utils::filtered(m_urlsToLoad, std::not_fn(isRemoteUrl));
const auto isLocalUrl = [this, isRemoteUrl](const QUrl &url) {
if (url.scheme() == "qrc")
return true;
if (m_basePath.isEmpty())
localUrls.clear();
if (!m_basePath.isEmpty() && !isRemoteUrl(url))
return true;
return false;
};
QSet<QUrl> remoteUrls = Utils::filtered(m_urlsToLoad, isRemoteUrl);
QSet<QUrl> localUrls = Utils::filtered(m_urlsToLoad, isLocalUrl);
if (!m_loadRemoteImages)
remoteUrls.clear();
@@ -384,22 +436,36 @@ public:
}
};
auto onLocalSetup = [localIterator,
basePath = m_basePath,
maxSize = m_imageHandler.maximumCacheSize()](
Async<EntryPointer> &async) {
const FilePath path = basePath.resolvePath(localIterator->path());
async.setConcurrentCallData(
[](QPromise<EntryPointer> &promise, const FilePath &path, qsizetype maxSize) {
auto data = path.fileContents();
if (!data || promise.isCanceled())
return;
auto onLocalSetup =
[localIterator, basePath = m_basePath, maxSize = m_imageHandler.maximumCacheSize()](
Async<EntryPointer> &async) {
const QUrl url = *localIterator;
async.setConcurrentCallData(
[](QPromise<EntryPointer> &promise,
const FilePath &basePath,
const QUrl &url,
qsizetype maxSize) {
if (url.scheme() == "qrc") {
QFile f(":" + url.path());
if (!f.open(QIODevice::ReadOnly))
return;
promise.addResult(AnimatedImageHandler::makeEntry(*data, maxSize));
},
path,
maxSize);
};
promise.addResult(
AnimatedImageHandler::makeEntry(f.readAll(), maxSize));
return;
}
const FilePath path = basePath.resolvePath(url.path());
auto data = path.fileContents();
if (!data || promise.isCanceled())
return;
promise.addResult(AnimatedImageHandler::makeEntry(*data, maxSize));
},
basePath,
url,
maxSize);
};
auto onLocalDone = [localIterator, this](const Async<EntryPointer> &async) {
EntryPointer result = async.result();
@@ -427,6 +493,21 @@ public:
});
}
int registerSnippet(const QString &code)
{
const int id = m_nextSnippetId++;
m_snippetMap.insert(id, code);
return id;
}
QString snippetById(int id) const { return m_snippetMap.value(id); }
void clearSnippets()
{
m_snippetMap.clear();
m_nextSnippetId = 0;
}
void scheduleLoad(const QUrl &url)
{
m_urlsToLoad.insert(url);
@@ -449,11 +530,24 @@ private:
FilePath m_basePath;
std::function<void(QNetworkRequest *)> m_requestHook;
QNetworkAccessManager *m_networkAccessManager = NetworkAccessManager::instance();
QMap<int, QString> m_snippetMap;
int m_nextSnippetId = 0;
};
static int registerSnippet(QTextDocument *document, const QString &code)
{
auto *animDoc = static_cast<AnimatedDocument *>(document);
return animDoc->registerSnippet(code);
}
MarkdownBrowser::MarkdownBrowser(QWidget *parent)
: QTextBrowser(parent)
, m_enableCodeCopyButton(false)
{
setOpenLinks(false);
connect(this, &QTextBrowser::anchorClicked, this, &MarkdownBrowser::handleAnchorClicked);
setDocument(new AnimatedDocument(this));
}
@@ -480,6 +574,11 @@ void MarkdownBrowser::setMargins(const QMargins &margins)
setViewportMargins(margins);
}
void MarkdownBrowser::setEnableCodeCopyButton(bool enable)
{
m_enableCodeCopyButton = enable;
}
void MarkdownBrowser::setAllowRemoteImages(bool allow)
{
static_cast<AnimatedDocument *>(document())->setAllowRemoteImages(allow);
@@ -500,6 +599,33 @@ void MarkdownBrowser::setMaximumCacheSize(qsizetype maxSize)
static_cast<AnimatedDocument *>(document())->setMaximumCacheSize(maxSize);
}
void MarkdownBrowser::handleAnchorClicked(const QUrl &link)
{
if (link.scheme() != QLatin1String("copy")) {
if (link.scheme() == "http" || link.scheme() == "https")
QDesktopServices::openUrl(link);
if (link.hasFragment() && link.path().isEmpty() && link.scheme().isEmpty()) {
// local anchor
scrollToAnchor(link.fragment(QUrl::FullyEncoded));
}
return;
}
bool ok = false;
const int snippetId = link.path().toInt(&ok);
if (!ok)
return;
auto *animDoc = static_cast<AnimatedDocument *>(document());
const QString snippet = animDoc->snippetById(snippetId).replace(QChar::ParagraphSeparator, '\n');
if (snippet.isEmpty())
return;
Utils::setClipboardAndSelection(snippet);
}
void MarkdownBrowser::setBasePath(const FilePath &filePath)
{
static_cast<AnimatedDocument *>(document())->setBasePath(filePath);
@@ -507,13 +633,26 @@ void MarkdownBrowser::setBasePath(const FilePath &filePath)
void MarkdownBrowser::setMarkdown(const QString &markdown)
{
QScrollBar *sb = verticalScrollBar();
int oldValue = sb->value();
auto *animDoc = static_cast<AnimatedDocument *>(document());
animDoc->clearSnippets();
document()->setMarkdown(markdown);
postProcessDocument(true);
QTimer::singleShot(0, this, [sb, oldValue] { sb->setValue(oldValue); });
// Reset cursor to start of the document, so that "show" does not
// scroll to the end of the document.
setTextCursor(QTextCursor(document()));
}
QString MarkdownBrowser::toMarkdown() const
{
return document()->toMarkdown();
}
void MarkdownBrowser::postProcessDocument(bool firstTime) const
{
const QFont contentFont = Utils::font(contentTF);
@@ -534,7 +673,7 @@ void MarkdownBrowser::postProcessDocument(bool firstTime) const
// Convert code blocks to highlighted frames
if (blockFormat.hasProperty(QTextFormat::BlockCodeLanguage)) {
const QString language = blockFormat.stringProperty(QTextFormat::BlockCodeLanguage);
highlightCodeBlock(document(), block, language);
highlightCodeBlock(document(), block, language, m_enableCodeCopyButton);
continue;
}

View File

@@ -25,6 +25,7 @@ public:
MarkdownBrowser(QWidget *parent = nullptr);
void setMarkdown(const QString &markdown);
QString toMarkdown() const;
void setBasePath(const FilePath &filePath);
void setAllowRemoteImages(bool allow);
void setNetworkAccessManager(QNetworkAccessManager *nam);
@@ -35,12 +36,17 @@ public:
QSize minimumSizeHint() const override;
void setMargins(const QMargins &margins);
void setEnableCodeCopyButton(bool enable);
protected:
void changeEvent(QEvent *event) override;
private:
void handleAnchorClicked(const QUrl &link);
void postProcessDocument(bool firstTime) const;
private:
bool m_enableCodeCopyButton;
};
} // namespace Utils

View File

@@ -115,6 +115,10 @@ bool NameValueItemsWidget::editVariable(const QString &name, Selection selection
}
};
skipWhiteSpace();
if (offset < line.length() && line.at(offset) == '#') {
++offset;
skipWhiteSpace();
}
if (line.mid(offset, name.size()) != name)
continue;
offset += name.size();

View File

@@ -295,4 +295,8 @@
<file>images/classrelationbackground.png</file>
<file>images/classrelationbackground@2x.png</file>
</qresource>
<qresource prefix="/markdownbrowser">
<file>images/code_copy_square.png</file>
<file>images/code_copy_square@2x.png</file>
</qresource>
</RCC>

View File

@@ -7,6 +7,8 @@ QtcPlugin {
condition: Qt.charts.present
pluginjson.replacements: ({APPSTATISTICSMONITOR_DISABLEDBYDEFAULT: "true"})
files: [
"appstatisticsmonitorplugin.cpp",
"appstatisticsmonitortr.h",

View File

@@ -48,7 +48,8 @@ static QPoint globalPosOnScreen(const QPoint &orig, const QSize &size)
qscreen = QGuiApplication::primaryScreen();
const QRect screen = qscreen->availableGeometry();
return QPoint(std::max(screen.x(), orig.x() - size.width()), orig.y() - size.height());
return QPoint(std::max(screen.x(), orig.x() - size.width()),
std::max(screen.y(), orig.y() - size.height()));
}
class FilterPopupWidget : public QFrame

View File

@@ -124,6 +124,7 @@ public:
rp.setUseContinueInsteadOfRun(true);
rp.setContinueAfterAttach(true);
rp.addSolibSearchDir("%{sysroot}/system/lib");
rp.setSkipDebugServer(true);
auto debuggee = createQdbDeviceInferiorWorker(runControl, QmlDebuggerServices);
worker->addStartDependency(debuggee);

View File

@@ -2007,12 +2007,14 @@ void CMakeBuildConfiguration::setBuildPresetToBuildSteps(const ProjectExplorer::
cbs->setToolArguments(nativeToolOptions.split(" "));
}
if (buildPresets[i].configuration)
if (buildPresets[i].configuration) {
cbs->setConfiguration(*buildPresets[i].configuration);
// Leave only the first build step enabled
if (i > 0)
cbs->setStepEnabled(false);
cbs->setStepEnabled(buildTypeAspect() == buildPresets[i].configuration);
} else {
// Leave only the first build step enabled
if (i > 0)
cbs->setStepEnabled(false);
}
}
}

View File

@@ -40,9 +40,9 @@ FileApiReader::FileApiReader()
: m_lastReplyTimestamp()
{
QObject::connect(&m_watcher,
&FileSystemWatcher::directoryChanged,
&FileSystemWatcher::fileChanged,
this,
&FileApiReader::handleReplyDirectoryChange);
&FileApiReader::handleReplyIndexFileChange);
}
FileApiReader::~FileApiReader()
@@ -60,11 +60,7 @@ void FileApiReader::setParameters(const BuildDirParameters &p)
m_parameters = p;
qCDebug(cmakeFileApiMode) << "Work directory:" << m_parameters.buildDirectory.toUserOutput();
FileApiParser::setupCMakeFileApi(m_parameters.buildDirectory);
const FilePath replyDirectory = FileApiParser::cmakeReplyDirectory(m_parameters.buildDirectory);
if (!m_watcher.watchesDirectory(replyDirectory))
m_watcher.addDirectory(replyDirectory.path(), FileSystemWatcher::WatchAllChanges);
setupCMakeFileApi();
resetData();
}
@@ -351,6 +347,15 @@ void FileApiReader::writeConfigurationIntoBuildDirectory(const QStringList &conf
QTC_ASSERT_EXPECTED(settingsFile.writeFileContents(contents), return);
}
void FileApiReader::setupCMakeFileApi()
{
FileApiParser::setupCMakeFileApi(m_parameters.buildDirectory);
const FilePath replyIndexfile = FileApiParser::scanForCMakeReplyFile(m_parameters.buildDirectory);
if (!replyIndexfile.isEmpty() && !m_watcher.watchesFile(replyIndexfile))
m_watcher.addFile(replyIndexfile.path(), FileSystemWatcher::WatchAllChanges);
}
QString FileApiReader::cmakeGenerator() const
{
return m_cmakeGenerator;
@@ -403,16 +408,13 @@ void FileApiReader::cmakeFinishedState(int exitCode)
if (m_lastCMakeExitCode != 0)
makeBackupConfiguration(false);
FileApiParser::setupCMakeFileApi(m_parameters.buildDirectory);
m_watcher.addDirectory(FileApiParser::cmakeReplyDirectory(m_parameters.buildDirectory).path(),
FileSystemWatcher::WatchAllChanges);
setupCMakeFileApi();
endState(FileApiParser::scanForCMakeReplyFile(m_parameters.buildDirectory),
m_lastCMakeExitCode != 0);
}
void FileApiReader::handleReplyDirectoryChange(const QString &directory)
void FileApiReader::handleReplyIndexFileChange(const QString &indexFile)
{
if (m_isParsing)
return; // This has been triggered by ourselves, ignore.
@@ -422,7 +424,7 @@ void FileApiReader::handleReplyDirectoryChange(const QString &directory)
if (dir.isEmpty())
return; // CMake started to fill the result dir, but has not written a result file yet
QTC_CHECK(dir.isLocal());
QTC_ASSERT(dir.path() == directory, return);
QTC_ASSERT(dir == FilePath::fromString(indexFile).parentDir(), return);
if (m_lastReplyTimestamp.isValid() && reply.lastModified() > m_lastReplyTimestamp) {
m_lastReplyTimestamp = reply.lastModified();

View File

@@ -78,10 +78,11 @@ private:
void startCMakeState(const QStringList &configurationArguments);
void cmakeFinishedState(int exitCode);
void handleReplyDirectoryChange(const QString &directory);
void handleReplyIndexFileChange(const QString &indexFile);
void makeBackupConfiguration(bool store);
void writeConfigurationIntoBuildDirectory(const QStringList &configuration);
void setupCMakeFileApi();
std::unique_ptr<CMakeProcess> m_cmakeProcess;

View File

@@ -42,7 +42,7 @@ namespace Copilot::Internal {
static LanguageClient::BaseClientInterface *clientInterface(const FilePath &nodePath,
const FilePath &distPath)
{
CommandLine cmd{nodePath, {distPath.toFSPathString()}};
CommandLine cmd{nodePath, {distPath.toFSPathString(), "--stdio"}};
const auto interface = new LanguageClient::StdIOClientInterface;
interface->setCommandLine(cmd);

View File

@@ -1618,7 +1618,8 @@ bool EditorManagerPrivate::closeEditors(const QList<IEditor*> &editors, CloseFla
emit m_instance->editorAboutToClose(editor);
const DocumentModel::Entry *entry = DocumentModel::entryForDocument(editor->document());
// If the file is pinned, closing it should remove the editor but keep it in Open Documents.
const bool removeSuspendedEntry = !entry->pinned && flag != CloseFlag::Suspend;
const bool isPinned = QTC_GUARD(entry) && entry->pinned;
const bool removeSuspendedEntry = !isPinned && flag != CloseFlag::Suspend;
removeEditor(editor, removeSuspendedEntry);
if (EditorView *view = viewForEditor(editor)) {
editorsPerView.insert(view, editor);

View File

@@ -681,7 +681,10 @@ void OutputWindow::registerPositionOf(unsigned taskId, int linkedOutputLines, in
return;
const int blocknumber = document()->blockCount() - offset;
const int firstLine = blocknumber - linkedOutputLines - skipLines;
// -1 because OutputFormatter has already added the newline.
const int firstLine = blocknumber - linkedOutputLines - skipLines - 1;
const int lastLine = firstLine + linkedOutputLines - 1;
d->taskPositions.insert(taskId, {firstLine, lastLine});

View File

@@ -413,6 +413,12 @@ static QString determineSessionToRestoreAtStartup()
return {};
}
bool SessionManager::loadsSessionOrFileAtStartup()
{
// "left-over arguments" usually mean a session or files
return !PluginManager::arguments().isEmpty() || !determineSessionToRestoreAtStartup().isEmpty();
}
void SessionManagerPrivate::restoreStartupSession()
{
NANOTRACE_SCOPE("Core", "SessionManagerPrivate::restoreStartupSession");

View File

@@ -28,6 +28,8 @@ public:
static SessionManager *instance();
static bool loadsSessionOrFileAtStartup();
// higher level session management
static QString activeSession();
static QString lastSession();

View File

@@ -29,7 +29,8 @@ public:
QDir::toNativeSeparators("../Src"),
".."};
Utils::FilePath licenseTemplatePath;
QString headerGuardTemplate = "%{JS: '%{Header:FileName}'.toUpperCase().replace(/[.]/g, '_')}";
QString headerGuardTemplate
= "%{JS: '%{Header:FileName}'.toUpperCase().replace(/^[1-9]/, '_').replace(/[^_a-zA-Z1-9]/g, '_')}";
bool headerPragmaOnce = false;
bool lowerCaseFiles = Constants::LOWERCASE_CPPFILES_DEFAULT;

View File

@@ -25,9 +25,12 @@
#include <texteditor/codeassist/iassistproposal.h>
#include <texteditor/codeassist/iassistproposalmodel.h>
#include <texteditor/icodestylepreferences.h>
#include <texteditor/storagesettings.h>
#include <texteditor/syntaxhighlighter.h>
#include <texteditor/tabsettings.h>
#include <texteditor/texteditor.h>
#include <texteditor/texteditorsettings.h>
#include <utils/environment.h>
#include <utils/fileutils.h>
@@ -232,6 +235,9 @@ bool TestCase::openCppEditor(const FilePath &filePath, TextEditor::BaseTextEdito
TextEditor::StorageSettings s = e->textDocument()->storageSettings();
s.m_addFinalNewLine = false;
e->textDocument()->setStorageSettings(s);
TextEditor::TabSettings ts = TextEditor::TextEditorSettings::codeStyle()->tabSettings();
ts.m_autoDetect = false;
e->textDocument()->setTabSettings(ts);
}
if (!QTest::qWaitFor(

View File

@@ -1019,7 +1019,7 @@ static QString trimmedFileName(const FilePath &fullPath)
const Project *project = ProjectTree::currentProject();
const FilePath projectDirectory = project ? project->projectDirectory() : FilePath();
if (projectDirectory.exists())
return FilePath::calcRelativePath(fullPath.path(), projectDirectory.toUserOutput());
return fullPath.relativePathFrom(projectDirectory).toUserOutput();
return fullPath.toUserOutput();
}

View File

@@ -268,6 +268,9 @@ public:
void setServerEssential(bool on) { m_serverEssential = on; }
bool serverEssential() const { return m_serverEssential; }
void setSkipDebugServer(bool on) { m_skipDebugServer = on; }
bool skipDebugServer() const { return m_skipDebugServer; }
void setAddQmlServerInferiorCmdArgIfNeeded(bool on) { m_addQmlServerInferiorCmdArgIfNeeded = on; }
bool isAddQmlServerInferiorCmdArgIfNeeded() const { return m_addQmlServerInferiorCmdArgIfNeeded; }
@@ -367,6 +370,7 @@ private:
Utils::ProcessHandle m_serverAttachPid;
bool m_serverUseMulti = true;
bool m_serverEssential = true;
bool m_skipDebugServer = false;
bool m_addQmlServerInferiorCmdArgIfNeeded = false;
};

View File

@@ -16,7 +16,7 @@ const Icon BREAKPOINT_PENDING({
{":/debugger/images/breakpoint_pending_overlay.png", Theme::PanelTextColorDark}}, Icon::IconStyleOptions(Icon::Tint | Icon::PunchEdges));
const Icon BREAKPOINT_WITH_LOCATION({
{":/utils/images/filledcircle.png", Theme::IconsErrorColor},
{":/debugger/images/location.png", Theme::IconsWarningToolBarColor}}, Icon::Tint);
{":/debugger/images/location.png", Theme::IconsWarningColor}}, Icon::Tint);
const Icon BREAKPOINTS(
":/debugger/images/debugger_breakpoints.png");
const Icon WATCHPOINT({
@@ -65,10 +65,10 @@ const Icon DEBUG_EXIT_SMALL_TOOLBAR({
{":/utils/images/debugger_overlay_small.png", Theme::IconsDebugColor}});
const Icon LOCATION({
{":/debugger/images/location_background.png", Theme::IconsCodeModelOverlayForegroundColor},
{":/debugger/images/location.png", Theme::IconsWarningToolBarColor}}, Icon::Tint);
{":/debugger/images/location.png", Theme::IconsWarningColor}}, Icon::Tint);
const Icon REVERSE_LOCATION({
{":/debugger/images/debugger_reversemode_background.png", Theme::IconsCodeModelOverlayForegroundColor},
{":/debugger/images/debugger_reversemode.png", Theme::IconsWarningToolBarColor}}, Icon::Tint);
{":/debugger/images/debugger_reversemode.png", Theme::IconsWarningColor}}, Icon::Tint);
const Icon REVERSE_MODE({
{":/debugger/images/debugger_reversemode_background.png", Theme::IconsCodeModelOverlayForegroundColor},
{":/debugger/images/debugger_reversemode.png", Theme::IconsInfoColor}}, Icon::Tint);

View File

@@ -562,7 +562,7 @@ void DebuggerRunTool::showMessage(const QString &msg, int channel, int timeout)
void DebuggerRunTool::startDebugServerIfNeededAndContinueStartup()
{
if (!runControl()->usesDebugChannel()) {
if (!runControl()->usesDebugChannel() || m_runParameters.skipDebugServer()) {
continueAfterDebugServerStart();
return;
}
@@ -680,9 +680,9 @@ void DebuggerRunTool::startDebugServerIfNeededAndContinueStartup()
});
connect(&d->debuggerServerProc, &Process::done, this, [this] {
if (d->terminalProc.error() != QProcess::UnknownError)
reportFailure(d->terminalProc.errorString());
if (d->terminalProc.error() != QProcess::FailedToStart && m_runParameters.serverEssential())
if (d->debuggerServerProc.error() != QProcess::UnknownError)
reportFailure(d->debuggerServerProc.errorString());
if (d->debuggerServerProc.error() != QProcess::FailedToStart && m_runParameters.serverEssential())
reportDone();
});

View File

@@ -1511,7 +1511,9 @@ void GdbEngine::handlePythonSetup(const DebuggerResponse &response)
GdbMi data = response.data;
watchHandler()->addDumpers(data["dumpers"]);
m_pythonVersion = data["python"].toInt();
if (m_pythonVersion < 30700) {
// Python 3.5.x: Released 2016-06-27, supported until 2018-12-24, security until 2021-12-23,
// used in Ubuntu 16.04 and Qt 5.15.10 Boot2Qt BSPs.
if (m_pythonVersion < 30502) {
int pythonMajor = m_pythonVersion / 10000;
int pythonMinor = (m_pythonVersion / 100) % 100;
QString out = "<p>"

View File

@@ -296,13 +296,18 @@ void ModulesHandler::updateModule(const Module &module)
m_model->rootItem()->appendChild(item);
}
try { // MinGW occasionallly throws std::bad_alloc.
ElfReader reader(path);
item->module.elfData = reader.readHeaders();
item->update();
} catch(...) {
qWarning("%s: An exception occurred while reading module '%s'",
Q_FUNC_INFO, qPrintable(module.modulePath.toUserOutput()));
if (path.isLocal()) {
try { // MinGW occasionallly throws std::bad_alloc.
ElfReader reader(path);
item->module.elfData = reader.readHeaders();
item->update();
} catch(...) {
qWarning("%s: An exception occurred while reading module '%s'",
Q_FUNC_INFO, qPrintable(module.modulePath.toUserOutput()));
}
} else {
m_model->engine->showMessage(
QString("Skipping elf-reading of remote path %1").arg(path.toUserOutput()));
}
item->updated = true;
}

View File

@@ -16,5 +16,4 @@ add_qtc_plugin(DiffEditor
selectabletexteditorwidget.cpp selectabletexteditorwidget.h
sidebysidediffeditorwidget.cpp sidebysidediffeditorwidget.h
unifieddiffeditorwidget.cpp unifieddiffeditorwidget.h
EXPLICIT_MOC diffeditor.h
)

View File

@@ -6,6 +6,8 @@ add_qtc_plugin(Docker
dockertr.h
dockerapi.cpp dockerapi.h
dockerconstants.h
dockercontainerthread.cpp
dockercontainerthread.h
dockerdevice.cpp dockerdevice.h
dockerdevicewidget.cpp dockerdevicewidget.h
dockerplugin.cpp

View File

@@ -16,6 +16,8 @@ QtcPlugin {
"dockerapi.cpp",
"dockerapi.h",
"dockerconstants.h",
"dockercontainerthread.cpp",
"dockercontainerthread.h",
"dockerdevice.cpp",
"dockerdevice.h",
"dockerdevicewidget.cpp",

View File

@@ -38,22 +38,19 @@ bool DockerApi::canConnect()
{
Process process;
FilePath dockerExe = dockerClient();
if (dockerExe.isEmpty() || !dockerExe.isExecutableFile())
if (dockerExe.isEmpty())
return false;
bool result = false;
process.setCommand({dockerExe, {"info"}});
connect(&process, &Process::done, [&process, &result] {
process.runBlocking();
const bool success = process.result() == ProcessResult::FinishedWithSuccess;
if (!success)
qCWarning(dockerApiLog) << "Failed to connect to docker daemon:" << process.allOutput();
else
qCInfo(dockerApiLog) << "'docker info' result:\n" << qPrintable(process.allOutput());
if (process.result() == ProcessResult::FinishedWithSuccess)
result = true;
});
process.start();
process.waitForFinished();
return result;
return process.result() == ProcessResult::FinishedWithSuccess;
}
bool DockerApi::isContainerRunning(const QString &containerId)

View File

@@ -0,0 +1,147 @@
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "dockercontainerthread.h"
#include "dockertr.h"
#include <utils/qtcprocess.h>
#include <QLoggingCategory>
using namespace Utils;
Q_LOGGING_CATEGORY(dockerThreadLog, "qtc.docker.device.thread", QtWarningMsg);
namespace Docker::Internal {
// THIS OBJECT MAY NEVER KNOW OR CALL ANY OTHER OBJECTS, EXCEPT ITS OWN !!!
class Internal : public QObject
{
public:
Internal(const DockerContainerThread::Init &init)
: m_init(init)
{}
~Internal()
{
if (m_startProcess && m_startProcess->isRunning()) {
// Kill instead of stop so we don't wait for the process to finish.
m_startProcess->kill();
m_startProcess->waitForFinished();
}
}
expected_str<QString> start()
{
QString containerId;
if (expected_str<QString> create = createContainer(); !create)
return make_unexpected(create.error());
else
containerId = *create;
if (Result start = startContainer(); !start)
return make_unexpected(start.error());
return containerId;
}
private:
expected_str<QString> createContainer()
{
Process createProcess;
createProcess.setCommand(m_init.createContainerCmd);
createProcess.runBlocking();
if (createProcess.result() != ProcessResult::FinishedWithSuccess) {
return make_unexpected(
Tr::tr("Failed creating Docker container. Exit code: %1, output: %2")
.arg(createProcess.exitCode())
.arg(createProcess.allOutput()));
}
m_containerId = createProcess.cleanedStdOut().trimmed();
if (m_containerId.isEmpty())
return make_unexpected(
Tr::tr("Failed creating Docker container. No container ID received."));
qCDebug(dockerThreadLog) << "ContainerId:" << m_containerId;
return m_containerId;
}
Result startContainer()
{
using namespace std::chrono_literals;
m_startProcess = new Process(this);
m_startProcess->setCommand(
{m_init.dockerBinaryPath, {"container", "start", "-a", "-i", m_containerId}});
m_startProcess->setProcessMode(ProcessMode::Writer);
m_startProcess->start();
if (!m_startProcess->waitForStarted(5s)) {
if (m_startProcess->state() == QProcess::NotRunning) {
return Result::Error(
Tr::tr("Failed starting Docker container. Exit code: %1, output: %2")
.arg(m_startProcess->exitCode())
.arg(m_startProcess->allOutput()));
}
// Lets assume it will start soon
qCWarning(dockerThreadLog)
<< "Docker container start process took more than 5 seconds to start.";
}
qCDebug(dockerThreadLog) << "Started container: " << m_startProcess->commandLine();
return Result::Ok;
}
private:
DockerContainerThread::Init m_init;
QString m_containerId;
Process *m_startProcess = nullptr;
};
DockerContainerThread::DockerContainerThread(Init init)
: m_internal(new Internal(init))
{
m_thread.setObjectName("Docker Container Thread");
m_internal->moveToThread(&m_thread);
QObject::connect(&m_thread, &QThread::finished, m_internal, &QObject::deleteLater);
m_thread.start();
}
Result DockerContainerThread::start()
{
expected_str<QString> result;
QMetaObject::invokeMethod(m_internal, &Internal::start, Qt::BlockingQueuedConnection, &result);
if (result) {
m_containerId = *result;
return Result::Ok;
}
return Result::Error(result.error());
}
DockerContainerThread::~DockerContainerThread()
{
m_thread.quit();
m_thread.wait();
}
QString DockerContainerThread::containerId() const
{
return m_containerId;
}
expected_str<std::unique_ptr<DockerContainerThread>> DockerContainerThread::create(const Init &init)
{
std::unique_ptr<DockerContainerThread> thread(new DockerContainerThread(init));
if (Result result = thread->start(); !result)
return make_unexpected(result.error());
return thread;
}
} // namespace Docker::Internal

View File

@@ -0,0 +1,40 @@
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <utils/commandline.h>
#include <QThread>
namespace Docker::Internal {
class Internal;
class DockerContainerThread
{
public:
struct Init
{
Utils::CommandLine createContainerCmd;
Utils::FilePath dockerBinaryPath;
};
public:
~DockerContainerThread();
QString containerId() const;
static Utils::expected_str<std::unique_ptr<DockerContainerThread>> create(const Init &init);
private:
DockerContainerThread(Init init);
Utils::Result start();
private:
QThread m_thread;
Internal *m_internal;
QString m_containerId;
};
} // namespace Docker::Internal

View File

@@ -5,6 +5,7 @@
#include "dockerapi.h"
#include "dockerconstants.h"
#include "dockercontainerthread.h"
#include "dockerdevicewidget.h"
#include "dockersettings.h"
#include "dockertr.h"
@@ -170,25 +171,19 @@ public:
DockerDevicePrivate(DockerDevice *parent)
: q(parent)
{
QObject::connect(q, &DockerDevice::applied, this, [this] {
if (!m_container.isEmpty()) {
stopCurrentContainer();
}
});
QObject::connect(q, &DockerDevice::applied, this, [this] { stopCurrentContainer(); });
}
~DockerDevicePrivate() { stopCurrentContainer(); }
CommandLine createCommandLine();
expected_str<void> updateContainerAccess();
expected_str<QString> updateContainerAccess();
void changeMounts(QStringList newMounts);
bool ensureReachable(const FilePath &other);
void shutdown();
expected_str<FilePath> localSource(const FilePath &other) const;
QString containerId() { return m_container; }
expected_str<QPair<Utils::OsType, Utils::OsArch>> osTypeAndArch() const;
expected_str<Environment> environment();
@@ -204,10 +199,8 @@ public:
bool prepareForBuild(const Target *target);
Tasks validateMounts() const;
expected_str<QString> createContainer();
expected_str<void> startContainer();
void stopCurrentContainer();
expected_str<void> fetchSystemEnviroment();
Result fetchSystemEnviroment();
expected_str<FilePath> getCmdBridgePath() const;
@@ -277,13 +270,10 @@ public:
FilePath containerPath;
};
QString m_container;
std::unique_ptr<Process> m_startProcess;
std::optional<Environment> m_cachedEnviroment;
bool m_isShutdown = false;
SynchronizedValue<std::unique_ptr<DeviceFileAccess>> m_fileAccess;
SynchronizedValue<std::unique_ptr<DockerContainerThread>> m_deviceThread;
};
class DockerProcessImpl : public ProcessInterface
@@ -299,9 +289,7 @@ private:
private:
DockerDevicePrivate *m_devicePrivate = nullptr;
// Store the IDevice::ConstPtr in order to extend the lifetime of device for as long
// as this object is alive.
IDevice::ConstPtr m_device;
std::weak_ptr<const IDevice> m_device;
Process m_process;
qint64 m_remotePID = 0;
@@ -312,7 +300,7 @@ private:
DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePrivate *devicePrivate)
: m_devicePrivate(devicePrivate)
, m_device(std::move(device))
, m_device(device)
, m_process(this)
{
connect(&m_process, &Process::started, this, [this] {
@@ -378,7 +366,6 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva
if (rest.size() > 0 || stdErr.size() > 0)
emit readyRead(rest, stdErr);
});
connect(&m_process, &Process::readyReadStandardError, this, [this] {
@@ -412,6 +399,15 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva
emit done(resultData);
});
connect(device.get(), &QObject::destroyed, this, [this] {
emit done(ProcessResultData{
-1,
QProcess::ExitStatus::CrashExit,
QProcess::ProcessError::UnknownError,
Tr::tr("Device is shut down"),
});
});
}
DockerProcessImpl::~DockerProcessImpl()
@@ -482,15 +478,19 @@ void DockerProcessImpl::sendControlSignal(ControlSignal controlSignal)
m_process.closeWriteChannel();
return;
}
auto dfa = dynamic_cast<DockerDeviceFileAccess *>(m_device->fileAccess());
auto device = m_device.lock();
if (!device)
return;
auto dfa = dynamic_cast<DockerDeviceFileAccess *>(device->fileAccess());
if (dfa) {
static_cast<DockerDeviceFileAccess *>(m_device->fileAccess())
static_cast<DockerDeviceFileAccess *>(device->fileAccess())
->signalProcess(m_remotePID, controlSignal);
} else {
const int signal = controlSignalToInt(controlSignal);
Process p;
p.setCommand(
{m_device->rootPath().withNewPath("kill"),
{device->rootPath().withNewPath("kill"),
{QString("-%1").arg(signal), QString("%2").arg(m_remotePID)}});
p.runBlocking();
}
@@ -602,7 +602,6 @@ DockerDevice::DockerDevice()
auto future = DockerApi::instance()->networks();
auto watcher = new QFutureWatcher<expected_str<QList<Network>>>(this);
watcher->setFuture(future);
QObject::connect(watcher,
&QFutureWatcher<expected_str<QList<Network>>>::finished,
this,
@@ -622,6 +621,7 @@ DockerDevice::DockerDevice()
cb({errorItem});
}
});
watcher->setFuture(future);
});
connect(DockerApi::instance(),
@@ -671,13 +671,10 @@ DockerDevice::DockerDevice()
const FilePath &workingDir) -> expected_str<void> {
Q_UNUSED(env); // TODO: That's the runnable's environment in general. Use it via -e below.
expected_str<void> result = d->updateContainerAccess();
expected_str<QString> result = d->updateContainerAccess();
if (!result)
return result;
if (d->containerId().isEmpty())
return make_unexpected(Tr::tr("Error starting remote shell. No container."));
return make_unexpected(result.error());
expected_str<FilePath> shell = Terminal::defaultShellForDevice(rootPath());
if (!shell)
@@ -716,9 +713,10 @@ void DockerDevice::shutdown()
d->shutdown();
}
expected_str<void> DockerDevice::updateContainerAccess() const
Result DockerDevice::updateContainerAccess() const
{
return d->updateContainerAccess();
expected_str<QString> result = d->updateContainerAccess();
return result ? Result::Ok : Result::Error(result.error());
}
expected_str<CommandLine> DockerDevicePrivate::withDockerExecCmd(
@@ -729,8 +727,12 @@ expected_str<CommandLine> DockerDevicePrivate::withDockerExecCmd(
bool withPty,
bool withMarker)
{
if (const auto result = updateContainerAccess(); !result)
QString containerId;
if (const expected_str<QString> result = updateContainerAccess(); !result)
return make_unexpected(result.error());
else
containerId = *result;
auto osAndArch = osTypeAndArch();
if (!osAndArch)
@@ -756,7 +758,7 @@ expected_str<CommandLine> DockerDevicePrivate::withDockerExecCmd(
if (workDir && !workDir->isEmpty())
dockerCmd.addArgs({"-w", q->rootPath().withNewMappedPath(*workDir).nativePath()});
dockerCmd.addArg(m_container);
dockerCmd.addArg(containerId);
dockerCmd.addArgs({"/bin/sh", "-c"}, osAndArch->first);
@@ -787,28 +789,12 @@ expected_str<CommandLine> DockerDevicePrivate::withDockerExecCmd(
void DockerDevicePrivate::stopCurrentContainer()
{
if (m_container.isEmpty())
return;
if (!DockerApi::isDockerDaemonAvailable(false).value_or(false))
return;
auto fileAccess = m_fileAccess.writeLocked();
if (*fileAccess) {
if (QThread::currentThread() == thread()) {
fileAccess->reset();
} else {
QMetaObject::invokeMethod(
this, [ptr = fileAccess->release()]() { delete ptr; }, Qt::QueuedConnection);
}
}
if (m_startProcess && m_startProcess->isRunning())
m_startProcess->kill(); // Kill instead of stop so we don't wait for the process to finish.
m_container.clear();
m_cachedEnviroment.reset();
auto fileAccess = m_fileAccess.writeLocked();
fileAccess->reset();
auto locked = m_deviceThread.writeLocked();
locked->reset();
}
bool DockerDevicePrivate::prepareForBuild(const Target *target)
@@ -949,8 +935,10 @@ CommandLine DockerDevicePrivate::createCommandLine()
#ifdef Q_OS_UNIX
// no getuid() and getgid() on Windows.
if (q->useLocalUidGid())
if (q->useLocalUidGid()) {
dockerCreate.addArgs({"-u", QString("%1:%2").arg(getuid()).arg(getgid())});
dockerCreate.addArgs({"-e", QString("HOME=/tmp/qtc_home/%1").arg(getuid())});
}
#endif
if (!q->network().isEmpty()) {
@@ -973,99 +961,36 @@ CommandLine DockerDevicePrivate::createCommandLine()
return dockerCreate;
}
expected_str<QString> DockerDevicePrivate::createContainer()
expected_str<QString> DockerDevicePrivate::updateContainerAccess()
{
if (!isImageAvailable())
return make_unexpected(Tr::tr("Image \"%1\" is not available.").arg(q->repoAndTag()));
const CommandLine cmdLine = createCommandLine();
qCDebug(dockerDeviceLog).noquote() << "RUNNING: " << cmdLine.toUserOutput();
Process createProcess;
createProcess.setCommand(cmdLine);
createProcess.runBlocking();
if (createProcess.result() != ProcessResult::FinishedWithSuccess) {
return make_unexpected(Tr::tr("Failed creating Docker container. Exit code: %1, output: %2")
.arg(createProcess.exitCode())
.arg(createProcess.allOutput()));
}
m_container = createProcess.cleanedStdOut().trimmed();
if (m_container.isEmpty())
return make_unexpected(
Tr::tr("Failed creating Docker container. No container ID received."));
qCDebug(dockerDeviceLog) << "ContainerId:" << m_container;
return m_container;
}
expected_str<void> DockerDevicePrivate::startContainer()
{
using namespace std::chrono_literals;
auto createResult = createContainer();
if (!createResult)
return make_unexpected(createResult.error());
if (m_startProcess)
m_startProcess->stop();
m_startProcess = std::make_unique<Process>();
m_startProcess->setCommand(
{settings().dockerBinaryPath(), {"container", "start", "-a", "-i", m_container}});
m_startProcess->setProcessMode(ProcessMode::Writer);
m_startProcess->start();
if (!m_startProcess->waitForStarted(5s)) {
if (m_startProcess->state() == QProcess::NotRunning) {
return make_unexpected(
Tr::tr("Failed starting Docker container. Exit code: %1, output: %2")
.arg(m_startProcess->exitCode())
.arg(m_startProcess->allOutput()));
}
// Lets assume it will start soon
qCWarning(dockerDeviceLog)
<< "Docker container start process took more than 5 seconds to start.";
}
QDeadlineTimer deadline(5s);
while (!DockerApi::instance()->isContainerRunning(m_container) && !deadline.hasExpired()) {
QThread::msleep(100);
}
if (deadline.hasExpired() && !DockerApi::instance()->isContainerRunning(m_container)) {
m_startProcess->stop();
return make_unexpected(Tr::tr("Failed to start container \"%1\".").arg(m_container));
}
qCDebug(dockerDeviceLog) << "Started container: " << m_startProcess->commandLine();
return {};
}
expected_str<void> DockerDevicePrivate::updateContainerAccess()
{
if (!m_container.isEmpty() && DockerApi::instance()->isContainerRunning(m_container))
return {};
if (m_isShutdown)
return make_unexpected(Tr::tr("Device is shut down"));
if (DockerApi::isDockerDaemonAvailable(false).value_or(false) == false)
return make_unexpected(Tr::tr("Docker system is not reachable"));
expected_str<void> result = startContainer();
QString containerStatus = result ? Tr::tr("Running") : result.error().trimmed();
auto lockedThread = m_deviceThread.writeLocked();
if (*lockedThread)
return (*lockedThread)->containerId();
if (!result)
result = make_unexpected(QString("Failed to start container: %1").arg(result.error()));
DockerContainerThread::Init init;
init.dockerBinaryPath = settings().dockerBinaryPath();
init.createContainerCmd = createCommandLine();
auto result = DockerContainerThread::create(init);
if (result)
lockedThread->reset(result->release());
QString containerStatus = result ? Tr::tr("Running") : result.error().trimmed();
QTimer::singleShot(0, this, [this, containerStatus] {
q->containerStatus.setText(containerStatus);
});
return result;
if (!result)
return make_unexpected(result.error());
return (*lockedThread)->containerId();
}
void DockerDevice::setMounts(const QStringList &mounts) const
@@ -1152,24 +1077,19 @@ void DockerDevice::aboutToBeRemoved() const
detector.undoAutoDetect(id().toString());
}
expected_str<void> DockerDevicePrivate::fetchSystemEnviroment()
Result DockerDevicePrivate::fetchSystemEnviroment()
{
if (m_cachedEnviroment)
return {};
return Result::Ok;
if (auto fileAccess = m_fileAccess.readLocked()->get()) {
m_cachedEnviroment = fileAccess->deviceEnvironment();
return {};
return Result::Ok;
}
expected_str<void> result = updateContainerAccess();
if (!result)
return result;
const expected_str<CommandLine> fullCommandLine = withDockerExecCmd(CommandLine{"env"});
if (!fullCommandLine)
return make_unexpected(fullCommandLine.error());
return Result::Error(fullCommandLine.error());
Process proc;
proc.setCommand(*fullCommandLine);
@@ -1180,9 +1100,9 @@ expected_str<void> DockerDevicePrivate::fetchSystemEnviroment()
QString stdErr = proc.cleanedStdErr();
if (stdErr.isEmpty())
return {};
return Result::Ok;
return make_unexpected("Could not read container environment: " + stdErr);
return Result::Error("Could not read container environment: " + stdErr);
}
// Factory
@@ -1385,19 +1305,19 @@ DockerDeviceFactory::DockerDeviceFactory()
});
setConstructionFunction([this] {
auto device = DockerDevice::create();
QMutexLocker lk(&m_deviceListMutex);
m_existingDevices.push_back(device);
m_existingDevices.writeLocked()->push_back(device);
return device;
});
}
void DockerDeviceFactory::shutdownExistingDevices()
{
QMutexLocker lk(&m_deviceListMutex);
for (const auto &weakDevice : m_existingDevices) {
if (std::shared_ptr<DockerDevice> device = weakDevice.lock())
device->shutdown();
}
m_existingDevices.read([](const std::vector<std::weak_ptr<DockerDevice>> &devices) {
for (const std::weak_ptr<DockerDevice> &weakDevice : devices) {
if (std::shared_ptr<DockerDevice> device = weakDevice.lock())
device->shutdown();
}
});
}
expected_str<QPair<Utils::OsType, Utils::OsArch>> DockerDevicePrivate::osTypeAndArch() const
@@ -1428,8 +1348,7 @@ expected_str<QPair<Utils::OsType, Utils::OsArch>> DockerDevicePrivate::osTypeAnd
expected_str<Environment> DockerDevicePrivate::environment()
{
if (!m_cachedEnviroment) {
expected_str<void> result = fetchSystemEnviroment();
if (!result)
if (Result result = fetchSystemEnviroment(); !result)
return make_unexpected(result.error());
}
@@ -1463,7 +1382,8 @@ expected_str<FilePath> DockerDevicePrivate::localSource(const FilePath &other) c
}
}
return make_unexpected(Tr::tr("localSource: No mount point found for %1").arg(other.toUrlishString()));
return make_unexpected(
Tr::tr("localSource: No mount point found for %1").arg(other.toUserOutput()));
}
bool DockerDevicePrivate::ensureReachable(const FilePath &other)

View File

@@ -8,7 +8,7 @@
#include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/devicesupport/idevicefactory.h>
#include <QMutex>
#include <utils/synchronizedvalue.h>
namespace Docker::Internal {
@@ -49,7 +49,7 @@ public:
Utils::expected_str<Utils::Environment> systemEnvironmentWithError() const override;
Utils::expected_str<void> updateContainerAccess() const;
Utils::Result updateContainerAccess() const;
void setMounts(const QStringList &mounts) const;
bool prepareForBuild(const ProjectExplorer::Target *target) override;
@@ -92,8 +92,7 @@ public:
void shutdownExistingDevices();
private:
QMutex m_deviceListMutex;
std::vector<std::weak_ptr<DockerDevice>> m_existingDevices;
Utils::SynchronizedValue<std::vector<std::weak_ptr<DockerDevice>>> m_existingDevices;
};
} // namespace Docker::Internal

View File

@@ -104,7 +104,7 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
this,
[this, logView, dockerDevice, searchPaths] {
logView->clear();
expected_str<void> startResult = dockerDevice->updateContainerAccess();
Result startResult = dockerDevice->updateContainerAccess();
if (!startResult) {
logView->append(Tr::tr("Failed to start container."));

View File

@@ -15,6 +15,7 @@
#include <utils/stylehelper.h>
#include <QGuiApplication>
#include <QSslSocket>
namespace ExtensionManager::Internal {
@@ -33,6 +34,13 @@ ExtensionManagerSettings::ExtensionManagerSettings()
useExternalRepo.setDefaultValue(false);
useExternalRepo.setLabelText(Tr::tr("Use external repository"));
const bool sslSupported = QSslSocket::supportsSsl();
useExternalRepo.setEnabled(sslSupported);
if (!sslSupported) {
useExternalRepo.setToolTip(Tr::tr("SSL support is not available."));
}
externalRepoUrl.setSettingsKey("ExternalRepoUrl");
externalRepoUrl.setDefaultValue("https://qc-extensions.qt.io");
externalRepoUrl.setDisplayStyle(Utils::StringAspect::LineEditDisplay);

View File

@@ -549,7 +549,11 @@ ExtensionsBrowser::ExtensionsBrowser(ExtensionsModel *model, QWidget *parent)
applyTf(titleLabel, titleTF);
auto externalRepoSwitch = new Switch("Use external repository");
externalRepoSwitch->setToolTip("<html>" + externalRepoWarningNote());
externalRepoSwitch->setEnabled(settings().useExternalRepo.isEnabled());
if (settings().useExternalRepo.isEnabled())
externalRepoSwitch->setToolTip("<html>" + externalRepoWarningNote());
else
externalRepoSwitch->setToolTip(settings().useExternalRepo.toolTip());
d->searchBox = new SearchBox;
d->searchBox->setPlaceholderText(Tr::tr("Search"));

View File

@@ -140,7 +140,7 @@ QString BlameMark::toolTipText(const CommitInfo &info) const
.arg(colors.hash, info.hash,
colors.author, info.author, info.authorMail,
colors.date, info.authorDate.toString("yyyy-MM-dd hh:mm:ss"),
colors.subject, info.subject);
colors.subject, info.subject.toHtmlEscaped());
QString result = actions + header;

View File

@@ -674,13 +674,7 @@ void LanguageClientManager::documentOpened(Core::IDocument *document)
void LanguageClientManager::documentClosed(Core::IDocument *document)
{
if (auto textDocument = qobject_cast<TextEditor::TextDocument *>(document)) {
openDocumentWithClient(textDocument, nullptr);
for (auto client : std::as_const(managerInstance->m_clients)) {
if (client->documentOpen(textDocument))
client->closeDocument(textDocument);
}
}
openDocumentWithClient(qobject_cast<TextEditor::TextDocument *>(document), nullptr);
}
void LanguageClientManager::updateProject(ProjectExplorer::Project *project)

View File

@@ -29,6 +29,7 @@ using namespace Utils;
using namespace Core;
using namespace TextEditor;
using namespace ProjectExplorer;
using namespace std::string_view_literals;
namespace {
@@ -264,21 +265,22 @@ public:
return make_unexpected(QString("init callback did not return a table or string"));
});
if (auto initOptionsTable = options.get<sol::optional<sol::table>>("initializationOptions"))
if (auto initOptionsTable = options.get<sol::optional<sol::table>>(
"initializationOptions"sv))
m_initializationOptions = ::Lua::toJsonString(*initOptionsTable);
else if (auto initOptionsString = options.get<sol::optional<QString>>("initializationOptions"))
else if (auto initOptionsString = options.get<sol::optional<QString>>("initializationOptions"sv))
m_initializationOptions = *initOptionsString;
m_name = options.get<QString>("name");
m_name = options.get<QString>("name"sv);
m_settingsTypeId = Utils::Id::fromString(QString("Lua_%1").arg(m_name));
m_serverName = options.get_or<QString>("serverName", "");
m_serverName = options.get_or<QString>("serverName"sv, "");
m_startBehavior = startBehaviorFromString(
options.get_or<QString>("startBehavior", "AlwaysOn"));
options.get_or<QString>("startBehavior"sv, "AlwaysOn"));
m_startFailedCallback = options.get<sol::protected_function>("onStartFailed");
m_startFailedCallback = options.get<sol::protected_function>("onStartFailed"sv);
QString transportType = options.get_or<QString>("transport", "stdio");
QString transportType = options.get_or<QString>("transport"sv, "stdio");
if (transportType == "stdio")
m_transportType = TransportType::StdIO;
else if (transportType == "localsocket")
@@ -286,7 +288,7 @@ public:
else
qWarning() << "Unknown transport type:" << transportType;
auto languageFilter = options.get<std::optional<sol::table>>("languageFilter");
auto languageFilter = options.get<std::optional<sol::table>>("languageFilter"sv);
if (languageFilter) {
auto patterns = languageFilter->get<std::optional<sol::table>>("patterns");
auto mimeTypes = languageFilter->get<std::optional<sol::table>>("mimeTypes");
@@ -300,10 +302,10 @@ public:
m_languageFilter.mimeTypes.push_back(v.as<QString>());
}
m_showInSettings = options.get<std::optional<bool>>("showInSettings").value_or(true);
m_showInSettings = options.get<std::optional<bool>>("showInSettings"sv).value_or(true);
// get<sol::optional<>> because on MSVC, get_or(..., nullptr) fails to compile
m_aspects = options.get<sol::optional<AspectContainer *>>("settings").value_or(nullptr);
m_aspects = options.get<sol::optional<AspectContainer *>>("settings"sv).value_or(nullptr);
if (m_aspects) {
connect(m_aspects, &AspectContainer::applied, this, [this] {

View File

@@ -26,6 +26,7 @@
using namespace Utils;
using namespace Core;
using namespace std::string_view_literals;
namespace Lua::Internal {
@@ -139,7 +140,7 @@ void setupFetchModule()
"Fetch",
[mod = std::move(module),
infoBarCleaner = InfoBarCleaner()](sol::state_view lua) mutable -> sol::object {
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec"sv);
sol::table async = lua.script("return require('async')", "_fetch_").get<sol::table>();
sol::function wrap = async["wrap"];
@@ -257,13 +258,13 @@ void setupFetchModule()
const sol::main_table &options,
const sol::main_function &callback,
const sol::this_state &thisState) {
auto url = options.get<QString>("url");
auto url = options.get<QString>("url"sv);
auto actualFetch = [guard, url, options, callback, thisState]() {
auto method = (options.get_or<QString>("method", "GET")).toLower();
auto headers = options.get_or<sol::table>("headers", {});
auto data = options.get_or<QString>("body", {});
auto method = (options.get_or<QString>("method"sv, "GET")).toLower();
auto headers = options.get_or<sol::table>("headers"sv, {});
auto data = options.get_or<QString>("body"sv, {});
bool convertToTable
= options.get<std::optional<bool>>("convertToTable").value_or(false);
= options.get<std::optional<bool>>("convertToTable"sv).value_or(false);
QNetworkRequest request((QUrl(url)));
if (headers && !headers.empty()) {

View File

@@ -11,9 +11,11 @@
#include <utils/layoutbuilder.h>
#include <QMetaEnum>
#include <QCompleter>
using namespace Layouting;
using namespace Utils;
using namespace std::string_view_literals;
namespace Lua::Internal {
@@ -67,8 +69,8 @@ static std::unique_ptr<T> construct(const sol::table &children)
template<class T>
void constructWidget(std::unique_ptr<T> &widget, const sol::table &children)
{
widget->setWindowTitle(children.get_or<QString>("windowTitle", ""));
widget->setToolTip(children.get_or<QString>("toolTip", ""));
widget->setWindowTitle(children.get_or<QString>("windowTitle"sv, ""));
widget->setToolTip(children.get_or<QString>("toolTip"sv, ""));
for (size_t i = 1; i <= children.size(); ++i) {
const auto &child = children[i];
@@ -115,91 +117,100 @@ CREATE_HAS_FUNC(setIcon, Utils::Icon());
CREATE_HAS_FUNC(setContentsMargins, int(), int(), int(), int());
CREATE_HAS_FUNC(setCursor, Qt::CursorShape())
CREATE_HAS_FUNC(setMinimumWidth, int());
CREATE_HAS_FUNC(setEnableCodeCopyButton, bool());
template<class T>
void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject *guard)
{
if constexpr (has_setContentsMargins<T>) {
sol::optional<QMargins> margins = children.get<sol::optional<QMargins>>("contentMargins");
sol::optional<QMargins> margins = children.get<sol::optional<QMargins>>("contentMargins"sv);
if (margins)
item->setContentsMargins(margins->left(), margins->top(), margins->right(), margins->bottom());
}
if constexpr (has_setCursor<T>) {
const auto cursor = children.get<sol::optional<Qt::CursorShape>>("cursor");
const auto cursor = children.get<sol::optional<Qt::CursorShape>>("cursor"sv);
if (cursor)
item->setCursor(*cursor);
}
if constexpr (has_setMinimumWidth<T>) {
const auto minw = children.get<sol::optional<int>>("minimumWidth");
const auto minw = children.get<sol::optional<int>>("minimumWidth"sv);
if (minw)
item->setMinimumWidth(*minw);
}
if constexpr (has_setEnableCodeCopyButton<T>) {
const auto enableCodeCopyButton = children.get<sol::optional<bool>>("enableCodeCopyButton");
if (enableCodeCopyButton)
item->setEnableCodeCopyButton(*enableCodeCopyButton);
}
if constexpr (has_setVisible<T>) {
const auto visible = children.get<sol::optional<bool>>("visible");
const auto visible = children.get<sol::optional<bool>>("visible"sv);
if (visible)
item->setVisible(*visible);
}
if constexpr (has_setIcon<T>) {
const auto icon = children.get<sol::optional<IconFilePathOrString>>("icon");
const auto icon = children.get<sol::optional<IconFilePathOrString>>("icon"sv);
if (icon)
item->setIcon(*toIcon(*icon));
}
if constexpr (has_setTextInteractionFlags<T>) {
const auto interactionFlags = children.get<sol::optional<sol::table>>("interactionFlags");
const auto interactionFlags = children.get<sol::optional<sol::table>>("interactionFlags"sv);
if (interactionFlags) {
item->setTextInteractionFlags(tableToFlags<Qt::TextInteractionFlag>(*interactionFlags));
}
}
if constexpr (has_setFixedSize<T>) {
sol::optional<QSize> size = children.get<sol::optional<QSize>>("fixedSize");
sol::optional<QSize> size = children.get<sol::optional<QSize>>("fixedSize"sv);
if (size)
item->setFixedSize(*size);
}
if constexpr (has_setWordWrap<T>) {
const auto wrap = children.get<sol::optional<bool>>("wordWrap");
const auto wrap = children.get<sol::optional<bool>>("wordWrap"sv);
if (wrap)
item->setWordWrap(*wrap);
}
if constexpr (has_setTextFormat<T>) {
const auto format = children.get<sol::optional<Qt::TextFormat>>("textFormat");
const auto format = children.get<sol::optional<Qt::TextFormat>>("textFormat"sv);
if (format)
item->setTextFormat(*format);
}
if constexpr (has_setRightSideIconPath<T>) {
const auto path = children.get<sol::optional<Utils::FilePath>>("rightSideIconPath");
const auto path = children.get<sol::optional<Utils::FilePath>>("rightSideIconPath"sv);
if (path)
item->setRightSideIconPath(*path);
}
if constexpr (has_setPlaceHolderText<T>) {
const auto text = children.get<sol::optional<QString>>("placeHolderText");
const auto text = children.get<sol::optional<QString>>("placeHolderText"sv);
if (text)
item->setPlaceHolderText(*text);
}
if constexpr (has_setCompleter<T>) {
const auto completer = children.get<QCompleter *>("completer");
if (completer)
const auto completer = children.get<QCompleter *>("completer"sv);
if (completer) {
item->setCompleter(completer);
completer->setParent(item->emerge());
}
}
if constexpr (has_setMinimumHeight<T>) {
const auto minHeight = children.get<sol::optional<int>>("minimumHeight");
const auto minHeight = children.get<sol::optional<int>>("minimumHeight"sv);
if (minHeight)
item->setMinimumHeight(*minHeight);
}
if constexpr (has_onReturnPressed<T>) {
const auto callback = children.get<sol::optional<sol::main_function>>("onReturnPressed");
const auto callback = children.get<sol::optional<sol::main_function>>("onReturnPressed"sv);
if (callback) {
item->onReturnPressed(guard, [func = *callback]() { void_safe_call(func); });
}
@@ -213,19 +224,19 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
}
if constexpr (has_setFlat<T>) {
const auto flat = children.get<sol::optional<bool>>("flat");
const auto flat = children.get<sol::optional<bool>>("flat"sv);
if (flat)
item->setFlat(*flat);
}
if constexpr (has_setIconPath<T>) {
const auto iconPath = children.get<sol::optional<FilePath>>("iconPath");
const auto iconPath = children.get<sol::optional<FilePath>>("iconPath"sv);
if (iconPath)
item->setIconPath(*iconPath);
}
if constexpr (has_setIconSize<T>) {
const auto iconSize = children.get<sol::optional<QSize>>("iconSize");
const auto iconSize = children.get<sol::optional<QSize>>("iconSize"sv);
if (iconSize)
item->setIconSize(*iconSize);
}
@@ -242,7 +253,7 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
}
if constexpr (has_setSize<T>) {
sol::optional<QSize> size = children.get<sol::optional<QSize>>("size");
sol::optional<QSize> size = children.get<sol::optional<QSize>>("size"sv);
if (size)
item->setSize(size->width(), size->height());
}
@@ -266,7 +277,7 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
if constexpr (has_onTextChanged<T>) {
sol::optional<sol::main_function> onTextChanged
= children.get<sol::optional<sol::main_function>>("onTextChanged");
= children.get<sol::optional<sol::main_function>>("onTextChanged"sv);
if (onTextChanged) {
item->onTextChanged(
guard,
@@ -278,7 +289,7 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
}
if constexpr (has_onClicked<T>) {
sol::optional<sol::main_function> onClicked
= children.get<sol::optional<sol::main_function>>("onClicked");
= children.get<sol::optional<sol::main_function>>("onClicked"sv);
if (onClicked) {
item->onClicked(
guard,
@@ -289,17 +300,17 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
}
}
if constexpr (has_setText<T>) {
auto text = children.get<sol::optional<QString>>("text");
auto text = children.get<sol::optional<QString>>("text"sv);
if (text)
item->setText(*text);
}
if constexpr (has_setMarkdown<T>) {
auto markdown = children.get<sol::optional<QString>>("markdown");
auto markdown = children.get<sol::optional<QString>>("markdown"sv);
if (markdown)
item->setMarkdown(*markdown);
}
if constexpr (has_setSizePolicy<T>) {
auto sizePolicy = children.get<sol::optional<sol::table>>("sizePolicy");
auto sizePolicy = children.get<sol::optional<sol::table>>("sizePolicy"sv);
if (sizePolicy) {
QTC_ASSERT(
sizePolicy->size() == 2,
@@ -312,21 +323,21 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
}
}
if constexpr (has_setTitle<T>) {
item->setTitle(children.get_or<QString>("title", ""));
item->setTitle(children.get_or<QString>("title"sv, ""));
}
if constexpr (has_setValue<T>) {
sol::optional<int> value = children.get<sol::optional<int>>("value");
sol::optional<int> value = children.get<sol::optional<int>>("value"sv);
if (value)
item->setValue(*value);
}
if constexpr (has_setReadOnly<T>) {
sol::optional<bool> readOnly = children.get<sol::optional<bool>>("readOnly");
sol::optional<bool> readOnly = children.get<sol::optional<bool>>("readOnly"sv);
if (readOnly)
item->setReadOnly(*readOnly);
}
if constexpr (has_setOpenExternalLinks<T>) {
sol::optional<bool> openExternalLinks = children.get<sol::optional<bool>>(
"openExternalLinks");
"openExternalLinks"sv);
if (openExternalLinks)
item->setOpenExternalLinks(*openExternalLinks);
}
@@ -420,7 +431,7 @@ std::unique_ptr<Splitter> constructSplitter(const sol::table &children)
std::unique_ptr<Splitter> item(new Splitter({}));
constructWidget(item, children);
if (const auto &orientation = children.get<sol::optional<QString>>("orientation")) {
if (const auto &orientation = children.get<sol::optional<QString>>("orientation"sv)) {
if (*orientation == "horizontal")
item->setOrientation(Qt::Horizontal);
else if (*orientation == "vertical")
@@ -429,7 +440,7 @@ std::unique_ptr<Splitter> constructSplitter(const sol::table &children)
throw sol::error(QString("Invalid orientation: %1").arg(*orientation).toStdString());
}
if (const auto collapsible = children.get<sol::optional<bool>>("collapsible"))
if (const auto collapsible = children.get<sol::optional<bool>>("collapsible"sv))
item->setChildrenCollapsible(*collapsible);
for (size_t i = 1; i <= children.size(); ++i) {
@@ -444,7 +455,7 @@ std::unique_ptr<Splitter> constructSplitter(const sol::table &children)
}
}
if (const auto &stretchFactors = children.get<sol::optional<sol::table>>("stretchFactors")) {
if (const auto &stretchFactors = children.get<sol::optional<sol::table>>("stretchFactors"sv)) {
for (const auto &kv : *stretchFactors) {
if (kv.second.get_type() != sol::type::number)
throw sol::error("Stretch factors must be numbers");
@@ -457,7 +468,7 @@ std::unique_ptr<Splitter> constructSplitter(const sol::table &children)
void setupGuiModule()
{
registerProvider("Gui", [](sol::state_view l) -> sol::object {
const ScriptPluginSpec *pluginSpec = l.get<ScriptPluginSpec *>("PluginSpec");
const ScriptPluginSpec *pluginSpec = l.get<ScriptPluginSpec *>("PluginSpec"sv);
QObject *guard = pluginSpec->connectionGuard.get();
sol::table gui = l.create_table();
@@ -545,6 +556,9 @@ void setupGuiModule()
sol::factories([guard](const sol::table &children) {
return constructWidgetType<Layouting::MarkdownBrowser>(children, guard);
}),
"markdown",
sol::property(
&Layouting::MarkdownBrowser::toMarkdown, &Layouting::MarkdownBrowser::setMarkdown),
sol::base_classes,
sol::bases<Widget, Object, Thing>());

View File

@@ -29,6 +29,7 @@
using namespace Core;
using namespace Tasking;
using namespace Utils;
using namespace std::string_view_literals;
namespace Lua::Internal {
@@ -268,7 +269,7 @@ void setupInstallModule()
sol::function wrap = async["wrap"];
sol::table install = lua.create_table();
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec"sv);
install["packageInfo"] =
[pluginSpec](const QString &name, sol::this_state l) -> sol::optional<sol::table> {

View File

@@ -17,13 +17,14 @@
using namespace ProjectExplorer;
using namespace Utils;
using namespace std::string_view_literals;
namespace Lua::Internal {
void setupProjectModule()
{
registerProvider("Project", [](sol::state_view lua) -> sol::object {
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec"sv);
QObject *guard = pluginSpec->connectionGuard.get();
sol::table result = lua.create_table();

View File

@@ -16,19 +16,28 @@
#include <QFontMetrics>
#include <QStandardPaths>
using namespace std::string_view_literals;
namespace Lua::Internal {
void setupQtModule()
{
registerProvider("Qt", [](sol::state_view lua) {
sol::table qt(lua, sol::create);
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec"sv);
qt.new_usertype<QCompleter>(
"QCompleter",
"create",
[](const QStringList &list) -> std::unique_ptr<QCompleter> {
return std::make_unique<QCompleter>(list);
[](const QStringList &list) -> QCompleter* {
return new QCompleter(list);
},
sol::meta_function::garbage_collect, [](QCompleter *self) {
// If the user never parented this QCompleter to any QObject,
// then we own it, so let's delete it to avoid a memory leak.
if (!self->parent()) {
self->deleteLater();
}
},
"currentCompletion",
&QCompleter::currentCompletion,

View File

@@ -9,13 +9,14 @@
#include <utils/qtcprocess.h>
using namespace Utils;
using namespace std::string_view_literals;
namespace Lua::Internal {
void setupProcessModule()
{
registerProvider("Process", [](sol::state_view lua) -> sol::object {
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec"sv);
QObject *guard = pluginSpec->connectionGuard.get();
sol::table async = lua.script("return require('async')", "_process_").get<sol::table>();
@@ -50,17 +51,17 @@ void setupProcessModule()
process["commandOutput"] = wrap(process["commandOutput_cb"]);
process["create"] = [](const sol::table &parameter) {
const auto cmd = toFilePath(parameter.get<std::variant<FilePath, QString>>("command"));
const auto cmd = toFilePath(parameter.get<std::variant<FilePath, QString>>("command"sv));
const QStringList arguments
= parameter.get_or<QStringList, const char *, QStringList>("arguments", {});
const std::optional<FilePath> workingDirectory = parameter.get<std::optional<FilePath>>(
"workingDirectory");
const auto stdOut = parameter.get<std::optional<sol::function>>("stdout");
const auto stdErr = parameter.get<std::optional<sol::function>>("stderr");
const auto stdIn = parameter.get<sol::optional<QString>>("stdin");
const auto onFinished = parameter.get<std::optional<sol::function>>("onFinished");
const auto stdOut = parameter.get<std::optional<sol::function>>("stdout"sv);
const auto stdErr = parameter.get<std::optional<sol::function>>("stderr"sv);
const auto stdIn = parameter.get<sol::optional<QString>>("stdin"sv);
const auto onFinished = parameter.get<std::optional<sol::function>>("onFinished"sv);
auto p = std::make_unique<Process>();

View File

@@ -14,6 +14,7 @@
using namespace Utils;
using namespace Core;
using namespace std::string_view_literals;
namespace Lua::Internal {
@@ -318,7 +319,7 @@ public:
void setupSettingsModule()
{
registerProvider("Settings", [pool = ObjectPool()](sol::state_view lua) -> sol::object {
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec"sv);
sol::table async = lua.script("return require('async')", "_process_").get<sol::table>();
sol::function wrap = async["wrap"];
@@ -658,19 +659,19 @@ void setupSettingsModule()
OptionsPage(const ScriptPluginSpec *spec, const sol::table &options)
{
setCategory(Id::fromString(
QString("%1.%2").arg(spec->id).arg(options.get<QString>("categoryId"))));
const QString catName = options.get<QString>("displayCategory");
const FilePath catIcon = options.get<std::optional<FilePath>>("categoryIconPath")
QString("%1.%2").arg(spec->id).arg(options.get<QString>("categoryId"sv))));
const QString catName = options.get<QString>("displayCategory"sv);
const FilePath catIcon = options.get<std::optional<FilePath>>("categoryIconPath"sv)
.value_or(FilePath::fromUserInput(
options.get_or<QString>("categoryIconPath", {})));
options.get_or<QString>("categoryIconPath"sv, {})));
if (!catName.isEmpty() || !catIcon.isEmpty())
IOptionsPage::registerCategory(category(), catName, catIcon);
setId(
Id::fromString(QString("%1.%2").arg(spec->id).arg(options.get<QString>("id"))));
setDisplayName(options.get<QString>("displayName"));
setId(Id::fromString(
QString("%1.%2").arg(spec->id).arg(options.get<QString>("id"sv))));
setDisplayName(options.get<QString>("displayName"sv));
AspectContainer *container = options.get<AspectContainer *>("aspectContainer");
AspectContainer *container = options.get<AspectContainer *>("aspectContainer"sv);
if (container->isAutoApply())
throw sol::error("AspectContainer must have autoApply set to false");

Some files were not shown because too many files have changed in this diff Show More