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/**'
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.8.1
|
||||
QT_VERSION: 6.8.2
|
||||
MACOS_DEPLOYMENT_TARGET: 11.0
|
||||
CLANG_VERSION: 19.1.6
|
||||
ELFUTILS_VERSION: 0.175
|
||||
|
@@ -80,6 +80,18 @@ find_package(Qt6
|
||||
find_package(Qt6 OPTIONAL_COMPONENTS Quick QuickWidgets Designer DesignerComponentsPrivate
|
||||
Help SerialPort Svg Tools LinguistTools QUIET)
|
||||
|
||||
if (QT_VERSION VERSION_GREATER_EQUAL 6.9.0)
|
||||
find_package(Qt6 OPTIONAL_COMPONENTS
|
||||
CorePrivate
|
||||
Core5CompatPrivate
|
||||
GuiPrivate
|
||||
DesignerComponentsPrivate
|
||||
QmlPrivate
|
||||
QuickPrivate
|
||||
QUIET
|
||||
)
|
||||
endif()
|
||||
|
||||
# depending on Qt version and compiler version enable or disable Qml Designer
|
||||
# can be overwritten by variable WITH_QMLDESIGNER / QTC_WITH_QMLDESIGNER (env)
|
||||
configure_qml_designer(${Qt6_VERSION})
|
||||
|
70
TESTING.md
Normal file
@@ -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")
|
||||
else ()
|
||||
# Small hack to silence a warning in the stable branch - but it means the value is incorrect
|
||||
if (NOT CMAKE_LIBRARY_ARCHITECTURE)
|
||||
if (NOT CMAKE_LIBRARY_ARCHITECTURE AND NOT CMAKE_INSTALL_LIBDIR)
|
||||
set(CMAKE_INSTALL_LIBDIR "lib")
|
||||
endif()
|
||||
include(GNUInstallDirs)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
set(IDE_VERSION "15.0.84") # The IDE version.
|
||||
set(IDE_VERSION_COMPAT "15.0.84") # The IDE Compatibility version.
|
||||
set(IDE_VERSION_DISPLAY "16.0.0-rc1") # The IDE display version.
|
||||
set(IDE_VERSION "16.0.0") # The IDE version.
|
||||
set(IDE_VERSION_COMPAT "16.0.0") # The IDE Compatibility version.
|
||||
set(IDE_VERSION_DISPLAY "16.0.0") # The IDE display version.
|
||||
|
||||
set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation.
|
||||
set(IDE_DISPLAY_NAME "Qt Creator") # The IDE display name.
|
||||
|
@@ -7,7 +7,7 @@ instructions:
|
||||
instructions:
|
||||
- type: EnvironmentVariable
|
||||
variableName: QTC_QT_BASE_URL
|
||||
variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/qt/6.8.0/release_content/"
|
||||
variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/qt/6.8.2/release_content/"
|
||||
- type: EnvironmentVariable
|
||||
variableName: MACOSX_DEPLOYMENT_TARGET
|
||||
variableValue: 12.0
|
||||
@@ -88,7 +88,7 @@ instructions:
|
||||
instructions:
|
||||
- type: EnvironmentVariable
|
||||
variableName: QTC_QT_POSTFIX
|
||||
variableValue: "-Linux-RHEL_8_8-GCC-Linux-RHEL_8_8-X86_64.7z"
|
||||
variableValue: "-Linux-RHEL_8_10-GCC-Linux-RHEL_8_10-X86_64.7z"
|
||||
- type: EnvironmentVariable
|
||||
variableName: QTC_ICU_URL
|
||||
variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/development_releases/prebuilt/icu/prebuilt/73.2/icu-linux-g++-Rhel8.6-x64.7z"
|
||||
@@ -141,7 +141,7 @@ instructions:
|
||||
instructions:
|
||||
- type: EnvironmentVariable
|
||||
variableName: QTC_QT_POSTFIX
|
||||
variableValue: "-Linux-Debian_11_6-GCC-Linux-Debian_11_6-AARCH64.7z"
|
||||
variableValue: "-Linux-Ubuntu_24_04-GCC-Linux-Ubuntu_24_04-AARCH64.7z"
|
||||
- type: EnvironmentVariable
|
||||
variableName: QTC_SDKTOOL_QT_EXT
|
||||
variableValue: ".tar.xz"
|
||||
|
68
dist/changelog/changes-16.0.0.md
vendored
@@ -36,6 +36,10 @@ Editing
|
||||
([QTCREATORBUG-32193](https://bugreports.qt.io/browse/QTCREATORBUG-32193))
|
||||
* Fixed a formatting issue when applying method signature changes
|
||||
([QTCREATORBUG-31931](https://bugreports.qt.io/browse/QTCREATORBUG-31931))
|
||||
* Fixed the generation of getters for local enum types
|
||||
([QTCREATORBUG-32473](https://bugreports.qt.io/browse/QTCREATORBUG-32473))
|
||||
* Fixed the header guard creation for file names with special characters
|
||||
([QTCREATORBUG-32539](https://bugreports.qt.io/browse/QTCREATORBUG-32539))
|
||||
* Built-in
|
||||
* Added support for init-statements in range-based `for` loops
|
||||
([QTCREATORBUG-31961](https://bugreports.qt.io/browse/QTCREATORBUG-31961))
|
||||
@@ -68,6 +72,16 @@ Editing
|
||||
([QTCREATORBUG-31878](https://bugreports.qt.io/browse/QTCREATORBUG-31878),
|
||||
[QTCREATORBUG-32163](https://bugreports.qt.io/browse/QTCREATORBUG-32163))
|
||||
|
||||
### Copilot
|
||||
|
||||
* Fixed issues with newer versions of the language server
|
||||
([QTCREATORBUG-32536](https://bugreports.qt.io/browse/QTCREATORBUG-32536))
|
||||
|
||||
### SCXML
|
||||
|
||||
* Fixed the colors of items
|
||||
([QTCREATORBUG-32477](https://bugreports.qt.io/browse/QTCREATORBUG-32477))
|
||||
|
||||
Projects
|
||||
--------
|
||||
|
||||
@@ -101,6 +115,11 @@ Projects
|
||||
([QTCREATORBUG-32350](https://bugreports.qt.io/browse/QTCREATORBUG-32350))
|
||||
* Fixed a crash when an application outputs lots of lines
|
||||
([QTCREATORBUG-32371](https://bugreports.qt.io/browse/QTCREATORBUG-32371))
|
||||
* Environment Editor
|
||||
* Fixed the `Disable` button for the first item
|
||||
([QTCREATORBUG-32495](https://bugreports.qt.io/browse/QTCREATORBUG-32495))
|
||||
* Fixed the `Edit` button for disabled items
|
||||
([QTCREATORBUG-32495](https://bugreports.qt.io/browse/QTCREATORBUG-32495))
|
||||
* Qt
|
||||
* Improved performance of Qt ABI detection when module `.json` files are
|
||||
available
|
||||
@@ -121,6 +140,7 @@ Projects
|
||||
* Added support for creating run configurations for custom CMake targets
|
||||
with the `qtc_runnable` `FOLDER` property
|
||||
([QTCREATORBUG-32324](https://bugreports.qt.io/browse/QTCREATORBUG-32324))
|
||||
* Improved the performance when CMake reply files change on disk
|
||||
* Fixed that manually created run configurations could be removed if
|
||||
`Create suitable run configurations automatically` was turned off
|
||||
([QTCREATORBUG-32289](https://bugreports.qt.io/browse/QTCREATORBUG-32289))
|
||||
@@ -130,6 +150,8 @@ Projects
|
||||
* Fixed that Ninja was not detected even when `CMAKE_MAKE_PROGRAM` was set
|
||||
to the `ninja` executable
|
||||
([QTCREATORBUG-32436](https://bugreports.qt.io/browse/QTCREATORBUG-32436))
|
||||
* Fixed the import of multi-config CMake presets
|
||||
([QTCREATORBUG-31554](https://bugreports.qt.io/browse/QTCREATORBUG-31554))
|
||||
* Package Manager Auto Setup
|
||||
* Changed the default installation directory to `/tmp` to ensure that the
|
||||
directory is writable
|
||||
@@ -160,7 +182,9 @@ Debugging
|
||||
|
||||
* Pretty printers
|
||||
* Added `QMultiHash`
|
||||
([QTCREATORBUG-32313](https://bugreports.qt.io/browse/QTCREATORBUG-32313))
|
||||
([QTCREATORBUG-32313](https://bugreports.qt.io/browse/QTCREATORBUG-32313))
|
||||
* Fixed issues with debuggers that use an older Python version
|
||||
([QTCREATORBUG-32475](https://bugreports.qt.io/browse/QTCREATORBUG-32475))
|
||||
* CDB
|
||||
* Disabled heap debugging by default and added the option
|
||||
`Enable heap debugging`
|
||||
@@ -180,11 +204,19 @@ Analyzer
|
||||
([QTCREATORBUG-31372](https://bugreports.qt.io/browse/QTCREATORBUG-31372))
|
||||
* Fixed that profiling could fail to start
|
||||
([QTCREATORBUG-32062](https://bugreports.qt.io/browse/QTCREATORBUG-32062))
|
||||
* Fixed the sorting of statistics
|
||||
([QTCREATORBUG-32398](https://bugreports.qt.io/browse/QTCREATORBUG-32398))
|
||||
|
||||
### Axivion
|
||||
|
||||
* Added support for images in the issue details
|
||||
* Moved Axivion preferences to `Preferences > Analyzer > Axivion`
|
||||
* Fixed that the display of data in the issues table did not adapt to the
|
||||
column's data type
|
||||
([QTCREATORBUG-32023](https://bugreports.qt.io/browse/QTCREATORBUG-32023))
|
||||
* Fixed that filters were shown even for issue types that do not suppor them
|
||||
* Fixed that the Filter menus opened at the wrong position
|
||||
([QTCREATORBUG-32506](https://bugreports.qt.io/browse/QTCREATORBUG-32506))
|
||||
|
||||
### Coco
|
||||
|
||||
@@ -192,6 +224,23 @@ Analyzer
|
||||
in `Projects > Project Settings > Coco Code Coverage`
|
||||
([Documentation]https://doc-snapshots.qt.io/qtcreator-16.0/creator-coco.html)
|
||||
|
||||
Terminal
|
||||
--------
|
||||
|
||||
* Fixed that the view didn't jump to the end on input
|
||||
([QTCREATORBUG-32407](https://bugreports.qt.io/browse/QTCREATORBUG-32407))
|
||||
* Fixed the title of tabs
|
||||
([QTCREATORBUG-32197](https://bugreports.qt.io/browse/QTCREATORBUG-32197))
|
||||
* Fixed killing the shell process
|
||||
([QTCREATORBUG-32509](https://bugreports.qt.io/browse/QTCREATORBUG-32509))
|
||||
* Fixed the scrolling behavior
|
||||
([QTCREATORBUG-32167](https://bugreports.qt.io/browse/QTCREATORBUG-32167),
|
||||
[QTCREATORBUG-32546](https://bugreports.qt.io/browse/QTCREATORBUG-32546))
|
||||
* Fixed the title of tabs
|
||||
([QTCREATORBUG-32197](https://bugreports.qt.io/browse/QTCREATORBUG-32197))
|
||||
* Fixed the handling of `Home` and `End` keys
|
||||
([QTCREATORBUG-32545](https://bugreports.qt.io/browse/QTCREATORBUG-32545))
|
||||
|
||||
Version Control Systems
|
||||
-----------------------
|
||||
|
||||
@@ -227,10 +276,17 @@ Platforms
|
||||
* Added support for the `terminator` terminal emulator
|
||||
([QTCREATORBUG-32111](https://bugreports.qt.io/browse/QTCREATORBUG-32111))
|
||||
|
||||
### macOS
|
||||
|
||||
* Fixed a crash when MinGW toolchains are detected on macOS hosts
|
||||
([QTCREATORBUG-32127](https://bugreports.qt.io/browse/QTCREATORBUG-32127))
|
||||
|
||||
### Android
|
||||
|
||||
* Fixed a performance problem when detecting the Android ABI
|
||||
([QTCREATORBUG-31068](https://bugreports.qt.io/browse/QTCREATORBUG-31068))
|
||||
* Fixed that the wrong `lldb-server` could be used
|
||||
([QTCREATORBUG-32494](https://bugreports.qt.io/browse/QTCREATORBUG-32494))
|
||||
|
||||
### iOS
|
||||
|
||||
@@ -251,12 +307,20 @@ Platforms
|
||||
|
||||
* Fixed an issue with running `pkg-config` in the container
|
||||
([QTCREATORBUG-32325](https://bugreports.qt.io/browse/QTCREATORBUG-32325))
|
||||
* Fixed an issue with shutting down the device access
|
||||
* Fixed soft asserts during container setup
|
||||
|
||||
### QNX
|
||||
|
||||
* Fixed issues with Clangd 19
|
||||
([QTCREATORBUG-32529](https://bugreports.qt.io/browse/QTCREATORBUG-32529))
|
||||
|
||||
Credits for these changes go to:
|
||||
--------------------------------
|
||||
Alessandro Portale
|
||||
Alexander Drozdov
|
||||
Alexander Pershin
|
||||
Alexandre Laurent
|
||||
Alexis Jeandet
|
||||
Ali Kianian
|
||||
Andre Hartmann
|
||||
@@ -292,6 +356,7 @@ Mats Honkamaa
|
||||
Miikka Heikkinen
|
||||
Mitch Curtis
|
||||
Morteza Jamshidi
|
||||
Nicholas Bennett
|
||||
Nikolaus Demmel
|
||||
Olivier De Cannière
|
||||
Orgad Shaneh
|
||||
@@ -311,4 +376,5 @@ Thiago Macieira
|
||||
Thomas Hartmann
|
||||
Tim Jenßen
|
||||
Vikas Pachdha
|
||||
Ville Lavonius
|
||||
Xu Jin
|
||||
|
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
|
||||
\previouspage creator-reference.html
|
||||
\previouspage creator-how-tos.html
|
||||
|
||||
\ingroup creator-reference-analyzer
|
||||
\ingroup creator-how-to-analyze
|
||||
|
||||
\title Coco
|
||||
\title Set up code coverage from Coco
|
||||
|
||||
\brief Measure and analyze the code coverage of tests.
|
||||
|
||||
With Coco, you can measure and analyze the code coverage of tests. You can
|
||||
set up a project for code coverage and display the coverage in \QC.
|
||||
With Coco, you can measure and analyze the code coverage of tests. The
|
||||
following sections describe how to set up a project for code coverage.
|
||||
For more information about viewing the results in \QC, see
|
||||
\l{View code coverage reports from Coco}.
|
||||
|
||||
To use the plugin, you must download and install Coco version 6.0 or later.
|
||||
|
||||
@@ -143,6 +143,9 @@
|
||||
loading an instrumentation database (a \c .csmes file), which was generated by
|
||||
Coco CoverageScanner.
|
||||
|
||||
For more information about how to set up a project for code coverage in \QC,
|
||||
see \l{Set up code coverage from Coco}.
|
||||
|
||||
To measure and check code coverage:
|
||||
|
||||
\list 1
|
||||
@@ -182,5 +185,6 @@
|
||||
\li Implicit Manual Coverage Validation
|
||||
\endlist
|
||||
|
||||
\sa {Enable and disable plugins}, {Font & Colors}, {Analyzing Code}, {Coco}
|
||||
\sa {Enable and disable plugins}, {Set up code coverage from Coco},
|
||||
{Font & Colors}, {Analyzing Code},
|
||||
*/
|
||||
|
@@ -9,12 +9,13 @@
|
||||
|
||||
\title Android Deploy Configuration
|
||||
|
||||
\brief Create Application Packages (APK) or Android App Bundles (AAB) to
|
||||
install and run on devices or to upload to the Google Play store.
|
||||
\brief Create packages to deploy to devices or to submit to the Google Play
|
||||
store, or create libraries for Android app modules.
|
||||
|
||||
Android applications are packaged as ZIP files called Application Packages
|
||||
(APK) or Android App Bundles (AAB). You can install and run APK files on a
|
||||
device. You can upload AAB files to the Google Play store.
|
||||
(APK), Android App Bundles (AAB), or Android Archives (AAR). You can
|
||||
install and run APK files on a device. You can upload AAB files to the
|
||||
Google Play store.
|
||||
|
||||
\l{Qt for Android} has binaries for armv7a, arm64-v8a, x86, and x86-64.
|
||||
To support several different ABIs in your application, build an AAB that
|
||||
@@ -27,10 +28,14 @@
|
||||
\list
|
||||
\li As a stand-alone, distributable application package (APK).
|
||||
\li As an app bundle (AAB) for distribution in the Google Play store.
|
||||
\li As an AAR, which fundamentally differs from the APK and AAB formats
|
||||
in that it is an Android library. You can use it as a dependency for
|
||||
an Android app module, but you cannot run it alone.
|
||||
|
||||
All Qt versions do not support AABs. Qt 6.3.0 and later support
|
||||
multi-abi builds for applications that you build with CMake. For
|
||||
more information, see \l{Deploying an Application on Android}.
|
||||
multi-abi builds for applications when you build with CMake. AARs
|
||||
are supported from Qt 6.8.0 onwards. For more information, see
|
||||
\l{Deploying an Application on Android}.
|
||||
\endlist
|
||||
|
||||
\note Since \QC 4.12, Ministro is not supported.
|
||||
@@ -123,6 +128,12 @@
|
||||
|
||||
\image qtcreator-android-build-steps.png {qmake settings for building AABs}
|
||||
|
||||
\section3 Building AARs
|
||||
|
||||
Select the AAR target in the \uicontrol {Build Steps} section.
|
||||
|
||||
\image qt-creator-android-build-aar.webp {Selecting the AAR target}
|
||||
|
||||
\section3 Signing Android Packages
|
||||
|
||||
To publish your application, you must sign it by using a \e {public-private
|
||||
@@ -492,8 +503,7 @@
|
||||
|
||||
Select the \uicontrol {Include default permissions for Qt modules} and
|
||||
\uicontrol {Include default features for Qt modules} check boxes to add the
|
||||
permissions needed by Qt libraries. This can be
|
||||
\c {android.permission.WRITE_EXTERNAL_STORAGE} for \l{Qt Core} or
|
||||
permissions needed by Qt libraries, such as
|
||||
\c {android.permission.ACCESS_BACKGROUND_LOCATION} for \l{Qt Positioning}.
|
||||
|
||||
To add a permission, select it from the list, and then select \uicontrol Add.
|
||||
|
@@ -20,6 +20,10 @@
|
||||
|
||||
\section1 Don't detect indentation settings
|
||||
|
||||
When you open a document, the editor tries to automatically detect if it uses tabs or
|
||||
spaces for indentation and the indentation width, by inspecting its contents.
|
||||
If the automatic detection fails, the default setting is used.
|
||||
|
||||
To turn off the automatic detection of indentation settings, go to
|
||||
\preferences > \uicontrol {Text Editor} > \uicontrol Behavior
|
||||
and clear \uicontrol {Auto detect}.
|
||||
@@ -28,10 +32,14 @@
|
||||
|
||||
\section1 Fix indentation in an open file
|
||||
|
||||
To fix the indentation settings for the file currently open in the editor, select a
|
||||
different setting with \uicontrol {Spaces} > \uicontrol {Document Settings} or
|
||||
\uicontrol {Tabs} > \uicontrol {Document Settings} on the editor toolbar.
|
||||
|
||||
To fix the indentation in the file currently open in the editor:
|
||||
|
||||
\list
|
||||
\li On the editor toolbar, select \uicontrol {Spaces}, and then select
|
||||
\li On the editor toolbar, select \uicontrol {Spaces} or \uicontrol {Tabs}, and then select
|
||||
\uicontrol {Auto-indent Selection} to automatically indent the
|
||||
selected text using the current settings.
|
||||
\li Go to \uicontrol Edit > \uicontrol Advanced, and select an
|
||||
|
@@ -137,7 +137,8 @@
|
||||
|
||||
Many of the error messages are similar to the ones in Douglas Crockford's
|
||||
\l{http://www.jslint.com}{JSLint} tool. For more information about JSLint
|
||||
errors, see \l{http://linterrors.com/js}{JSLint Error Explanations}.
|
||||
errors, see \l{https://github.com/jamesallardice/jslint-error-explanations}
|
||||
{JSLint Error Explanations}.
|
||||
|
||||
\table
|
||||
\header
|
||||
@@ -204,33 +205,30 @@
|
||||
\li M10
|
||||
\li Error
|
||||
\li Duplicate property binding
|
||||
\li See also: \l{http://linterrors.com/js/duplicate-key-a}
|
||||
{Duplicate key '{a}'}.
|
||||
\li For more information, see \e {Duplicate key '{a}'} in
|
||||
\e {JSLint Error Explanations}.
|
||||
|
||||
\row
|
||||
\li M11
|
||||
\li Error
|
||||
\li Id expected
|
||||
\li See also:
|
||||
\l{http://linterrors.com/js/expected-an-identifier-and-instead-saw-a-a-reserved-word}
|
||||
{Expected an identifier and instead saw '{a}' (a reserved word)}.
|
||||
\li For more information, see
|
||||
\e {Expected an identifier and instead saw '{a}' (a reserved word)}
|
||||
in \e {JSLint Error Explanations}.
|
||||
|
||||
\row
|
||||
\li M14
|
||||
\li Error
|
||||
\li Invalid id
|
||||
\li See also:
|
||||
\l{http://linterrors.com/js/expected-an-identifier-and-instead-saw-a-a-reserved-word}
|
||||
{Expected an identifier and instead saw '{a}' (a reserved word)}.
|
||||
|
||||
\li For more information, see
|
||||
\e {Expected an identifier and instead saw '{a}' (a reserved word)}.
|
||||
|
||||
\row
|
||||
\li M15
|
||||
\li Error
|
||||
\li Duplicate id
|
||||
\li Ids in a file must be unique.
|
||||
See also: \l{http://linterrors.com/js/duplicate-key-a}
|
||||
{Duplicate key '{a}'}.
|
||||
For more information, see \e {Duplicate key '{a}'}.
|
||||
|
||||
\row
|
||||
\li M16
|
||||
@@ -270,7 +268,8 @@
|
||||
\li M23
|
||||
\li Warning
|
||||
\li Do not use \c eval
|
||||
\li See also: \l{http://linterrors.com/js/eval-is-evil}{eval is evil}.
|
||||
\li For more information, see \e {eval is evil} in
|
||||
\e {JSLint Error Explanations}.
|
||||
|
||||
\row
|
||||
\li M28
|
||||
@@ -282,8 +281,8 @@
|
||||
\li M29
|
||||
\li Warning
|
||||
\li Do not use \c with
|
||||
\li See also: \l{http://linterrors.com/js/unexpected-with}
|
||||
{Unexpected 'with'}.
|
||||
\li For more information, see \e {Unexpected 'with'} in
|
||||
\e {JSLint Error Explanations}.
|
||||
|
||||
\row
|
||||
\li M30
|
||||
@@ -333,51 +332,48 @@
|
||||
\li M108
|
||||
\li Warning
|
||||
\li Function \c name is used before its declaration
|
||||
\li See also: \l{http://linterrors.com/js/a-was-used-before-it-was-defined}
|
||||
{{a} was used before it was defined}.
|
||||
\li For more information, see \e {{a} was used before it was defined} in
|
||||
\e {JSLint Error Explanations}.
|
||||
|
||||
\row
|
||||
\li M109
|
||||
\li Warning
|
||||
\li Do not use \c Boolean as a constructor
|
||||
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
|
||||
{Do not use {a} as a constructor}.
|
||||
\li For more information, see \e {Do not use {a} as a constructor} in
|
||||
\e {JSLint Error Explanations}.
|
||||
|
||||
\row
|
||||
\li M110
|
||||
\li Warning
|
||||
\li Do not use \c String as a constructor
|
||||
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
|
||||
{Do not use {a} as a constructor}.
|
||||
\li For more information, see \e {Do not use {a} as a constructor}.
|
||||
|
||||
\row
|
||||
\li M111
|
||||
\li Warning
|
||||
\li Do not use \c Object as a constructor
|
||||
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
|
||||
{Do not use {a} as a constructor}.
|
||||
\li For more information, see \e {Do not use {a} as a constructor}.
|
||||
|
||||
\row
|
||||
\li M112
|
||||
\li Warning
|
||||
\li Do not use \c Array as a constructor
|
||||
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
|
||||
{Do not use {a} as a constructor}.
|
||||
\li For more information, see \e {Do not use {a} as a constructor}.
|
||||
|
||||
\row
|
||||
\li M113
|
||||
\li Warning
|
||||
\li Do not use \c Function as a constructor
|
||||
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
|
||||
{Do not use {a} as a constructor}.
|
||||
\li For more information, see \e {Do not use {a} as a constructor}.
|
||||
|
||||
\row
|
||||
\li M114
|
||||
\li Hint
|
||||
\li The \c function keyword and the opening parenthesis should be
|
||||
separated by a single space
|
||||
\li See also: \l{http://linterrors.com/js/expected-exactly-one-space-between-a-and-b}
|
||||
{Expected exactly one space between {a} and {b}}.
|
||||
\li For more information, see
|
||||
\e {Expected exactly one space between {a} and {b}} in
|
||||
\e {JSLint Error Explanations}.
|
||||
|
||||
\row
|
||||
\li M115
|
||||
@@ -397,15 +393,15 @@
|
||||
\li M117
|
||||
\li Warning
|
||||
\li Confusing pluses
|
||||
\li See also: \l{http://linterrors.com/js/confusing-pluses}
|
||||
{Confusing pluses}.
|
||||
\li For more information, see \e {Confusing pluses} in
|
||||
\e {JSLint Error Explanations}.
|
||||
|
||||
\row
|
||||
\li M119
|
||||
\li Warning
|
||||
\li Confusing minuses
|
||||
\li See also: \l{http://linterrors.com/js/confusing-minuses}
|
||||
{Confusing minuses}.
|
||||
\li For more information, see \e {Confusing minuses} in
|
||||
\e {JSLint Error Explanations}.
|
||||
|
||||
\row
|
||||
\li M121
|
||||
@@ -453,9 +449,9 @@
|
||||
\li M201
|
||||
\li Hint
|
||||
\li Place var declarations at the start of a function
|
||||
\li See also:
|
||||
\l{http://linterrors.com/js/move-var-declarations-to-the-top-of-the-function}
|
||||
{Move 'var' declarations to the top of the function}.
|
||||
\li For more information, see
|
||||
\e {Move 'var' declarations to the top of the function} in
|
||||
\e {JSLint Error Explanations}.
|
||||
|
||||
\row
|
||||
\li M202
|
||||
@@ -609,15 +605,14 @@
|
||||
\li M307
|
||||
\li Warning
|
||||
\li Use \c new only with functions that start with an uppercase letter
|
||||
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
|
||||
{Do not use {a} as a constructor}.
|
||||
\li For more information, see \e {Do not use {a} as a constructor} in
|
||||
\e {JSLint Error Explanations}.
|
||||
|
||||
\row
|
||||
\li M308
|
||||
\li Warning
|
||||
\li Do not use \c Number as a constructor
|
||||
\li See also: \l{http://linterrors.com/js/do-not-use-a-as-a-constructor}
|
||||
{Do not use {a} as a constructor}.
|
||||
\li For more information, see \e {Do not use {a} as a constructor}.
|
||||
|
||||
\row
|
||||
\li M309
|
||||
@@ -707,9 +702,9 @@
|
||||
\li M323
|
||||
\li Error
|
||||
\li \c Number elements expected in array value
|
||||
\li See also:
|
||||
\l{http://linterrors.com/js/the-array-literal-notation-is-preferrable}
|
||||
{The array literal notation [] is preferable}.
|
||||
\li For more information, see
|
||||
\e {The array literal notation [] is preferable} in
|
||||
\e {JSLint Error Explanations}.
|
||||
|
||||
\row
|
||||
\li M324
|
||||
|
@@ -42,6 +42,53 @@
|
||||
then select \uicontrol Install.
|
||||
\endlist
|
||||
|
||||
\section1 Enable code syntax highlighting in the inline chat window
|
||||
|
||||
To enable code syntax highlighting in the inline chat window, go to
|
||||
\preferences > \uicontrol {Text Editor} > \uicontrol {Generic Highlighter},
|
||||
and then select \uicontrol {Download Definitions}.
|
||||
\image qtcreator-syntax-highlighter.png {Generic Highlighter preferences}
|
||||
For more information, see \l{Download highlight definitions}.
|
||||
|
||||
\section1 Install and use Ollama
|
||||
|
||||
To use LLMs running locally on your computer with the Qt AI Assistant extension,
|
||||
install Ollama. You can run models available from the Ollama selection as well
|
||||
as custom models added by you to Ollama.
|
||||
|
||||
\section2 Run models on Ollama
|
||||
|
||||
To run models, enter:
|
||||
|
||||
\code
|
||||
ollama run <model-name>
|
||||
\endcode
|
||||
|
||||
For example:
|
||||
|
||||
\code
|
||||
ollama run codellama:7b-code
|
||||
\endcode
|
||||
|
||||
\section2 Supported models from Ollama
|
||||
|
||||
You can use the following models directly from Ollama:
|
||||
|
||||
\list
|
||||
\li \c codellama:7b-code
|
||||
\li \c deepseek-coder-v2:lite
|
||||
\li \c starcoder2:7b
|
||||
\endlist
|
||||
|
||||
\section2 Custom models
|
||||
|
||||
For custom models, follow the specific installation instructions for that mode.
|
||||
You can use the following custom models:
|
||||
|
||||
\list
|
||||
\li \l {https://huggingface.co/QtGroup/CodeLlama-13B-QML}{codellama:13b-code-qml}
|
||||
\endlist
|
||||
|
||||
\section1 Connect to an LLM
|
||||
|
||||
You can connect to the following LLMs:
|
||||
|
@@ -75,7 +75,15 @@
|
||||
*/
|
||||
/*!
|
||||
\externalpage https://doc.qt.io/QtForMCUs/qtul-getting-started-on-nxp.html
|
||||
\title Getting Started on NXP
|
||||
\title Getting started on NXP (BareMetal and FreeRTOS)
|
||||
*/
|
||||
/*!
|
||||
\externalpage https://doc.qt.io/QtForMCUs/qtul-getting-started-on-nxp-linux.html
|
||||
\title Getting started on NXP (Linux)
|
||||
*/
|
||||
/*!
|
||||
\externalpage https://doc.qt.io/QtForMCUs/qtul-getting-started-on-nxp-zephyr.html
|
||||
\title Getting started on NXP (Zephyr)
|
||||
*/
|
||||
/*!
|
||||
\externalpage https://doc.qt.io/QtForMCUs/qtul-getting-started-on-infineon.html
|
||||
|
@@ -11,8 +11,7 @@
|
||||
|
||||
\l{https://marketplace.qt.io/}{Qt Marketplace} has links to \QC plugins that
|
||||
you can download and install either for free or for a price set by their
|
||||
publisher. Browse the available plugins in the \uicontrol Marketplace tab
|
||||
in the \uicontrol Welcome mode.
|
||||
publisher.
|
||||
|
||||
You can also install plugins from other sources, such as
|
||||
\l{https://github.com/}{GitHub}.
|
||||
|
@@ -41,7 +41,12 @@
|
||||
The hardware-specific requirements vary depending on the hardware platform you are developing for.
|
||||
For more information see:
|
||||
\list
|
||||
\li \l{Getting Started on NXP}
|
||||
\li Getting Started on NXP
|
||||
\list
|
||||
\li \l {Getting started on NXP (BareMetal and FreeRTOS)}
|
||||
\li \l {Getting started on NXP (Linux)}
|
||||
\li \l {Getting started on NXP (Zephyr)}
|
||||
\endlist
|
||||
\li \l{Getting Started on STM}
|
||||
\li \l{Getting Started on Renesas}
|
||||
\li \l{Getting Started on Infineon}
|
||||
@@ -57,8 +62,17 @@
|
||||
\li \QC version
|
||||
\li \QMCU SDK version
|
||||
\row
|
||||
\li 12.0.2 or later
|
||||
\li 2.7 or later
|
||||
\li 16.0.0 or later
|
||||
\li 2.10 or later
|
||||
\row
|
||||
\li 15.0.0
|
||||
\li 2.9
|
||||
\row
|
||||
\li 13.0.2
|
||||
\li 2.8
|
||||
\row
|
||||
\li 12.0.2
|
||||
\li 2.7
|
||||
\row
|
||||
\li 11.0.3
|
||||
\li 2.6
|
||||
@@ -91,17 +105,17 @@
|
||||
\li 1.0
|
||||
\endtable
|
||||
|
||||
\sa {Enable and disable plugins}, {MCUs}{How To: Develop for MCUs},
|
||||
{Developing for MCUs}, {\QMCU}
|
||||
\sa {Enable and disable plugins}, {MCUs}{How To: Develop for MCUs}, {\QMCU}
|
||||
*/
|
||||
|
||||
/*!
|
||||
\page creator-how-to-create-mcu-kits.html
|
||||
\page creator-how-to-add-mcu-kits.html
|
||||
\previouspage creator-how-tos.html
|
||||
|
||||
\ingroup creator-how-to-mcu
|
||||
\ingroup creator-how-to-sdks
|
||||
|
||||
\title Connect MCU devices
|
||||
\title Add MCU SDKs
|
||||
|
||||
\note Enable the McuSupport plugin to develop for MCUs.
|
||||
|
||||
@@ -154,13 +168,25 @@
|
||||
\li Select \uicontrol Apply to save the preferences.
|
||||
\endlist
|
||||
|
||||
\section1 Add MCU devices
|
||||
\sa {Enable and disable plugins}, {MCUs}{How To: Develop for MCUs},
|
||||
{Developing for MCUs}
|
||||
*/
|
||||
|
||||
/*!
|
||||
\page creator-how-to-add-mcu-devices.html
|
||||
\previouspage creator-how-tos.html
|
||||
|
||||
\ingroup creator-how-to-mcu
|
||||
|
||||
\title Add MCU devices
|
||||
|
||||
\note Enable the McuSupport plugin to develop for MCUs.
|
||||
|
||||
\QC automatically adds a default MCU device when you select
|
||||
\uicontrol Apply in the \uicontrol MCU tab after configuring the
|
||||
MCU toolchain.
|
||||
\uicontrol Apply in \preferences > \uicontrol SDKs > \uicontrol MCU after
|
||||
adding an SDK.
|
||||
|
||||
\image qtcreator-mcu-device.png {MCU devices}
|
||||
\image qtcreator-mcu-device.webp {MCU devices}
|
||||
|
||||
To add MCU devices, select \preferences > \uicontrol Devices > \uicontrol Add
|
||||
> \uicontrol {MCU Device} > \uicontrol {Start Wizard}:
|
||||
@@ -175,7 +201,6 @@
|
||||
{Developing for MCUs}
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\page creator-how-to-manage-mcu-kits.html
|
||||
\previouspage creator-how-tos.html
|
||||
@@ -189,9 +214,10 @@
|
||||
|
||||
\QC automatically adds kits for all the available MCU targets if you select
|
||||
\uicontrol {Automatically create kits for all available targets on start}
|
||||
in \preferences > \uicontrol SDKs > \uicontrol MCU.
|
||||
in \preferences > \uicontrol SDKs > \uicontrol MCU. This setting is selected
|
||||
by default.
|
||||
|
||||
\image qtcreator-preferences-kits-mcu.webp {MCU kit}
|
||||
\image qtcreator-mcu-new-kit.webp {Automatically create MCU kits}
|
||||
|
||||
\note When you update the \QMCU SDK, \QC asks you whether you want to replace
|
||||
the existing kits or create additional kits. To do this manually for each
|
||||
@@ -206,6 +232,8 @@
|
||||
|
||||
To change or remove individual kits, go to \preferences > \uicontrol Kits.
|
||||
|
||||
\image qtcreator-preferences-kits-mcu.webp {MCU kit}
|
||||
|
||||
The \uicontrol {MCU dependencies} field displays paths to 3rd party
|
||||
software required for MCU development with the current kit.
|
||||
|
||||
|
@@ -4,16 +4,16 @@ import qbs.FileInfo
|
||||
import qbs.Utilities
|
||||
|
||||
Module {
|
||||
property string qtcreator_display_version: '16.0.0-rc1'
|
||||
property string ide_version_major: '15'
|
||||
property string qtcreator_display_version: '16.0.0'
|
||||
property string ide_version_major: '16'
|
||||
property string ide_version_minor: '0'
|
||||
property string ide_version_release: '84'
|
||||
property string ide_version_release: '0'
|
||||
property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.'
|
||||
+ ide_version_release
|
||||
|
||||
property string ide_compat_version_major: '15'
|
||||
property string ide_compat_version_major: '16'
|
||||
property string ide_compat_version_minor: '0'
|
||||
property string ide_compat_version_release: '84'
|
||||
property string ide_compat_version_release: '0'
|
||||
property string qtcreator_compat_version: ide_compat_version_major + '.'
|
||||
+ ide_compat_version_minor + '.' + ide_compat_version_release
|
||||
|
||||
|
@@ -78,6 +78,7 @@ local function setup()
|
||||
end,
|
||||
})
|
||||
require 'tst_texteditor'.setup()
|
||||
require 'tst_markdownbrowser'.setup()
|
||||
end
|
||||
|
||||
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 <QMessageBox>
|
||||
|
||||
using namespace Core;
|
||||
|
||||
namespace %{PluginName}::Internal {
|
||||
|
||||
class %{CN} final : public ExtensionSystem::IPlugin
|
||||
@@ -46,16 +48,15 @@ public:
|
||||
// bool IPlugin::initialize(const QStringList &arguments, QString *errorString)
|
||||
// overload.
|
||||
|
||||
auto action = new QAction(Tr::tr("%{PluginName} Action"), this);
|
||||
Core::Command *cmd = Core::ActionManager::registerAction(
|
||||
action, Constants::ACTION_ID, Core::Context(Core::Constants::C_GLOBAL));
|
||||
cmd->setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Alt+Meta+A")));
|
||||
connect(action, &QAction::triggered, this, &%{CN}::triggerAction);
|
||||
|
||||
Core::ActionContainer *menu = Core::ActionManager::createMenu(Constants::MENU_ID);
|
||||
ActionContainer *menu = ActionManager::createMenu(Constants::MENU_ID);
|
||||
menu->menu()->setTitle(Tr::tr("%{PluginName}"));
|
||||
menu->addAction(cmd);
|
||||
Core::ActionManager::actionContainer(Core::Constants::M_TOOLS)->addMenu(menu);
|
||||
ActionManager::actionContainer(Core::Constants::M_TOOLS)->addMenu(menu);
|
||||
|
||||
ActionBuilder(this, Constants::ACTION_ID)
|
||||
.addToContainer(Constants::MENU_ID)
|
||||
.setText(Tr::tr("%{PluginName} Action"))
|
||||
.setDefaultKeySequence(Tr::tr("Ctrl+Alt+Meta+A"))
|
||||
.addOnTriggered(this, &%{CN}::triggerAction);
|
||||
}
|
||||
|
||||
void extensionsInitialized() final
|
||||
@@ -77,7 +78,7 @@ public:
|
||||
private:
|
||||
void triggerAction()
|
||||
{
|
||||
QMessageBox::information(Core::ICore::mainWindow(),
|
||||
QMessageBox::information(ICore::dialogParent(),
|
||||
Tr::tr("Action Triggered"),
|
||||
Tr::tr("This is an action from %{PluginName}."));
|
||||
}
|
||||
|
@@ -15,8 +15,8 @@ CodeModel_Info_TextMarkColor=Token_Notification_Neutral_Default
|
||||
CodeModel_Warning_TextMarkColor=Token_Notification_Alert_Default
|
||||
ComboBoxTextColor=Token_Text_Muted
|
||||
Debugger_Breakpoint_TextMarkColor=Token_Notification_Danger_Default
|
||||
Debugger_WatchItem_ValueChanged=Token_Notification_Danger_Muted
|
||||
Debugger_WatchItem_ValueInvalid=Token_Background_Subtle
|
||||
Debugger_WatchItem_ValueChanged=Token_Notification_Danger_Default
|
||||
Debugger_WatchItem_ValueInvalid=Token_Text_Muted
|
||||
Debugger_WatchItem_ValueNormal=Token_Text_Default
|
||||
DockWidgetResizeHandleColor=Token_Stroke_Subtle
|
||||
EditorPlaceholderColor=Token_Background_Muted
|
||||
@@ -66,11 +66,10 @@ PaletteAlternateBase=Token_Background_Muted
|
||||
PaletteAlternateBaseDisabled=Token_Background_Subtle
|
||||
PaletteBase=Token_Background_Default
|
||||
PaletteBaseDisabled=Token_Background_Subtle
|
||||
PaletteBrightText=Token_Notification_Danger_Default
|
||||
PaletteBrightText=Token_Text_Default
|
||||
PaletteBrightTextDisabled=Token_Text_Subtle
|
||||
PaletteButton=Token_Background_Default
|
||||
PaletteButtonDisabled=Token_Background_Subtle
|
||||
PaletteButtonDisabled=Token_Background_Default
|
||||
PaletteButtonText=Token_Text_Default
|
||||
PaletteButtonTextDisabled=Token_Text_Subtle
|
||||
PaletteDark=Token_Background_Default
|
||||
@@ -118,7 +117,7 @@ TextColorError=Token_Notification_Danger_Default
|
||||
TextColorLink=Token_Text_Accent
|
||||
TextColorNormal=Token_Text_Default
|
||||
TextEditor_CurrentLine_ScrollBarColor=Token_Foreground_Muted
|
||||
TextEditor_SearchResult_ScrollBarColor=Token_Notification_Alert_Default
|
||||
TextEditor_SearchResult_ScrollBarColor=Token_Notification_Success_Default
|
||||
TextEditor_Selection_ScrollBarColor=Token_Foreground_Subtle
|
||||
Timeline_BackgroundColor1=Token_Background_Default
|
||||
Timeline_BackgroundColor2=Token_Background_Muted
|
||||
|
@@ -337,6 +337,11 @@ TerminalAnsi13=d22dde
|
||||
TerminalAnsi14=69e2e4
|
||||
TerminalAnsi15=e5e5e6
|
||||
|
||||
;Hack for QTCREATORBUG-32572. Use these two colors from "flat/Hybrid (2016)" theme rather than
|
||||
;using color tokens. Revert when Red and Yellow tokens are available.
|
||||
IconsErrorColor=ffdf4f4f
|
||||
IconsWarningColor=ffecbc1c
|
||||
|
||||
[Flags]
|
||||
ComboBoxDrawTextShadow=false
|
||||
DerivePaletteFromTheme=true
|
||||
|
@@ -25,12 +25,12 @@ Primitive-Neon-100=FFDBFDEC
|
||||
Primitive-Neon-200=FFB9F9D9
|
||||
Primitive-Neon-300=FF83F2BA
|
||||
Primitive-Neon-400=FF2CDE85
|
||||
Primitive-Neon-500=FF1EC974
|
||||
Primitive-Neon-600=FF12A75D
|
||||
Primitive-Neon-500=FF27BF73
|
||||
Primitive-Neon-600=FF1F9B5D
|
||||
Primitive-Neon-700=FF12834B
|
||||
Primitive-Neon-800=FF14673E
|
||||
Primitive-Neon-900=FF0D4328
|
||||
Primitive-Neon-1000=FF092C1B
|
||||
Primitive-Neon-900=FF13432B
|
||||
Primitive-Neon-1000=FF133122
|
||||
|
||||
Primitive-Red-100=FFFACED9
|
||||
Primitive-Red-200=FFF0A4B7
|
||||
|
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;
|
||||
private:
|
||||
FullySpecifiedType _type;
|
||||
const Name *_conceptName;
|
||||
const Name *_conceptName = nullptr;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
// See MSFT:19918626
|
||||
// First break the signal pipe - this will trigger conhost to tear itself down
|
||||
if (_HandleIsValid(pPty->hSignal))
|
||||
{
|
||||
CloseHandle(pPty->hSignal);
|
||||
pPty->hSignal = nullptr;
|
||||
}
|
||||
// Then, wait on the conhost process before killing it.
|
||||
// We do this to make sure the conhost finishes flushing any output it
|
||||
// has yet to send before we hard kill it.
|
||||
if (_HandleIsValid(pPty->hConPtyProcess))
|
||||
{
|
||||
TerminateProcess(pPty->hConPtyProcess, 0);
|
||||
CloseHandle(pPty->hConPtyProcess);
|
||||
pPty->hConPtyProcess = nullptr;
|
||||
}
|
||||
// Then take care of the reference handle.
|
||||
// TODO GH#1810: Closing the reference handle late leaves conhost thinking
|
||||
// that we have an outstanding connected client.
|
||||
if (_HandleIsValid(pPty->hPtyReference))
|
||||
{
|
||||
CloseHandle(pPty->hPtyReference);
|
||||
pPty->hPtyReference = nullptr;
|
||||
}
|
||||
if (_HandleIsValid(pPty->hConPtyProcess))
|
||||
{
|
||||
CloseHandle(pPty->hConPtyProcess);
|
||||
pPty->hConPtyProcess = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -338,7 +338,8 @@ expected_str<QFuture<Environment>> Client::start()
|
||||
return;
|
||||
}
|
||||
// Broken package, search for next magic marker
|
||||
qCWarning(clientLog) << "Magic marker was not found";
|
||||
qCWarning(clientLog)
|
||||
<< "Magic marker was not found, buffer content:" << buffer;
|
||||
// If we don't find a magic marker, the rest of the buffer is trash.
|
||||
buffer.clear();
|
||||
} else {
|
||||
@@ -445,8 +446,7 @@ static Utils::expected_str<QFuture<R>> createJob(
|
||||
std::make_exception_ptr(std::system_error(ENOENT, std::generic_category())));
|
||||
promise->finish();
|
||||
} else if (errType == "NormalExit") {
|
||||
promise->setException(
|
||||
std::make_exception_ptr(std::runtime_error(err.toStdString())));
|
||||
promise->setException(std::make_exception_ptr(std::runtime_error("NormalExit")));
|
||||
promise->finish();
|
||||
} else {
|
||||
qCWarning(clientLog) << "Error (" << errType << "):" << err;
|
||||
@@ -857,10 +857,22 @@ Utils::expected_str<QFuture<void>> Client::signalProcess(int pid, Utils::Control
|
||||
bool Client::exit()
|
||||
{
|
||||
try {
|
||||
createVoidJob(d.get(), QCborMap{{"Type", "exit"}}, "exitres")->waitForFinished();
|
||||
createVoidJob(d.get(), QCborMap{{"Type", "exit"}}, "exitres").and_then([](auto future) {
|
||||
future.waitForFinished();
|
||||
return expected_str<void>();
|
||||
});
|
||||
return true;
|
||||
} catch (const std::runtime_error &e) {
|
||||
if (e.what() == std::string("NormalExit"))
|
||||
return true;
|
||||
|
||||
qCWarning(clientLog) << "Client::exit() caught exception:" << e.what();
|
||||
return false;
|
||||
} catch (const std::exception &e) {
|
||||
qCWarning(clientLog) << "Client::exit() caught exception:" << e.what();
|
||||
return false;
|
||||
} catch (...) {
|
||||
qCWarning(clientLog) << "Client::exit() caught exception";
|
||||
qCWarning(clientLog) << "Client::exit() caught unexpected exception";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -124,7 +124,7 @@ func readPacket(decoder *cbor.Decoder) (*command, error) {
|
||||
|
||||
func sendError(out chan<- []byte, cmd command, err error) {
|
||||
errMsg := err.Error()
|
||||
errType := reflect.TypeOf(err).Elem().Name()
|
||||
errType := reflect.TypeOf(err).Name()
|
||||
if e, ok := err.(*os.PathError); ok {
|
||||
errMsg = e.Err.Error()
|
||||
errType = reflect.TypeOf(e.Err).Name()
|
||||
|
@@ -145,6 +145,7 @@ static QHash<Utils::MimeType, QString> mimeTypeLanguageIdMap()
|
||||
{"application/xml", "xml"},
|
||||
{"application/xslt+xml", "xsl"},
|
||||
{"application/x-yaml", "yaml"},
|
||||
{"text/x-swift", "swift"},
|
||||
};
|
||||
for (const QPair<QString, QString> &languageIdForMimeTypeName : languageIdsForMimeTypeNames) {
|
||||
const Utils::MimeType &mimeType = Utils::mimeTypeForName(languageIdForMimeTypeName.first);
|
||||
|
@@ -966,12 +966,6 @@ void TerminalView::keyPressEvent(QKeyEvent *event)
|
||||
verticalScrollBar()->value() - d->m_surface->liveSize().height(),
|
||||
verticalScrollBar()->maximum()));
|
||||
break;
|
||||
case Qt::Key_End:
|
||||
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
|
||||
break;
|
||||
case Qt::Key_Home:
|
||||
verticalScrollBar()->setValue(0);
|
||||
break;
|
||||
default:
|
||||
if (event->key() < Qt::Key_Shift || event->key() > Qt::Key_ScrollLock)
|
||||
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
|
||||
@@ -1015,8 +1009,10 @@ void TerminalView::applySizeChange()
|
||||
void TerminalView::updateScrollBars()
|
||||
{
|
||||
int scrollSize = d->m_surface->fullSize().height() - d->m_surface->liveSize().height();
|
||||
const bool shouldScroll = verticalScrollBar()->value() == verticalScrollBar()->maximum();
|
||||
verticalScrollBar()->setRange(0, scrollSize);
|
||||
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
|
||||
if (shouldScroll)
|
||||
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
|
||||
updateViewport();
|
||||
}
|
||||
|
||||
@@ -1110,6 +1106,11 @@ void TerminalView::focusOutEvent(QFocusEvent *)
|
||||
|
||||
void TerminalView::inputMethodEvent(QInputMethodEvent *event)
|
||||
{
|
||||
// Gnome sends empty events when switching virtual desktops, so ignore those.
|
||||
if (event->commitString().isEmpty() && event->preeditString().isEmpty()
|
||||
&& event->attributes().empty() && d->m_preEditString.isEmpty())
|
||||
return;
|
||||
|
||||
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
|
||||
|
||||
d->m_preEditString = event->preeditString();
|
||||
|
@@ -1479,10 +1479,11 @@ expected_str<QByteArray> UnixDeviceFileAccess::fileContents(const FilePath &file
|
||||
}
|
||||
#ifndef UTILS_STATIC_LIBRARY
|
||||
const FilePath dd = filePath.withNewPath("dd");
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
Process p;
|
||||
p.setCommand({dd, args, OsType::OsTypeLinux});
|
||||
p.runBlocking();
|
||||
p.runBlocking(0s); // Run forever
|
||||
if (p.exitCode() != 0) {
|
||||
return make_unexpected(Tr::tr("Failed reading file \"%1\": %2")
|
||||
.arg(filePath.toUserOutput(), p.readAllStandardError()));
|
||||
|
@@ -356,7 +356,7 @@ void EnvironmentModel::toggleVariable(const QModelIndex &idx)
|
||||
{
|
||||
const QString name = indexToVariable(idx);
|
||||
const auto newIt = d->m_resultNameValueDictionary.find(name);
|
||||
QTC_ASSERT(newIt != d->m_resultNameValueDictionary.begin(), return);
|
||||
QTC_ASSERT(newIt != d->m_resultNameValueDictionary.end(), return);
|
||||
const auto op = newIt.enabled() ? EnvironmentItem::SetDisabled : EnvironmentItem::SetEnabled;
|
||||
const int changesPos = d->findInChanges(name);
|
||||
if (changesPos != -1) {
|
||||
|
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);
|
||||
}
|
||||
|
||||
void Widget::setMinimumHeight(int height)
|
||||
{
|
||||
access(this)->setMinimumHeight(height);
|
||||
}
|
||||
|
||||
void Widget::setSizePolicy(const QSizePolicy &policy)
|
||||
{
|
||||
access(this)->setSizePolicy(policy);
|
||||
@@ -1109,6 +1114,11 @@ MarkdownBrowser::MarkdownBrowser(std::initializer_list<I> ps)
|
||||
apply(this, ps);
|
||||
}
|
||||
|
||||
QString MarkdownBrowser::toMarkdown() const
|
||||
{
|
||||
return access(this)->toMarkdown();
|
||||
}
|
||||
|
||||
void MarkdownBrowser::setMarkdown(const QString &markdown)
|
||||
{
|
||||
access(this)->setMarkdown(markdown);
|
||||
@@ -1119,6 +1129,11 @@ void MarkdownBrowser::setBasePath(const Utils::FilePath &path)
|
||||
access(this)->setBasePath(path);
|
||||
}
|
||||
|
||||
void MarkdownBrowser::setEnableCodeCopyButton(bool enable)
|
||||
{
|
||||
access(this)->setEnableCodeCopyButton(enable);
|
||||
}
|
||||
|
||||
// Special If
|
||||
|
||||
If::If(
|
||||
@@ -1245,11 +1260,6 @@ void LineEdit::setCompleter(QCompleter *completer)
|
||||
access(this)->setSpecialCompleter(completer);
|
||||
}
|
||||
|
||||
void LineEdit::setMinimumHeight(int height)
|
||||
{
|
||||
access(this)->setMinimumHeight(height);
|
||||
}
|
||||
|
||||
void LineEdit::onReturnPressed(QObject *guard, const std::function<void()> &func)
|
||||
{
|
||||
static_cast<LineEditImpl *>(access(this))->acceptReturnKeys = true;
|
||||
|
@@ -266,6 +266,7 @@ public:
|
||||
void setContentsMargins(int left, int top, int right, int bottom);
|
||||
void setCursor(Qt::CursorShape shape);
|
||||
void setMinimumWidth(int);
|
||||
void setMinimumHeight(int height);
|
||||
|
||||
void activateWindow();
|
||||
void close();
|
||||
@@ -357,7 +358,6 @@ public:
|
||||
void setRightSideIconPath(const Utils::FilePath &path);
|
||||
void setPlaceHolderText(const QString &text);
|
||||
void setCompleter(QCompleter *completer);
|
||||
void setMinimumHeight(int height);
|
||||
void onReturnPressed(QObject *guard, const std::function<void()> &);
|
||||
void onRightSideIconClicked(QObject *guard, const std::function<void()> &);
|
||||
};
|
||||
@@ -456,8 +456,10 @@ public:
|
||||
|
||||
MarkdownBrowser(std::initializer_list<I> items);
|
||||
|
||||
QString toMarkdown() const;
|
||||
void setMarkdown(const QString &);
|
||||
void setBasePath(const Utils::FilePath &);
|
||||
void setEnableCodeCopyButton(bool enable);
|
||||
};
|
||||
|
||||
// Special
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include "mimeutils.h"
|
||||
#include "movie.h"
|
||||
#include "networkaccessmanager.h"
|
||||
#include "stringutils.h"
|
||||
#include "stylehelper.h"
|
||||
#include "textutils.h"
|
||||
#include "theme/theme.h"
|
||||
@@ -19,8 +20,11 @@
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QCache>
|
||||
#include <QClipboard>
|
||||
#include <QDesktopServices>
|
||||
#include <QGuiApplication>
|
||||
#include <QPainter>
|
||||
#include <QScrollBar>
|
||||
#include <QTextBlock>
|
||||
#include <QTextBrowser>
|
||||
#include <QTextDocument>
|
||||
@@ -81,9 +85,12 @@ static QStringList defaultCodeFontFamilies()
|
||||
return {"Menlo", "Source Code Pro", "Monospace", "Courier"};
|
||||
}
|
||||
|
||||
static void highlightCodeBlock(QTextDocument *document, QTextBlock &block, const QString &language)
|
||||
static int registerSnippet(QTextDocument *document, const QString &code);
|
||||
|
||||
static void highlightCodeBlock(
|
||||
QTextDocument *document, QTextBlock &block, const QString &language, bool enableCopy)
|
||||
{
|
||||
const int position = block.position();
|
||||
const int startPos = block.position();
|
||||
// Find the end of the code block ...
|
||||
for (block = block.next(); block.isValid(); block = block.next()) {
|
||||
if (!block.blockFormat().hasProperty(QTextFormat::BlockCodeLanguage))
|
||||
@@ -91,43 +98,81 @@ static void highlightCodeBlock(QTextDocument *document, QTextBlock &block, const
|
||||
if (language != block.blockFormat().stringProperty(QTextFormat::BlockCodeLanguage))
|
||||
break;
|
||||
}
|
||||
const int end = (block.isValid() ? block.position() : document->characterCount()) - 1;
|
||||
const int endPos = (block.isValid() ? block.position() : document->characterCount()) - 1;
|
||||
|
||||
// Get the text of the code block and erase it
|
||||
QTextCursor eraseCursor(document);
|
||||
eraseCursor.setPosition(position);
|
||||
eraseCursor.setPosition(end, QTextCursor::KeepAnchor);
|
||||
|
||||
eraseCursor.setPosition(startPos);
|
||||
eraseCursor.setPosition(endPos, QTextCursor::KeepAnchor);
|
||||
const QString code = eraseCursor.selectedText();
|
||||
eraseCursor.removeSelectedText();
|
||||
|
||||
// Create a new Frame and insert the highlighted code ...
|
||||
block = document->findBlock(position);
|
||||
|
||||
// Reposition the main cursor to startPos, to insert new content
|
||||
block = document->findBlock(startPos);
|
||||
QTextCursor cursor(block);
|
||||
QTextFrameFormat format;
|
||||
format.setBorderStyle(QTextFrameFormat::BorderStyle_Solid);
|
||||
format.setBackground(creatorColor(Theme::Token_Background_Muted));
|
||||
format.setPadding(SpacingTokens::ExPaddingGapM);
|
||||
format.setLeftMargin(SpacingTokens::VGapM);
|
||||
format.setRightMargin(SpacingTokens::VGapM);
|
||||
|
||||
QTextFrame *frame = cursor.insertFrame(format);
|
||||
QTextFrameFormat frameFormat;
|
||||
frameFormat.setBorderStyle(QTextFrameFormat::BorderStyle_Solid);
|
||||
frameFormat.setBackground(creatorColor(Theme::Token_Background_Muted));
|
||||
frameFormat.setPadding(SpacingTokens::ExPaddingGapM);
|
||||
frameFormat.setLeftMargin(SpacingTokens::VGapM);
|
||||
frameFormat.setRightMargin(SpacingTokens::VGapM);
|
||||
|
||||
QTextFrame *frame = cursor.insertFrame(frameFormat);
|
||||
QTextCursor frameCursor(frame);
|
||||
|
||||
std::unique_ptr<QTextDocument> codeDocument(highlightText(code, language));
|
||||
bool first = true;
|
||||
if (enableCopy) {
|
||||
QTextBlockFormat linkBlockFmt;
|
||||
linkBlockFmt.setAlignment(Qt::AlignRight);
|
||||
frameCursor.insertBlock(linkBlockFmt);
|
||||
|
||||
for (auto block = codeDocument->begin(); block != codeDocument->end(); block = block.next()) {
|
||||
if (!first)
|
||||
frameCursor.insertBlock();
|
||||
const int snippetId = registerSnippet(document, code);
|
||||
const QString copy_id = QString("copy:%1").arg(snippetId);
|
||||
|
||||
QTextCharFormat charFormat = block.charFormat();
|
||||
charFormat.setFontFamilies(defaultCodeFontFamilies());
|
||||
frameCursor.setCharFormat(charFormat);
|
||||
// Insert copy icon
|
||||
QTextImageFormat imageFormat;
|
||||
imageFormat.setName("qrc:/markdownbrowser/images/code_copy_square.png");
|
||||
imageFormat.setAnchor(true);
|
||||
imageFormat.setAnchorHref(copy_id);
|
||||
imageFormat.setWidth(16);
|
||||
imageFormat.setHeight(16);
|
||||
frameCursor.insertImage(imageFormat);
|
||||
|
||||
first = false;
|
||||
auto formats = block.layout()->formats();
|
||||
frameCursor.insertText(block.text());
|
||||
// Create a clickable anchor for the "Copy" text
|
||||
QTextCharFormat anchorFormat;
|
||||
anchorFormat.setAnchor(true);
|
||||
anchorFormat.setAnchorHref(copy_id);
|
||||
anchorFormat.setForeground(QColor("#888"));
|
||||
anchorFormat.setFontPointSize(10);
|
||||
frameCursor.setCharFormat(anchorFormat);
|
||||
frameCursor.insertText(" Copy");
|
||||
|
||||
// Insert a new left-aligned block to start the first line of code
|
||||
QTextBlockFormat codeBlockFmt;
|
||||
codeBlockFmt.setAlignment(Qt::AlignLeft);
|
||||
frameCursor.insertBlock(codeBlockFmt);
|
||||
}
|
||||
|
||||
std::unique_ptr<QTextDocument> codeDoc(highlightText(code, language));
|
||||
|
||||
// Iterate each line in codeDoc and copy it out
|
||||
bool firstLine = true;
|
||||
for (auto tempBlock = codeDoc->begin(); tempBlock != codeDoc->end();
|
||||
tempBlock = tempBlock.next()) {
|
||||
// For each subsequent line, insert another block
|
||||
if (!firstLine) {
|
||||
QTextBlockFormat codeBlockFmt;
|
||||
codeBlockFmt.setAlignment(Qt::AlignLeft);
|
||||
frameCursor.insertBlock(codeBlockFmt);
|
||||
}
|
||||
firstLine = false;
|
||||
|
||||
QTextCharFormat lineFormat = tempBlock.charFormat();
|
||||
lineFormat.setFontFamilies(defaultCodeFontFamilies());
|
||||
frameCursor.setCharFormat(lineFormat);
|
||||
|
||||
auto formats = tempBlock.layout()->formats();
|
||||
frameCursor.insertText(tempBlock.text());
|
||||
frameCursor.block().layout()->setFormats(formats);
|
||||
}
|
||||
|
||||
@@ -315,11 +360,18 @@ public:
|
||||
|| (url.isRelative() && isBaseHttp);
|
||||
};
|
||||
|
||||
QSet<QUrl> remoteUrls = Utils::filtered(m_urlsToLoad, isRemoteUrl);
|
||||
QSet<QUrl> localUrls = Utils::filtered(m_urlsToLoad, std::not_fn(isRemoteUrl));
|
||||
const auto isLocalUrl = [this, isRemoteUrl](const QUrl &url) {
|
||||
if (url.scheme() == "qrc")
|
||||
return true;
|
||||
|
||||
if (m_basePath.isEmpty())
|
||||
localUrls.clear();
|
||||
if (!m_basePath.isEmpty() && !isRemoteUrl(url))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
QSet<QUrl> remoteUrls = Utils::filtered(m_urlsToLoad, isRemoteUrl);
|
||||
QSet<QUrl> localUrls = Utils::filtered(m_urlsToLoad, isLocalUrl);
|
||||
|
||||
if (!m_loadRemoteImages)
|
||||
remoteUrls.clear();
|
||||
@@ -384,22 +436,36 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
auto onLocalSetup = [localIterator,
|
||||
basePath = m_basePath,
|
||||
maxSize = m_imageHandler.maximumCacheSize()](
|
||||
Async<EntryPointer> &async) {
|
||||
const FilePath path = basePath.resolvePath(localIterator->path());
|
||||
async.setConcurrentCallData(
|
||||
[](QPromise<EntryPointer> &promise, const FilePath &path, qsizetype maxSize) {
|
||||
auto data = path.fileContents();
|
||||
if (!data || promise.isCanceled())
|
||||
return;
|
||||
auto onLocalSetup =
|
||||
[localIterator, basePath = m_basePath, maxSize = m_imageHandler.maximumCacheSize()](
|
||||
Async<EntryPointer> &async) {
|
||||
const QUrl url = *localIterator;
|
||||
async.setConcurrentCallData(
|
||||
[](QPromise<EntryPointer> &promise,
|
||||
const FilePath &basePath,
|
||||
const QUrl &url,
|
||||
qsizetype maxSize) {
|
||||
if (url.scheme() == "qrc") {
|
||||
QFile f(":" + url.path());
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
return;
|
||||
|
||||
promise.addResult(AnimatedImageHandler::makeEntry(*data, maxSize));
|
||||
},
|
||||
path,
|
||||
maxSize);
|
||||
};
|
||||
promise.addResult(
|
||||
AnimatedImageHandler::makeEntry(f.readAll(), maxSize));
|
||||
return;
|
||||
}
|
||||
|
||||
const FilePath path = basePath.resolvePath(url.path());
|
||||
auto data = path.fileContents();
|
||||
if (!data || promise.isCanceled())
|
||||
return;
|
||||
|
||||
promise.addResult(AnimatedImageHandler::makeEntry(*data, maxSize));
|
||||
},
|
||||
basePath,
|
||||
url,
|
||||
maxSize);
|
||||
};
|
||||
|
||||
auto onLocalDone = [localIterator, this](const Async<EntryPointer> &async) {
|
||||
EntryPointer result = async.result();
|
||||
@@ -427,6 +493,21 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
int registerSnippet(const QString &code)
|
||||
{
|
||||
const int id = m_nextSnippetId++;
|
||||
m_snippetMap.insert(id, code);
|
||||
return id;
|
||||
}
|
||||
|
||||
QString snippetById(int id) const { return m_snippetMap.value(id); }
|
||||
|
||||
void clearSnippets()
|
||||
{
|
||||
m_snippetMap.clear();
|
||||
m_nextSnippetId = 0;
|
||||
}
|
||||
|
||||
void scheduleLoad(const QUrl &url)
|
||||
{
|
||||
m_urlsToLoad.insert(url);
|
||||
@@ -449,11 +530,24 @@ private:
|
||||
FilePath m_basePath;
|
||||
std::function<void(QNetworkRequest *)> m_requestHook;
|
||||
QNetworkAccessManager *m_networkAccessManager = NetworkAccessManager::instance();
|
||||
QMap<int, QString> m_snippetMap;
|
||||
int m_nextSnippetId = 0;
|
||||
};
|
||||
|
||||
static int registerSnippet(QTextDocument *document, const QString &code)
|
||||
{
|
||||
auto *animDoc = static_cast<AnimatedDocument *>(document);
|
||||
return animDoc->registerSnippet(code);
|
||||
}
|
||||
|
||||
MarkdownBrowser::MarkdownBrowser(QWidget *parent)
|
||||
: QTextBrowser(parent)
|
||||
, m_enableCodeCopyButton(false)
|
||||
{
|
||||
setOpenLinks(false);
|
||||
|
||||
connect(this, &QTextBrowser::anchorClicked, this, &MarkdownBrowser::handleAnchorClicked);
|
||||
|
||||
setDocument(new AnimatedDocument(this));
|
||||
}
|
||||
|
||||
@@ -480,6 +574,11 @@ void MarkdownBrowser::setMargins(const QMargins &margins)
|
||||
setViewportMargins(margins);
|
||||
}
|
||||
|
||||
void MarkdownBrowser::setEnableCodeCopyButton(bool enable)
|
||||
{
|
||||
m_enableCodeCopyButton = enable;
|
||||
}
|
||||
|
||||
void MarkdownBrowser::setAllowRemoteImages(bool allow)
|
||||
{
|
||||
static_cast<AnimatedDocument *>(document())->setAllowRemoteImages(allow);
|
||||
@@ -500,6 +599,33 @@ void MarkdownBrowser::setMaximumCacheSize(qsizetype maxSize)
|
||||
static_cast<AnimatedDocument *>(document())->setMaximumCacheSize(maxSize);
|
||||
}
|
||||
|
||||
void MarkdownBrowser::handleAnchorClicked(const QUrl &link)
|
||||
{
|
||||
if (link.scheme() != QLatin1String("copy")) {
|
||||
if (link.scheme() == "http" || link.scheme() == "https")
|
||||
QDesktopServices::openUrl(link);
|
||||
|
||||
if (link.hasFragment() && link.path().isEmpty() && link.scheme().isEmpty()) {
|
||||
// local anchor
|
||||
scrollToAnchor(link.fragment(QUrl::FullyEncoded));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
const int snippetId = link.path().toInt(&ok);
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
auto *animDoc = static_cast<AnimatedDocument *>(document());
|
||||
const QString snippet = animDoc->snippetById(snippetId).replace(QChar::ParagraphSeparator, '\n');
|
||||
if (snippet.isEmpty())
|
||||
return;
|
||||
|
||||
Utils::setClipboardAndSelection(snippet);
|
||||
}
|
||||
|
||||
void MarkdownBrowser::setBasePath(const FilePath &filePath)
|
||||
{
|
||||
static_cast<AnimatedDocument *>(document())->setBasePath(filePath);
|
||||
@@ -507,13 +633,26 @@ void MarkdownBrowser::setBasePath(const FilePath &filePath)
|
||||
|
||||
void MarkdownBrowser::setMarkdown(const QString &markdown)
|
||||
{
|
||||
QScrollBar *sb = verticalScrollBar();
|
||||
int oldValue = sb->value();
|
||||
|
||||
auto *animDoc = static_cast<AnimatedDocument *>(document());
|
||||
animDoc->clearSnippets();
|
||||
document()->setMarkdown(markdown);
|
||||
postProcessDocument(true);
|
||||
|
||||
QTimer::singleShot(0, this, [sb, oldValue] { sb->setValue(oldValue); });
|
||||
|
||||
// Reset cursor to start of the document, so that "show" does not
|
||||
// scroll to the end of the document.
|
||||
setTextCursor(QTextCursor(document()));
|
||||
}
|
||||
|
||||
QString MarkdownBrowser::toMarkdown() const
|
||||
{
|
||||
return document()->toMarkdown();
|
||||
}
|
||||
|
||||
void MarkdownBrowser::postProcessDocument(bool firstTime) const
|
||||
{
|
||||
const QFont contentFont = Utils::font(contentTF);
|
||||
@@ -534,7 +673,7 @@ void MarkdownBrowser::postProcessDocument(bool firstTime) const
|
||||
// Convert code blocks to highlighted frames
|
||||
if (blockFormat.hasProperty(QTextFormat::BlockCodeLanguage)) {
|
||||
const QString language = blockFormat.stringProperty(QTextFormat::BlockCodeLanguage);
|
||||
highlightCodeBlock(document(), block, language);
|
||||
highlightCodeBlock(document(), block, language, m_enableCodeCopyButton);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@@ -25,6 +25,7 @@ public:
|
||||
MarkdownBrowser(QWidget *parent = nullptr);
|
||||
|
||||
void setMarkdown(const QString &markdown);
|
||||
QString toMarkdown() const;
|
||||
void setBasePath(const FilePath &filePath);
|
||||
void setAllowRemoteImages(bool allow);
|
||||
void setNetworkAccessManager(QNetworkAccessManager *nam);
|
||||
@@ -35,12 +36,17 @@ public:
|
||||
QSize minimumSizeHint() const override;
|
||||
|
||||
void setMargins(const QMargins &margins);
|
||||
void setEnableCodeCopyButton(bool enable);
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *event) override;
|
||||
|
||||
private:
|
||||
void handleAnchorClicked(const QUrl &link);
|
||||
void postProcessDocument(bool firstTime) const;
|
||||
|
||||
private:
|
||||
bool m_enableCodeCopyButton;
|
||||
};
|
||||
|
||||
} // namespace Utils
|
||||
|
@@ -115,6 +115,10 @@ bool NameValueItemsWidget::editVariable(const QString &name, Selection selection
|
||||
}
|
||||
};
|
||||
skipWhiteSpace();
|
||||
if (offset < line.length() && line.at(offset) == '#') {
|
||||
++offset;
|
||||
skipWhiteSpace();
|
||||
}
|
||||
if (line.mid(offset, name.size()) != name)
|
||||
continue;
|
||||
offset += name.size();
|
||||
|
@@ -295,4 +295,8 @@
|
||||
<file>images/classrelationbackground.png</file>
|
||||
<file>images/classrelationbackground@2x.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/markdownbrowser">
|
||||
<file>images/code_copy_square.png</file>
|
||||
<file>images/code_copy_square@2x.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -7,6 +7,8 @@ QtcPlugin {
|
||||
|
||||
condition: Qt.charts.present
|
||||
|
||||
pluginjson.replacements: ({APPSTATISTICSMONITOR_DISABLEDBYDEFAULT: "true"})
|
||||
|
||||
files: [
|
||||
"appstatisticsmonitorplugin.cpp",
|
||||
"appstatisticsmonitortr.h",
|
||||
|
@@ -48,7 +48,8 @@ static QPoint globalPosOnScreen(const QPoint &orig, const QSize &size)
|
||||
qscreen = QGuiApplication::primaryScreen();
|
||||
const QRect screen = qscreen->availableGeometry();
|
||||
|
||||
return QPoint(std::max(screen.x(), orig.x() - size.width()), orig.y() - size.height());
|
||||
return QPoint(std::max(screen.x(), orig.x() - size.width()),
|
||||
std::max(screen.y(), orig.y() - size.height()));
|
||||
}
|
||||
|
||||
class FilterPopupWidget : public QFrame
|
||||
|
@@ -124,6 +124,7 @@ public:
|
||||
rp.setUseContinueInsteadOfRun(true);
|
||||
rp.setContinueAfterAttach(true);
|
||||
rp.addSolibSearchDir("%{sysroot}/system/lib");
|
||||
rp.setSkipDebugServer(true);
|
||||
|
||||
auto debuggee = createQdbDeviceInferiorWorker(runControl, QmlDebuggerServices);
|
||||
worker->addStartDependency(debuggee);
|
||||
|
@@ -2007,12 +2007,14 @@ void CMakeBuildConfiguration::setBuildPresetToBuildSteps(const ProjectExplorer::
|
||||
cbs->setToolArguments(nativeToolOptions.split(" "));
|
||||
}
|
||||
|
||||
if (buildPresets[i].configuration)
|
||||
if (buildPresets[i].configuration) {
|
||||
cbs->setConfiguration(*buildPresets[i].configuration);
|
||||
|
||||
// Leave only the first build step enabled
|
||||
if (i > 0)
|
||||
cbs->setStepEnabled(false);
|
||||
cbs->setStepEnabled(buildTypeAspect() == buildPresets[i].configuration);
|
||||
} else {
|
||||
// Leave only the first build step enabled
|
||||
if (i > 0)
|
||||
cbs->setStepEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -40,9 +40,9 @@ FileApiReader::FileApiReader()
|
||||
: m_lastReplyTimestamp()
|
||||
{
|
||||
QObject::connect(&m_watcher,
|
||||
&FileSystemWatcher::directoryChanged,
|
||||
&FileSystemWatcher::fileChanged,
|
||||
this,
|
||||
&FileApiReader::handleReplyDirectoryChange);
|
||||
&FileApiReader::handleReplyIndexFileChange);
|
||||
}
|
||||
|
||||
FileApiReader::~FileApiReader()
|
||||
@@ -60,11 +60,7 @@ void FileApiReader::setParameters(const BuildDirParameters &p)
|
||||
m_parameters = p;
|
||||
qCDebug(cmakeFileApiMode) << "Work directory:" << m_parameters.buildDirectory.toUserOutput();
|
||||
|
||||
FileApiParser::setupCMakeFileApi(m_parameters.buildDirectory);
|
||||
|
||||
const FilePath replyDirectory = FileApiParser::cmakeReplyDirectory(m_parameters.buildDirectory);
|
||||
if (!m_watcher.watchesDirectory(replyDirectory))
|
||||
m_watcher.addDirectory(replyDirectory.path(), FileSystemWatcher::WatchAllChanges);
|
||||
setupCMakeFileApi();
|
||||
|
||||
resetData();
|
||||
}
|
||||
@@ -351,6 +347,15 @@ void FileApiReader::writeConfigurationIntoBuildDirectory(const QStringList &conf
|
||||
QTC_ASSERT_EXPECTED(settingsFile.writeFileContents(contents), return);
|
||||
}
|
||||
|
||||
void FileApiReader::setupCMakeFileApi()
|
||||
{
|
||||
FileApiParser::setupCMakeFileApi(m_parameters.buildDirectory);
|
||||
|
||||
const FilePath replyIndexfile = FileApiParser::scanForCMakeReplyFile(m_parameters.buildDirectory);
|
||||
if (!replyIndexfile.isEmpty() && !m_watcher.watchesFile(replyIndexfile))
|
||||
m_watcher.addFile(replyIndexfile.path(), FileSystemWatcher::WatchAllChanges);
|
||||
}
|
||||
|
||||
QString FileApiReader::cmakeGenerator() const
|
||||
{
|
||||
return m_cmakeGenerator;
|
||||
@@ -403,16 +408,13 @@ void FileApiReader::cmakeFinishedState(int exitCode)
|
||||
if (m_lastCMakeExitCode != 0)
|
||||
makeBackupConfiguration(false);
|
||||
|
||||
FileApiParser::setupCMakeFileApi(m_parameters.buildDirectory);
|
||||
|
||||
m_watcher.addDirectory(FileApiParser::cmakeReplyDirectory(m_parameters.buildDirectory).path(),
|
||||
FileSystemWatcher::WatchAllChanges);
|
||||
setupCMakeFileApi();
|
||||
|
||||
endState(FileApiParser::scanForCMakeReplyFile(m_parameters.buildDirectory),
|
||||
m_lastCMakeExitCode != 0);
|
||||
}
|
||||
|
||||
void FileApiReader::handleReplyDirectoryChange(const QString &directory)
|
||||
void FileApiReader::handleReplyIndexFileChange(const QString &indexFile)
|
||||
{
|
||||
if (m_isParsing)
|
||||
return; // This has been triggered by ourselves, ignore.
|
||||
@@ -422,7 +424,7 @@ void FileApiReader::handleReplyDirectoryChange(const QString &directory)
|
||||
if (dir.isEmpty())
|
||||
return; // CMake started to fill the result dir, but has not written a result file yet
|
||||
QTC_CHECK(dir.isLocal());
|
||||
QTC_ASSERT(dir.path() == directory, return);
|
||||
QTC_ASSERT(dir == FilePath::fromString(indexFile).parentDir(), return);
|
||||
|
||||
if (m_lastReplyTimestamp.isValid() && reply.lastModified() > m_lastReplyTimestamp) {
|
||||
m_lastReplyTimestamp = reply.lastModified();
|
||||
|
@@ -78,10 +78,11 @@ private:
|
||||
void startCMakeState(const QStringList &configurationArguments);
|
||||
void cmakeFinishedState(int exitCode);
|
||||
|
||||
void handleReplyDirectoryChange(const QString &directory);
|
||||
void handleReplyIndexFileChange(const QString &indexFile);
|
||||
void makeBackupConfiguration(bool store);
|
||||
|
||||
void writeConfigurationIntoBuildDirectory(const QStringList &configuration);
|
||||
void setupCMakeFileApi();
|
||||
|
||||
std::unique_ptr<CMakeProcess> m_cmakeProcess;
|
||||
|
||||
|
@@ -42,7 +42,7 @@ namespace Copilot::Internal {
|
||||
static LanguageClient::BaseClientInterface *clientInterface(const FilePath &nodePath,
|
||||
const FilePath &distPath)
|
||||
{
|
||||
CommandLine cmd{nodePath, {distPath.toFSPathString()}};
|
||||
CommandLine cmd{nodePath, {distPath.toFSPathString(), "--stdio"}};
|
||||
|
||||
const auto interface = new LanguageClient::StdIOClientInterface;
|
||||
interface->setCommandLine(cmd);
|
||||
|
@@ -1618,7 +1618,8 @@ bool EditorManagerPrivate::closeEditors(const QList<IEditor*> &editors, CloseFla
|
||||
emit m_instance->editorAboutToClose(editor);
|
||||
const DocumentModel::Entry *entry = DocumentModel::entryForDocument(editor->document());
|
||||
// If the file is pinned, closing it should remove the editor but keep it in Open Documents.
|
||||
const bool removeSuspendedEntry = !entry->pinned && flag != CloseFlag::Suspend;
|
||||
const bool isPinned = QTC_GUARD(entry) && entry->pinned;
|
||||
const bool removeSuspendedEntry = !isPinned && flag != CloseFlag::Suspend;
|
||||
removeEditor(editor, removeSuspendedEntry);
|
||||
if (EditorView *view = viewForEditor(editor)) {
|
||||
editorsPerView.insert(view, editor);
|
||||
|
@@ -681,7 +681,10 @@ void OutputWindow::registerPositionOf(unsigned taskId, int linkedOutputLines, in
|
||||
return;
|
||||
|
||||
const int blocknumber = document()->blockCount() - offset;
|
||||
const int firstLine = blocknumber - linkedOutputLines - skipLines;
|
||||
|
||||
// -1 because OutputFormatter has already added the newline.
|
||||
const int firstLine = blocknumber - linkedOutputLines - skipLines - 1;
|
||||
|
||||
const int lastLine = firstLine + linkedOutputLines - 1;
|
||||
|
||||
d->taskPositions.insert(taskId, {firstLine, lastLine});
|
||||
|
@@ -413,6 +413,12 @@ static QString determineSessionToRestoreAtStartup()
|
||||
return {};
|
||||
}
|
||||
|
||||
bool SessionManager::loadsSessionOrFileAtStartup()
|
||||
{
|
||||
// "left-over arguments" usually mean a session or files
|
||||
return !PluginManager::arguments().isEmpty() || !determineSessionToRestoreAtStartup().isEmpty();
|
||||
}
|
||||
|
||||
void SessionManagerPrivate::restoreStartupSession()
|
||||
{
|
||||
NANOTRACE_SCOPE("Core", "SessionManagerPrivate::restoreStartupSession");
|
||||
|
@@ -28,6 +28,8 @@ public:
|
||||
|
||||
static SessionManager *instance();
|
||||
|
||||
static bool loadsSessionOrFileAtStartup();
|
||||
|
||||
// higher level session management
|
||||
static QString activeSession();
|
||||
static QString lastSession();
|
||||
|
@@ -29,7 +29,8 @@ public:
|
||||
QDir::toNativeSeparators("../Src"),
|
||||
".."};
|
||||
Utils::FilePath licenseTemplatePath;
|
||||
QString headerGuardTemplate = "%{JS: '%{Header:FileName}'.toUpperCase().replace(/[.]/g, '_')}";
|
||||
QString headerGuardTemplate
|
||||
= "%{JS: '%{Header:FileName}'.toUpperCase().replace(/^[1-9]/, '_').replace(/[^_a-zA-Z1-9]/g, '_')}";
|
||||
bool headerPragmaOnce = false;
|
||||
bool lowerCaseFiles = Constants::LOWERCASE_CPPFILES_DEFAULT;
|
||||
|
||||
|
@@ -25,9 +25,12 @@
|
||||
|
||||
#include <texteditor/codeassist/iassistproposal.h>
|
||||
#include <texteditor/codeassist/iassistproposalmodel.h>
|
||||
#include <texteditor/icodestylepreferences.h>
|
||||
#include <texteditor/storagesettings.h>
|
||||
#include <texteditor/syntaxhighlighter.h>
|
||||
#include <texteditor/tabsettings.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <texteditor/texteditorsettings.h>
|
||||
|
||||
#include <utils/environment.h>
|
||||
#include <utils/fileutils.h>
|
||||
@@ -232,6 +235,9 @@ bool TestCase::openCppEditor(const FilePath &filePath, TextEditor::BaseTextEdito
|
||||
TextEditor::StorageSettings s = e->textDocument()->storageSettings();
|
||||
s.m_addFinalNewLine = false;
|
||||
e->textDocument()->setStorageSettings(s);
|
||||
TextEditor::TabSettings ts = TextEditor::TextEditorSettings::codeStyle()->tabSettings();
|
||||
ts.m_autoDetect = false;
|
||||
e->textDocument()->setTabSettings(ts);
|
||||
}
|
||||
|
||||
if (!QTest::qWaitFor(
|
||||
|
@@ -1019,7 +1019,7 @@ static QString trimmedFileName(const FilePath &fullPath)
|
||||
const Project *project = ProjectTree::currentProject();
|
||||
const FilePath projectDirectory = project ? project->projectDirectory() : FilePath();
|
||||
if (projectDirectory.exists())
|
||||
return FilePath::calcRelativePath(fullPath.path(), projectDirectory.toUserOutput());
|
||||
return fullPath.relativePathFrom(projectDirectory).toUserOutput();
|
||||
|
||||
return fullPath.toUserOutput();
|
||||
}
|
||||
|
@@ -268,6 +268,9 @@ public:
|
||||
void setServerEssential(bool on) { m_serverEssential = on; }
|
||||
bool serverEssential() const { return m_serverEssential; }
|
||||
|
||||
void setSkipDebugServer(bool on) { m_skipDebugServer = on; }
|
||||
bool skipDebugServer() const { return m_skipDebugServer; }
|
||||
|
||||
void setAddQmlServerInferiorCmdArgIfNeeded(bool on) { m_addQmlServerInferiorCmdArgIfNeeded = on; }
|
||||
bool isAddQmlServerInferiorCmdArgIfNeeded() const { return m_addQmlServerInferiorCmdArgIfNeeded; }
|
||||
|
||||
@@ -367,6 +370,7 @@ private:
|
||||
Utils::ProcessHandle m_serverAttachPid;
|
||||
bool m_serverUseMulti = true;
|
||||
bool m_serverEssential = true;
|
||||
bool m_skipDebugServer = false;
|
||||
bool m_addQmlServerInferiorCmdArgIfNeeded = false;
|
||||
};
|
||||
|
||||
|
@@ -16,7 +16,7 @@ const Icon BREAKPOINT_PENDING({
|
||||
{":/debugger/images/breakpoint_pending_overlay.png", Theme::PanelTextColorDark}}, Icon::IconStyleOptions(Icon::Tint | Icon::PunchEdges));
|
||||
const Icon BREAKPOINT_WITH_LOCATION({
|
||||
{":/utils/images/filledcircle.png", Theme::IconsErrorColor},
|
||||
{":/debugger/images/location.png", Theme::IconsWarningToolBarColor}}, Icon::Tint);
|
||||
{":/debugger/images/location.png", Theme::IconsWarningColor}}, Icon::Tint);
|
||||
const Icon BREAKPOINTS(
|
||||
":/debugger/images/debugger_breakpoints.png");
|
||||
const Icon WATCHPOINT({
|
||||
@@ -65,10 +65,10 @@ const Icon DEBUG_EXIT_SMALL_TOOLBAR({
|
||||
{":/utils/images/debugger_overlay_small.png", Theme::IconsDebugColor}});
|
||||
const Icon LOCATION({
|
||||
{":/debugger/images/location_background.png", Theme::IconsCodeModelOverlayForegroundColor},
|
||||
{":/debugger/images/location.png", Theme::IconsWarningToolBarColor}}, Icon::Tint);
|
||||
{":/debugger/images/location.png", Theme::IconsWarningColor}}, Icon::Tint);
|
||||
const Icon REVERSE_LOCATION({
|
||||
{":/debugger/images/debugger_reversemode_background.png", Theme::IconsCodeModelOverlayForegroundColor},
|
||||
{":/debugger/images/debugger_reversemode.png", Theme::IconsWarningToolBarColor}}, Icon::Tint);
|
||||
{":/debugger/images/debugger_reversemode.png", Theme::IconsWarningColor}}, Icon::Tint);
|
||||
const Icon REVERSE_MODE({
|
||||
{":/debugger/images/debugger_reversemode_background.png", Theme::IconsCodeModelOverlayForegroundColor},
|
||||
{":/debugger/images/debugger_reversemode.png", Theme::IconsInfoColor}}, Icon::Tint);
|
||||
|
@@ -562,7 +562,7 @@ void DebuggerRunTool::showMessage(const QString &msg, int channel, int timeout)
|
||||
|
||||
void DebuggerRunTool::startDebugServerIfNeededAndContinueStartup()
|
||||
{
|
||||
if (!runControl()->usesDebugChannel()) {
|
||||
if (!runControl()->usesDebugChannel() || m_runParameters.skipDebugServer()) {
|
||||
continueAfterDebugServerStart();
|
||||
return;
|
||||
}
|
||||
@@ -680,9 +680,9 @@ void DebuggerRunTool::startDebugServerIfNeededAndContinueStartup()
|
||||
});
|
||||
|
||||
connect(&d->debuggerServerProc, &Process::done, this, [this] {
|
||||
if (d->terminalProc.error() != QProcess::UnknownError)
|
||||
reportFailure(d->terminalProc.errorString());
|
||||
if (d->terminalProc.error() != QProcess::FailedToStart && m_runParameters.serverEssential())
|
||||
if (d->debuggerServerProc.error() != QProcess::UnknownError)
|
||||
reportFailure(d->debuggerServerProc.errorString());
|
||||
if (d->debuggerServerProc.error() != QProcess::FailedToStart && m_runParameters.serverEssential())
|
||||
reportDone();
|
||||
});
|
||||
|
||||
|
@@ -1511,7 +1511,9 @@ void GdbEngine::handlePythonSetup(const DebuggerResponse &response)
|
||||
GdbMi data = response.data;
|
||||
watchHandler()->addDumpers(data["dumpers"]);
|
||||
m_pythonVersion = data["python"].toInt();
|
||||
if (m_pythonVersion < 30700) {
|
||||
// Python 3.5.x: Released 2016-06-27, supported until 2018-12-24, security until 2021-12-23,
|
||||
// used in Ubuntu 16.04 and Qt 5.15.10 Boot2Qt BSPs.
|
||||
if (m_pythonVersion < 30502) {
|
||||
int pythonMajor = m_pythonVersion / 10000;
|
||||
int pythonMinor = (m_pythonVersion / 100) % 100;
|
||||
QString out = "<p>"
|
||||
|
@@ -296,13 +296,18 @@ void ModulesHandler::updateModule(const Module &module)
|
||||
m_model->rootItem()->appendChild(item);
|
||||
}
|
||||
|
||||
try { // MinGW occasionallly throws std::bad_alloc.
|
||||
ElfReader reader(path);
|
||||
item->module.elfData = reader.readHeaders();
|
||||
item->update();
|
||||
} catch(...) {
|
||||
qWarning("%s: An exception occurred while reading module '%s'",
|
||||
Q_FUNC_INFO, qPrintable(module.modulePath.toUserOutput()));
|
||||
if (path.isLocal()) {
|
||||
try { // MinGW occasionallly throws std::bad_alloc.
|
||||
ElfReader reader(path);
|
||||
item->module.elfData = reader.readHeaders();
|
||||
item->update();
|
||||
} catch(...) {
|
||||
qWarning("%s: An exception occurred while reading module '%s'",
|
||||
Q_FUNC_INFO, qPrintable(module.modulePath.toUserOutput()));
|
||||
}
|
||||
} else {
|
||||
m_model->engine->showMessage(
|
||||
QString("Skipping elf-reading of remote path %1").arg(path.toUserOutput()));
|
||||
}
|
||||
item->updated = true;
|
||||
}
|
||||
|
@@ -16,5 +16,4 @@ add_qtc_plugin(DiffEditor
|
||||
selectabletexteditorwidget.cpp selectabletexteditorwidget.h
|
||||
sidebysidediffeditorwidget.cpp sidebysidediffeditorwidget.h
|
||||
unifieddiffeditorwidget.cpp unifieddiffeditorwidget.h
|
||||
EXPLICIT_MOC diffeditor.h
|
||||
)
|
||||
|
@@ -6,6 +6,8 @@ add_qtc_plugin(Docker
|
||||
dockertr.h
|
||||
dockerapi.cpp dockerapi.h
|
||||
dockerconstants.h
|
||||
dockercontainerthread.cpp
|
||||
dockercontainerthread.h
|
||||
dockerdevice.cpp dockerdevice.h
|
||||
dockerdevicewidget.cpp dockerdevicewidget.h
|
||||
dockerplugin.cpp
|
||||
|
@@ -16,6 +16,8 @@ QtcPlugin {
|
||||
"dockerapi.cpp",
|
||||
"dockerapi.h",
|
||||
"dockerconstants.h",
|
||||
"dockercontainerthread.cpp",
|
||||
"dockercontainerthread.h",
|
||||
"dockerdevice.cpp",
|
||||
"dockerdevice.h",
|
||||
"dockerdevicewidget.cpp",
|
||||
|
@@ -38,22 +38,19 @@ bool DockerApi::canConnect()
|
||||
{
|
||||
Process process;
|
||||
FilePath dockerExe = dockerClient();
|
||||
if (dockerExe.isEmpty() || !dockerExe.isExecutableFile())
|
||||
if (dockerExe.isEmpty())
|
||||
return false;
|
||||
|
||||
bool result = false;
|
||||
|
||||
process.setCommand({dockerExe, {"info"}});
|
||||
connect(&process, &Process::done, [&process, &result] {
|
||||
process.runBlocking();
|
||||
|
||||
const bool success = process.result() == ProcessResult::FinishedWithSuccess;
|
||||
if (!success)
|
||||
qCWarning(dockerApiLog) << "Failed to connect to docker daemon:" << process.allOutput();
|
||||
else
|
||||
qCInfo(dockerApiLog) << "'docker info' result:\n" << qPrintable(process.allOutput());
|
||||
if (process.result() == ProcessResult::FinishedWithSuccess)
|
||||
result = true;
|
||||
});
|
||||
|
||||
process.start();
|
||||
process.waitForFinished();
|
||||
|
||||
return result;
|
||||
return process.result() == ProcessResult::FinishedWithSuccess;
|
||||
}
|
||||
|
||||
bool DockerApi::isContainerRunning(const QString &containerId)
|
||||
|
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 "dockerconstants.h"
|
||||
#include "dockercontainerthread.h"
|
||||
#include "dockerdevicewidget.h"
|
||||
#include "dockersettings.h"
|
||||
#include "dockertr.h"
|
||||
@@ -170,25 +171,19 @@ public:
|
||||
DockerDevicePrivate(DockerDevice *parent)
|
||||
: q(parent)
|
||||
{
|
||||
QObject::connect(q, &DockerDevice::applied, this, [this] {
|
||||
if (!m_container.isEmpty()) {
|
||||
stopCurrentContainer();
|
||||
}
|
||||
});
|
||||
QObject::connect(q, &DockerDevice::applied, this, [this] { stopCurrentContainer(); });
|
||||
}
|
||||
|
||||
~DockerDevicePrivate() { stopCurrentContainer(); }
|
||||
|
||||
CommandLine createCommandLine();
|
||||
|
||||
expected_str<void> updateContainerAccess();
|
||||
expected_str<QString> updateContainerAccess();
|
||||
void changeMounts(QStringList newMounts);
|
||||
bool ensureReachable(const FilePath &other);
|
||||
void shutdown();
|
||||
expected_str<FilePath> localSource(const FilePath &other) const;
|
||||
|
||||
QString containerId() { return m_container; }
|
||||
|
||||
expected_str<QPair<Utils::OsType, Utils::OsArch>> osTypeAndArch() const;
|
||||
|
||||
expected_str<Environment> environment();
|
||||
@@ -204,10 +199,8 @@ public:
|
||||
bool prepareForBuild(const Target *target);
|
||||
Tasks validateMounts() const;
|
||||
|
||||
expected_str<QString> createContainer();
|
||||
expected_str<void> startContainer();
|
||||
void stopCurrentContainer();
|
||||
expected_str<void> fetchSystemEnviroment();
|
||||
Result fetchSystemEnviroment();
|
||||
|
||||
expected_str<FilePath> getCmdBridgePath() const;
|
||||
|
||||
@@ -277,13 +270,10 @@ public:
|
||||
FilePath containerPath;
|
||||
};
|
||||
|
||||
QString m_container;
|
||||
|
||||
std::unique_ptr<Process> m_startProcess;
|
||||
|
||||
std::optional<Environment> m_cachedEnviroment;
|
||||
bool m_isShutdown = false;
|
||||
SynchronizedValue<std::unique_ptr<DeviceFileAccess>> m_fileAccess;
|
||||
SynchronizedValue<std::unique_ptr<DockerContainerThread>> m_deviceThread;
|
||||
};
|
||||
|
||||
class DockerProcessImpl : public ProcessInterface
|
||||
@@ -299,9 +289,7 @@ private:
|
||||
|
||||
private:
|
||||
DockerDevicePrivate *m_devicePrivate = nullptr;
|
||||
// Store the IDevice::ConstPtr in order to extend the lifetime of device for as long
|
||||
// as this object is alive.
|
||||
IDevice::ConstPtr m_device;
|
||||
std::weak_ptr<const IDevice> m_device;
|
||||
|
||||
Process m_process;
|
||||
qint64 m_remotePID = 0;
|
||||
@@ -312,7 +300,7 @@ private:
|
||||
|
||||
DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePrivate *devicePrivate)
|
||||
: m_devicePrivate(devicePrivate)
|
||||
, m_device(std::move(device))
|
||||
, m_device(device)
|
||||
, m_process(this)
|
||||
{
|
||||
connect(&m_process, &Process::started, this, [this] {
|
||||
@@ -378,7 +366,6 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva
|
||||
|
||||
if (rest.size() > 0 || stdErr.size() > 0)
|
||||
emit readyRead(rest, stdErr);
|
||||
|
||||
});
|
||||
|
||||
connect(&m_process, &Process::readyReadStandardError, this, [this] {
|
||||
@@ -412,6 +399,15 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva
|
||||
|
||||
emit done(resultData);
|
||||
});
|
||||
|
||||
connect(device.get(), &QObject::destroyed, this, [this] {
|
||||
emit done(ProcessResultData{
|
||||
-1,
|
||||
QProcess::ExitStatus::CrashExit,
|
||||
QProcess::ProcessError::UnknownError,
|
||||
Tr::tr("Device is shut down"),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
DockerProcessImpl::~DockerProcessImpl()
|
||||
@@ -482,15 +478,19 @@ void DockerProcessImpl::sendControlSignal(ControlSignal controlSignal)
|
||||
m_process.closeWriteChannel();
|
||||
return;
|
||||
}
|
||||
auto dfa = dynamic_cast<DockerDeviceFileAccess *>(m_device->fileAccess());
|
||||
auto device = m_device.lock();
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
auto dfa = dynamic_cast<DockerDeviceFileAccess *>(device->fileAccess());
|
||||
if (dfa) {
|
||||
static_cast<DockerDeviceFileAccess *>(m_device->fileAccess())
|
||||
static_cast<DockerDeviceFileAccess *>(device->fileAccess())
|
||||
->signalProcess(m_remotePID, controlSignal);
|
||||
} else {
|
||||
const int signal = controlSignalToInt(controlSignal);
|
||||
Process p;
|
||||
p.setCommand(
|
||||
{m_device->rootPath().withNewPath("kill"),
|
||||
{device->rootPath().withNewPath("kill"),
|
||||
{QString("-%1").arg(signal), QString("%2").arg(m_remotePID)}});
|
||||
p.runBlocking();
|
||||
}
|
||||
@@ -602,7 +602,6 @@ DockerDevice::DockerDevice()
|
||||
auto future = DockerApi::instance()->networks();
|
||||
|
||||
auto watcher = new QFutureWatcher<expected_str<QList<Network>>>(this);
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher,
|
||||
&QFutureWatcher<expected_str<QList<Network>>>::finished,
|
||||
this,
|
||||
@@ -622,6 +621,7 @@ DockerDevice::DockerDevice()
|
||||
cb({errorItem});
|
||||
}
|
||||
});
|
||||
watcher->setFuture(future);
|
||||
});
|
||||
|
||||
connect(DockerApi::instance(),
|
||||
@@ -671,13 +671,10 @@ DockerDevice::DockerDevice()
|
||||
const FilePath &workingDir) -> expected_str<void> {
|
||||
Q_UNUSED(env); // TODO: That's the runnable's environment in general. Use it via -e below.
|
||||
|
||||
expected_str<void> result = d->updateContainerAccess();
|
||||
expected_str<QString> result = d->updateContainerAccess();
|
||||
|
||||
if (!result)
|
||||
return result;
|
||||
|
||||
if (d->containerId().isEmpty())
|
||||
return make_unexpected(Tr::tr("Error starting remote shell. No container."));
|
||||
return make_unexpected(result.error());
|
||||
|
||||
expected_str<FilePath> shell = Terminal::defaultShellForDevice(rootPath());
|
||||
if (!shell)
|
||||
@@ -716,9 +713,10 @@ void DockerDevice::shutdown()
|
||||
d->shutdown();
|
||||
}
|
||||
|
||||
expected_str<void> DockerDevice::updateContainerAccess() const
|
||||
Result DockerDevice::updateContainerAccess() const
|
||||
{
|
||||
return d->updateContainerAccess();
|
||||
expected_str<QString> result = d->updateContainerAccess();
|
||||
return result ? Result::Ok : Result::Error(result.error());
|
||||
}
|
||||
|
||||
expected_str<CommandLine> DockerDevicePrivate::withDockerExecCmd(
|
||||
@@ -729,8 +727,12 @@ expected_str<CommandLine> DockerDevicePrivate::withDockerExecCmd(
|
||||
bool withPty,
|
||||
bool withMarker)
|
||||
{
|
||||
if (const auto result = updateContainerAccess(); !result)
|
||||
QString containerId;
|
||||
|
||||
if (const expected_str<QString> result = updateContainerAccess(); !result)
|
||||
return make_unexpected(result.error());
|
||||
else
|
||||
containerId = *result;
|
||||
|
||||
auto osAndArch = osTypeAndArch();
|
||||
if (!osAndArch)
|
||||
@@ -756,7 +758,7 @@ expected_str<CommandLine> DockerDevicePrivate::withDockerExecCmd(
|
||||
if (workDir && !workDir->isEmpty())
|
||||
dockerCmd.addArgs({"-w", q->rootPath().withNewMappedPath(*workDir).nativePath()});
|
||||
|
||||
dockerCmd.addArg(m_container);
|
||||
dockerCmd.addArg(containerId);
|
||||
|
||||
dockerCmd.addArgs({"/bin/sh", "-c"}, osAndArch->first);
|
||||
|
||||
@@ -787,28 +789,12 @@ expected_str<CommandLine> DockerDevicePrivate::withDockerExecCmd(
|
||||
|
||||
void DockerDevicePrivate::stopCurrentContainer()
|
||||
{
|
||||
if (m_container.isEmpty())
|
||||
return;
|
||||
|
||||
if (!DockerApi::isDockerDaemonAvailable(false).value_or(false))
|
||||
return;
|
||||
|
||||
auto fileAccess = m_fileAccess.writeLocked();
|
||||
if (*fileAccess) {
|
||||
if (QThread::currentThread() == thread()) {
|
||||
fileAccess->reset();
|
||||
} else {
|
||||
QMetaObject::invokeMethod(
|
||||
this, [ptr = fileAccess->release()]() { delete ptr; }, Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_startProcess && m_startProcess->isRunning())
|
||||
m_startProcess->kill(); // Kill instead of stop so we don't wait for the process to finish.
|
||||
|
||||
m_container.clear();
|
||||
|
||||
m_cachedEnviroment.reset();
|
||||
auto fileAccess = m_fileAccess.writeLocked();
|
||||
fileAccess->reset();
|
||||
|
||||
auto locked = m_deviceThread.writeLocked();
|
||||
locked->reset();
|
||||
}
|
||||
|
||||
bool DockerDevicePrivate::prepareForBuild(const Target *target)
|
||||
@@ -949,8 +935,10 @@ CommandLine DockerDevicePrivate::createCommandLine()
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
// no getuid() and getgid() on Windows.
|
||||
if (q->useLocalUidGid())
|
||||
if (q->useLocalUidGid()) {
|
||||
dockerCreate.addArgs({"-u", QString("%1:%2").arg(getuid()).arg(getgid())});
|
||||
dockerCreate.addArgs({"-e", QString("HOME=/tmp/qtc_home/%1").arg(getuid())});
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!q->network().isEmpty()) {
|
||||
@@ -973,99 +961,36 @@ CommandLine DockerDevicePrivate::createCommandLine()
|
||||
return dockerCreate;
|
||||
}
|
||||
|
||||
expected_str<QString> DockerDevicePrivate::createContainer()
|
||||
expected_str<QString> DockerDevicePrivate::updateContainerAccess()
|
||||
{
|
||||
if (!isImageAvailable())
|
||||
return make_unexpected(Tr::tr("Image \"%1\" is not available.").arg(q->repoAndTag()));
|
||||
|
||||
const CommandLine cmdLine = createCommandLine();
|
||||
|
||||
qCDebug(dockerDeviceLog).noquote() << "RUNNING: " << cmdLine.toUserOutput();
|
||||
Process createProcess;
|
||||
createProcess.setCommand(cmdLine);
|
||||
createProcess.runBlocking();
|
||||
|
||||
if (createProcess.result() != ProcessResult::FinishedWithSuccess) {
|
||||
return make_unexpected(Tr::tr("Failed creating Docker container. Exit code: %1, output: %2")
|
||||
.arg(createProcess.exitCode())
|
||||
.arg(createProcess.allOutput()));
|
||||
}
|
||||
|
||||
m_container = createProcess.cleanedStdOut().trimmed();
|
||||
if (m_container.isEmpty())
|
||||
return make_unexpected(
|
||||
Tr::tr("Failed creating Docker container. No container ID received."));
|
||||
|
||||
qCDebug(dockerDeviceLog) << "ContainerId:" << m_container;
|
||||
return m_container;
|
||||
}
|
||||
|
||||
expected_str<void> DockerDevicePrivate::startContainer()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
auto createResult = createContainer();
|
||||
if (!createResult)
|
||||
return make_unexpected(createResult.error());
|
||||
|
||||
if (m_startProcess)
|
||||
m_startProcess->stop();
|
||||
|
||||
m_startProcess = std::make_unique<Process>();
|
||||
|
||||
m_startProcess->setCommand(
|
||||
{settings().dockerBinaryPath(), {"container", "start", "-a", "-i", m_container}});
|
||||
m_startProcess->setProcessMode(ProcessMode::Writer);
|
||||
m_startProcess->start();
|
||||
if (!m_startProcess->waitForStarted(5s)) {
|
||||
if (m_startProcess->state() == QProcess::NotRunning) {
|
||||
return make_unexpected(
|
||||
Tr::tr("Failed starting Docker container. Exit code: %1, output: %2")
|
||||
.arg(m_startProcess->exitCode())
|
||||
.arg(m_startProcess->allOutput()));
|
||||
}
|
||||
// Lets assume it will start soon
|
||||
qCWarning(dockerDeviceLog)
|
||||
<< "Docker container start process took more than 5 seconds to start.";
|
||||
}
|
||||
|
||||
QDeadlineTimer deadline(5s);
|
||||
while (!DockerApi::instance()->isContainerRunning(m_container) && !deadline.hasExpired()) {
|
||||
QThread::msleep(100);
|
||||
}
|
||||
|
||||
if (deadline.hasExpired() && !DockerApi::instance()->isContainerRunning(m_container)) {
|
||||
m_startProcess->stop();
|
||||
return make_unexpected(Tr::tr("Failed to start container \"%1\".").arg(m_container));
|
||||
}
|
||||
|
||||
qCDebug(dockerDeviceLog) << "Started container: " << m_startProcess->commandLine();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
expected_str<void> DockerDevicePrivate::updateContainerAccess()
|
||||
{
|
||||
if (!m_container.isEmpty() && DockerApi::instance()->isContainerRunning(m_container))
|
||||
return {};
|
||||
|
||||
if (m_isShutdown)
|
||||
return make_unexpected(Tr::tr("Device is shut down"));
|
||||
|
||||
if (DockerApi::isDockerDaemonAvailable(false).value_or(false) == false)
|
||||
return make_unexpected(Tr::tr("Docker system is not reachable"));
|
||||
|
||||
expected_str<void> result = startContainer();
|
||||
QString containerStatus = result ? Tr::tr("Running") : result.error().trimmed();
|
||||
auto lockedThread = m_deviceThread.writeLocked();
|
||||
if (*lockedThread)
|
||||
return (*lockedThread)->containerId();
|
||||
|
||||
if (!result)
|
||||
result = make_unexpected(QString("Failed to start container: %1").arg(result.error()));
|
||||
DockerContainerThread::Init init;
|
||||
init.dockerBinaryPath = settings().dockerBinaryPath();
|
||||
init.createContainerCmd = createCommandLine();
|
||||
|
||||
auto result = DockerContainerThread::create(init);
|
||||
|
||||
if (result)
|
||||
lockedThread->reset(result->release());
|
||||
|
||||
QString containerStatus = result ? Tr::tr("Running") : result.error().trimmed();
|
||||
|
||||
QTimer::singleShot(0, this, [this, containerStatus] {
|
||||
q->containerStatus.setText(containerStatus);
|
||||
});
|
||||
|
||||
return result;
|
||||
if (!result)
|
||||
return make_unexpected(result.error());
|
||||
|
||||
return (*lockedThread)->containerId();
|
||||
}
|
||||
|
||||
void DockerDevice::setMounts(const QStringList &mounts) const
|
||||
@@ -1152,24 +1077,19 @@ void DockerDevice::aboutToBeRemoved() const
|
||||
detector.undoAutoDetect(id().toString());
|
||||
}
|
||||
|
||||
expected_str<void> DockerDevicePrivate::fetchSystemEnviroment()
|
||||
Result DockerDevicePrivate::fetchSystemEnviroment()
|
||||
{
|
||||
if (m_cachedEnviroment)
|
||||
return {};
|
||||
return Result::Ok;
|
||||
|
||||
if (auto fileAccess = m_fileAccess.readLocked()->get()) {
|
||||
m_cachedEnviroment = fileAccess->deviceEnvironment();
|
||||
return {};
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
expected_str<void> result = updateContainerAccess();
|
||||
|
||||
if (!result)
|
||||
return result;
|
||||
|
||||
const expected_str<CommandLine> fullCommandLine = withDockerExecCmd(CommandLine{"env"});
|
||||
if (!fullCommandLine)
|
||||
return make_unexpected(fullCommandLine.error());
|
||||
return Result::Error(fullCommandLine.error());
|
||||
|
||||
Process proc;
|
||||
proc.setCommand(*fullCommandLine);
|
||||
@@ -1180,9 +1100,9 @@ expected_str<void> DockerDevicePrivate::fetchSystemEnviroment()
|
||||
QString stdErr = proc.cleanedStdErr();
|
||||
|
||||
if (stdErr.isEmpty())
|
||||
return {};
|
||||
return Result::Ok;
|
||||
|
||||
return make_unexpected("Could not read container environment: " + stdErr);
|
||||
return Result::Error("Could not read container environment: " + stdErr);
|
||||
}
|
||||
|
||||
// Factory
|
||||
@@ -1385,19 +1305,19 @@ DockerDeviceFactory::DockerDeviceFactory()
|
||||
});
|
||||
setConstructionFunction([this] {
|
||||
auto device = DockerDevice::create();
|
||||
QMutexLocker lk(&m_deviceListMutex);
|
||||
m_existingDevices.push_back(device);
|
||||
m_existingDevices.writeLocked()->push_back(device);
|
||||
return device;
|
||||
});
|
||||
}
|
||||
|
||||
void DockerDeviceFactory::shutdownExistingDevices()
|
||||
{
|
||||
QMutexLocker lk(&m_deviceListMutex);
|
||||
for (const auto &weakDevice : m_existingDevices) {
|
||||
if (std::shared_ptr<DockerDevice> device = weakDevice.lock())
|
||||
device->shutdown();
|
||||
}
|
||||
m_existingDevices.read([](const std::vector<std::weak_ptr<DockerDevice>> &devices) {
|
||||
for (const std::weak_ptr<DockerDevice> &weakDevice : devices) {
|
||||
if (std::shared_ptr<DockerDevice> device = weakDevice.lock())
|
||||
device->shutdown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
expected_str<QPair<Utils::OsType, Utils::OsArch>> DockerDevicePrivate::osTypeAndArch() const
|
||||
@@ -1428,8 +1348,7 @@ expected_str<QPair<Utils::OsType, Utils::OsArch>> DockerDevicePrivate::osTypeAnd
|
||||
expected_str<Environment> DockerDevicePrivate::environment()
|
||||
{
|
||||
if (!m_cachedEnviroment) {
|
||||
expected_str<void> result = fetchSystemEnviroment();
|
||||
if (!result)
|
||||
if (Result result = fetchSystemEnviroment(); !result)
|
||||
return make_unexpected(result.error());
|
||||
}
|
||||
|
||||
@@ -1463,7 +1382,8 @@ expected_str<FilePath> DockerDevicePrivate::localSource(const FilePath &other) c
|
||||
}
|
||||
}
|
||||
|
||||
return make_unexpected(Tr::tr("localSource: No mount point found for %1").arg(other.toUrlishString()));
|
||||
return make_unexpected(
|
||||
Tr::tr("localSource: No mount point found for %1").arg(other.toUserOutput()));
|
||||
}
|
||||
|
||||
bool DockerDevicePrivate::ensureReachable(const FilePath &other)
|
||||
|
@@ -8,7 +8,7 @@
|
||||
#include <projectexplorer/devicesupport/idevice.h>
|
||||
#include <projectexplorer/devicesupport/idevicefactory.h>
|
||||
|
||||
#include <QMutex>
|
||||
#include <utils/synchronizedvalue.h>
|
||||
|
||||
namespace Docker::Internal {
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
|
||||
Utils::expected_str<Utils::Environment> systemEnvironmentWithError() const override;
|
||||
|
||||
Utils::expected_str<void> updateContainerAccess() const;
|
||||
Utils::Result updateContainerAccess() const;
|
||||
void setMounts(const QStringList &mounts) const;
|
||||
|
||||
bool prepareForBuild(const ProjectExplorer::Target *target) override;
|
||||
@@ -92,8 +92,7 @@ public:
|
||||
void shutdownExistingDevices();
|
||||
|
||||
private:
|
||||
QMutex m_deviceListMutex;
|
||||
std::vector<std::weak_ptr<DockerDevice>> m_existingDevices;
|
||||
Utils::SynchronizedValue<std::vector<std::weak_ptr<DockerDevice>>> m_existingDevices;
|
||||
};
|
||||
|
||||
} // namespace Docker::Internal
|
||||
|
@@ -104,7 +104,7 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
|
||||
this,
|
||||
[this, logView, dockerDevice, searchPaths] {
|
||||
logView->clear();
|
||||
expected_str<void> startResult = dockerDevice->updateContainerAccess();
|
||||
Result startResult = dockerDevice->updateContainerAccess();
|
||||
|
||||
if (!startResult) {
|
||||
logView->append(Tr::tr("Failed to start container."));
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include <utils/stylehelper.h>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QSslSocket>
|
||||
|
||||
namespace ExtensionManager::Internal {
|
||||
|
||||
@@ -33,6 +34,13 @@ ExtensionManagerSettings::ExtensionManagerSettings()
|
||||
useExternalRepo.setDefaultValue(false);
|
||||
useExternalRepo.setLabelText(Tr::tr("Use external repository"));
|
||||
|
||||
const bool sslSupported = QSslSocket::supportsSsl();
|
||||
|
||||
useExternalRepo.setEnabled(sslSupported);
|
||||
if (!sslSupported) {
|
||||
useExternalRepo.setToolTip(Tr::tr("SSL support is not available."));
|
||||
}
|
||||
|
||||
externalRepoUrl.setSettingsKey("ExternalRepoUrl");
|
||||
externalRepoUrl.setDefaultValue("https://qc-extensions.qt.io");
|
||||
externalRepoUrl.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
|
@@ -549,7 +549,11 @@ ExtensionsBrowser::ExtensionsBrowser(ExtensionsModel *model, QWidget *parent)
|
||||
applyTf(titleLabel, titleTF);
|
||||
|
||||
auto externalRepoSwitch = new Switch("Use external repository");
|
||||
externalRepoSwitch->setToolTip("<html>" + externalRepoWarningNote());
|
||||
externalRepoSwitch->setEnabled(settings().useExternalRepo.isEnabled());
|
||||
if (settings().useExternalRepo.isEnabled())
|
||||
externalRepoSwitch->setToolTip("<html>" + externalRepoWarningNote());
|
||||
else
|
||||
externalRepoSwitch->setToolTip(settings().useExternalRepo.toolTip());
|
||||
|
||||
d->searchBox = new SearchBox;
|
||||
d->searchBox->setPlaceholderText(Tr::tr("Search"));
|
||||
|
@@ -140,7 +140,7 @@ QString BlameMark::toolTipText(const CommitInfo &info) const
|
||||
.arg(colors.hash, info.hash,
|
||||
colors.author, info.author, info.authorMail,
|
||||
colors.date, info.authorDate.toString("yyyy-MM-dd hh:mm:ss"),
|
||||
colors.subject, info.subject);
|
||||
colors.subject, info.subject.toHtmlEscaped());
|
||||
|
||||
QString result = actions + header;
|
||||
|
||||
|
@@ -674,13 +674,7 @@ void LanguageClientManager::documentOpened(Core::IDocument *document)
|
||||
|
||||
void LanguageClientManager::documentClosed(Core::IDocument *document)
|
||||
{
|
||||
if (auto textDocument = qobject_cast<TextEditor::TextDocument *>(document)) {
|
||||
openDocumentWithClient(textDocument, nullptr);
|
||||
for (auto client : std::as_const(managerInstance->m_clients)) {
|
||||
if (client->documentOpen(textDocument))
|
||||
client->closeDocument(textDocument);
|
||||
}
|
||||
}
|
||||
openDocumentWithClient(qobject_cast<TextEditor::TextDocument *>(document), nullptr);
|
||||
}
|
||||
|
||||
void LanguageClientManager::updateProject(ProjectExplorer::Project *project)
|
||||
|
@@ -29,6 +29,7 @@ using namespace Utils;
|
||||
using namespace Core;
|
||||
using namespace TextEditor;
|
||||
using namespace ProjectExplorer;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -264,21 +265,22 @@ public:
|
||||
return make_unexpected(QString("init callback did not return a table or string"));
|
||||
});
|
||||
|
||||
if (auto initOptionsTable = options.get<sol::optional<sol::table>>("initializationOptions"))
|
||||
if (auto initOptionsTable = options.get<sol::optional<sol::table>>(
|
||||
"initializationOptions"sv))
|
||||
m_initializationOptions = ::Lua::toJsonString(*initOptionsTable);
|
||||
else if (auto initOptionsString = options.get<sol::optional<QString>>("initializationOptions"))
|
||||
else if (auto initOptionsString = options.get<sol::optional<QString>>("initializationOptions"sv))
|
||||
m_initializationOptions = *initOptionsString;
|
||||
|
||||
m_name = options.get<QString>("name");
|
||||
m_name = options.get<QString>("name"sv);
|
||||
m_settingsTypeId = Utils::Id::fromString(QString("Lua_%1").arg(m_name));
|
||||
m_serverName = options.get_or<QString>("serverName", "");
|
||||
m_serverName = options.get_or<QString>("serverName"sv, "");
|
||||
|
||||
m_startBehavior = startBehaviorFromString(
|
||||
options.get_or<QString>("startBehavior", "AlwaysOn"));
|
||||
options.get_or<QString>("startBehavior"sv, "AlwaysOn"));
|
||||
|
||||
m_startFailedCallback = options.get<sol::protected_function>("onStartFailed");
|
||||
m_startFailedCallback = options.get<sol::protected_function>("onStartFailed"sv);
|
||||
|
||||
QString transportType = options.get_or<QString>("transport", "stdio");
|
||||
QString transportType = options.get_or<QString>("transport"sv, "stdio");
|
||||
if (transportType == "stdio")
|
||||
m_transportType = TransportType::StdIO;
|
||||
else if (transportType == "localsocket")
|
||||
@@ -286,7 +288,7 @@ public:
|
||||
else
|
||||
qWarning() << "Unknown transport type:" << transportType;
|
||||
|
||||
auto languageFilter = options.get<std::optional<sol::table>>("languageFilter");
|
||||
auto languageFilter = options.get<std::optional<sol::table>>("languageFilter"sv);
|
||||
if (languageFilter) {
|
||||
auto patterns = languageFilter->get<std::optional<sol::table>>("patterns");
|
||||
auto mimeTypes = languageFilter->get<std::optional<sol::table>>("mimeTypes");
|
||||
@@ -300,10 +302,10 @@ public:
|
||||
m_languageFilter.mimeTypes.push_back(v.as<QString>());
|
||||
}
|
||||
|
||||
m_showInSettings = options.get<std::optional<bool>>("showInSettings").value_or(true);
|
||||
m_showInSettings = options.get<std::optional<bool>>("showInSettings"sv).value_or(true);
|
||||
|
||||
// get<sol::optional<>> because on MSVC, get_or(..., nullptr) fails to compile
|
||||
m_aspects = options.get<sol::optional<AspectContainer *>>("settings").value_or(nullptr);
|
||||
m_aspects = options.get<sol::optional<AspectContainer *>>("settings"sv).value_or(nullptr);
|
||||
|
||||
if (m_aspects) {
|
||||
connect(m_aspects, &AspectContainer::applied, this, [this] {
|
||||
|
@@ -26,6 +26,7 @@
|
||||
|
||||
using namespace Utils;
|
||||
using namespace Core;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
namespace Lua::Internal {
|
||||
|
||||
@@ -139,7 +140,7 @@ void setupFetchModule()
|
||||
"Fetch",
|
||||
[mod = std::move(module),
|
||||
infoBarCleaner = InfoBarCleaner()](sol::state_view lua) mutable -> sol::object {
|
||||
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
|
||||
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec"sv);
|
||||
|
||||
sol::table async = lua.script("return require('async')", "_fetch_").get<sol::table>();
|
||||
sol::function wrap = async["wrap"];
|
||||
@@ -257,13 +258,13 @@ void setupFetchModule()
|
||||
const sol::main_table &options,
|
||||
const sol::main_function &callback,
|
||||
const sol::this_state &thisState) {
|
||||
auto url = options.get<QString>("url");
|
||||
auto url = options.get<QString>("url"sv);
|
||||
auto actualFetch = [guard, url, options, callback, thisState]() {
|
||||
auto method = (options.get_or<QString>("method", "GET")).toLower();
|
||||
auto headers = options.get_or<sol::table>("headers", {});
|
||||
auto data = options.get_or<QString>("body", {});
|
||||
auto method = (options.get_or<QString>("method"sv, "GET")).toLower();
|
||||
auto headers = options.get_or<sol::table>("headers"sv, {});
|
||||
auto data = options.get_or<QString>("body"sv, {});
|
||||
bool convertToTable
|
||||
= options.get<std::optional<bool>>("convertToTable").value_or(false);
|
||||
= options.get<std::optional<bool>>("convertToTable"sv).value_or(false);
|
||||
|
||||
QNetworkRequest request((QUrl(url)));
|
||||
if (headers && !headers.empty()) {
|
||||
|
@@ -11,9 +11,11 @@
|
||||
#include <utils/layoutbuilder.h>
|
||||
|
||||
#include <QMetaEnum>
|
||||
#include <QCompleter>
|
||||
|
||||
using namespace Layouting;
|
||||
using namespace Utils;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
namespace Lua::Internal {
|
||||
|
||||
@@ -67,8 +69,8 @@ static std::unique_ptr<T> construct(const sol::table &children)
|
||||
template<class T>
|
||||
void constructWidget(std::unique_ptr<T> &widget, const sol::table &children)
|
||||
{
|
||||
widget->setWindowTitle(children.get_or<QString>("windowTitle", ""));
|
||||
widget->setToolTip(children.get_or<QString>("toolTip", ""));
|
||||
widget->setWindowTitle(children.get_or<QString>("windowTitle"sv, ""));
|
||||
widget->setToolTip(children.get_or<QString>("toolTip"sv, ""));
|
||||
|
||||
for (size_t i = 1; i <= children.size(); ++i) {
|
||||
const auto &child = children[i];
|
||||
@@ -115,91 +117,100 @@ CREATE_HAS_FUNC(setIcon, Utils::Icon());
|
||||
CREATE_HAS_FUNC(setContentsMargins, int(), int(), int(), int());
|
||||
CREATE_HAS_FUNC(setCursor, Qt::CursorShape())
|
||||
CREATE_HAS_FUNC(setMinimumWidth, int());
|
||||
CREATE_HAS_FUNC(setEnableCodeCopyButton, bool());
|
||||
|
||||
template<class T>
|
||||
void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject *guard)
|
||||
{
|
||||
if constexpr (has_setContentsMargins<T>) {
|
||||
sol::optional<QMargins> margins = children.get<sol::optional<QMargins>>("contentMargins");
|
||||
sol::optional<QMargins> margins = children.get<sol::optional<QMargins>>("contentMargins"sv);
|
||||
if (margins)
|
||||
item->setContentsMargins(margins->left(), margins->top(), margins->right(), margins->bottom());
|
||||
}
|
||||
|
||||
if constexpr (has_setCursor<T>) {
|
||||
const auto cursor = children.get<sol::optional<Qt::CursorShape>>("cursor");
|
||||
const auto cursor = children.get<sol::optional<Qt::CursorShape>>("cursor"sv);
|
||||
if (cursor)
|
||||
item->setCursor(*cursor);
|
||||
}
|
||||
|
||||
if constexpr (has_setMinimumWidth<T>) {
|
||||
const auto minw = children.get<sol::optional<int>>("minimumWidth");
|
||||
const auto minw = children.get<sol::optional<int>>("minimumWidth"sv);
|
||||
if (minw)
|
||||
item->setMinimumWidth(*minw);
|
||||
}
|
||||
|
||||
if constexpr (has_setEnableCodeCopyButton<T>) {
|
||||
const auto enableCodeCopyButton = children.get<sol::optional<bool>>("enableCodeCopyButton");
|
||||
if (enableCodeCopyButton)
|
||||
item->setEnableCodeCopyButton(*enableCodeCopyButton);
|
||||
}
|
||||
|
||||
if constexpr (has_setVisible<T>) {
|
||||
const auto visible = children.get<sol::optional<bool>>("visible");
|
||||
const auto visible = children.get<sol::optional<bool>>("visible"sv);
|
||||
if (visible)
|
||||
item->setVisible(*visible);
|
||||
}
|
||||
|
||||
if constexpr (has_setIcon<T>) {
|
||||
const auto icon = children.get<sol::optional<IconFilePathOrString>>("icon");
|
||||
const auto icon = children.get<sol::optional<IconFilePathOrString>>("icon"sv);
|
||||
if (icon)
|
||||
item->setIcon(*toIcon(*icon));
|
||||
}
|
||||
|
||||
if constexpr (has_setTextInteractionFlags<T>) {
|
||||
const auto interactionFlags = children.get<sol::optional<sol::table>>("interactionFlags");
|
||||
const auto interactionFlags = children.get<sol::optional<sol::table>>("interactionFlags"sv);
|
||||
if (interactionFlags) {
|
||||
item->setTextInteractionFlags(tableToFlags<Qt::TextInteractionFlag>(*interactionFlags));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (has_setFixedSize<T>) {
|
||||
sol::optional<QSize> size = children.get<sol::optional<QSize>>("fixedSize");
|
||||
sol::optional<QSize> size = children.get<sol::optional<QSize>>("fixedSize"sv);
|
||||
if (size)
|
||||
item->setFixedSize(*size);
|
||||
}
|
||||
|
||||
if constexpr (has_setWordWrap<T>) {
|
||||
const auto wrap = children.get<sol::optional<bool>>("wordWrap");
|
||||
const auto wrap = children.get<sol::optional<bool>>("wordWrap"sv);
|
||||
if (wrap)
|
||||
item->setWordWrap(*wrap);
|
||||
}
|
||||
|
||||
if constexpr (has_setTextFormat<T>) {
|
||||
const auto format = children.get<sol::optional<Qt::TextFormat>>("textFormat");
|
||||
const auto format = children.get<sol::optional<Qt::TextFormat>>("textFormat"sv);
|
||||
if (format)
|
||||
item->setTextFormat(*format);
|
||||
}
|
||||
|
||||
if constexpr (has_setRightSideIconPath<T>) {
|
||||
const auto path = children.get<sol::optional<Utils::FilePath>>("rightSideIconPath");
|
||||
const auto path = children.get<sol::optional<Utils::FilePath>>("rightSideIconPath"sv);
|
||||
if (path)
|
||||
item->setRightSideIconPath(*path);
|
||||
}
|
||||
|
||||
if constexpr (has_setPlaceHolderText<T>) {
|
||||
const auto text = children.get<sol::optional<QString>>("placeHolderText");
|
||||
const auto text = children.get<sol::optional<QString>>("placeHolderText"sv);
|
||||
if (text)
|
||||
item->setPlaceHolderText(*text);
|
||||
}
|
||||
|
||||
if constexpr (has_setCompleter<T>) {
|
||||
const auto completer = children.get<QCompleter *>("completer");
|
||||
if (completer)
|
||||
const auto completer = children.get<QCompleter *>("completer"sv);
|
||||
if (completer) {
|
||||
item->setCompleter(completer);
|
||||
completer->setParent(item->emerge());
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (has_setMinimumHeight<T>) {
|
||||
const auto minHeight = children.get<sol::optional<int>>("minimumHeight");
|
||||
const auto minHeight = children.get<sol::optional<int>>("minimumHeight"sv);
|
||||
if (minHeight)
|
||||
item->setMinimumHeight(*minHeight);
|
||||
}
|
||||
|
||||
if constexpr (has_onReturnPressed<T>) {
|
||||
const auto callback = children.get<sol::optional<sol::main_function>>("onReturnPressed");
|
||||
const auto callback = children.get<sol::optional<sol::main_function>>("onReturnPressed"sv);
|
||||
if (callback) {
|
||||
item->onReturnPressed(guard, [func = *callback]() { void_safe_call(func); });
|
||||
}
|
||||
@@ -213,19 +224,19 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
|
||||
}
|
||||
|
||||
if constexpr (has_setFlat<T>) {
|
||||
const auto flat = children.get<sol::optional<bool>>("flat");
|
||||
const auto flat = children.get<sol::optional<bool>>("flat"sv);
|
||||
if (flat)
|
||||
item->setFlat(*flat);
|
||||
}
|
||||
|
||||
if constexpr (has_setIconPath<T>) {
|
||||
const auto iconPath = children.get<sol::optional<FilePath>>("iconPath");
|
||||
const auto iconPath = children.get<sol::optional<FilePath>>("iconPath"sv);
|
||||
if (iconPath)
|
||||
item->setIconPath(*iconPath);
|
||||
}
|
||||
|
||||
if constexpr (has_setIconSize<T>) {
|
||||
const auto iconSize = children.get<sol::optional<QSize>>("iconSize");
|
||||
const auto iconSize = children.get<sol::optional<QSize>>("iconSize"sv);
|
||||
if (iconSize)
|
||||
item->setIconSize(*iconSize);
|
||||
}
|
||||
@@ -242,7 +253,7 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
|
||||
}
|
||||
|
||||
if constexpr (has_setSize<T>) {
|
||||
sol::optional<QSize> size = children.get<sol::optional<QSize>>("size");
|
||||
sol::optional<QSize> size = children.get<sol::optional<QSize>>("size"sv);
|
||||
if (size)
|
||||
item->setSize(size->width(), size->height());
|
||||
}
|
||||
@@ -266,7 +277,7 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
|
||||
|
||||
if constexpr (has_onTextChanged<T>) {
|
||||
sol::optional<sol::main_function> onTextChanged
|
||||
= children.get<sol::optional<sol::main_function>>("onTextChanged");
|
||||
= children.get<sol::optional<sol::main_function>>("onTextChanged"sv);
|
||||
if (onTextChanged) {
|
||||
item->onTextChanged(
|
||||
guard,
|
||||
@@ -278,7 +289,7 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
|
||||
}
|
||||
if constexpr (has_onClicked<T>) {
|
||||
sol::optional<sol::main_function> onClicked
|
||||
= children.get<sol::optional<sol::main_function>>("onClicked");
|
||||
= children.get<sol::optional<sol::main_function>>("onClicked"sv);
|
||||
if (onClicked) {
|
||||
item->onClicked(
|
||||
guard,
|
||||
@@ -289,17 +300,17 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
|
||||
}
|
||||
}
|
||||
if constexpr (has_setText<T>) {
|
||||
auto text = children.get<sol::optional<QString>>("text");
|
||||
auto text = children.get<sol::optional<QString>>("text"sv);
|
||||
if (text)
|
||||
item->setText(*text);
|
||||
}
|
||||
if constexpr (has_setMarkdown<T>) {
|
||||
auto markdown = children.get<sol::optional<QString>>("markdown");
|
||||
auto markdown = children.get<sol::optional<QString>>("markdown"sv);
|
||||
if (markdown)
|
||||
item->setMarkdown(*markdown);
|
||||
}
|
||||
if constexpr (has_setSizePolicy<T>) {
|
||||
auto sizePolicy = children.get<sol::optional<sol::table>>("sizePolicy");
|
||||
auto sizePolicy = children.get<sol::optional<sol::table>>("sizePolicy"sv);
|
||||
if (sizePolicy) {
|
||||
QTC_ASSERT(
|
||||
sizePolicy->size() == 2,
|
||||
@@ -312,21 +323,21 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
|
||||
}
|
||||
}
|
||||
if constexpr (has_setTitle<T>) {
|
||||
item->setTitle(children.get_or<QString>("title", ""));
|
||||
item->setTitle(children.get_or<QString>("title"sv, ""));
|
||||
}
|
||||
if constexpr (has_setValue<T>) {
|
||||
sol::optional<int> value = children.get<sol::optional<int>>("value");
|
||||
sol::optional<int> value = children.get<sol::optional<int>>("value"sv);
|
||||
if (value)
|
||||
item->setValue(*value);
|
||||
}
|
||||
if constexpr (has_setReadOnly<T>) {
|
||||
sol::optional<bool> readOnly = children.get<sol::optional<bool>>("readOnly");
|
||||
sol::optional<bool> readOnly = children.get<sol::optional<bool>>("readOnly"sv);
|
||||
if (readOnly)
|
||||
item->setReadOnly(*readOnly);
|
||||
}
|
||||
if constexpr (has_setOpenExternalLinks<T>) {
|
||||
sol::optional<bool> openExternalLinks = children.get<sol::optional<bool>>(
|
||||
"openExternalLinks");
|
||||
"openExternalLinks"sv);
|
||||
if (openExternalLinks)
|
||||
item->setOpenExternalLinks(*openExternalLinks);
|
||||
}
|
||||
@@ -420,7 +431,7 @@ std::unique_ptr<Splitter> constructSplitter(const sol::table &children)
|
||||
std::unique_ptr<Splitter> item(new Splitter({}));
|
||||
constructWidget(item, children);
|
||||
|
||||
if (const auto &orientation = children.get<sol::optional<QString>>("orientation")) {
|
||||
if (const auto &orientation = children.get<sol::optional<QString>>("orientation"sv)) {
|
||||
if (*orientation == "horizontal")
|
||||
item->setOrientation(Qt::Horizontal);
|
||||
else if (*orientation == "vertical")
|
||||
@@ -429,7 +440,7 @@ std::unique_ptr<Splitter> constructSplitter(const sol::table &children)
|
||||
throw sol::error(QString("Invalid orientation: %1").arg(*orientation).toStdString());
|
||||
}
|
||||
|
||||
if (const auto collapsible = children.get<sol::optional<bool>>("collapsible"))
|
||||
if (const auto collapsible = children.get<sol::optional<bool>>("collapsible"sv))
|
||||
item->setChildrenCollapsible(*collapsible);
|
||||
|
||||
for (size_t i = 1; i <= children.size(); ++i) {
|
||||
@@ -444,7 +455,7 @@ std::unique_ptr<Splitter> constructSplitter(const sol::table &children)
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto &stretchFactors = children.get<sol::optional<sol::table>>("stretchFactors")) {
|
||||
if (const auto &stretchFactors = children.get<sol::optional<sol::table>>("stretchFactors"sv)) {
|
||||
for (const auto &kv : *stretchFactors) {
|
||||
if (kv.second.get_type() != sol::type::number)
|
||||
throw sol::error("Stretch factors must be numbers");
|
||||
@@ -457,7 +468,7 @@ std::unique_ptr<Splitter> constructSplitter(const sol::table &children)
|
||||
void setupGuiModule()
|
||||
{
|
||||
registerProvider("Gui", [](sol::state_view l) -> sol::object {
|
||||
const ScriptPluginSpec *pluginSpec = l.get<ScriptPluginSpec *>("PluginSpec");
|
||||
const ScriptPluginSpec *pluginSpec = l.get<ScriptPluginSpec *>("PluginSpec"sv);
|
||||
QObject *guard = pluginSpec->connectionGuard.get();
|
||||
|
||||
sol::table gui = l.create_table();
|
||||
@@ -545,6 +556,9 @@ void setupGuiModule()
|
||||
sol::factories([guard](const sol::table &children) {
|
||||
return constructWidgetType<Layouting::MarkdownBrowser>(children, guard);
|
||||
}),
|
||||
"markdown",
|
||||
sol::property(
|
||||
&Layouting::MarkdownBrowser::toMarkdown, &Layouting::MarkdownBrowser::setMarkdown),
|
||||
sol::base_classes,
|
||||
sol::bases<Widget, Object, Thing>());
|
||||
|
||||
|
@@ -29,6 +29,7 @@
|
||||
using namespace Core;
|
||||
using namespace Tasking;
|
||||
using namespace Utils;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
namespace Lua::Internal {
|
||||
|
||||
@@ -268,7 +269,7 @@ void setupInstallModule()
|
||||
sol::function wrap = async["wrap"];
|
||||
|
||||
sol::table install = lua.create_table();
|
||||
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
|
||||
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec"sv);
|
||||
|
||||
install["packageInfo"] =
|
||||
[pluginSpec](const QString &name, sol::this_state l) -> sol::optional<sol::table> {
|
||||
|
@@ -17,13 +17,14 @@
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
namespace Lua::Internal {
|
||||
|
||||
void setupProjectModule()
|
||||
{
|
||||
registerProvider("Project", [](sol::state_view lua) -> sol::object {
|
||||
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
|
||||
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec"sv);
|
||||
QObject *guard = pluginSpec->connectionGuard.get();
|
||||
|
||||
sol::table result = lua.create_table();
|
||||
|
@@ -16,19 +16,28 @@
|
||||
#include <QFontMetrics>
|
||||
#include <QStandardPaths>
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
namespace Lua::Internal {
|
||||
|
||||
void setupQtModule()
|
||||
{
|
||||
registerProvider("Qt", [](sol::state_view lua) {
|
||||
sol::table qt(lua, sol::create);
|
||||
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
|
||||
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec"sv);
|
||||
|
||||
qt.new_usertype<QCompleter>(
|
||||
"QCompleter",
|
||||
"create",
|
||||
[](const QStringList &list) -> std::unique_ptr<QCompleter> {
|
||||
return std::make_unique<QCompleter>(list);
|
||||
[](const QStringList &list) -> QCompleter* {
|
||||
return new QCompleter(list);
|
||||
},
|
||||
sol::meta_function::garbage_collect, [](QCompleter *self) {
|
||||
// If the user never parented this QCompleter to any QObject,
|
||||
// then we own it, so let's delete it to avoid a memory leak.
|
||||
if (!self->parent()) {
|
||||
self->deleteLater();
|
||||
}
|
||||
},
|
||||
"currentCompletion",
|
||||
&QCompleter::currentCompletion,
|
||||
|
@@ -9,13 +9,14 @@
|
||||
#include <utils/qtcprocess.h>
|
||||
|
||||
using namespace Utils;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
namespace Lua::Internal {
|
||||
|
||||
void setupProcessModule()
|
||||
{
|
||||
registerProvider("Process", [](sol::state_view lua) -> sol::object {
|
||||
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
|
||||
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec"sv);
|
||||
QObject *guard = pluginSpec->connectionGuard.get();
|
||||
|
||||
sol::table async = lua.script("return require('async')", "_process_").get<sol::table>();
|
||||
@@ -50,17 +51,17 @@ void setupProcessModule()
|
||||
process["commandOutput"] = wrap(process["commandOutput_cb"]);
|
||||
|
||||
process["create"] = [](const sol::table ¶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
|
||||
= parameter.get_or<QStringList, const char *, QStringList>("arguments", {});
|
||||
const std::optional<FilePath> workingDirectory = parameter.get<std::optional<FilePath>>(
|
||||
"workingDirectory");
|
||||
|
||||
const auto stdOut = parameter.get<std::optional<sol::function>>("stdout");
|
||||
const auto stdErr = parameter.get<std::optional<sol::function>>("stderr");
|
||||
const auto stdIn = parameter.get<sol::optional<QString>>("stdin");
|
||||
const auto onFinished = parameter.get<std::optional<sol::function>>("onFinished");
|
||||
const auto stdOut = parameter.get<std::optional<sol::function>>("stdout"sv);
|
||||
const auto stdErr = parameter.get<std::optional<sol::function>>("stderr"sv);
|
||||
const auto stdIn = parameter.get<sol::optional<QString>>("stdin"sv);
|
||||
const auto onFinished = parameter.get<std::optional<sol::function>>("onFinished"sv);
|
||||
|
||||
auto p = std::make_unique<Process>();
|
||||
|
||||
|
@@ -14,6 +14,7 @@
|
||||
|
||||
using namespace Utils;
|
||||
using namespace Core;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
namespace Lua::Internal {
|
||||
|
||||
@@ -318,7 +319,7 @@ public:
|
||||
void setupSettingsModule()
|
||||
{
|
||||
registerProvider("Settings", [pool = ObjectPool()](sol::state_view lua) -> sol::object {
|
||||
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
|
||||
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec"sv);
|
||||
sol::table async = lua.script("return require('async')", "_process_").get<sol::table>();
|
||||
sol::function wrap = async["wrap"];
|
||||
|
||||
@@ -658,19 +659,19 @@ void setupSettingsModule()
|
||||
OptionsPage(const ScriptPluginSpec *spec, const sol::table &options)
|
||||
{
|
||||
setCategory(Id::fromString(
|
||||
QString("%1.%2").arg(spec->id).arg(options.get<QString>("categoryId"))));
|
||||
const QString catName = options.get<QString>("displayCategory");
|
||||
const FilePath catIcon = options.get<std::optional<FilePath>>("categoryIconPath")
|
||||
QString("%1.%2").arg(spec->id).arg(options.get<QString>("categoryId"sv))));
|
||||
const QString catName = options.get<QString>("displayCategory"sv);
|
||||
const FilePath catIcon = options.get<std::optional<FilePath>>("categoryIconPath"sv)
|
||||
.value_or(FilePath::fromUserInput(
|
||||
options.get_or<QString>("categoryIconPath", {})));
|
||||
options.get_or<QString>("categoryIconPath"sv, {})));
|
||||
if (!catName.isEmpty() || !catIcon.isEmpty())
|
||||
IOptionsPage::registerCategory(category(), catName, catIcon);
|
||||
|
||||
setId(
|
||||
Id::fromString(QString("%1.%2").arg(spec->id).arg(options.get<QString>("id"))));
|
||||
setDisplayName(options.get<QString>("displayName"));
|
||||
setId(Id::fromString(
|
||||
QString("%1.%2").arg(spec->id).arg(options.get<QString>("id"sv))));
|
||||
setDisplayName(options.get<QString>("displayName"sv));
|
||||
|
||||
AspectContainer *container = options.get<AspectContainer *>("aspectContainer");
|
||||
AspectContainer *container = options.get<AspectContainer *>("aspectContainer"sv);
|
||||
if (container->isAutoApply())
|
||||
throw sol::error("AspectContainer must have autoApply set to false");
|
||||
|
||||
|