Merge "Merge remote-tracking branch 'origin/16.0' into qds/dev" into qds/dev
2
.github/workflows/build_cmake.yml
vendored
@@ -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
|
||||||
|
@@ -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
@@ -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).
|
@@ -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)
|
||||||
|
@@ -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.
|
||||||
|
@@ -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"
|
||||||
|
68
dist/changelog/changes-16.0.0.md
vendored
@@ -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
|
||||||
|
BIN
doc/qtcreator/images/qt-creator-android-build-aar.webp
Normal file
After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 8.4 KiB |
BIN
doc/qtcreator/images/qtcreator-mcu-device.webp
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
doc/qtcreator/images/qtcreator-mcu-new-kit.webp
Normal file
After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 22 KiB |
@@ -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},
|
||||||
*/
|
*/
|
||||||
|
@@ -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.
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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:
|
||||||
|
@@ -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
|
||||||
|
@@ -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}.
|
||||||
|
@@ -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.
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
@@ -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 }
|
||||||
|
44
share/qtcreator/lua-plugins/luatests/tst_markdownbrowser.lua
Normal 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,
|
||||||
|
}
|
@@ -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}."));
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 151 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 48 KiB |
2
src/libs/3rdparty/cplusplus/Symbols.h
vendored
@@ -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
|
||||||
|
19
src/libs/3rdparty/libptyqt/conptyprocess.cpp
vendored
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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()
|
||||||
|
@@ -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);
|
||||||
|
@@ -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();
|
||||||
|
@@ -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()));
|
||||||
|
@@ -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) {
|
||||||
|
BIN
src/libs/utils/images/code_copy_square.png
Normal file
After Width: | Height: | Size: 353 B |
BIN
src/libs/utils/images/code_copy_square@2x.png
Normal file
After Width: | Height: | Size: 556 B |
@@ -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;
|
||||||
|
@@ -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
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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();
|
||||||
|
@@ -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>
|
||||||
|
@@ -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",
|
||||||
|
@@ -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
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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();
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
@@ -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});
|
||||||
|
@@ -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");
|
||||||
|
@@ -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();
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -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(
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
@@ -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();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -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>"
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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
|
|
||||||
)
|
)
|
||||||
|
@@ -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
|
||||||
|
@@ -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",
|
||||||
|
@@ -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)
|
||||||
|
147
src/plugins/docker/dockercontainerthread.cpp
Normal 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
|
40
src/plugins/docker/dockercontainerthread.h
Normal 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
|
@@ -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)
|
||||||
|
@@ -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
|
||||||
|
@@ -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."));
|
||||||
|
@@ -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);
|
||||||
|
@@ -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"));
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
|
@@ -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] {
|
||||||
|
@@ -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()) {
|
||||||
|
@@ -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>());
|
||||||
|
|
||||||
|
@@ -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> {
|
||||||
|
@@ -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();
|
||||||
|
@@ -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,
|
||||||
|
@@ -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 ¶meter) {
|
process["create"] = [](const sol::table ¶meter) {
|
||||||
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>();
|
||||||
|
|
||||||
|
@@ -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");
|
||||||
|
|
||||||
|