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/**' - 'doc/**'
env: env:
QT_VERSION: 6.8.1 QT_VERSION: 6.8.2
MACOS_DEPLOYMENT_TARGET: 11.0 MACOS_DEPLOYMENT_TARGET: 11.0
CLANG_VERSION: 19.1.6 CLANG_VERSION: 19.1.6
ELFUTILS_VERSION: 0.175 ELFUTILS_VERSION: 0.175

View File

@@ -80,6 +80,18 @@ find_package(Qt6
find_package(Qt6 OPTIONAL_COMPONENTS Quick QuickWidgets Designer DesignerComponentsPrivate find_package(Qt6 OPTIONAL_COMPONENTS Quick QuickWidgets Designer DesignerComponentsPrivate
Help SerialPort Svg Tools LinguistTools QUIET) 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 # depending on Qt version and compiler version enable or disable Qml Designer
# can be overwritten by variable WITH_QMLDESIGNER / QTC_WITH_QMLDESIGNER (env) # can be overwritten by variable WITH_QMLDESIGNER / QTC_WITH_QMLDESIGNER (env)
configure_qml_designer(${Qt6_VERSION}) 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") set(_IDE_CMAKE_INSTALL_PATH "lib/cmake")
else () else ()
# Small hack to silence a warning in the stable branch - but it means the value is incorrect # 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") set(CMAKE_INSTALL_LIBDIR "lib")
endif() endif()
include(GNUInstallDirs) include(GNUInstallDirs)

View File

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

View File

@@ -7,7 +7,7 @@ instructions:
instructions: instructions:
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: QTC_QT_BASE_URL 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 - type: EnvironmentVariable
variableName: MACOSX_DEPLOYMENT_TARGET variableName: MACOSX_DEPLOYMENT_TARGET
variableValue: 12.0 variableValue: 12.0
@@ -88,7 +88,7 @@ instructions:
instructions: instructions:
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: QTC_QT_POSTFIX 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 - type: EnvironmentVariable
variableName: QTC_ICU_URL 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" 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: instructions:
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: QTC_QT_POSTFIX 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 - type: EnvironmentVariable
variableName: QTC_SDKTOOL_QT_EXT variableName: QTC_SDKTOOL_QT_EXT
variableValue: ".tar.xz" variableValue: ".tar.xz"

View File

@@ -36,6 +36,10 @@ Editing
([QTCREATORBUG-32193](https://bugreports.qt.io/browse/QTCREATORBUG-32193)) ([QTCREATORBUG-32193](https://bugreports.qt.io/browse/QTCREATORBUG-32193))
* Fixed a formatting issue when applying method signature changes * Fixed a formatting issue when applying method signature changes
([QTCREATORBUG-31931](https://bugreports.qt.io/browse/QTCREATORBUG-31931)) ([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 * Built-in
* Added support for init-statements in range-based `for` loops * Added support for init-statements in range-based `for` loops
([QTCREATORBUG-31961](https://bugreports.qt.io/browse/QTCREATORBUG-31961)) ([QTCREATORBUG-31961](https://bugreports.qt.io/browse/QTCREATORBUG-31961))
@@ -68,6 +72,16 @@ Editing
([QTCREATORBUG-31878](https://bugreports.qt.io/browse/QTCREATORBUG-31878), ([QTCREATORBUG-31878](https://bugreports.qt.io/browse/QTCREATORBUG-31878),
[QTCREATORBUG-32163](https://bugreports.qt.io/browse/QTCREATORBUG-32163)) [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 Projects
-------- --------
@@ -101,6 +115,11 @@ Projects
([QTCREATORBUG-32350](https://bugreports.qt.io/browse/QTCREATORBUG-32350)) ([QTCREATORBUG-32350](https://bugreports.qt.io/browse/QTCREATORBUG-32350))
* Fixed a crash when an application outputs lots of lines * Fixed a crash when an application outputs lots of lines
([QTCREATORBUG-32371](https://bugreports.qt.io/browse/QTCREATORBUG-32371)) ([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 * Qt
* Improved performance of Qt ABI detection when module `.json` files are * Improved performance of Qt ABI detection when module `.json` files are
available available
@@ -121,6 +140,7 @@ Projects
* Added support for creating run configurations for custom CMake targets * Added support for creating run configurations for custom CMake targets
with the `qtc_runnable` `FOLDER` property with the `qtc_runnable` `FOLDER` property
([QTCREATORBUG-32324](https://bugreports.qt.io/browse/QTCREATORBUG-32324)) ([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 * Fixed that manually created run configurations could be removed if
`Create suitable run configurations automatically` was turned off `Create suitable run configurations automatically` was turned off
([QTCREATORBUG-32289](https://bugreports.qt.io/browse/QTCREATORBUG-32289)) ([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 * Fixed that Ninja was not detected even when `CMAKE_MAKE_PROGRAM` was set
to the `ninja` executable to the `ninja` executable
([QTCREATORBUG-32436](https://bugreports.qt.io/browse/QTCREATORBUG-32436)) ([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 * Package Manager Auto Setup
* Changed the default installation directory to `/tmp` to ensure that the * Changed the default installation directory to `/tmp` to ensure that the
directory is writable directory is writable
@@ -160,7 +182,9 @@ Debugging
* Pretty printers * Pretty printers
* Added `QMultiHash` * 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 * CDB
* Disabled heap debugging by default and added the option * Disabled heap debugging by default and added the option
`Enable heap debugging` `Enable heap debugging`
@@ -180,11 +204,19 @@ Analyzer
([QTCREATORBUG-31372](https://bugreports.qt.io/browse/QTCREATORBUG-31372)) ([QTCREATORBUG-31372](https://bugreports.qt.io/browse/QTCREATORBUG-31372))
* Fixed that profiling could fail to start * Fixed that profiling could fail to start
([QTCREATORBUG-32062](https://bugreports.qt.io/browse/QTCREATORBUG-32062)) ([QTCREATORBUG-32062](https://bugreports.qt.io/browse/QTCREATORBUG-32062))
* Fixed the sorting of statistics
([QTCREATORBUG-32398](https://bugreports.qt.io/browse/QTCREATORBUG-32398))
### Axivion ### Axivion
* Added support for images in the issue details * Added support for images in the issue details
* Moved Axivion preferences to `Preferences > Analyzer > Axivion` * 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 ### Coco
@@ -192,6 +224,23 @@ Analyzer
in `Projects > Project Settings > Coco Code Coverage` in `Projects > Project Settings > Coco Code Coverage`
([Documentation]https://doc-snapshots.qt.io/qtcreator-16.0/creator-coco.html) ([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 Version Control Systems
----------------------- -----------------------
@@ -227,10 +276,17 @@ Platforms
* Added support for the `terminator` terminal emulator * Added support for the `terminator` terminal emulator
([QTCREATORBUG-32111](https://bugreports.qt.io/browse/QTCREATORBUG-32111)) ([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 ### Android
* Fixed a performance problem when detecting the Android ABI * Fixed a performance problem when detecting the Android ABI
([QTCREATORBUG-31068](https://bugreports.qt.io/browse/QTCREATORBUG-31068)) ([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 ### iOS
@@ -251,12 +307,20 @@ Platforms
* Fixed an issue with running `pkg-config` in the container * Fixed an issue with running `pkg-config` in the container
([QTCREATORBUG-32325](https://bugreports.qt.io/browse/QTCREATORBUG-32325)) ([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: Credits for these changes go to:
-------------------------------- --------------------------------
Alessandro Portale Alessandro Portale
Alexander Drozdov Alexander Drozdov
Alexander Pershin Alexander Pershin
Alexandre Laurent
Alexis Jeandet Alexis Jeandet
Ali Kianian Ali Kianian
Andre Hartmann Andre Hartmann
@@ -292,6 +356,7 @@ Mats Honkamaa
Miikka Heikkinen Miikka Heikkinen
Mitch Curtis Mitch Curtis
Morteza Jamshidi Morteza Jamshidi
Nicholas Bennett
Nikolaus Demmel Nikolaus Demmel
Olivier De Cannière Olivier De Cannière
Orgad Shaneh Orgad Shaneh
@@ -311,4 +376,5 @@ Thiago Macieira
Thomas Hartmann Thomas Hartmann
Tim Jenßen Tim Jenßen
Vikas Pachdha Vikas Pachdha
Ville Lavonius
Xu Jin 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 \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. The
following sections describe how to set up a project for code coverage.
With Coco, you can measure and analyze the code coverage of tests. You can For more information about viewing the results in \QC, see
set up a project for code coverage and display the coverage in \QC. \l{View code coverage reports from Coco}.
To use the plugin, you must download and install Coco version 6.0 or later. 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 loading an instrumentation database (a \c .csmes file), which was generated by
Coco CoverageScanner. 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: To measure and check code coverage:
\list 1 \list 1
@@ -182,5 +185,6 @@
\li Implicit Manual Coverage Validation \li Implicit Manual Coverage Validation
\endlist \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 \title Android Deploy Configuration
\brief Create Application Packages (APK) or Android App Bundles (AAB) to \brief Create packages to deploy to devices or to submit to the Google Play
install and run on devices or to upload to the Google Play store. store, or create libraries for Android app modules.
Android applications are packaged as ZIP files called Application Packages 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 (APK), Android App Bundles (AAB), or Android Archives (AAR). You can
device. You can upload AAB files to the Google Play store. 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. \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 To support several different ABIs in your application, build an AAB that
@@ -27,10 +28,14 @@
\list \list
\li As a stand-alone, distributable application package (APK). \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 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 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 multi-abi builds for applications when you build with CMake. AARs
more information, see \l{Deploying an Application on Android}. are supported from Qt 6.8.0 onwards. For more information, see
\l{Deploying an Application on Android}.
\endlist \endlist
\note Since \QC 4.12, Ministro is not supported. \note Since \QC 4.12, Ministro is not supported.
@@ -123,6 +128,12 @@
\image qtcreator-android-build-steps.png {qmake settings for building AABs} \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 \section3 Signing Android Packages
To publish your application, you must sign it by using a \e {public-private 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 Select the \uicontrol {Include default permissions for Qt modules} and
\uicontrol {Include default features for Qt modules} check boxes to add the \uicontrol {Include default features for Qt modules} check boxes to add the
permissions needed by Qt libraries. This can be permissions needed by Qt libraries, such as
\c {android.permission.WRITE_EXTERNAL_STORAGE} for \l{Qt Core} or
\c {android.permission.ACCESS_BACKGROUND_LOCATION} for \l{Qt Positioning}. \c {android.permission.ACCESS_BACKGROUND_LOCATION} for \l{Qt Positioning}.
To add a permission, select it from the list, and then select \uicontrol Add. 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 \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 To turn off the automatic detection of indentation settings, go to
\preferences > \uicontrol {Text Editor} > \uicontrol Behavior \preferences > \uicontrol {Text Editor} > \uicontrol Behavior
and clear \uicontrol {Auto detect}. and clear \uicontrol {Auto detect}.
@@ -28,10 +32,14 @@
\section1 Fix indentation in an open file \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: To fix the indentation in the file currently open in the editor:
\list \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 \uicontrol {Auto-indent Selection} to automatically indent the
selected text using the current settings. selected text using the current settings.
\li Go to \uicontrol Edit > \uicontrol Advanced, and select an \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 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 \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 \table
\header \header
@@ -204,33 +205,30 @@
\li M10 \li M10
\li Error \li Error
\li Duplicate property binding \li Duplicate property binding
\li See also: \l{http://linterrors.com/js/duplicate-key-a} \li For more information, see \e {Duplicate key '{a}'} in
{Duplicate key '{a}'}. \e {JSLint Error Explanations}.
\row \row
\li M11 \li M11
\li Error \li Error
\li Id expected \li Id expected
\li See also: \li For more information, see
\l{http://linterrors.com/js/expected-an-identifier-and-instead-saw-a-a-reserved-word} \e {Expected an identifier and instead saw '{a}' (a reserved word)}
{Expected an identifier and instead saw '{a}' (a reserved word)}. in \e {JSLint Error Explanations}.
\row \row
\li M14 \li M14
\li Error \li Error
\li Invalid id \li Invalid id
\li See also: \li For more information, see
\l{http://linterrors.com/js/expected-an-identifier-and-instead-saw-a-a-reserved-word} \e {Expected an identifier and instead saw '{a}' (a reserved word)}.
{Expected an identifier and instead saw '{a}' (a reserved word)}.
\row \row
\li M15 \li M15
\li Error \li Error
\li Duplicate id \li Duplicate id
\li Ids in a file must be unique. \li Ids in a file must be unique.
See also: \l{http://linterrors.com/js/duplicate-key-a} For more information, see \e {Duplicate key '{a}'}.
{Duplicate key '{a}'}.
\row \row
\li M16 \li M16
@@ -270,7 +268,8 @@
\li M23 \li M23
\li Warning \li Warning
\li Do not use \c eval \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 \row
\li M28 \li M28
@@ -282,8 +281,8 @@
\li M29 \li M29
\li Warning \li Warning
\li Do not use \c with \li Do not use \c with
\li See also: \l{http://linterrors.com/js/unexpected-with} \li For more information, see \e {Unexpected 'with'} in
{Unexpected 'with'}. \e {JSLint Error Explanations}.
\row \row
\li M30 \li M30
@@ -333,51 +332,48 @@
\li M108 \li M108
\li Warning \li Warning
\li Function \c name is used before its declaration \li Function \c name is used before its declaration
\li See also: \l{http://linterrors.com/js/a-was-used-before-it-was-defined} \li For more information, see \e {{a} was used before it was defined} in
{{a} was used before it was defined}. \e {JSLint Error Explanations}.
\row \row
\li M109 \li M109
\li Warning \li Warning
\li Do not use \c Boolean as a constructor \li Do not use \c Boolean as a constructor
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor} \li For more information, see \e {Do not use {a} as a constructor} in
{Do not use {a} as a constructor}. \e {JSLint Error Explanations}.
\row \row
\li M110 \li M110
\li Warning \li Warning
\li Do not use \c String as a constructor \li Do not use \c String as a constructor
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor} \li For more information, see \e {Do not use {a} as a constructor}.
{Do not use {a} as a constructor}.
\row \row
\li M111 \li M111
\li Warning \li Warning
\li Do not use \c Object as a constructor \li Do not use \c Object as a constructor
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor} \li For more information, see \e {Do not use {a} as a constructor}.
{Do not use {a} as a constructor}.
\row \row
\li M112 \li M112
\li Warning \li Warning
\li Do not use \c Array as a constructor \li Do not use \c Array as a constructor
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor} \li For more information, see \e {Do not use {a} as a constructor}.
{Do not use {a} as a constructor}.
\row \row
\li M113 \li M113
\li Warning \li Warning
\li Do not use \c Function as a constructor \li Do not use \c Function as a constructor
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor} \li For more information, see \e {Do not use {a} as a constructor}.
{Do not use {a} as a constructor}.
\row \row
\li M114 \li M114
\li Hint \li Hint
\li The \c function keyword and the opening parenthesis should be \li The \c function keyword and the opening parenthesis should be
separated by a single space separated by a single space
\li See also: \l{http://linterrors.com/js/expected-exactly-one-space-between-a-and-b} \li For more information, see
{Expected exactly one space between {a} and {b}}. \e {Expected exactly one space between {a} and {b}} in
\e {JSLint Error Explanations}.
\row \row
\li M115 \li M115
@@ -397,15 +393,15 @@
\li M117 \li M117
\li Warning \li Warning
\li Confusing pluses \li Confusing pluses
\li See also: \l{http://linterrors.com/js/confusing-pluses} \li For more information, see \e {Confusing pluses} in
{Confusing pluses}. \e {JSLint Error Explanations}.
\row \row
\li M119 \li M119
\li Warning \li Warning
\li Confusing minuses \li Confusing minuses
\li See also: \l{http://linterrors.com/js/confusing-minuses} \li For more information, see \e {Confusing minuses} in
{Confusing minuses}. \e {JSLint Error Explanations}.
\row \row
\li M121 \li M121
@@ -453,9 +449,9 @@
\li M201 \li M201
\li Hint \li Hint
\li Place var declarations at the start of a function \li Place var declarations at the start of a function
\li See also: \li For more information, see
\l{http://linterrors.com/js/move-var-declarations-to-the-top-of-the-function} \e {Move 'var' declarations to the top of the function} in
{Move 'var' declarations to the top of the function}. \e {JSLint Error Explanations}.
\row \row
\li M202 \li M202
@@ -609,15 +605,14 @@
\li M307 \li M307
\li Warning \li Warning
\li Use \c new only with functions that start with an uppercase letter \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} \li For more information, see \e {Do not use {a} as a constructor} in
{Do not use {a} as a constructor}. \e {JSLint Error Explanations}.
\row \row
\li M308 \li M308
\li Warning \li Warning
\li Do not use \c Number as a constructor \li Do not use \c Number as a constructor
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor} \li For more information, see \e {Do not use {a} as a constructor}.
{Do not use {a} as a constructor}.
\row \row
\li M309 \li M309
@@ -707,9 +702,9 @@
\li M323 \li M323
\li Error \li Error
\li \c Number elements expected in array value \li \c Number elements expected in array value
\li See also: \li For more information, see
\l{http://linterrors.com/js/the-array-literal-notation-is-preferrable} \e {The array literal notation [] is preferable} in
{The array literal notation [] is preferable}. \e {JSLint Error Explanations}.
\row \row
\li M324 \li M324

View File

@@ -42,6 +42,53 @@
then select \uicontrol Install. then select \uicontrol Install.
\endlist \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 \section1 Connect to an LLM
You can connect to the following LLMs: 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 \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 \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 \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 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 publisher.
in the \uicontrol Welcome mode.
You can also install plugins from other sources, such as You can also install plugins from other sources, such as
\l{https://github.com/}{GitHub}. \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. The hardware-specific requirements vary depending on the hardware platform you are developing for.
For more information see: For more information see:
\list \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 STM}
\li \l{Getting Started on Renesas} \li \l{Getting Started on Renesas}
\li \l{Getting Started on Infineon} \li \l{Getting Started on Infineon}
@@ -57,8 +62,17 @@
\li \QC version \li \QC version
\li \QMCU SDK version \li \QMCU SDK version
\row \row
\li 12.0.2 or later \li 16.0.0 or later
\li 2.7 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 \row
\li 11.0.3 \li 11.0.3
\li 2.6 \li 2.6
@@ -91,17 +105,17 @@
\li 1.0 \li 1.0
\endtable \endtable
\sa {Enable and disable plugins}, {MCUs}{How To: Develop for MCUs}, \sa {Enable and disable plugins}, {MCUs}{How To: Develop for MCUs}, {\QMCU}
{Developing for MCUs}, {\QMCU}
*/ */
/*! /*!
\page creator-how-to-create-mcu-kits.html \page creator-how-to-add-mcu-kits.html
\previouspage creator-how-tos.html \previouspage creator-how-tos.html
\ingroup creator-how-to-mcu \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. \note Enable the McuSupport plugin to develop for MCUs.
@@ -154,13 +168,25 @@
\li Select \uicontrol Apply to save the preferences. \li Select \uicontrol Apply to save the preferences.
\endlist \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 \QC automatically adds a default MCU device when you select
\uicontrol Apply in the \uicontrol MCU tab after configuring the \uicontrol Apply in \preferences > \uicontrol SDKs > \uicontrol MCU after
MCU toolchain. 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 To add MCU devices, select \preferences > \uicontrol Devices > \uicontrol Add
> \uicontrol {MCU Device} > \uicontrol {Start Wizard}: > \uicontrol {MCU Device} > \uicontrol {Start Wizard}:
@@ -175,7 +201,6 @@
{Developing for MCUs} {Developing for MCUs}
*/ */
/*! /*!
\page creator-how-to-manage-mcu-kits.html \page creator-how-to-manage-mcu-kits.html
\previouspage creator-how-tos.html \previouspage creator-how-tos.html
@@ -189,9 +214,10 @@
\QC automatically adds kits for all the available MCU targets if you select \QC automatically adds kits for all the available MCU targets if you select
\uicontrol {Automatically create kits for all available targets on start} \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 \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 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. 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 The \uicontrol {MCU dependencies} field displays paths to 3rd party
software required for MCU development with the current kit. software required for MCU development with the current kit.

View File

@@ -4,16 +4,16 @@ import qbs.FileInfo
import qbs.Utilities import qbs.Utilities
Module { Module {
property string qtcreator_display_version: '16.0.0-rc1' property string qtcreator_display_version: '16.0.0'
property string ide_version_major: '15' property string ide_version_major: '16'
property string ide_version_minor: '0' 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 + '.' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.'
+ ide_version_release + 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_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 + '.' property string qtcreator_compat_version: ide_compat_version_major + '.'
+ ide_compat_version_minor + '.' + ide_compat_version_release + ide_compat_version_minor + '.' + ide_compat_version_release

View File

@@ -78,6 +78,7 @@ local function setup()
end, end,
}) })
require 'tst_texteditor'.setup() require 'tst_texteditor'.setup()
require 'tst_markdownbrowser'.setup()
end end
return { setup = setup } 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 <QMenu>
#include <QMessageBox> #include <QMessageBox>
using namespace Core;
namespace %{PluginName}::Internal { namespace %{PluginName}::Internal {
class %{CN} final : public ExtensionSystem::IPlugin class %{CN} final : public ExtensionSystem::IPlugin
@@ -46,16 +48,15 @@ public:
// bool IPlugin::initialize(const QStringList &arguments, QString *errorString) // bool IPlugin::initialize(const QStringList &arguments, QString *errorString)
// overload. // overload.
auto action = new QAction(Tr::tr("%{PluginName} Action"), this); ActionContainer *menu = ActionManager::createMenu(Constants::MENU_ID);
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);
menu->menu()->setTitle(Tr::tr("%{PluginName}")); menu->menu()->setTitle(Tr::tr("%{PluginName}"));
menu->addAction(cmd); ActionManager::actionContainer(Core::Constants::M_TOOLS)->addMenu(menu);
Core::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 void extensionsInitialized() final
@@ -77,7 +78,7 @@ public:
private: private:
void triggerAction() void triggerAction()
{ {
QMessageBox::information(Core::ICore::mainWindow(), QMessageBox::information(ICore::dialogParent(),
Tr::tr("Action Triggered"), Tr::tr("Action Triggered"),
Tr::tr("This is an action from %{PluginName}.")); 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 CodeModel_Warning_TextMarkColor=Token_Notification_Alert_Default
ComboBoxTextColor=Token_Text_Muted ComboBoxTextColor=Token_Text_Muted
Debugger_Breakpoint_TextMarkColor=Token_Notification_Danger_Default Debugger_Breakpoint_TextMarkColor=Token_Notification_Danger_Default
Debugger_WatchItem_ValueChanged=Token_Notification_Danger_Muted Debugger_WatchItem_ValueChanged=Token_Notification_Danger_Default
Debugger_WatchItem_ValueInvalid=Token_Background_Subtle Debugger_WatchItem_ValueInvalid=Token_Text_Muted
Debugger_WatchItem_ValueNormal=Token_Text_Default Debugger_WatchItem_ValueNormal=Token_Text_Default
DockWidgetResizeHandleColor=Token_Stroke_Subtle DockWidgetResizeHandleColor=Token_Stroke_Subtle
EditorPlaceholderColor=Token_Background_Muted EditorPlaceholderColor=Token_Background_Muted
@@ -66,11 +66,10 @@ PaletteAlternateBase=Token_Background_Muted
PaletteAlternateBaseDisabled=Token_Background_Subtle PaletteAlternateBaseDisabled=Token_Background_Subtle
PaletteBase=Token_Background_Default PaletteBase=Token_Background_Default
PaletteBaseDisabled=Token_Background_Subtle PaletteBaseDisabled=Token_Background_Subtle
PaletteBrightText=Token_Notification_Danger_Default
PaletteBrightText=Token_Text_Default PaletteBrightText=Token_Text_Default
PaletteBrightTextDisabled=Token_Text_Subtle PaletteBrightTextDisabled=Token_Text_Subtle
PaletteButton=Token_Background_Default PaletteButton=Token_Background_Default
PaletteButtonDisabled=Token_Background_Subtle PaletteButtonDisabled=Token_Background_Default
PaletteButtonText=Token_Text_Default PaletteButtonText=Token_Text_Default
PaletteButtonTextDisabled=Token_Text_Subtle PaletteButtonTextDisabled=Token_Text_Subtle
PaletteDark=Token_Background_Default PaletteDark=Token_Background_Default
@@ -118,7 +117,7 @@ TextColorError=Token_Notification_Danger_Default
TextColorLink=Token_Text_Accent TextColorLink=Token_Text_Accent
TextColorNormal=Token_Text_Default TextColorNormal=Token_Text_Default
TextEditor_CurrentLine_ScrollBarColor=Token_Foreground_Muted 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 TextEditor_Selection_ScrollBarColor=Token_Foreground_Subtle
Timeline_BackgroundColor1=Token_Background_Default Timeline_BackgroundColor1=Token_Background_Default
Timeline_BackgroundColor2=Token_Background_Muted Timeline_BackgroundColor2=Token_Background_Muted

View File

@@ -337,6 +337,11 @@ TerminalAnsi13=d22dde
TerminalAnsi14=69e2e4 TerminalAnsi14=69e2e4
TerminalAnsi15=e5e5e6 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] [Flags]
ComboBoxDrawTextShadow=false ComboBoxDrawTextShadow=false
DerivePaletteFromTheme=true DerivePaletteFromTheme=true

View File

@@ -25,12 +25,12 @@ Primitive-Neon-100=FFDBFDEC
Primitive-Neon-200=FFB9F9D9 Primitive-Neon-200=FFB9F9D9
Primitive-Neon-300=FF83F2BA Primitive-Neon-300=FF83F2BA
Primitive-Neon-400=FF2CDE85 Primitive-Neon-400=FF2CDE85
Primitive-Neon-500=FF1EC974 Primitive-Neon-500=FF27BF73
Primitive-Neon-600=FF12A75D Primitive-Neon-600=FF1F9B5D
Primitive-Neon-700=FF12834B Primitive-Neon-700=FF12834B
Primitive-Neon-800=FF14673E Primitive-Neon-800=FF14673E
Primitive-Neon-900=FF0D4328 Primitive-Neon-900=FF13432B
Primitive-Neon-1000=FF092C1B Primitive-Neon-1000=FF133122
Primitive-Red-100=FFFACED9 Primitive-Red-100=FFFACED9
Primitive-Red-200=FFF0A4B7 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; void visitSymbol0(SymbolVisitor *visitor) override;
private: private:
FullySpecifiedType _type; FullySpecifiedType _type;
const Name *_conceptName; const Name *_conceptName = nullptr;
}; };
class CPLUSPLUS_EXPORT Block final : public Scope class CPLUSPLUS_EXPORT Block final : public Scope

View File

@@ -570,30 +570,21 @@ void _ClosePseudoConsoleMembers(_In_ PseudoConsole* pPty)
{ {
if (pPty != nullptr) if (pPty != nullptr)
{ {
// See MSFT:19918626
// First break the signal pipe - this will trigger conhost to tear itself down
if (_HandleIsValid(pPty->hSignal)) if (_HandleIsValid(pPty->hSignal))
{ {
CloseHandle(pPty->hSignal); CloseHandle(pPty->hSignal);
pPty->hSignal = nullptr; 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)) if (_HandleIsValid(pPty->hPtyReference))
{ {
CloseHandle(pPty->hPtyReference); CloseHandle(pPty->hPtyReference);
pPty->hPtyReference = nullptr; 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; return;
} }
// Broken package, search for next magic marker // 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. // If we don't find a magic marker, the rest of the buffer is trash.
buffer.clear(); buffer.clear();
} else { } else {
@@ -445,8 +446,7 @@ static Utils::expected_str<QFuture<R>> createJob(
std::make_exception_ptr(std::system_error(ENOENT, std::generic_category()))); std::make_exception_ptr(std::system_error(ENOENT, std::generic_category())));
promise->finish(); promise->finish();
} else if (errType == "NormalExit") { } else if (errType == "NormalExit") {
promise->setException( promise->setException(std::make_exception_ptr(std::runtime_error("NormalExit")));
std::make_exception_ptr(std::runtime_error(err.toStdString())));
promise->finish(); promise->finish();
} else { } else {
qCWarning(clientLog) << "Error (" << errType << "):" << err; qCWarning(clientLog) << "Error (" << errType << "):" << err;
@@ -857,10 +857,22 @@ Utils::expected_str<QFuture<void>> Client::signalProcess(int pid, Utils::Control
bool Client::exit() bool Client::exit()
{ {
try { 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; 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 (...) { } catch (...) {
qCWarning(clientLog) << "Client::exit() caught exception"; qCWarning(clientLog) << "Client::exit() caught unexpected exception";
return false; return false;
} }
} }

View File

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

View File

@@ -145,6 +145,7 @@ static QHash<Utils::MimeType, QString> mimeTypeLanguageIdMap()
{"application/xml", "xml"}, {"application/xml", "xml"},
{"application/xslt+xml", "xsl"}, {"application/xslt+xml", "xsl"},
{"application/x-yaml", "yaml"}, {"application/x-yaml", "yaml"},
{"text/x-swift", "swift"},
}; };
for (const QPair<QString, QString> &languageIdForMimeTypeName : languageIdsForMimeTypeNames) { for (const QPair<QString, QString> &languageIdForMimeTypeName : languageIdsForMimeTypeNames) {
const Utils::MimeType &mimeType = Utils::mimeTypeForName(languageIdForMimeTypeName.first); 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()->value() - d->m_surface->liveSize().height(),
verticalScrollBar()->maximum())); verticalScrollBar()->maximum()));
break; break;
case Qt::Key_End:
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
break;
case Qt::Key_Home:
verticalScrollBar()->setValue(0);
break;
default: default:
if (event->key() < Qt::Key_Shift || event->key() > Qt::Key_ScrollLock) if (event->key() < Qt::Key_Shift || event->key() > Qt::Key_ScrollLock)
verticalScrollBar()->setValue(verticalScrollBar()->maximum()); verticalScrollBar()->setValue(verticalScrollBar()->maximum());
@@ -1015,8 +1009,10 @@ void TerminalView::applySizeChange()
void TerminalView::updateScrollBars() void TerminalView::updateScrollBars()
{ {
int scrollSize = d->m_surface->fullSize().height() - d->m_surface->liveSize().height(); int scrollSize = d->m_surface->fullSize().height() - d->m_surface->liveSize().height();
const bool shouldScroll = verticalScrollBar()->value() == verticalScrollBar()->maximum();
verticalScrollBar()->setRange(0, scrollSize); verticalScrollBar()->setRange(0, scrollSize);
verticalScrollBar()->setValue(verticalScrollBar()->maximum()); if (shouldScroll)
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
updateViewport(); updateViewport();
} }
@@ -1110,6 +1106,11 @@ void TerminalView::focusOutEvent(QFocusEvent *)
void TerminalView::inputMethodEvent(QInputMethodEvent *event) 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()); verticalScrollBar()->setValue(verticalScrollBar()->maximum());
d->m_preEditString = event->preeditString(); d->m_preEditString = event->preeditString();

View File

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

View File

@@ -356,7 +356,7 @@ void EnvironmentModel::toggleVariable(const QModelIndex &idx)
{ {
const QString name = indexToVariable(idx); const QString name = indexToVariable(idx);
const auto newIt = d->m_resultNameValueDictionary.find(name); 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 auto op = newIt.enabled() ? EnvironmentItem::SetDisabled : EnvironmentItem::SetEnabled;
const int changesPos = d->findInChanges(name); const int changesPos = d->findInChanges(name);
if (changesPos != -1) { 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); access(this)->setMinimumWidth(minw);
} }
void Widget::setMinimumHeight(int height)
{
access(this)->setMinimumHeight(height);
}
void Widget::setSizePolicy(const QSizePolicy &policy) void Widget::setSizePolicy(const QSizePolicy &policy)
{ {
access(this)->setSizePolicy(policy); access(this)->setSizePolicy(policy);
@@ -1109,6 +1114,11 @@ MarkdownBrowser::MarkdownBrowser(std::initializer_list<I> ps)
apply(this, ps); apply(this, ps);
} }
QString MarkdownBrowser::toMarkdown() const
{
return access(this)->toMarkdown();
}
void MarkdownBrowser::setMarkdown(const QString &markdown) void MarkdownBrowser::setMarkdown(const QString &markdown)
{ {
access(this)->setMarkdown(markdown); access(this)->setMarkdown(markdown);
@@ -1119,6 +1129,11 @@ void MarkdownBrowser::setBasePath(const Utils::FilePath &path)
access(this)->setBasePath(path); access(this)->setBasePath(path);
} }
void MarkdownBrowser::setEnableCodeCopyButton(bool enable)
{
access(this)->setEnableCodeCopyButton(enable);
}
// Special If // Special If
If::If( If::If(
@@ -1245,11 +1260,6 @@ void LineEdit::setCompleter(QCompleter *completer)
access(this)->setSpecialCompleter(completer); access(this)->setSpecialCompleter(completer);
} }
void LineEdit::setMinimumHeight(int height)
{
access(this)->setMinimumHeight(height);
}
void LineEdit::onReturnPressed(QObject *guard, const std::function<void()> &func) void LineEdit::onReturnPressed(QObject *guard, const std::function<void()> &func)
{ {
static_cast<LineEditImpl *>(access(this))->acceptReturnKeys = true; 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 setContentsMargins(int left, int top, int right, int bottom);
void setCursor(Qt::CursorShape shape); void setCursor(Qt::CursorShape shape);
void setMinimumWidth(int); void setMinimumWidth(int);
void setMinimumHeight(int height);
void activateWindow(); void activateWindow();
void close(); void close();
@@ -357,7 +358,6 @@ public:
void setRightSideIconPath(const Utils::FilePath &path); void setRightSideIconPath(const Utils::FilePath &path);
void setPlaceHolderText(const QString &text); void setPlaceHolderText(const QString &text);
void setCompleter(QCompleter *completer); void setCompleter(QCompleter *completer);
void setMinimumHeight(int height);
void onReturnPressed(QObject *guard, const std::function<void()> &); void onReturnPressed(QObject *guard, const std::function<void()> &);
void onRightSideIconClicked(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); MarkdownBrowser(std::initializer_list<I> items);
QString toMarkdown() const;
void setMarkdown(const QString &); void setMarkdown(const QString &);
void setBasePath(const Utils::FilePath &); void setBasePath(const Utils::FilePath &);
void setEnableCodeCopyButton(bool enable);
}; };
// Special // Special

View File

@@ -8,6 +8,7 @@
#include "mimeutils.h" #include "mimeutils.h"
#include "movie.h" #include "movie.h"
#include "networkaccessmanager.h" #include "networkaccessmanager.h"
#include "stringutils.h"
#include "stylehelper.h" #include "stylehelper.h"
#include "textutils.h" #include "textutils.h"
#include "theme/theme.h" #include "theme/theme.h"
@@ -19,8 +20,11 @@
#include <QBuffer> #include <QBuffer>
#include <QCache> #include <QCache>
#include <QClipboard>
#include <QDesktopServices>
#include <QGuiApplication> #include <QGuiApplication>
#include <QPainter> #include <QPainter>
#include <QScrollBar>
#include <QTextBlock> #include <QTextBlock>
#include <QTextBrowser> #include <QTextBrowser>
#include <QTextDocument> #include <QTextDocument>
@@ -81,9 +85,12 @@ static QStringList defaultCodeFontFamilies()
return {"Menlo", "Source Code Pro", "Monospace", "Courier"}; 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 ... // Find the end of the code block ...
for (block = block.next(); block.isValid(); block = block.next()) { for (block = block.next(); block.isValid(); block = block.next()) {
if (!block.blockFormat().hasProperty(QTextFormat::BlockCodeLanguage)) 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)) if (language != block.blockFormat().stringProperty(QTextFormat::BlockCodeLanguage))
break; 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 // Get the text of the code block and erase it
QTextCursor eraseCursor(document); QTextCursor eraseCursor(document);
eraseCursor.setPosition(position); eraseCursor.setPosition(startPos);
eraseCursor.setPosition(end, QTextCursor::KeepAnchor); eraseCursor.setPosition(endPos, QTextCursor::KeepAnchor);
const QString code = eraseCursor.selectedText(); const QString code = eraseCursor.selectedText();
eraseCursor.removeSelectedText(); eraseCursor.removeSelectedText();
// Create a new Frame and insert the highlighted code ... // Reposition the main cursor to startPos, to insert new content
block = document->findBlock(position); block = document->findBlock(startPos);
QTextCursor cursor(block); 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); QTextCursor frameCursor(frame);
std::unique_ptr<QTextDocument> codeDocument(highlightText(code, language)); if (enableCopy) {
bool first = true; QTextBlockFormat linkBlockFmt;
linkBlockFmt.setAlignment(Qt::AlignRight);
frameCursor.insertBlock(linkBlockFmt);
for (auto block = codeDocument->begin(); block != codeDocument->end(); block = block.next()) { const int snippetId = registerSnippet(document, code);
if (!first) const QString copy_id = QString("copy:%1").arg(snippetId);
frameCursor.insertBlock();
QTextCharFormat charFormat = block.charFormat(); // Insert copy icon
charFormat.setFontFamilies(defaultCodeFontFamilies()); QTextImageFormat imageFormat;
frameCursor.setCharFormat(charFormat); 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; // Create a clickable anchor for the "Copy" text
auto formats = block.layout()->formats(); QTextCharFormat anchorFormat;
frameCursor.insertText(block.text()); 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); frameCursor.block().layout()->setFormats(formats);
} }
@@ -315,11 +360,18 @@ public:
|| (url.isRelative() && isBaseHttp); || (url.isRelative() && isBaseHttp);
}; };
QSet<QUrl> remoteUrls = Utils::filtered(m_urlsToLoad, isRemoteUrl); const auto isLocalUrl = [this, isRemoteUrl](const QUrl &url) {
QSet<QUrl> localUrls = Utils::filtered(m_urlsToLoad, std::not_fn(isRemoteUrl)); if (url.scheme() == "qrc")
return true;
if (m_basePath.isEmpty()) if (!m_basePath.isEmpty() && !isRemoteUrl(url))
localUrls.clear(); return true;
return false;
};
QSet<QUrl> remoteUrls = Utils::filtered(m_urlsToLoad, isRemoteUrl);
QSet<QUrl> localUrls = Utils::filtered(m_urlsToLoad, isLocalUrl);
if (!m_loadRemoteImages) if (!m_loadRemoteImages)
remoteUrls.clear(); remoteUrls.clear();
@@ -384,22 +436,36 @@ public:
} }
}; };
auto onLocalSetup = [localIterator, auto onLocalSetup =
basePath = m_basePath, [localIterator, basePath = m_basePath, maxSize = m_imageHandler.maximumCacheSize()](
maxSize = m_imageHandler.maximumCacheSize()]( Async<EntryPointer> &async) {
Async<EntryPointer> &async) { const QUrl url = *localIterator;
const FilePath path = basePath.resolvePath(localIterator->path()); async.setConcurrentCallData(
async.setConcurrentCallData( [](QPromise<EntryPointer> &promise,
[](QPromise<EntryPointer> &promise, const FilePath &path, qsizetype maxSize) { const FilePath &basePath,
auto data = path.fileContents(); const QUrl &url,
if (!data || promise.isCanceled()) qsizetype maxSize) {
return; if (url.scheme() == "qrc") {
QFile f(":" + url.path());
if (!f.open(QIODevice::ReadOnly))
return;
promise.addResult(AnimatedImageHandler::makeEntry(*data, maxSize)); promise.addResult(
}, AnimatedImageHandler::makeEntry(f.readAll(), maxSize));
path, return;
maxSize); }
};
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) { auto onLocalDone = [localIterator, this](const Async<EntryPointer> &async) {
EntryPointer result = async.result(); 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) void scheduleLoad(const QUrl &url)
{ {
m_urlsToLoad.insert(url); m_urlsToLoad.insert(url);
@@ -449,11 +530,24 @@ private:
FilePath m_basePath; FilePath m_basePath;
std::function<void(QNetworkRequest *)> m_requestHook; std::function<void(QNetworkRequest *)> m_requestHook;
QNetworkAccessManager *m_networkAccessManager = NetworkAccessManager::instance(); 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) MarkdownBrowser::MarkdownBrowser(QWidget *parent)
: QTextBrowser(parent) : QTextBrowser(parent)
, m_enableCodeCopyButton(false)
{ {
setOpenLinks(false);
connect(this, &QTextBrowser::anchorClicked, this, &MarkdownBrowser::handleAnchorClicked);
setDocument(new AnimatedDocument(this)); setDocument(new AnimatedDocument(this));
} }
@@ -480,6 +574,11 @@ void MarkdownBrowser::setMargins(const QMargins &margins)
setViewportMargins(margins); setViewportMargins(margins);
} }
void MarkdownBrowser::setEnableCodeCopyButton(bool enable)
{
m_enableCodeCopyButton = enable;
}
void MarkdownBrowser::setAllowRemoteImages(bool allow) void MarkdownBrowser::setAllowRemoteImages(bool allow)
{ {
static_cast<AnimatedDocument *>(document())->setAllowRemoteImages(allow); static_cast<AnimatedDocument *>(document())->setAllowRemoteImages(allow);
@@ -500,6 +599,33 @@ void MarkdownBrowser::setMaximumCacheSize(qsizetype maxSize)
static_cast<AnimatedDocument *>(document())->setMaximumCacheSize(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) void MarkdownBrowser::setBasePath(const FilePath &filePath)
{ {
static_cast<AnimatedDocument *>(document())->setBasePath(filePath); static_cast<AnimatedDocument *>(document())->setBasePath(filePath);
@@ -507,13 +633,26 @@ void MarkdownBrowser::setBasePath(const FilePath &filePath)
void MarkdownBrowser::setMarkdown(const QString &markdown) void MarkdownBrowser::setMarkdown(const QString &markdown)
{ {
QScrollBar *sb = verticalScrollBar();
int oldValue = sb->value();
auto *animDoc = static_cast<AnimatedDocument *>(document());
animDoc->clearSnippets();
document()->setMarkdown(markdown); document()->setMarkdown(markdown);
postProcessDocument(true); postProcessDocument(true);
QTimer::singleShot(0, this, [sb, oldValue] { sb->setValue(oldValue); });
// Reset cursor to start of the document, so that "show" does not // Reset cursor to start of the document, so that "show" does not
// scroll to the end of the document. // scroll to the end of the document.
setTextCursor(QTextCursor(document())); setTextCursor(QTextCursor(document()));
} }
QString MarkdownBrowser::toMarkdown() const
{
return document()->toMarkdown();
}
void MarkdownBrowser::postProcessDocument(bool firstTime) const void MarkdownBrowser::postProcessDocument(bool firstTime) const
{ {
const QFont contentFont = Utils::font(contentTF); const QFont contentFont = Utils::font(contentTF);
@@ -534,7 +673,7 @@ void MarkdownBrowser::postProcessDocument(bool firstTime) const
// Convert code blocks to highlighted frames // Convert code blocks to highlighted frames
if (blockFormat.hasProperty(QTextFormat::BlockCodeLanguage)) { if (blockFormat.hasProperty(QTextFormat::BlockCodeLanguage)) {
const QString language = blockFormat.stringProperty(QTextFormat::BlockCodeLanguage); const QString language = blockFormat.stringProperty(QTextFormat::BlockCodeLanguage);
highlightCodeBlock(document(), block, language); highlightCodeBlock(document(), block, language, m_enableCodeCopyButton);
continue; continue;
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -48,7 +48,8 @@ static QPoint globalPosOnScreen(const QPoint &orig, const QSize &size)
qscreen = QGuiApplication::primaryScreen(); qscreen = QGuiApplication::primaryScreen();
const QRect screen = qscreen->availableGeometry(); 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 class FilterPopupWidget : public QFrame

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1618,7 +1618,8 @@ bool EditorManagerPrivate::closeEditors(const QList<IEditor*> &editors, CloseFla
emit m_instance->editorAboutToClose(editor); emit m_instance->editorAboutToClose(editor);
const DocumentModel::Entry *entry = DocumentModel::entryForDocument(editor->document()); 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. // 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); removeEditor(editor, removeSuspendedEntry);
if (EditorView *view = viewForEditor(editor)) { if (EditorView *view = viewForEditor(editor)) {
editorsPerView.insert(view, editor); editorsPerView.insert(view, editor);

View File

@@ -681,7 +681,10 @@ void OutputWindow::registerPositionOf(unsigned taskId, int linkedOutputLines, in
return; return;
const int blocknumber = document()->blockCount() - offset; 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; const int lastLine = firstLine + linkedOutputLines - 1;
d->taskPositions.insert(taskId, {firstLine, lastLine}); d->taskPositions.insert(taskId, {firstLine, lastLine});

View File

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

View File

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

View File

@@ -29,7 +29,8 @@ public:
QDir::toNativeSeparators("../Src"), QDir::toNativeSeparators("../Src"),
".."}; ".."};
Utils::FilePath licenseTemplatePath; 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 headerPragmaOnce = false;
bool lowerCaseFiles = Constants::LOWERCASE_CPPFILES_DEFAULT; bool lowerCaseFiles = Constants::LOWERCASE_CPPFILES_DEFAULT;

View File

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

View File

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

View File

@@ -268,6 +268,9 @@ public:
void setServerEssential(bool on) { m_serverEssential = on; } void setServerEssential(bool on) { m_serverEssential = on; }
bool serverEssential() const { return m_serverEssential; } 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; } void setAddQmlServerInferiorCmdArgIfNeeded(bool on) { m_addQmlServerInferiorCmdArgIfNeeded = on; }
bool isAddQmlServerInferiorCmdArgIfNeeded() const { return m_addQmlServerInferiorCmdArgIfNeeded; } bool isAddQmlServerInferiorCmdArgIfNeeded() const { return m_addQmlServerInferiorCmdArgIfNeeded; }
@@ -367,6 +370,7 @@ private:
Utils::ProcessHandle m_serverAttachPid; Utils::ProcessHandle m_serverAttachPid;
bool m_serverUseMulti = true; bool m_serverUseMulti = true;
bool m_serverEssential = true; bool m_serverEssential = true;
bool m_skipDebugServer = false;
bool m_addQmlServerInferiorCmdArgIfNeeded = 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)); {":/debugger/images/breakpoint_pending_overlay.png", Theme::PanelTextColorDark}}, Icon::IconStyleOptions(Icon::Tint | Icon::PunchEdges));
const Icon BREAKPOINT_WITH_LOCATION({ const Icon BREAKPOINT_WITH_LOCATION({
{":/utils/images/filledcircle.png", Theme::IconsErrorColor}, {":/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( const Icon BREAKPOINTS(
":/debugger/images/debugger_breakpoints.png"); ":/debugger/images/debugger_breakpoints.png");
const Icon WATCHPOINT({ const Icon WATCHPOINT({
@@ -65,10 +65,10 @@ const Icon DEBUG_EXIT_SMALL_TOOLBAR({
{":/utils/images/debugger_overlay_small.png", Theme::IconsDebugColor}}); {":/utils/images/debugger_overlay_small.png", Theme::IconsDebugColor}});
const Icon LOCATION({ const Icon LOCATION({
{":/debugger/images/location_background.png", Theme::IconsCodeModelOverlayForegroundColor}, {":/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({ const Icon REVERSE_LOCATION({
{":/debugger/images/debugger_reversemode_background.png", Theme::IconsCodeModelOverlayForegroundColor}, {":/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({ const Icon REVERSE_MODE({
{":/debugger/images/debugger_reversemode_background.png", Theme::IconsCodeModelOverlayForegroundColor}, {":/debugger/images/debugger_reversemode_background.png", Theme::IconsCodeModelOverlayForegroundColor},
{":/debugger/images/debugger_reversemode.png", Theme::IconsInfoColor}}, Icon::Tint); {":/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() void DebuggerRunTool::startDebugServerIfNeededAndContinueStartup()
{ {
if (!runControl()->usesDebugChannel()) { if (!runControl()->usesDebugChannel() || m_runParameters.skipDebugServer()) {
continueAfterDebugServerStart(); continueAfterDebugServerStart();
return; return;
} }
@@ -680,9 +680,9 @@ void DebuggerRunTool::startDebugServerIfNeededAndContinueStartup()
}); });
connect(&d->debuggerServerProc, &Process::done, this, [this] { connect(&d->debuggerServerProc, &Process::done, this, [this] {
if (d->terminalProc.error() != QProcess::UnknownError) if (d->debuggerServerProc.error() != QProcess::UnknownError)
reportFailure(d->terminalProc.errorString()); reportFailure(d->debuggerServerProc.errorString());
if (d->terminalProc.error() != QProcess::FailedToStart && m_runParameters.serverEssential()) if (d->debuggerServerProc.error() != QProcess::FailedToStart && m_runParameters.serverEssential())
reportDone(); reportDone();
}); });

View File

@@ -1511,7 +1511,9 @@ void GdbEngine::handlePythonSetup(const DebuggerResponse &response)
GdbMi data = response.data; GdbMi data = response.data;
watchHandler()->addDumpers(data["dumpers"]); watchHandler()->addDumpers(data["dumpers"]);
m_pythonVersion = data["python"].toInt(); 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 pythonMajor = m_pythonVersion / 10000;
int pythonMinor = (m_pythonVersion / 100) % 100; int pythonMinor = (m_pythonVersion / 100) % 100;
QString out = "<p>" QString out = "<p>"

View File

@@ -296,13 +296,18 @@ void ModulesHandler::updateModule(const Module &module)
m_model->rootItem()->appendChild(item); m_model->rootItem()->appendChild(item);
} }
try { // MinGW occasionallly throws std::bad_alloc. if (path.isLocal()) {
ElfReader reader(path); try { // MinGW occasionallly throws std::bad_alloc.
item->module.elfData = reader.readHeaders(); ElfReader reader(path);
item->update(); item->module.elfData = reader.readHeaders();
} catch(...) { item->update();
qWarning("%s: An exception occurred while reading module '%s'", } catch(...) {
Q_FUNC_INFO, qPrintable(module.modulePath.toUserOutput())); 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; item->updated = true;
} }

View File

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

View File

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

View File

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

View File

@@ -38,22 +38,19 @@ bool DockerApi::canConnect()
{ {
Process process; Process process;
FilePath dockerExe = dockerClient(); FilePath dockerExe = dockerClient();
if (dockerExe.isEmpty() || !dockerExe.isExecutableFile()) if (dockerExe.isEmpty())
return false; return false;
bool result = false;
process.setCommand({dockerExe, {"info"}}); 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()); qCInfo(dockerApiLog) << "'docker info' result:\n" << qPrintable(process.allOutput());
if (process.result() == ProcessResult::FinishedWithSuccess)
result = true;
});
process.start(); return process.result() == ProcessResult::FinishedWithSuccess;
process.waitForFinished();
return result;
} }
bool DockerApi::isContainerRunning(const QString &containerId) 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 "dockerapi.h"
#include "dockerconstants.h" #include "dockerconstants.h"
#include "dockercontainerthread.h"
#include "dockerdevicewidget.h" #include "dockerdevicewidget.h"
#include "dockersettings.h" #include "dockersettings.h"
#include "dockertr.h" #include "dockertr.h"
@@ -170,25 +171,19 @@ public:
DockerDevicePrivate(DockerDevice *parent) DockerDevicePrivate(DockerDevice *parent)
: q(parent) : q(parent)
{ {
QObject::connect(q, &DockerDevice::applied, this, [this] { QObject::connect(q, &DockerDevice::applied, this, [this] { stopCurrentContainer(); });
if (!m_container.isEmpty()) {
stopCurrentContainer();
}
});
} }
~DockerDevicePrivate() { stopCurrentContainer(); } ~DockerDevicePrivate() { stopCurrentContainer(); }
CommandLine createCommandLine(); CommandLine createCommandLine();
expected_str<void> updateContainerAccess(); expected_str<QString> updateContainerAccess();
void changeMounts(QStringList newMounts); void changeMounts(QStringList newMounts);
bool ensureReachable(const FilePath &other); bool ensureReachable(const FilePath &other);
void shutdown(); void shutdown();
expected_str<FilePath> localSource(const FilePath &other) const; expected_str<FilePath> localSource(const FilePath &other) const;
QString containerId() { return m_container; }
expected_str<QPair<Utils::OsType, Utils::OsArch>> osTypeAndArch() const; expected_str<QPair<Utils::OsType, Utils::OsArch>> osTypeAndArch() const;
expected_str<Environment> environment(); expected_str<Environment> environment();
@@ -204,10 +199,8 @@ public:
bool prepareForBuild(const Target *target); bool prepareForBuild(const Target *target);
Tasks validateMounts() const; Tasks validateMounts() const;
expected_str<QString> createContainer();
expected_str<void> startContainer();
void stopCurrentContainer(); void stopCurrentContainer();
expected_str<void> fetchSystemEnviroment(); Result fetchSystemEnviroment();
expected_str<FilePath> getCmdBridgePath() const; expected_str<FilePath> getCmdBridgePath() const;
@@ -277,13 +270,10 @@ public:
FilePath containerPath; FilePath containerPath;
}; };
QString m_container;
std::unique_ptr<Process> m_startProcess;
std::optional<Environment> m_cachedEnviroment; std::optional<Environment> m_cachedEnviroment;
bool m_isShutdown = false; bool m_isShutdown = false;
SynchronizedValue<std::unique_ptr<DeviceFileAccess>> m_fileAccess; SynchronizedValue<std::unique_ptr<DeviceFileAccess>> m_fileAccess;
SynchronizedValue<std::unique_ptr<DockerContainerThread>> m_deviceThread;
}; };
class DockerProcessImpl : public ProcessInterface class DockerProcessImpl : public ProcessInterface
@@ -299,9 +289,7 @@ private:
private: private:
DockerDevicePrivate *m_devicePrivate = nullptr; DockerDevicePrivate *m_devicePrivate = nullptr;
// Store the IDevice::ConstPtr in order to extend the lifetime of device for as long std::weak_ptr<const IDevice> m_device;
// as this object is alive.
IDevice::ConstPtr m_device;
Process m_process; Process m_process;
qint64 m_remotePID = 0; qint64 m_remotePID = 0;
@@ -312,7 +300,7 @@ private:
DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePrivate *devicePrivate) DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePrivate *devicePrivate)
: m_devicePrivate(devicePrivate) : m_devicePrivate(devicePrivate)
, m_device(std::move(device)) , m_device(device)
, m_process(this) , m_process(this)
{ {
connect(&m_process, &Process::started, this, [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) if (rest.size() > 0 || stdErr.size() > 0)
emit readyRead(rest, stdErr); emit readyRead(rest, stdErr);
}); });
connect(&m_process, &Process::readyReadStandardError, this, [this] { connect(&m_process, &Process::readyReadStandardError, this, [this] {
@@ -412,6 +399,15 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva
emit done(resultData); 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() DockerProcessImpl::~DockerProcessImpl()
@@ -482,15 +478,19 @@ void DockerProcessImpl::sendControlSignal(ControlSignal controlSignal)
m_process.closeWriteChannel(); m_process.closeWriteChannel();
return; 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) { if (dfa) {
static_cast<DockerDeviceFileAccess *>(m_device->fileAccess()) static_cast<DockerDeviceFileAccess *>(device->fileAccess())
->signalProcess(m_remotePID, controlSignal); ->signalProcess(m_remotePID, controlSignal);
} else { } else {
const int signal = controlSignalToInt(controlSignal); const int signal = controlSignalToInt(controlSignal);
Process p; Process p;
p.setCommand( p.setCommand(
{m_device->rootPath().withNewPath("kill"), {device->rootPath().withNewPath("kill"),
{QString("-%1").arg(signal), QString("%2").arg(m_remotePID)}}); {QString("-%1").arg(signal), QString("%2").arg(m_remotePID)}});
p.runBlocking(); p.runBlocking();
} }
@@ -602,7 +602,6 @@ DockerDevice::DockerDevice()
auto future = DockerApi::instance()->networks(); auto future = DockerApi::instance()->networks();
auto watcher = new QFutureWatcher<expected_str<QList<Network>>>(this); auto watcher = new QFutureWatcher<expected_str<QList<Network>>>(this);
watcher->setFuture(future);
QObject::connect(watcher, QObject::connect(watcher,
&QFutureWatcher<expected_str<QList<Network>>>::finished, &QFutureWatcher<expected_str<QList<Network>>>::finished,
this, this,
@@ -622,6 +621,7 @@ DockerDevice::DockerDevice()
cb({errorItem}); cb({errorItem});
} }
}); });
watcher->setFuture(future);
}); });
connect(DockerApi::instance(), connect(DockerApi::instance(),
@@ -671,13 +671,10 @@ DockerDevice::DockerDevice()
const FilePath &workingDir) -> expected_str<void> { const FilePath &workingDir) -> expected_str<void> {
Q_UNUSED(env); // TODO: That's the runnable's environment in general. Use it via -e below. 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) if (!result)
return result; return make_unexpected(result.error());
if (d->containerId().isEmpty())
return make_unexpected(Tr::tr("Error starting remote shell. No container."));
expected_str<FilePath> shell = Terminal::defaultShellForDevice(rootPath()); expected_str<FilePath> shell = Terminal::defaultShellForDevice(rootPath());
if (!shell) if (!shell)
@@ -716,9 +713,10 @@ void DockerDevice::shutdown()
d->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( expected_str<CommandLine> DockerDevicePrivate::withDockerExecCmd(
@@ -729,8 +727,12 @@ expected_str<CommandLine> DockerDevicePrivate::withDockerExecCmd(
bool withPty, bool withPty,
bool withMarker) bool withMarker)
{ {
if (const auto result = updateContainerAccess(); !result) QString containerId;
if (const expected_str<QString> result = updateContainerAccess(); !result)
return make_unexpected(result.error()); return make_unexpected(result.error());
else
containerId = *result;
auto osAndArch = osTypeAndArch(); auto osAndArch = osTypeAndArch();
if (!osAndArch) if (!osAndArch)
@@ -756,7 +758,7 @@ expected_str<CommandLine> DockerDevicePrivate::withDockerExecCmd(
if (workDir && !workDir->isEmpty()) if (workDir && !workDir->isEmpty())
dockerCmd.addArgs({"-w", q->rootPath().withNewMappedPath(*workDir).nativePath()}); dockerCmd.addArgs({"-w", q->rootPath().withNewMappedPath(*workDir).nativePath()});
dockerCmd.addArg(m_container); dockerCmd.addArg(containerId);
dockerCmd.addArgs({"/bin/sh", "-c"}, osAndArch->first); dockerCmd.addArgs({"/bin/sh", "-c"}, osAndArch->first);
@@ -787,28 +789,12 @@ expected_str<CommandLine> DockerDevicePrivate::withDockerExecCmd(
void DockerDevicePrivate::stopCurrentContainer() 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(); m_cachedEnviroment.reset();
auto fileAccess = m_fileAccess.writeLocked();
fileAccess->reset();
auto locked = m_deviceThread.writeLocked();
locked->reset();
} }
bool DockerDevicePrivate::prepareForBuild(const Target *target) bool DockerDevicePrivate::prepareForBuild(const Target *target)
@@ -949,8 +935,10 @@ CommandLine DockerDevicePrivate::createCommandLine()
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
// no getuid() and getgid() on Windows. // no getuid() and getgid() on Windows.
if (q->useLocalUidGid()) if (q->useLocalUidGid()) {
dockerCreate.addArgs({"-u", QString("%1:%2").arg(getuid()).arg(getgid())}); dockerCreate.addArgs({"-u", QString("%1:%2").arg(getuid()).arg(getgid())});
dockerCreate.addArgs({"-e", QString("HOME=/tmp/qtc_home/%1").arg(getuid())});
}
#endif #endif
if (!q->network().isEmpty()) { if (!q->network().isEmpty()) {
@@ -973,99 +961,36 @@ CommandLine DockerDevicePrivate::createCommandLine()
return dockerCreate; 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) if (m_isShutdown)
return make_unexpected(Tr::tr("Device is shut down")); return make_unexpected(Tr::tr("Device is shut down"));
if (DockerApi::isDockerDaemonAvailable(false).value_or(false) == false) if (DockerApi::isDockerDaemonAvailable(false).value_or(false) == false)
return make_unexpected(Tr::tr("Docker system is not reachable")); return make_unexpected(Tr::tr("Docker system is not reachable"));
expected_str<void> result = startContainer(); auto lockedThread = m_deviceThread.writeLocked();
QString containerStatus = result ? Tr::tr("Running") : result.error().trimmed(); if (*lockedThread)
return (*lockedThread)->containerId();
if (!result) DockerContainerThread::Init init;
result = make_unexpected(QString("Failed to start container: %1").arg(result.error())); 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] { QTimer::singleShot(0, this, [this, containerStatus] {
q->containerStatus.setText(containerStatus); q->containerStatus.setText(containerStatus);
}); });
return result; if (!result)
return make_unexpected(result.error());
return (*lockedThread)->containerId();
} }
void DockerDevice::setMounts(const QStringList &mounts) const void DockerDevice::setMounts(const QStringList &mounts) const
@@ -1152,24 +1077,19 @@ void DockerDevice::aboutToBeRemoved() const
detector.undoAutoDetect(id().toString()); detector.undoAutoDetect(id().toString());
} }
expected_str<void> DockerDevicePrivate::fetchSystemEnviroment() Result DockerDevicePrivate::fetchSystemEnviroment()
{ {
if (m_cachedEnviroment) if (m_cachedEnviroment)
return {}; return Result::Ok;
if (auto fileAccess = m_fileAccess.readLocked()->get()) { if (auto fileAccess = m_fileAccess.readLocked()->get()) {
m_cachedEnviroment = fileAccess->deviceEnvironment(); 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"}); const expected_str<CommandLine> fullCommandLine = withDockerExecCmd(CommandLine{"env"});
if (!fullCommandLine) if (!fullCommandLine)
return make_unexpected(fullCommandLine.error()); return Result::Error(fullCommandLine.error());
Process proc; Process proc;
proc.setCommand(*fullCommandLine); proc.setCommand(*fullCommandLine);
@@ -1180,9 +1100,9 @@ expected_str<void> DockerDevicePrivate::fetchSystemEnviroment()
QString stdErr = proc.cleanedStdErr(); QString stdErr = proc.cleanedStdErr();
if (stdErr.isEmpty()) 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 // Factory
@@ -1385,19 +1305,19 @@ DockerDeviceFactory::DockerDeviceFactory()
}); });
setConstructionFunction([this] { setConstructionFunction([this] {
auto device = DockerDevice::create(); auto device = DockerDevice::create();
QMutexLocker lk(&m_deviceListMutex); m_existingDevices.writeLocked()->push_back(device);
m_existingDevices.push_back(device);
return device; return device;
}); });
} }
void DockerDeviceFactory::shutdownExistingDevices() void DockerDeviceFactory::shutdownExistingDevices()
{ {
QMutexLocker lk(&m_deviceListMutex); m_existingDevices.read([](const std::vector<std::weak_ptr<DockerDevice>> &devices) {
for (const auto &weakDevice : m_existingDevices) { for (const std::weak_ptr<DockerDevice> &weakDevice : devices) {
if (std::shared_ptr<DockerDevice> device = weakDevice.lock()) if (std::shared_ptr<DockerDevice> device = weakDevice.lock())
device->shutdown(); device->shutdown();
} }
});
} }
expected_str<QPair<Utils::OsType, Utils::OsArch>> DockerDevicePrivate::osTypeAndArch() const 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() expected_str<Environment> DockerDevicePrivate::environment()
{ {
if (!m_cachedEnviroment) { if (!m_cachedEnviroment) {
expected_str<void> result = fetchSystemEnviroment(); if (Result result = fetchSystemEnviroment(); !result)
if (!result)
return make_unexpected(result.error()); 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) bool DockerDevicePrivate::ensureReachable(const FilePath &other)

View File

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

View File

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

View File

@@ -15,6 +15,7 @@
#include <utils/stylehelper.h> #include <utils/stylehelper.h>
#include <QGuiApplication> #include <QGuiApplication>
#include <QSslSocket>
namespace ExtensionManager::Internal { namespace ExtensionManager::Internal {
@@ -33,6 +34,13 @@ ExtensionManagerSettings::ExtensionManagerSettings()
useExternalRepo.setDefaultValue(false); useExternalRepo.setDefaultValue(false);
useExternalRepo.setLabelText(Tr::tr("Use external repository")); 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.setSettingsKey("ExternalRepoUrl");
externalRepoUrl.setDefaultValue("https://qc-extensions.qt.io"); externalRepoUrl.setDefaultValue("https://qc-extensions.qt.io");
externalRepoUrl.setDisplayStyle(Utils::StringAspect::LineEditDisplay); externalRepoUrl.setDisplayStyle(Utils::StringAspect::LineEditDisplay);

View File

@@ -549,7 +549,11 @@ ExtensionsBrowser::ExtensionsBrowser(ExtensionsModel *model, QWidget *parent)
applyTf(titleLabel, titleTF); applyTf(titleLabel, titleTF);
auto externalRepoSwitch = new Switch("Use external repository"); 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 = new SearchBox;
d->searchBox->setPlaceholderText(Tr::tr("Search")); d->searchBox->setPlaceholderText(Tr::tr("Search"));

View File

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

View File

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

View File

@@ -29,6 +29,7 @@ using namespace Utils;
using namespace Core; using namespace Core;
using namespace TextEditor; using namespace TextEditor;
using namespace ProjectExplorer; using namespace ProjectExplorer;
using namespace std::string_view_literals;
namespace { namespace {
@@ -264,21 +265,22 @@ public:
return make_unexpected(QString("init callback did not return a table or string")); 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); 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_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_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( 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") if (transportType == "stdio")
m_transportType = TransportType::StdIO; m_transportType = TransportType::StdIO;
else if (transportType == "localsocket") else if (transportType == "localsocket")
@@ -286,7 +288,7 @@ public:
else else
qWarning() << "Unknown transport type:" << transportType; 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) { if (languageFilter) {
auto patterns = languageFilter->get<std::optional<sol::table>>("patterns"); auto patterns = languageFilter->get<std::optional<sol::table>>("patterns");
auto mimeTypes = languageFilter->get<std::optional<sol::table>>("mimeTypes"); auto mimeTypes = languageFilter->get<std::optional<sol::table>>("mimeTypes");
@@ -300,10 +302,10 @@ public:
m_languageFilter.mimeTypes.push_back(v.as<QString>()); 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 // 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) { if (m_aspects) {
connect(m_aspects, &AspectContainer::applied, this, [this] { connect(m_aspects, &AspectContainer::applied, this, [this] {

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,19 +16,28 @@
#include <QFontMetrics> #include <QFontMetrics>
#include <QStandardPaths> #include <QStandardPaths>
using namespace std::string_view_literals;
namespace Lua::Internal { namespace Lua::Internal {
void setupQtModule() void setupQtModule()
{ {
registerProvider("Qt", [](sol::state_view lua) { registerProvider("Qt", [](sol::state_view lua) {
sol::table qt(lua, sol::create); 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>( qt.new_usertype<QCompleter>(
"QCompleter", "QCompleter",
"create", "create",
[](const QStringList &list) -> std::unique_ptr<QCompleter> { [](const QStringList &list) -> QCompleter* {
return std::make_unique<QCompleter>(list); 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", "currentCompletion",
&QCompleter::currentCompletion, &QCompleter::currentCompletion,

View File

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

View File

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