Merge remote-tracking branch 'origin/4.9'

Conflicts:
	qbs/modules/qtc/qtc.qbs
	qtcreator.pri
	src/plugins/debugger/debuggerkitinformation.cpp
	src/plugins/languageclient/languageclientmanager.cpp
	src/plugins/plugins.pro
	src/plugins/projectexplorer/kit.cpp
	src/plugins/projectexplorer/kitmanager.cpp

Change-Id: I66fb941202991f35f7d7761430b21e42dfc678a8
This commit is contained in:
Eike Ziller
2019-03-14 15:14:40 +01:00
154 changed files with 2211 additions and 1068 deletions

View File

@@ -8,6 +8,8 @@
# Use ../../tests/manual/clang-format-for-qtc/test.cpp for documenting problems
# or testing changes.
#
# In case you update this configuration please also update the qtcStyle() in src\plugins\clangformat\clangformatutils.cpp
#
# [1] https://doc-snapshots.qt.io/qtcreator-extending/coding-style.html
# [2] https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#

View File

@@ -34,9 +34,10 @@ Prerequisites:
* Python 3.5 or later (optional, needed for the python enabled debug helper)
* On Mac OS X: latest Xcode
* On Linux: g++ 5.3 or later
* LLVM/Clang 6.0.0 or later (optional, needed for the Clang Code Model, see the
section "Get LLVM/Clang for the Clang Code Model")
* CMake (only for manual builds of LLVM/Clang)
* LLVM/Clang 7.0.0 or later (optional, needed for the Clang Code Model, Clang Tools, ClangFormat,
Clang PCH Manager and Clang Refactoring plugins, see the section
"Get LLVM/Clang for the Clang Code Model")
* CMake (only for manual builds of LLVM/Clang)
* Qbs 1.7.x (optional, sources also contain Qbs itself)
The installed toolchains have to match the one Qt was compiled with.
@@ -49,6 +50,10 @@ You can build Qt Creator with
export QBS_INSTALL_DIR=/path/to/qbs
# Optional, needed for the Python enabled dumper on Windows
set PYTHON_INSTALL_DIR=C:\path\to\python
# Optional, needed to use system KSyntaxHighlighting:
set KSYNTAXHIGHLIGHTING_LIB_DIR to folder holding the KSyntaxHighlighting library
# if automatic deducing of include folder fails set KSYNTAXHIGHLIGHTING_INCLUDE_DIR as well
# both variables can also be passed as qmake variables
cd $SOURCE_DIRECTORY
qmake -r
@@ -220,7 +225,7 @@ or using shadow builds.
## Get LLVM/Clang for the Clang Code Model
The Clang Code Model depends on the LLVM/Clang libraries. The currently
supported LLVM/Clang version is 6.0.
supported LLVM/Clang version is 7.0.
### Prebuilt LLVM/Clang packages
@@ -247,9 +252,9 @@ GCC 4 binaries. On Ubuntu, you can download the package from
http://apt.llvm.org/ with:
wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-add-repository "deb http://apt.llvm.org/`lsb_release -cs`/ llvm-toolchain-`lsb_release -cs`-6.0 main"
sudo apt-add-repository "deb http://apt.llvm.org/`lsb_release -cs`/ llvm-toolchain-`lsb_release -cs`-7.0 main"
sudo apt-get update
sudo apt-get install llvm-6.0 libclang-6.0-dev
sudo apt-get install llvm-7.0 libclang-7.0-dev
There is a workaround to set _GLIBCXX_USE_CXX11_ABI to 1 or 0, but we recommend
to download the package from http://apt.llvm.org/.

10
dist/changes-4.9.0.md vendored
View File

@@ -52,6 +52,10 @@ QMake Projects
* Fixed updating of `LD_LIBRARY_PATH` environment variable (QTCREATORBUG-21475)
* Fixed updating of project tree in case of wildcards in corresponding QMake
variable (QTCREATORBUG-21603)
* Fixed issues with project tree when files are directly added to `RESOURCES`
(QTCREATORBUG-20103)
* Fixed that importing build unnecessarily created temporary kit
(QTCREATORBUG-18153)
CMake Projects
@@ -78,6 +82,8 @@ C++ Support
* Clang Code Model
* Added buttons for copying and ignoring diagnostics to tooltip
* Fixed issue with high memory consumption (QTCREATORBUG-19543)
* Fixed inconsistency between `Follow Symbol` and `Ctrl + Click`
(QTCREATORBUG-21637)
* Clang Format
* Added option to format code instead of only indenting code
@@ -98,6 +104,9 @@ Nim Support
Debugging
* Fixed that debugger toolbar could force large minimum window size
(QTCREATORBUG-21885)
* Added pretty printing of `QSizePolicy`
* GDB
* Added support for rvalue references in function arguments
* LLDB
@@ -167,6 +176,7 @@ Windows
* Added support for MSVC 2019
* Changed toolchain detection to use `vswhere` by default, which is recommended
by Microsoft
* Fixed issue with UNC paths in `.pro` files (QTCREATORBUG-21881)
Linux

View File

@@ -109,15 +109,19 @@ linux {
macx {
APPBUNDLE = "$$OUT_PWD/bin/$${IDE_APP_TARGET}.app"
BINDIST_SOURCE = "$$OUT_PWD/bin/$${IDE_APP_TARGET}.app"
BINDIST_SOURCE.release = "$$OUT_PWD/bin/$${IDE_APP_TARGET}.app"
BINDIST_SOURCE.debug = "$$OUT_PWD/bin"
BINDIST_EXCLUDE_ARG.debug = "--exclude-toplevel"
deployqt.commands = $$PWD/scripts/deployqtHelper_mac.sh \"$${APPBUNDLE}\" \"$$[QT_INSTALL_BINS]\" \"$$[QT_INSTALL_TRANSLATIONS]\" \"$$[QT_INSTALL_PLUGINS]\" \"$$[QT_INSTALL_IMPORTS]\" \"$$[QT_INSTALL_QML]\"
codesign.commands = codesign --deep -s \"$(SIGNING_IDENTITY)\" $(SIGNING_FLAGS) \"$${APPBUNDLE}\"
dmg.commands = python -u \"$$PWD/scripts/makedmg.py\" \"$${BASENAME}.dmg\" \"Qt Creator\" \"$$IDE_SOURCE_TREE\" \"$$OUT_PWD/bin\"
#dmg.depends = deployqt
QMAKE_EXTRA_TARGETS += codesign dmg
} else {
BINDIST_SOURCE = "$(INSTALL_ROOT)$$QTC_PREFIX"
BINDIST_EXCLUDE_ARG = "--exclude-toplevel"
BINDIST_SOURCE.release = "$(INSTALL_ROOT)$$QTC_PREFIX"
BINDIST_EXCLUDE_ARG.release = "--exclude-toplevel"
BINDIST_SOURCE.debug = $${BINDIST_SOURCE.release}
BINDIST_EXCLUDE_ARG.debug = $${BINDIST_EXCLUDE_ARG.release}
deployqt.commands = python -u $$PWD/scripts/deployqt.py -i \"$(INSTALL_ROOT)$$QTC_PREFIX/bin/$${IDE_APP_TARGET}\" \"$(QMAKE)\"
deployqt.depends = install
win32 {
@@ -140,9 +144,9 @@ isEmpty(INSTALLER_ARCHIVE_FROM_ENV) {
INSTALLER_ARCHIVE_DEBUG = $$INSTALLER_ARCHIVE
INSTALLER_ARCHIVE_DEBUG ~= s/(.*)[.]7z/\1-debug.7z
bindist.commands = python -u $$PWD/scripts/createDistPackage.py $$OUT_PWD/$${BASENAME}.7z \"$$BINDIST_SOURCE\"
bindist_installer.commands = python -u $$PWD/scripts/createDistPackage.py $$BINDIST_EXCLUDE_ARG $${INSTALLER_ARCHIVE} \"$$BINDIST_SOURCE\"
bindist_debug.commands = python -u $$PWD/scripts/createDistPackage.py --debug $$BINDIST_EXCLUDE_ARG $${INSTALLER_ARCHIVE_DEBUG} \"$$BINDIST_SOURCE\"
bindist.commands = python -u $$PWD/scripts/createDistPackage.py $$OUT_PWD/$${BASENAME}.7z \"$${BINDIST_SOURCE.release}\"
bindist_installer.commands = python -u $$PWD/scripts/createDistPackage.py $${BINDIST_EXCLUDE_ARG.release} $${INSTALLER_ARCHIVE} \"$${BINDIST_SOURCE.release}\"
bindist_debug.commands = python -u $$PWD/scripts/createDistPackage.py --debug $${BINDIST_EXCLUDE_ARG.debug} $${INSTALLER_ARCHIVE_DEBUG} \"$${BINDIST_SOURCE.debug}\"
win32 {
deployqt.commands ~= s,/,\\\\,g

50
scripts/flake2tasks.py Executable file
View File

@@ -0,0 +1,50 @@
#!/usr/bin/env python
############################################################################
#
# Copyright (C) 2019 The Qt Company Ltd.
# Contact: https://www.qt.io/licensing/
#
# This file is part of Qt Creator.
#
# Commercial License Usage
# Licensees holding valid commercial Qt licenses may use this file in
# accordance with the commercial license agreement provided with the
# Software or, alternatively, in accordance with the terms contained in
# a written agreement between you and The Qt Company. For licensing terms
# and conditions see https://www.qt.io/terms-conditions. For further
# information use the contact form at https://www.qt.io/contact-us.
#
# GNU General Public License Usage
# Alternatively, this file may be used under the terms of the GNU
# General Public License version 3 as published by the Free Software
# Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
# included in the packaging of this file. Please review the following
# information to ensure the GNU General Public License requirements will
# be met: https://www.gnu.org/licenses/gpl-3.0.html.
#
############################################################################
'''
flake2tasks.py - Convert flake8 warnings into Qt Creator task files.
SYNOPSIS
flake2tasks.py < logfile > taskfile
'''
import sys
import re
if __name__ == '__main__':
pattern = re.compile(r'^([^:]+):(\d+):\d+: E\d+ (.*)$')
while True:
line = sys.stdin.readline().rstrip()
if not line:
break
match = pattern.match(line)
if match:
file_name = match.group(1).replace('\\', '/')
line_number = match.group(2)
text = match.group(3)
output = "{}\t{}\twarn\t{}".format(file_name, line_number, text)
print(output)

View File

@@ -957,6 +957,12 @@ class Dumper(DumperBase):
return
self.report('pid="%s"' % self.process.GetProcessID())
self.reportState('enginerunandinferiorrunok')
if self.target is not None:
broadcaster = self.target.GetBroadcaster()
listener = self.debugger.GetListener()
broadcaster.AddListener(listener, lldb.SBTarget.eBroadcastBitBreakpointChanged)
listener.StartListeningForEvents(broadcaster, lldb.SBTarget.eBroadcastBitBreakpointChanged)
def loop(self):
event = lldb.SBEvent()
@@ -1116,6 +1122,11 @@ class Dumper(DumperBase):
# logview pane feature.
self.report('token(\"%s\")' % args["token"])
def reportBreakpointUpdate(self, bp):
self.report('breakpointmodified={%s}' % self.describeBreakpoint(bp))
def readRawMemory(self, address, size):
if size == 0:
return bytes()
@@ -1288,7 +1299,20 @@ class Dumper(DumperBase):
self.process.Kill()
self.reportResult('', args)
def handleBreakpointEvent(self, event):
eventType = lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent(event)
# handle only the resolved locations for now..
if eventType & lldb.eBreakpointEventTypeLocationsResolved:
bp = lldb.SBBreakpoint.GetBreakpointFromEvent(event)
if bp is not None:
self.reportBreakpointUpdate(bp)
def handleEvent(self, event):
if lldb.SBBreakpoint.EventIsBreakpointEvent(event):
self.handleBreakpointEvent(event)
return
out = lldb.SBStream()
event.GetDescription(out)
#warn("EVENT: %s" % event)

View File

@@ -3,7 +3,7 @@
"supportedProjectTypes": [ "PythonProject" ],
"id": "U.QtForPythonApplicationEmpty",
"category": "F.Application",
"trDescription": "Creates a Qt for Python application that only the main code for a QApplication",
"trDescription": "Creates a Qt for Python application that contains only the main code for a QApplication.",
"trDisplayName": "Qt for Python - Empty",
"trDisplayCategory": "Application",
"icon": "icon.png",

View File

@@ -5,8 +5,9 @@ TEMPLATE = app
CONFIG += qtc_runnable sliced_bundle
TARGET = $$IDE_APP_TARGET
DESTDIR = $$IDE_APP_PATH
VERSION = $$QTCREATOR_VERSION
QT -= testlib
# work around QTBUG-74265
win32: VERSION=
HEADERS += ../tools/qtcreatorcrashhandler/crashhandlersetup.h
SOURCES += main.cpp ../tools/qtcreatorcrashhandler/crashhandlersetup.cpp

View File

@@ -51,6 +51,7 @@ public:
commandLine.reserve(1024);
addCompiler(projectInfo.language);
disableWarnings();
addToolChainArguments(toolChainArguments);
addExtraFlags();
addLanguage(projectInfo, sourceType);
@@ -74,6 +75,8 @@ public:
commandLine.emplace_back("clang");
}
void disableWarnings() { commandLine.emplace_back("-w"); }
void addToolChainArguments(const Utils::SmallStringVector &toolChainArguments)
{
for (Utils::SmallStringView argument : toolChainArguments)

View File

@@ -143,6 +143,8 @@ public:
const Sqlite::Column &projectPartIdColumn = table.addColumn("projectPartId", Sqlite::ColumnType::Integer);
const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
table.addColumn("sourceType", Sqlite::ColumnType::Integer);
table.addColumn("pchCreationTimeStamp", Sqlite::ColumnType::Integer);
table.addColumn("hasMissingIncludes", Sqlite::ColumnType::Integer);
table.addUniqueIndex({sourceIdColumn, projectPartIdColumn});
table.addIndex({projectPartIdColumn});
@@ -168,11 +170,11 @@ public:
Sqlite::Table table;
table.setUseIfNotExists(true);
table.setName("fileStatuses");
table.addColumn("sourceId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
table.addColumn("sourceId",
Sqlite::ColumnType::Integer,
Sqlite::Contraint::PrimaryKey);
table.addColumn("size", Sqlite::ColumnType::Integer);
table.addColumn("lastModified", Sqlite::ColumnType::Integer);
table.addColumn("buildDependencyTimeStamp", Sqlite::ColumnType::Integer);
table.addColumn("isInPrecompiledHeader", Sqlite::ColumnType::Integer);
table.initialize(database);
}

View File

@@ -264,7 +264,7 @@ int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) const
break;
} else if (tk.is(T_LPAREN) || tk.is(T_LBRACE)) {
return scanner.startPosition() + tk.utf16charsBegin();
} else if (tk.is(T_RPAREN)) {
} else if (tk.is(T_RPAREN) || tk.is(T_RBRACE)) {
int matchingBrace = scanner.startOfMatchingBrace(index);
if (matchingBrace == index) // If no matching brace found

View File

@@ -31,9 +31,27 @@ for(l, SUBDIRS) {
}
SUBDIRS += \
utils/process_stub.pro \
3rdparty/syntax-highlighting \
3rdparty/syntax-highlighting/data
utils/process_stub.pro
isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR): KSYNTAXHIGHLIGHTING_LIB_DIR=$$(KSYNTAXHIGHLIGHTING_LIB_DIR)
!isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) {
# enable short information message
KSYNTAX_WARN_ON = 1
}
include(../shared/syntax/syntax_shared.pri)
isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) {
SUBDIRS += \
3rdparty/syntax-highlighting \
3rdparty/syntax-highlighting/data
equals(KSYNTAX_WARN_ON, 1) {
message("Either KSYNTAXHIGHLIGHTING_LIB_DIR does not exist or include path could not be deduced.")
unset(KSYNTAX_WARN_ON)
}
} else {
message("Using KSyntaxHighlighting provided at $${KSYNTAXHIGHLIGHTING_LIB_DIR}.")
}
win32:SUBDIRS += utils/process_ctrlc_stub.pro

View File

@@ -748,8 +748,8 @@ void Check::endVisit(UiObjectInitializer *)
{
m_propertyStack.pop();
m_typeStack.pop();
UiObjectDefinition *objectDenition = cast<UiObjectDefinition *>(parent());
if (objectDenition && objectDenition->qualifiedTypeNameId->name == "Component")
UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(parent());
if (objectDefinition && objectDefinition->qualifiedTypeNameId->name == "Component")
m_idStack.pop();
UiObjectBinding *objectBinding = cast<UiObjectBinding *>(parent());
if (objectBinding && objectBinding->qualifiedTypeNameId->name == "Component")

View File

@@ -69,7 +69,7 @@ SshRemoteProcess::SshRemoteProcess(const QByteArray &command, const QStringList
connect(this, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this] {
QString error;
if (exitStatus() == QProcess::CrashExit)
error = tr("The ssh binary crashed: %1").arg(errorString());
error = tr("The ssh process crashed: %1").arg(errorString());
else if (exitCode() == 255)
error = tr("Remote process crashed.");
emit done(error);

View File

@@ -311,9 +311,10 @@ QString FileUtils::normalizePathName(const QString &name)
if (FAILED(hr))
return name;
TCHAR buffer[MAX_PATH];
if (!SHGetPathFromIDList(file, buffer))
return name;
return QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const ushort *>(buffer)));
const bool success = SHGetPathFromIDList(file, buffer);
ILFree(file);
return success ? QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const ushort *>(buffer)))
: name;
#elif defined(Q_OS_OSX)
return Internal::normalizePathName(name);
#else // do not try to handle case-insensitive file systems on Linux

View File

@@ -63,9 +63,9 @@ QVariant Utils::JsonTreeItem::data(int column, int role) const
if (column == 2)
return typeName(m_value.type());
if (m_value.isObject())
return QString('[' + QString::number(m_value.toObject().size()) + ' ' + tr("Items") + ']');
return QString('[' + tr("%n Items", nullptr, m_value.toObject().size()) + ']');
if (m_value.isArray())
return QString('[' + QString::number(m_value.toArray().size()) + ' ' + tr("Items") + ']');
return QString('[' + tr("%n Items", nullptr, m_value.toArray().size()) + ']');
return m_value.toVariant();
}

View File

@@ -171,7 +171,8 @@ LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset)
lineColumn.line = static_cast<int>(
std::count(utf8Buffer.begin(), utf8Buffer.begin() + utf8Offset, '\n'))
+ 1;
const int startOfLineOffset = utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1;
const int startOfLineOffset = utf8Offset ? (utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1)
: 0;
lineColumn.column = QString::fromUtf8(
utf8Buffer.mid(startOfLineOffset, utf8Offset - startOfLineOffset))
.length()
@@ -181,7 +182,9 @@ LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset)
QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset)
{
const int lineStartUtf8Offset = utf8Buffer.lastIndexOf('\n', currentUtf8Offset - 1) + 1;
const int lineStartUtf8Offset = currentUtf8Offset
? (utf8Buffer.lastIndexOf('\n', currentUtf8Offset - 1) + 1)
: 0;
const int lineEndUtf8Offset = utf8Buffer.indexOf('\n', currentUtf8Offset);
return QString::fromUtf8(
utf8Buffer.mid(lineStartUtf8Offset, lineEndUtf8Offset - lineStartUtf8Offset));

View File

@@ -101,7 +101,7 @@ public:
setSummaryText(displayName());
auto uninstallPreviousPackage = new QCheckBox(this);
uninstallPreviousPackage->setText(tr("Uninstall previous package"));
uninstallPreviousPackage->setText(AndroidDeployQtStep::tr("Uninstall previous package"));
uninstallPreviousPackage->setChecked(step->uninstallPreviousPackage() > AndroidDeployQtStep::Keep);
uninstallPreviousPackage->setEnabled(step->uninstallPreviousPackage() != AndroidDeployQtStep::ForceUnintall);

View File

@@ -68,13 +68,12 @@ void ClangCodeModelPlugin::generateCompilationDB() {
using namespace CppTools;
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
if (!project)
if (!project || !project->activeTarget())
return;
m_generatorWatcher.setFuture(QtConcurrent::run(
&Utils::generateCompilationDB,
project->projectDirectory(),
CppModelManager::instance()->projectInfo(project)));
m_generatorWatcher.setFuture(
QtConcurrent::run(&Utils::generateCompilationDB,
CppModelManager::instance()->projectInfo(project)));
}
static bool isDBGenerationEnabled(ProjectExplorer::Project *project)

View File

@@ -214,6 +214,9 @@ void ClangCompletionAssistProcessor::handleAvailableCompletions(const CodeComple
setAsyncProposalAvailable(createFunctionHintProposal(completions));
return;
}
if (!m_fallbackToNormalCompletion)
return;
// else: Proceed with a normal completion in case:
// 1) it was not a function call, but e.g. a function declaration like "void f("
// 2) '{' meant not a constructor call.
@@ -286,6 +289,14 @@ static QByteArray modifyInput(QTextDocument *doc, int endOfExpression) {
return modifiedInput;
}
static QChar lastPrecedingNonWhitespaceChar(const ClangCompletionAssistInterface *interface)
{
int pos = interface->position();
while (pos >= 0 && interface->characterAt(pos).isSpace())
--pos;
return pos >= 0 ? interface->characterAt(pos) : QChar::Null;
}
IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper()
{
ClangCompletionContextAnalyzer analyzer(m_interface.data(), m_interface->languageFeatures());
@@ -323,6 +334,8 @@ IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper()
}
case ClangCompletionContextAnalyzer::PassThroughToLibClangAfterLeftParen: {
m_sentRequestType = FunctionHintCompletion;
if (lastPrecedingNonWhitespaceChar(m_interface.data()) == ',')
m_fallbackToNormalCompletion = false;
m_requestSent = sendCompletionRequest(analyzer.positionForClang(), QByteArray(),
analyzer.functionNameStart());
break;

View File

@@ -97,6 +97,7 @@ private:
CompletionRequestType m_sentRequestType = NormalCompletion;
bool m_requestSent = false;
bool m_addSnippets = false; // For type == Type::NormalCompletion
bool m_fallbackToNormalCompletion = true;
};
} // namespace Internal

View File

@@ -110,6 +110,8 @@ int ClangCompletionContextAnalyzer::startOfFunctionCall(int endOfOperator) const
functionNameSelector.setPosition(functionNameStart);
functionNameSelector.setPosition(index, QTextCursor::KeepAnchor);
const QString functionName = functionNameSelector.selectedText().trimmed();
if (functionName.isEmpty() && m_completionOperator == T_LBRACE)
return endOfOperator;
return functionName.isEmpty() ? -1 : functionNameStart;
}
@@ -139,7 +141,10 @@ void ClangCompletionContextAnalyzer::handleCommaInFunctionCall()
const int start = expressionUnderCursor.startOfFunctionCall(textCursor);
m_positionEndOfExpression = start;
m_positionForProposal = start + 1; // After '(' of function call
m_completionOperator = T_LPAREN;
if (m_interface->characterAt(start) == '(')
m_completionOperator = T_LPAREN;
else
m_completionOperator = T_LBRACE;
}
}

View File

@@ -34,12 +34,13 @@
#include <coreplugin/idocument.h>
#include <cpptools/baseeditordocumentparser.h>
#include <cpptools/compileroptionsbuilder.h>
#include <cpptools/cppcodemodelsettings.h>
#include <cpptools/cppmodelmanager.h>
#include <cpptools/cpptoolsreuse.h>
#include <cpptools/editordocumenthandle.h>
#include <cpptools/projectpart.h>
#include <cpptools/cppcodemodelsettings.h>
#include <cpptools/cpptoolsreuse.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
@@ -300,12 +301,24 @@ QString diagnosticCategoryPrefixRemoved(const QString &text)
return text;
}
static ::Utils::FileName buildDirectory(const CppTools::ProjectPart &projectPart)
static ::Utils::FileName compilerPath(const CppTools::ProjectPart &projectPart)
{
ProjectExplorer::Target *target = projectPart.project->activeTarget();
if (!target)
return ::Utils::FileName();
ProjectExplorer::ToolChain *toolchain = ProjectExplorer::ToolChainKitAspect::toolChain(
target->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID);
return toolchain->compilerCommand();
}
static ::Utils::FileName buildDirectory(const ProjectExplorer::Project &project)
{
ProjectExplorer::Target *target = project.activeTarget();
if (!target)
return ::Utils::FileName();
ProjectExplorer::BuildConfiguration *buildConfig = target->activeBuildConfiguration();
if (!buildConfig)
return ::Utils::FileName();
@@ -313,42 +326,84 @@ static ::Utils::FileName buildDirectory(const CppTools::ProjectPart &projectPart
return buildConfig->buildDirectory();
}
static QJsonObject createFileObject(CompilerOptionsBuilder &optionsBuilder,
const ProjectFile &projFile,
const ::Utils::FileName &buildDir)
static QStringList projectPartArguments(const ProjectPart &projectPart)
{
const ProjectFile::Kind kind = ProjectFile::classify(projFile.path);
optionsBuilder.updateFileLanguage(kind);
QStringList args;
args << compilerPath(projectPart).toString();
args << "-c";
if (projectPart.toolchainType != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) {
args << "--target=" + projectPart.toolChainTargetTriple;
args << (projectPart.toolChainWordWidth == ProjectPart::WordWidth64Bit
? QLatin1String("-m64")
: QLatin1String("-m32"));
}
args << projectPart.compilerFlags;
for (const ProjectExplorer::HeaderPath &headerPath : projectPart.headerPaths) {
if (headerPath.type == ProjectExplorer::HeaderPathType::User) {
args << "-I" + headerPath.path;
} else if (headerPath.type == ProjectExplorer::HeaderPathType::System) {
args << (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID
? "-I"
: "-isystem")
+ headerPath.path;
}
}
for (const ProjectExplorer::Macro &macro : projectPart.projectMacros) {
args.append(QString::fromUtf8(
macro.toKeyValue(macro.type == ProjectExplorer::MacroType::Define ? "-D" : "-U")));
}
return args;
}
static QJsonObject createFileObject(const ::Utils::FileName &buildDir,
const QStringList &arguments,
const ProjectPart &projectPart,
const ProjectFile &projFile)
{
QJsonObject fileObject;
fileObject["file"] = projFile.path;
QJsonArray args = QJsonArray::fromStringList(optionsBuilder.options());
args.prepend(kind == ProjectFile::CXXSource ? "clang++" : "clang");
QJsonArray args = QJsonArray::fromStringList(arguments);
const ProjectFile::Kind kind = ProjectFile::classify(projFile.path);
if (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID
|| projectPart.toolchainType == ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID) {
if (ProjectFile::isC(kind))
args.append("/TC");
else if (ProjectFile::isCxx(kind))
args.append("/TP");
} else {
QStringList langOption
= createLanguageOptionGcc(kind,
projectPart.languageExtensions
& ::Utils::LanguageExtension::ObjectiveC);
for (const QString &langOptionPart : langOption)
args.append(langOptionPart);
}
args.append(QDir::toNativeSeparators(projFile.path));
fileObject["arguments"] = args;
fileObject["directory"] = buildDir.toString();
return fileObject;
}
void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo)
void generateCompilationDB(CppTools::ProjectInfo projectInfo)
{
QFile compileCommandsFile(projectDir.toString() + "/compile_commands.json");
const ::Utils::FileName buildDir = buildDirectory(*projectInfo.project());
QTC_ASSERT(!buildDir.isEmpty(), return;);
QDir dir(buildDir.toString());
if (!dir.exists())
dir.mkpath(dir.path());
QFile compileCommandsFile(buildDir.toString() + "/compile_commands.json");
const bool fileOpened = compileCommandsFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
if (!fileOpened)
return;
compileCommandsFile.write("[");
for (ProjectPart::Ptr projectPart : projectInfo.projectParts()) {
const ::Utils::FileName buildDir = buildDirectory(*projectPart);
CompilerOptionsBuilder optionsBuilder(*projectPart,
UseSystemHeader::No,
UseTweakedHeaderPaths::No);
optionsBuilder.build(CppTools::ProjectFile::Unclassified,
CppTools::UsePrecompiledHeaders::No);
const QStringList args = projectPartArguments(*projectPart);
for (const ProjectFile &projFile : projectPart->files) {
const QJsonObject json = createFileObject(optionsBuilder, projFile, buildDir);
const QJsonObject json = createFileObject(buildDir, args, *projectPart, projFile);
if (compileCommandsFile.size() > 1)
compileCommandsFile.write(",");
compileCommandsFile.write('\n' + QJsonDocument(json).toJson().trimmed());

View File

@@ -70,7 +70,7 @@ QString diagnosticCategoryPrefixRemoved(const QString &text);
::Utils::CodeModelIcon::Type iconTypeForToken(const ClangBackEnd::TokenInfoContainer &token);
void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo);
void generateCompilationDB(CppTools::ProjectInfo projectInfo);
class DiagnosticTextInfo
{

View File

@@ -2,7 +2,7 @@
\"Name\" : \"ClangFormat\",
\"Version\" : \"$$QTCREATOR_VERSION\",
\"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
\"Experimental\" : true,
\"DisabledByDefault\" : true,
\"Vendor\" : \"The Qt Company Ltd\",
\"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\",
\"License\" : [ \"Commercial Usage\",

View File

@@ -29,9 +29,10 @@
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/textutils.h>
#include <utils/qtcassert.h>
#include <utils/textutils.h>
#include <QDebug>
#include <QTextDocument>
namespace ClangFormat {
@@ -126,9 +127,85 @@ void trimRHSWhitespace(const QTextBlock &block)
cursor.endEditBlock();
}
QTextBlock reverseFindLastEmptyBlock(QTextBlock start)
{
if (start.position() > 0) {
start = start.previous();
while (start.position() > 0 && start.text().trimmed().isEmpty())
start = start.previous();
if (!start.text().trimmed().isEmpty())
start = start.next();
}
return start;
}
enum class CharacterContext { AfterComma, LastAfterComma, NewStatement, Continuation, Unknown };
QChar findFirstNonWhitespaceCharacter(const QTextBlock &currentBlock)
{
const QTextDocument *doc = currentBlock.document();
int currentPos = currentBlock.position();
while (currentPos < doc->characterCount() && doc->characterAt(currentPos).isSpace())
++currentPos;
return currentPos < doc->characterCount() ? doc->characterAt(currentPos) : QChar::Null;
}
CharacterContext characterContext(const QTextBlock &currentBlock,
const QTextBlock &previousNonEmptyBlock)
{
const QString prevLineText = previousNonEmptyBlock.text().trimmed();
const QChar firstNonWhitespaceChar = findFirstNonWhitespaceCharacter(currentBlock);
if (prevLineText.endsWith(',')) {
// We don't need to add comma in case it's the last argument.
if (firstNonWhitespaceChar == '}' || firstNonWhitespaceChar == ')')
return CharacterContext::LastAfterComma;
return CharacterContext::AfterComma;
}
if (prevLineText.endsWith(';') || prevLineText.endsWith('{') || prevLineText.endsWith('}')
|| firstNonWhitespaceChar == QChar::Null) {
return CharacterContext::NewStatement;
}
return CharacterContext::Continuation;
}
bool nextBlockExistsAndEmpty(const QTextBlock &currentBlock)
{
QTextBlock nextBlock = currentBlock.next();
if (!nextBlock.isValid() || nextBlock.position() == currentBlock.position())
return false;
return nextBlock.text().trimmed().isEmpty();
}
QByteArray dummyTextForContext(CharacterContext context, bool closingBraceBlock)
{
if (closingBraceBlock
&& (context == CharacterContext::NewStatement
|| context == CharacterContext::Continuation)) {
return QByteArray();
}
switch (context) {
case CharacterContext::Unknown:
QTC_ASSERT(false, return "";);
case CharacterContext::AfterComma:
return "a,";
case CharacterContext::NewStatement:
return "a;";
case CharacterContext::Continuation:
case CharacterContext::LastAfterComma:
return "& a &";
}
}
// Add extra text in case of the empty line or the line starting with ')'.
// Track such extra pieces of text in isInsideModifiedLine().
int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool secondTry)
int forceIndentWithExtraText(QByteArray &buffer,
CharacterContext &charContext,
const QTextBlock &block,
bool secondTry)
{
const QString blockText = block.text();
int firstNonWhitespace = Utils::indexOf(blockText,
@@ -143,26 +220,33 @@ int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool s
const bool closingParenBlock = firstNonWhitespace >= 0
&& blockText.at(firstNonWhitespace) == ')';
const bool closingBraceBlock = firstNonWhitespace >= 0
&& blockText.at(firstNonWhitespace) == '}';
int extraLength = 0;
if (firstNonWhitespace < 0 || closingParenBlock) {
//This extra text works for the most cases.
QByteArray dummyText("a;a;");
QByteArray dummyText;
if (firstNonWhitespace < 0 && charContext != CharacterContext::Unknown
&& nextBlockExistsAndEmpty(block)) {
// If the next line is also empty it's safer to use a comment line.
dummyText = "//";
} else if (firstNonWhitespace < 0 || closingParenBlock || closingBraceBlock) {
if (charContext == CharacterContext::LastAfterComma) {
charContext = CharacterContext::AfterComma;
} else if (charContext == CharacterContext::Unknown || firstNonWhitespace >= 0) {
QTextBlock lastBlock = reverseFindLastEmptyBlock(block);
if (lastBlock.position() > 0)
lastBlock = lastBlock.previous();
// Search for previous character
QTextBlock prevBlock = block.previous();
bool prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty();
while (prevBlockIsEmpty) {
prevBlock = prevBlock.previous();
prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty();
// If we don't know yet the dummy text, let's guess it and use for this line and before.
charContext = characterContext(block, lastBlock);
}
if (closingParenBlock || prevBlock.text().endsWith(','))
dummyText = "&& a";
buffer.insert(utf8Offset, dummyText);
extraLength += dummyText.length();
dummyText = dummyTextForContext(charContext, closingBraceBlock);
}
buffer.insert(utf8Offset, dummyText);
extraLength += dummyText.length();
if (secondTry) {
int nextLinePos = buffer.indexOf('\n', utf8Offset);
if (nextLinePos < 0)
@@ -170,7 +254,7 @@ int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool s
if (nextLinePos > 0) {
// If first try was not successful try to put ')' in the end of the line to close possibly
// unclosed parentheses.
// unclosed parenthesis.
// TODO: Does it help to add different endings depending on the context?
buffer.insert(nextLinePos, ')');
extraLength += 1;
@@ -300,18 +384,6 @@ bool doNotIndentInContext(QTextDocument *doc, int pos)
return false;
}
QTextBlock reverseFindLastEmptyBlock(QTextBlock start)
{
if (start.position() > 0) {
start = start.previous();
while (start.position() > 0 && start.text().trimmed().isEmpty())
start = start.previous();
if (!start.text().trimmed().isEmpty())
start = start.next();
}
return start;
}
int formattingRangeStart(const QTextBlock &currentBlock,
const QByteArray &buffer,
int documentRevision)
@@ -355,23 +427,14 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
rangeStart = formattingRangeStart(startBlock, buffer, lastSaveRevision());
adjustFormatStyleForLineBreak(style, replacementsToKeep);
if (typedChar == QChar::Null) {
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) {
if (utf8Offset > 0) {
buffer.insert(utf8Offset - 1, " //");
utf8Offset += 3;
}
if (replacementsToKeep == ReplacementsToKeep::OnlyIndent) {
CharacterContext currentCharContext = CharacterContext::Unknown;
// Iterate backwards to reuse the same dummy text for all empty lines.
for (int index = endBlock.blockNumber(); index >= startBlock.blockNumber(); --index) {
utf8Length += forceIndentWithExtraText(buffer,
cursorPositionInEditor < 0
? endBlock
: m_doc->findBlock(cursorPositionInEditor),
currentCharContext,
m_doc->findBlockByNumber(index),
secondTry);
} else {
for (int index = startBlock.blockNumber(); index <= endBlock.blockNumber(); ++index) {
utf8Length += forceIndentWithExtraText(buffer,
m_doc->findBlockByNumber(index),
secondTry);
}
}
}
@@ -432,9 +495,24 @@ TextEditor::Replacements ClangFormatBaseIndenter::format(
static_cast<unsigned int>(utf8RangeLength));
}
clang::format::FormatStyle style = styleForFile();
const std::string assumedFileName = m_fileName.toString().toStdString();
clang::tooling::Replacements clangReplacements = clang::format::sortIncludes(style,
buffer.data(),
ranges,
assumedFileName);
auto changedCode = clang::tooling::applyAllReplacements(buffer.data(), clangReplacements);
QTC_ASSERT(changedCode, {
qDebug() << QString::fromStdString(llvm::toString(changedCode.takeError()));
return TextEditor::Replacements();
});
ranges = clang::tooling::calculateRangesAfterReplacements(clangReplacements, ranges);
clang::format::FormattingAttemptStatus status;
const clang::tooling::Replacements clangReplacements
= reformat(styleForFile(), buffer.data(), ranges, m_fileName.toString().toStdString(), &status);
const clang::tooling::Replacements formatReplacements
= reformat(style, *changedCode, ranges, m_fileName.toString().toStdString(), &status);
clangReplacements = clangReplacements.merge(formatReplacements);
const TextEditor::Replacements toReplace = utf16Replacements(m_doc, buffer, clangReplacements);
applyReplacements(m_doc, toReplace);
@@ -443,7 +521,6 @@ TextEditor::Replacements ClangFormatBaseIndenter::format(
TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlock,
const QTextBlock &endBlock,
const QByteArray &buffer,
const QChar &typedChar,
int cursorPositionInEditor)
{
@@ -461,10 +538,12 @@ TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlo
cursorPositionInEditor += startBlock.position() - startBlockPosition;
}
const QByteArray buffer = m_doc->toPlainText().toUtf8();
ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent;
if (formatWhileTyping()
&& (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition)
&& (typedChar == QChar::Null || typedChar == ';' || typedChar == '}')) {
&& (typedChar == ';' || typedChar == '}')) {
// Format before current position only in case the cursor is inside the indented block.
// So if cursor position is less then the block position then the current line is before
// the indented block - don't trigger extra formatting in this case.
@@ -487,9 +566,7 @@ void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock,
const QChar &typedChar,
int cursorPositionInEditor)
{
const QByteArray buffer = m_doc->toPlainText().toUtf8();
applyReplacements(m_doc,
indentsFor(startBlock, endBlock, buffer, typedChar, cursorPositionInEditor));
applyReplacements(m_doc, indentsFor(startBlock, endBlock, typedChar, cursorPositionInEditor));
}
void ClangFormatBaseIndenter::indent(const QTextCursor &cursor,
@@ -533,15 +610,14 @@ int ClangFormatBaseIndenter::indentFor(const QTextBlock &block,
const TextEditor::TabSettings & /*tabSettings*/,
int cursorPositionInEditor)
{
const QByteArray buffer = m_doc->toPlainText().toUtf8();
TextEditor::Replacements toReplace = indentsFor(block,
block,
buffer,
QChar::Null,
cursorPositionInEditor);
if (toReplace.empty())
return -1;
const QByteArray buffer = m_doc->toPlainText().toUtf8();
return indentationForBlock(toReplace, buffer, block);
}
@@ -553,13 +629,12 @@ TextEditor::IndentationForBlock ClangFormatBaseIndenter::indentationForBlocks(
TextEditor::IndentationForBlock ret;
if (blocks.isEmpty())
return ret;
const QByteArray buffer = m_doc->toPlainText().toUtf8();
TextEditor::Replacements toReplace = indentsFor(blocks.front(),
blocks.back(),
buffer,
QChar::Null,
cursorPositionInEditor);
const QByteArray buffer = m_doc->toPlainText().toUtf8();
for (const QTextBlock &block : blocks)
ret.insert(block.blockNumber(), indentationForBlock(toReplace, buffer, block));
return ret;

View File

@@ -81,7 +81,6 @@ private:
int cursorPositionInEditor);
TextEditor::Replacements indentsFor(QTextBlock startBlock,
const QTextBlock &endBlock,
const QByteArray &buffer,
const QChar &typedChar,
int cursorPositionInEditor);
TextEditor::Replacements replacements(QByteArray buffer,

View File

@@ -59,6 +59,24 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(ProjectExplorer::Project *proje
{
m_ui->setupUi(this);
m_preview = new TextEditor::SnippetEditorWidget(this);
m_ui->horizontalLayout_2->addWidget(m_preview);
if (m_project) {
m_ui->applyButton->show();
hideGlobalCheckboxes();
m_ui->overrideDefault->setChecked(
m_project->namedSettings(Constants::OVERRIDE_FILE_ID).toBool());
} else {
m_ui->applyButton->hide();
showGlobalCheckboxes();
m_ui->overrideDefault->setChecked(ClangFormatSettings::instance().overrideDefaultFile());
}
connect(m_ui->overrideDefault, &QCheckBox::toggled, this, [this](bool checked) {
if (checked)
createStyleFileIfNeeded(!m_project);
initialize();
});
initialize();
}
@@ -81,15 +99,19 @@ void ClangFormatConfigWidget::showGlobalCheckboxes()
m_ui->formatOnSave->show();
}
static bool projectConfigExists()
{
return Utils::FileName::fromString(Core::ICore::userResourcePath())
.appendPath("clang-format")
.appendPath(currentProjectUniqueId())
.appendPath((Constants::SETTINGS_FILE_NAME))
.exists();
}
void ClangFormatConfigWidget::initialize()
{
m_ui->projectHasClangFormat->show();
m_ui->clangFormatOptionsTable->show();
m_ui->applyButton->show();
hideGlobalCheckboxes();
m_ui->projectHasClangFormat->hide();
m_preview = new TextEditor::SnippetEditorWidget(this);
m_ui->horizontalLayout_2->addWidget(m_preview);
m_preview->setPlainText(QLatin1String(CppTools::Constants::DEFAULT_CODE_STYLE_SNIPPETS[0]));
m_preview->textDocument()->setIndenter(new ClangFormatIndenter(m_preview->document()));
m_preview->textDocument()->setFontSettings(TextEditor::TextEditorSettings::fontSettings());
@@ -103,21 +125,15 @@ void ClangFormatConfigWidget::initialize()
if (lastItem->spacerItem())
m_ui->verticalLayout->removeItem(lastItem);
if (m_project
&& !m_project->projectDirectory().appendPath(Constants::SETTINGS_FILE_NAME).exists()) {
m_ui->projectHasClangFormat->setText(tr("No .clang-format file for the project."));
if (!m_ui->overrideDefault->isChecked()) {
m_ui->clangFormatOptionsTable->hide();
m_ui->applyButton->hide();
m_preview->hide();
m_ui->verticalLayout->addStretch(1);
connect(m_ui->createFileButton, &QPushButton::clicked, this, [this]() {
createStyleFileIfNeeded(false);
initialize();
});
return;
}
m_ui->createFileButton->hide();
m_ui->clangFormatOptionsTable->show();
m_preview->show();
Utils::FileName fileName;
if (m_project) {
@@ -126,19 +142,13 @@ void ClangFormatConfigWidget::initialize()
fileName = m_project->projectFilePath().appendPath("snippet.cpp");
} else {
const Project *currentProject = SessionManager::startupProject();
if (!currentProject
|| !currentProject->projectDirectory()
.appendPath(Constants::SETTINGS_FILE_NAME)
.exists()) {
if (!currentProject || !projectConfigExists()) {
m_ui->projectHasClangFormat->hide();
} else {
m_ui->projectHasClangFormat->setText(
tr("Current project has its own .clang-format file "
tr("Current project has its own overridden .clang-format file "
"and can be configured in Projects > Code Style > C++."));
}
createStyleFileIfNeeded(true);
showGlobalCheckboxes();
m_ui->applyButton->hide();
fileName = Utils::FileName::fromString(Core::ICore::userResourcePath())
.appendPath("snippet.cpp");
}
@@ -160,7 +170,7 @@ void ClangFormatConfigWidget::fillTable()
{
clang::format::FormatStyle style = m_project ? currentProjectStyle() : currentGlobalStyle();
std::string configText = clang::format::configurationAsText(style);
const std::string configText = clang::format::configurationAsText(style);
m_ui->clangFormatOptionsTable->setPlainText(QString::fromStdString(configText));
}
@@ -168,13 +178,19 @@ ClangFormatConfigWidget::~ClangFormatConfigWidget() = default;
void ClangFormatConfigWidget::apply()
{
ClangFormatSettings &settings = ClangFormatSettings::instance();
if (!m_project) {
ClangFormatSettings &settings = ClangFormatSettings::instance();
settings.setFormatCodeInsteadOfIndent(m_ui->formatAlways->isChecked());
settings.setFormatWhileTyping(m_ui->formatWhileTyping->isChecked());
settings.setFormatOnSave(m_ui->formatOnSave->isChecked());
settings.write();
settings.setOverrideDefaultFile(m_ui->overrideDefault->isChecked());
} else {
m_project->setNamedSettings(Constants::OVERRIDE_FILE_ID, m_ui->overrideDefault->isChecked());
}
settings.write();
if (!m_ui->overrideDefault->isChecked())
return;
const QString text = m_ui->clangFormatOptionsTable->toPlainText();
clang::format::FormatStyle style;
@@ -184,16 +200,18 @@ void ClangFormatConfigWidget::apply()
QMessageBox::warning(this,
tr("Error in ClangFormat configuration"),
QString::fromStdString(error.message()));
fillTable();
updatePreview();
if (m_ui->overrideDefault->isChecked()) {
fillTable();
updatePreview();
}
return;
}
QString filePath;
QString filePath = Core::ICore::userResourcePath();
if (m_project)
filePath = m_project->projectDirectory().appendPath(Constants::SETTINGS_FILE_NAME).toString();
else
filePath = Core::ICore::userResourcePath() + "/" + Constants::SETTINGS_FILE_NAME;
filePath += "/clang-format/" + currentProjectUniqueId();
filePath += "/" + QLatin1String(Constants::SETTINGS_FILE_NAME);
QFile file(filePath);
if (!file.open(QFile::WriteOnly))
return;
@@ -201,7 +219,8 @@ void ClangFormatConfigWidget::apply()
file.write(text.toUtf8());
file.close();
updatePreview();
if (m_ui->overrideDefault->isChecked())
updatePreview();
}
} // namespace ClangFormat

View File

@@ -54,6 +54,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="overrideDefault">
<property name="text">
<string>Override Clang Format configuration file</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
@@ -63,13 +70,6 @@
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="createFileButton">
<property name="text">
<string>Create Clang Format Configuration File</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="applyButton">
<property name="text">

View File

@@ -34,5 +34,7 @@ static const char SETTINGS_ID[] = "ClangFormat";
static const char FORMAT_CODE_INSTEAD_OF_INDENT_ID[] = "ClangFormat.FormatCodeInsteadOfIndent";
static const char FORMAT_WHILE_TYPING_ID[] = "ClangFormat.FormatWhileTyping";
static const char FORMAT_CODE_ON_SAVE_ID[] = "ClangFormat.FormatCodeOnSave";
static const char OVERRIDE_FILE_ID[] = "ClangFormat.OverrideFile";
static const char OPEN_CURRENT_CONFIG_ID[] = "ClangFormat.OpenCurrentConfig";
} // namespace Constants
} // namespace ClangFormat

View File

@@ -57,7 +57,7 @@ bool ClangFormatIndenter::formatWhileTyping() const
Utils::optional<TabSettings> ClangFormatIndenter::tabSettings() const
{
FormatStyle style = currentProjectStyle();
FormatStyle style = styleForFile();
TabSettings tabSettings;
switch (style.UseTab) {

View File

@@ -26,16 +26,23 @@
#include "clangformatplugin.h"
#include "clangformatconfigwidget.h"
#include "clangformatconstants.h"
#include "clangformatindenter.h"
#include "clangformatutils.h"
#include <utils/qtcassert.h>
#include <coreplugin/icore.h>
#include <coreplugin/icontext.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
#include <coreplugin/idocument.h>
#include <cppeditor/cppeditorconstants.h>
#include <cpptools/cppcodestylepreferencesfactory.h>
#include <cpptools/cpptoolsconstants.h>
@@ -103,6 +110,48 @@ bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorS
Q_UNUSED(errorString);
#ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED
replaceCppCodeStyle();
Core::ActionContainer *contextMenu = Core::ActionManager::actionContainer(
CppEditor::Constants::M_CONTEXT);
if (contextMenu) {
auto openClangFormatConfigAction
= new QAction(tr("Open Used .clang-format Configuration File"), this);
Core::Command *command
= Core::ActionManager::registerAction(openClangFormatConfigAction,
Constants::OPEN_CURRENT_CONFIG_ID);
contextMenu->addSeparator();
contextMenu->addAction(command);
if (Core::EditorManager::currentEditor()) {
const Core::IDocument *doc = Core::EditorManager::currentEditor()->document();
if (doc)
openClangFormatConfigAction->setData(doc->filePath().toString());
}
connect(openClangFormatConfigAction,
&QAction::triggered,
this,
[openClangFormatConfigAction]() {
const QString fileName = openClangFormatConfigAction->data().toString();
if (!fileName.isEmpty()) {
const QString clangFormatConfigPath = configForFile(
Utils::FileName::fromString(fileName));
Core::EditorManager::openEditor(clangFormatConfigPath);
}
});
connect(Core::EditorManager::instance(),
&Core::EditorManager::currentEditorChanged,
this,
[openClangFormatConfigAction](Core::IEditor *editor) {
if (!editor)
return;
const Core::IDocument *doc = editor->document();
if (doc)
openClangFormatConfigAction->setData(doc->filePath().toString());
});
}
#endif
return true;
}

View File

@@ -46,6 +46,8 @@ ClangFormatSettings::ClangFormatSettings()
.toBool();
m_formatOnSave = settings->value(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), false)
.toBool();
m_overrideDefaultFile = settings->value(QLatin1String(Constants::OVERRIDE_FILE_ID), false)
.toBool();
settings->endGroup();
}
@@ -57,6 +59,7 @@ void ClangFormatSettings::write() const
m_formatCodeInsteadOfIndent);
settings->setValue(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), m_formatWhileTyping);
settings->setValue(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), m_formatOnSave);
settings->setValue(QLatin1String(Constants::OVERRIDE_FILE_ID), m_overrideDefaultFile);
settings->endGroup();
}
@@ -90,4 +93,14 @@ bool ClangFormatSettings::formatOnSave() const
return m_formatOnSave;
}
void ClangFormatSettings::setOverrideDefaultFile(bool enable)
{
m_overrideDefaultFile = enable;
}
bool ClangFormatSettings::overrideDefaultFile() const
{
return m_overrideDefaultFile;
}
} // namespace ClangFormat

View File

@@ -25,6 +25,8 @@
#pragma once
#include <QString>
namespace ClangFormat {
class ClangFormatSettings
@@ -43,10 +45,14 @@ public:
void setFormatOnSave(bool enable);
bool formatOnSave() const;
void setOverrideDefaultFile(bool enable);
bool overrideDefaultFile() const;
private:
bool m_formatCodeInsteadOfIndent = false;
bool m_formatWhileTyping = false;
bool m_formatOnSave = false;
bool m_overrideDefaultFile = false;
};
} // namespace ClangFormat

View File

@@ -26,6 +26,7 @@
#include "clangformatutils.h"
#include "clangformatconstants.h"
#include "clangformatsettings.h"
#include <coreplugin/icore.h>
#include <cpptools/cppcodestylesettings.h>
@@ -33,6 +34,8 @@
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <QCryptographicHash>
using namespace clang;
using namespace format;
using namespace llvm;
@@ -42,6 +45,104 @@ using namespace TextEditor;
namespace ClangFormat {
static clang::format::FormatStyle qtcStyle()
{
clang::format::FormatStyle style = getLLVMStyle();
style.Language = FormatStyle::LK_Cpp;
style.AccessModifierOffset = -4;
style.AlignAfterOpenBracket = FormatStyle::BAS_Align;
style.AlignConsecutiveAssignments = false;
style.AlignConsecutiveDeclarations = false;
style.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign;
style.AlignOperands = true;
style.AlignTrailingComments = true;
style.AllowAllParametersOfDeclarationOnNextLine = true;
style.AllowShortBlocksOnASingleLine = false;
style.AllowShortCaseLabelsOnASingleLine = false;
style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
style.AllowShortIfStatementsOnASingleLine = false;
style.AllowShortLoopsOnASingleLine = false;
style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
style.AlwaysBreakBeforeMultilineStrings = false;
style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes;
style.BinPackArguments = false;
style.BinPackParameters = false;
style.BraceWrapping.AfterClass = true;
style.BraceWrapping.AfterControlStatement = false;
style.BraceWrapping.AfterEnum = false;
style.BraceWrapping.AfterFunction = true;
style.BraceWrapping.AfterNamespace = false;
style.BraceWrapping.AfterObjCDeclaration = false;
style.BraceWrapping.AfterStruct = true;
style.BraceWrapping.AfterUnion = false;
style.BraceWrapping.BeforeCatch = false;
style.BraceWrapping.BeforeElse = false;
style.BraceWrapping.IndentBraces = false;
style.BraceWrapping.SplitEmptyFunction = false;
style.BraceWrapping.SplitEmptyRecord = false;
style.BraceWrapping.SplitEmptyNamespace = false;
style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
style.BreakBeforeBraces = FormatStyle::BS_Custom;
style.BreakBeforeTernaryOperators = true;
style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
style.BreakAfterJavaFieldAnnotations = false;
style.BreakStringLiterals = true;
style.ColumnLimit = 100;
style.CommentPragmas = "^ IWYU pragma:";
style.CompactNamespaces = false;
style.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
style.ConstructorInitializerIndentWidth = 4;
style.ContinuationIndentWidth = 4;
style.Cpp11BracedListStyle = true;
style.DerivePointerAlignment = false;
style.DisableFormat = false;
style.ExperimentalAutoDetectBinPacking = false;
style.FixNamespaceComments = true;
style.ForEachMacros = {"forever", "foreach", "Q_FOREACH", "BOOST_FOREACH"};
style.IncludeStyle.IncludeCategories = {{"^<Q.*", 200}};
style.IncludeStyle.IncludeIsMainRegex = "(Test)?$";
style.IndentCaseLabels = false;
style.IndentWidth = 4;
style.IndentWrappedFunctionNames = false;
style.JavaScriptQuotes = FormatStyle::JSQS_Leave;
style.JavaScriptWrapImports = true;
style.KeepEmptyLinesAtTheStartOfBlocks = false;
// Do not add QT_BEGIN_NAMESPACE/QT_END_NAMESPACE as this will indent lines in between.
style.MacroBlockBegin = "";
style.MacroBlockEnd = "";
style.MaxEmptyLinesToKeep = 1;
style.NamespaceIndentation = FormatStyle::NI_None;
style.ObjCBlockIndentWidth = 4;
style.ObjCSpaceAfterProperty = false;
style.ObjCSpaceBeforeProtocolList = true;
style.PenaltyBreakAssignment = 150;
style.PenaltyBreakBeforeFirstCallParameter = 300;
style.PenaltyBreakComment = 500;
style.PenaltyBreakFirstLessLess = 400;
style.PenaltyBreakString = 600;
style.PenaltyExcessCharacter = 50;
style.PenaltyReturnTypeOnItsOwnLine = 300;
style.PointerAlignment = FormatStyle::PAS_Right;
style.ReflowComments = false;
style.SortIncludes = true;
style.SortUsingDeclarations = true;
style.SpaceAfterCStyleCast = true;
style.SpaceAfterTemplateKeyword = false;
style.SpaceBeforeAssignmentOperators = true;
style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
style.SpaceInEmptyParentheses = false;
style.SpacesBeforeTrailingComments = 1;
style.SpacesInAngles = false;
style.SpacesInContainerLiterals = false;
style.SpacesInCStyleCastParentheses = false;
style.SpacesInParentheses = false;
style.SpacesInSquareBrackets = false;
style.Standard = FormatStyle::LS_Cpp11;
style.TabWidth = 4;
style.UseTab = FormatStyle::UT_Never;
return style;
}
static void applyTabSettings(clang::format::FormatStyle &style, const TabSettings &settings)
{
style.IndentWidth = static_cast<unsigned>(settings.m_indentSize);
@@ -63,42 +164,26 @@ static void applyTabSettings(clang::format::FormatStyle &style, const TabSetting
}
}
static void applyCppCodeStyleSettings(clang::format::FormatStyle &style,
const CppCodeStyleSettings &settings)
static bool useGlobalOverriddenSettings()
{
style.IndentCaseLabels = settings.indentSwitchLabels;
style.AlignOperands = settings.alignAssignments;
style.NamespaceIndentation = FormatStyle::NI_None;
if (settings.indentNamespaceBody)
style.NamespaceIndentation = FormatStyle::NI_All;
style.BraceWrapping.IndentBraces = false;
if (settings.indentBlockBraces) {
if (settings.indentClassBraces && settings.indentEnumBraces
&& settings.indentNamespaceBraces && settings.indentFunctionBraces) {
style.BraceWrapping.IndentBraces = true;
} else {
style.BreakBeforeBraces = FormatStyle::BS_GNU;
}
}
if (settings.bindStarToIdentifier || settings.bindStarToRightSpecifier)
style.PointerAlignment = FormatStyle::PAS_Right;
else
style.PointerAlignment = FormatStyle::PAS_Left;
style.AccessModifierOffset = settings.indentAccessSpecifiers
? 0
: - static_cast<int>(style.IndentWidth);
return ClangFormatSettings::instance().overrideDefaultFile();
}
static Utils::FileName projectPath()
QString currentProjectUniqueId()
{
const Project *project = SessionManager::startupProject();
if (project)
return project->projectDirectory();
if (!project)
return QString();
return Utils::FileName();
return QString::fromUtf8(QCryptographicHash::hash(project->projectFilePath().toString().toUtf8(),
QCryptographicHash::Md5)
.toHex(0));
}
static bool useProjectOverriddenSettings()
{
const Project *project = SessionManager::startupProject();
return project ? project->namedSettings(Constants::OVERRIDE_FILE_ID).toBool() : false;
}
static Utils::FileName globalPath()
@@ -106,29 +191,59 @@ static Utils::FileName globalPath()
return Utils::FileName::fromString(Core::ICore::userResourcePath());
}
static QString configForFile(Utils::FileName fileName)
static Utils::FileName projectPath()
{
Utils::FileName topProjectPath = projectPath();
if (topProjectPath.isEmpty())
return QString();
const Project *project = SessionManager::startupProject();
if (project)
return globalPath().appendPath("clang-format").appendPath(currentProjectUniqueId());
QDir projectDir(fileName.parentDir().toString());
while (!projectDir.exists(Constants::SETTINGS_FILE_NAME)
&& !projectDir.exists(Constants::SETTINGS_FILE_ALT_NAME)) {
if (projectDir.path() == topProjectPath.toString()
|| !Utils::FileName::fromString(projectDir.path()).isChildOf(topProjectPath)
|| !projectDir.cdUp()) {
return QString();
}
}
if (projectDir.exists(Constants::SETTINGS_FILE_NAME))
return projectDir.filePath(Constants::SETTINGS_FILE_NAME);
return projectDir.filePath(Constants::SETTINGS_FILE_ALT_NAME);
return Utils::FileName();
}
static clang::format::FormatStyle constructStyle(bool isGlobal,
const QByteArray &baseStyle = QByteArray())
static QString findConfig(Utils::FileName fileName)
{
QDir parentDir(fileName.parentDir().toString());
while (!parentDir.exists(Constants::SETTINGS_FILE_NAME)
&& !parentDir.exists(Constants::SETTINGS_FILE_ALT_NAME)) {
if (!parentDir.cdUp())
return QString();
}
if (parentDir.exists(Constants::SETTINGS_FILE_NAME))
return parentDir.filePath(Constants::SETTINGS_FILE_NAME);
return parentDir.filePath(Constants::SETTINGS_FILE_ALT_NAME);
}
static QString configForFile(Utils::FileName fileName, bool checkForSettings)
{
QDir overrideDir;
if (!checkForSettings || useProjectOverriddenSettings()) {
overrideDir = projectPath().toString();
if (!overrideDir.isEmpty() && overrideDir.exists(Constants::SETTINGS_FILE_NAME))
return overrideDir.filePath(Constants::SETTINGS_FILE_NAME);
}
if (!checkForSettings || useGlobalOverriddenSettings()) {
overrideDir = globalPath().toString();
if (!overrideDir.isEmpty() && overrideDir.exists(Constants::SETTINGS_FILE_NAME))
return overrideDir.filePath(Constants::SETTINGS_FILE_NAME);
}
return findConfig(fileName);
}
QString configForFile(Utils::FileName fileName)
{
return configForFile(fileName, true);
}
Utils::FileName assumedPathForConfig(const QString &configFile)
{
Utils::FileName fileName = Utils::FileName::fromString(configFile);
return fileName.parentDir().appendPath("test.cpp");
}
static clang::format::FormatStyle constructStyle(const QByteArray &baseStyle = QByteArray())
{
if (!baseStyle.isEmpty()) {
// Try to get the style for this base style.
@@ -144,21 +259,7 @@ static clang::format::FormatStyle constructStyle(bool isGlobal,
// Fallthrough to the default style.
}
FormatStyle style = getLLVMStyle();
style.BreakBeforeBraces = FormatStyle::BS_Custom;
const CppCodeStyleSettings codeStyleSettings = isGlobal
? CppCodeStyleSettings::currentGlobalCodeStyle()
: CppCodeStyleSettings::currentProjectCodeStyle()
.value_or(CppCodeStyleSettings::currentGlobalCodeStyle());
const TabSettings tabSettings = isGlobal
? CppCodeStyleSettings::currentGlobalTabSettings()
: CppCodeStyleSettings::currentProjectTabSettings();
applyTabSettings(style, tabSettings);
applyCppCodeStyleSettings(style, codeStyleSettings);
return style;
return qtcStyle();
}
void createStyleFileIfNeeded(bool isGlobal)
@@ -169,9 +270,21 @@ void createStyleFileIfNeeded(bool isGlobal)
if (QFile::exists(configFile))
return;
QDir().mkpath(path.parentDir().toString());
if (!isGlobal) {
const Project *project = SessionManager::startupProject();
Utils::FileName possibleProjectConfig = project->rootProjectDirectory().appendPath(
Constants::SETTINGS_FILE_NAME);
if (possibleProjectConfig.exists()) {
// Just copy th .clang-format if current project has one.
QFile::copy(possibleProjectConfig.toString(), configFile);
return;
}
}
std::fstream newStyleFile(configFile.toStdString(), std::fstream::out);
if (newStyleFile.is_open()) {
newStyleFile << clang::format::configurationAsText(constructStyle(isGlobal));
newStyleFile << clang::format::configurationAsText(constructStyle());
newStyleFile.close();
}
}
@@ -198,17 +311,13 @@ static QByteArray configBaseStyleName(const QString &configFile)
.trimmed();
}
clang::format::FormatStyle styleForFile(Utils::FileName fileName)
static clang::format::FormatStyle styleForFile(Utils::FileName fileName, bool checkForSettings)
{
bool isGlobal = false;
QString configFile = configForFile(fileName);
if (configFile.isEmpty()) {
Utils::FileName path = fileName = globalPath();
fileName.appendPath(Constants::SAMPLE_FILE_NAME);
createStyleFileIfNeeded(true);
configFile = path.appendPath(Constants::SETTINGS_FILE_NAME).toString();
}
QString configFile = configForFile(fileName, checkForSettings);
if (configFile.isEmpty())
return constructStyle();
fileName = assumedPathForConfig(configFile);
Expected<FormatStyle> style = format::getStyle("file",
fileName.toString().toStdString(),
"none");
@@ -219,17 +328,21 @@ clang::format::FormatStyle styleForFile(Utils::FileName fileName)
// do nothing
});
return constructStyle(isGlobal, configBaseStyleName(configFile));
return constructStyle(configBaseStyleName(configFile));
}
clang::format::FormatStyle styleForFile(Utils::FileName fileName)
{
return styleForFile(fileName, true);
}
clang::format::FormatStyle currentProjectStyle()
{
return styleForFile(projectPath().appendPath(Constants::SAMPLE_FILE_NAME));
return styleForFile(projectPath().appendPath(Constants::SAMPLE_FILE_NAME), false);
}
clang::format::FormatStyle currentGlobalStyle()
{
return styleForFile(globalPath().appendPath(Constants::SAMPLE_FILE_NAME));
}
return styleForFile(globalPath().appendPath(Constants::SAMPLE_FILE_NAME), false);
}
} // namespace ClangFormat

View File

@@ -25,6 +25,7 @@
#pragma once
#include <coreplugin/id.h>
#include <utils/fileutils.h>
#include <clang/Format/Format.h>
@@ -37,10 +38,13 @@ namespace ClangFormat {
// Creates the style for the current project or the global style if needed.
void createStyleFileIfNeeded(bool isGlobal);
QString currentProjectUniqueId();
clang::format::FormatStyle currentProjectStyle();
clang::format::FormatStyle currentGlobalStyle();
// Is the style from the matching .clang-format file or global one if it's not found.
QString configForFile(Utils::FileName fileName);
clang::format::FormatStyle styleForFile(Utils::FileName fileName);
}

View File

@@ -452,12 +452,12 @@ void ClangTidyClazyTool::handleStateUpdate()
if (issuesFound)
message = tr("Running - %n diagnostics", nullptr, issuesFound);
else
message = tr("Running - No diagnostics", nullptr, issuesFound);
message = tr("Running - No diagnostics");
} else {
if (issuesFound)
message = tr("Finished - %n diagnostics", nullptr, issuesFound);
else
message = tr("Finished - No diagnostics", nullptr, issuesFound);
message = tr("Finished - No diagnostics");
}
Debugger::showPermanentStatusMessage(message);

View File

@@ -78,6 +78,21 @@ void SearchResultTreeView::addResults(const QList<SearchResultItem> &items, Sear
}
}
void SearchResultTreeView::keyPressEvent(QKeyEvent *event)
{
if ((event->key() == Qt::Key_Return
|| event->key() == Qt::Key_Enter)
&& event->modifiers() == 0
&& currentIndex().isValid()
&& state() != QAbstractItemView::EditingState) {
const SearchResultItem item
= model()->data(currentIndex(), ItemDataRoles::ResultItemRole).value<SearchResultItem>();
emit jumpToSearchResult(item);
return;
}
TreeView::keyPressEvent(event);
}
void SearchResultTreeView::emitJumpToSearchResult(const QModelIndex &index)
{
if (model()->data(index, ItemDataRoles::IsGeneratedRole).toBool())

View File

@@ -49,6 +49,8 @@ public:
SearchResultTreeModel *model() const;
void addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode);
void keyPressEvent(QKeyEvent *event) override;
signals:
void jumpToSearchResult(const SearchResultItem &item);

View File

@@ -84,10 +84,9 @@ public:
const Links &links() const;
const Links bestLinks() const;
const QString keyword() const;
private:
bool isFuzzyMatch() const;
private:
QUrl m_helpUrl;
QStringList m_helpIds;
QString m_docMark;

View File

@@ -252,6 +252,14 @@ void LocatorModel::addEntries(const QList<LocatorFilterEntry> &entries)
CompletionList::CompletionList(QWidget *parent)
: Utils::TreeView(parent)
{
// on macOS and Windows the popup doesn't really get focus, so fake the selection color
// which would then just be a very light gray, but should look as if it had focus
QPalette p = palette();
p.setBrush(QPalette::Inactive,
QPalette::Highlight,
p.brush(QPalette::Normal, QPalette::Highlight));
setPalette(p);
setItemDelegate(new CompletionDelegate(this));
setRootIsDecorated(false);
setUniformRowHeights(true);

View File

@@ -507,7 +507,6 @@ void OutputPaneManager::showPage(int idx, int flags)
ensurePageVisible(idx);
IOutputPane *out = g_outputPanes.at(idx).pane;
out->visibilityChanged(true);
if (flags & IOutputPane::WithFocus) {
if (out->canFocus())
out->setFocus();
@@ -538,7 +537,10 @@ void OutputPaneManager::setCurrentIndex(int idx)
m_outputWidgetPane->setCurrentIndex(idx);
m_opToolBarWidgets->setCurrentIndex(idx);
IOutputPane *pane = g_outputPanes.at(idx).pane;
OutputPaneData &data = g_outputPanes[idx];
IOutputPane *pane = data.pane;
data.button->show();
data.buttonVisible = true;
pane->visibilityChanged(true);
bool canNavigate = pane->canNavigate();
@@ -574,8 +576,6 @@ void OutputPaneManager::popupMenu()
data.button->hide();
data.buttonVisible = false;
} else {
data.button->show();
data.buttonVisible = true;
showPage(idx, IOutputPane::ModeSwitch);
}
}

View File

@@ -860,11 +860,11 @@ void ClangDiagnosticConfigsWidget::syncClazyChecksGroupBox()
return !m_clazySortFilterProxyModel->filterAcceptsRow(index.row(), index.parent());
};
const bool hasEnabledButHidden = m_clazyTreeModel->hasEnabledButNotVisibleChecks(isHidden);
const QString title = hasEnabledButHidden ? tr("Checks (%1 enabled, some are filtered out)")
: tr("Checks (%1 enabled)");
const QStringList checks = m_clazyTreeModel->enabledChecks();
m_clazyChecks->checksGroupBox->setTitle(title.arg(checks.count()));
const int checksCount = m_clazyTreeModel->enabledChecks().count();
const QString title = hasEnabledButHidden ? tr("Checks (%n enabled, some are filtered out)",
nullptr, checksCount)
: tr("Checks (%n enabled)", nullptr, checksCount);
m_clazyChecks->checksGroupBox->setTitle(title);
}
void ClangDiagnosticConfigsWidget::updateConfig(const ClangDiagnosticConfig &config)

View File

@@ -172,7 +172,7 @@ void CompilerOptionsBuilder::addSyntaxOnly()
isClStyle() ? add("/Zs") : add("-fsyntax-only");
}
static QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt)
QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt)
{
QStringList options;
@@ -741,6 +741,15 @@ void CompilerOptionsBuilder::evaluateCompilerFlags()
continue;
}
if (option.startsWith("/Y", Qt::CaseSensitive)
|| (option.startsWith("/F", Qt::CaseSensitive) && option != "/F")) {
// Precompiled header flags.
// Skip also the next option if it's not glued to the current one.
if (option.size() > 3)
skipNext = true;
continue;
}
// Check whether a language version is already used.
QString theOption = option;
if (theOption.startsWith("-std=")) {

View File

@@ -40,6 +40,7 @@ enum class UseBuildSystemWarnings : char { Yes, No };
CPPTOOLS_EXPORT QStringList XclangArgs(const QStringList &args);
CPPTOOLS_EXPORT QStringList clangArgsForCl(const QStringList &args);
CPPTOOLS_EXPORT QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt);
class CPPTOOLS_EXPORT CompilerOptionsBuilder
{

View File

@@ -99,10 +99,10 @@ These prefixes are used in addition to current file name on Switch Header/Source
<item row="7" column="1">
<widget class="QCheckBox" name="headerPragmaOnceCheckBox">
<property name="toolTip">
<string>Uses #pragma once instead of #ifndef include guards.</string>
<string>Uses &quot;#pragma once&quot; instead of &quot;#ifndef&quot; include guards.</string>
</property>
<property name="text">
<string>Use '#pragma once' instead of '#ifndef' guards</string>
<string>Use &quot;#pragma once&quot; instead of &quot;#ifndef&quot; guards</string>
</property>
</widget>
</item>

View File

@@ -211,7 +211,7 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
expander->registerVariable(
"Cpp:PragmaOnce",
tr("Insert #pragma once instead of #ifndef include guards into header file"),
tr("Insert \"#pragma once\" instead of \"#ifndef\" include guards into header file"),
[] { return usePragmaOnce() ? QString("true") : QString(); });
return true;

View File

@@ -58,7 +58,7 @@ public:
QWidget *outputWidget(QWidget *) override;
QList<QWidget *> toolBarWidgets() const override;
QString displayName() const override { return tr("Debugger Console"); }
QString displayName() const override { return tr("QML Debugger Console"); }
int priorityInStatusBar() const override;
void clearContents() override;
void visibilityChanged(bool visible) override;

View File

@@ -748,7 +748,8 @@ void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers()
dir.setPath(base.toFileInfo().absoluteFilePath());
foreach (const QString &entry, dir.entryList()) {
if (entry.startsWith("lldb-platform-")
|| entry.startsWith("lldb-gdbserver-")) {
|| entry.startsWith("lldb-gdbserver-")
|| entry.startsWith("lldb-mi-")) {
continue;
}
suspects.append(FileName::fromString(dir.absoluteFilePath(entry)));

View File

@@ -152,24 +152,7 @@ DebuggerKitAspect::DebuggerKitAspect()
setPriority(28000);
}
QVariant DebuggerKitAspect::defaultValue(const Kit *k) const
{
const Abi toolChainAbi = ToolChainKitAspect::targetAbi(k);
const Utils::FileNameList paths = Environment::systemEnvironment().path();
QVariant nextBestFit;
for (const DebuggerItem &item : DebuggerItemManager::debuggers()) {
for (const Abi &targetAbi : item.abis()) {
if (targetAbi.isCompatibleWith(toolChainAbi)) {
if (paths.contains(item.command()))
return item.id(); // prefer debuggers found in PATH over those found elsewhere
if (nextBestFit.isNull())
nextBestFit = item.id();
}
}
}
return nextBestFit;
}
QVariant DebuggerKitAspect::defaultValue(const Kit *) const { return QVariant(); }
void DebuggerKitAspect::setup(Kit *k)
{

View File

@@ -119,6 +119,7 @@ public:
void resetCurrentPerspective();
int indexInChooser(Perspective *perspective) const;
void fixupLayoutIfNeeded();
void updatePerspectiveChooserWidth();
DebuggerMainWindow *q = nullptr;
Perspective *m_currentPerspective = nullptr;
@@ -416,10 +417,17 @@ void DebuggerMainWindowPrivate::selectPerspective(Perspective *perspective)
fixupLayoutIfNeeded();
}
updatePerspectiveChooserWidth();
}
void DebuggerMainWindowPrivate::updatePerspectiveChooserWidth()
{
Perspective *perspective = m_currentPerspective;
int index = indexInChooser(m_currentPerspective);
if (index == -1) {
if (Perspective *parent = Perspective::findPerspective(m_currentPerspective->d->m_parentPerspectiveId))
index = indexInChooser(parent);
perspective = Perspective::findPerspective(m_currentPerspective->d->m_parentPerspectiveId);
if (perspective)
index = indexInChooser(perspective);
}
if (index != -1) {

View File

@@ -61,6 +61,7 @@
#include <utils/temporarydirectory.h>
#include <utils/temporaryfile.h>
#include <utils/url.h>
#include <utils/winutils.h>
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
@@ -565,6 +566,17 @@ void DebuggerRunTool::start()
if (!fixupParameters())
return;
if (m_runParameters.cppEngineType == CdbEngineType
&& Utils::is64BitWindowsBinary(m_runParameters.inferior.executable)
&& !Utils::is64BitWindowsBinary(m_runParameters.debugger.executable)) {
reportFailure(
DebuggerPlugin::tr(
"%1 is a 64 bit executable which can not be debugged by a 32 bit Debugger.\n"
"Please select a 64 bit Debugger in the kit settings for this kit.")
.arg(m_runParameters.inferior.executable));
return;
}
Utils::globalMacroExpander()->registerFileVariables(
"DebuggedExecutable", tr("Debugged executable"),
[this] { return m_runParameters.inferior.executable; }

View File

@@ -395,6 +395,8 @@ void LldbEngine::handleResponse(const QString &response)
handleOutputNotification(item);
else if (name == "pid")
notifyInferiorPid(item.toProcessHandle());
else if (name == "breakpointmodified")
handleInterpreterBreakpointModified(item);
}
}
@@ -607,6 +609,31 @@ void LldbEngine::handleOutputNotification(const GdbMi &output)
showMessage(data, ch);
}
void LldbEngine::handleInterpreterBreakpointModified(const GdbMi &bpItem)
{
QTC_ASSERT(bpItem.childCount(), return);
QString id = bpItem.childAt(0).m_data;
Breakpoint bp = breakHandler()->findBreakpointByResponseId(id);
if (!bp) // FIXME adapt whole bp handling and turn into soft assert
return;
// this function got triggered by a lldb internal breakpoint event
// avoid asserts regarding unexpected state transitions
switch (bp->state()) {
case BreakpointInsertionRequested: // was a pending bp
bp->gotoState(BreakpointInsertionProceeding, BreakpointInsertionRequested);
break;
case BreakpointInserted: // was an inserted, gets updated now
bp->gotoState(BreakpointUpdateRequested, BreakpointInserted);
notifyBreakpointChangeProceeding(bp);
break;
default:
break;
}
updateBreakpointData(bp, bpItem, false);
}
void LldbEngine::loadSymbols(const QString &moduleName)
{
Q_UNUSED(moduleName)

View File

@@ -120,6 +120,7 @@ private:
void handleStateNotification(const GdbMi &item);
void handleLocationNotification(const GdbMi &location);
void handleOutputNotification(const GdbMi &output);
void handleInterpreterBreakpointModified(const GdbMi &item);
void handleResponse(const QString &data);
void updateAll() override;

View File

@@ -657,7 +657,7 @@ void HelpPluginPrivate::showContextHelp(const HelpItem &contextHelp)
.arg(contextHelp.helpIds().join(", "))
.arg(HelpPlugin::tr("No documentation available.")));
}
} else if (links.size() == 1) {
} else if (links.size() == 1 && !contextHelp.isFuzzyMatch()) {
showHelpUrl(links.front().second, LocalHelpManager::contextHelpOption());
} else {
QMap<QString, QUrl> map;

View File

@@ -208,17 +208,6 @@ void Client::openDocument(Core::IDocument *document)
connect(textDocument, &QObject::destroyed, this, [this, textDocument]{
m_resetAssistProvider.remove(textDocument);
});
if (BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(textDocument)) {
if (QPointer<TextEditorWidget> widget = editor->editorWidget()) {
connect(widget, &TextEditorWidget::cursorPositionChanged, this, [this, widget](){
// TODO This would better be a compressing timer
QTimer::singleShot(50, this, [this, widget]() {
if (widget)
cursorPositionChanged(widget);
});
});
}
}
}
m_openedDocument.append(document->filePath());
@@ -344,7 +333,7 @@ void Client::documentContentsChanged(Core::IDocument *document)
if (textDocument) {
using namespace TextEditor;
if (BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(textDocument))
for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(textDocument))
if (TextEditorWidget *widget = editor->editorWidget())
widget->setRefactorMarkers(RefactorMarker::filterOutType(widget->refactorMarkers(), id()));
requestDocumentSymbols(textDocument);
@@ -766,6 +755,11 @@ const DynamicCapabilities &Client::dynamicCapabilities() const
return m_dynamicCapabilities;
}
const BaseClientInterface *Client::clientInterface() const
{
return m_clientInterface.data();
}
void Client::log(const ShowMessageParams &message,
Core::MessageManager::PrintToOutputPaneFlag flag)
{

View File

@@ -147,6 +147,7 @@ public:
const LanguageServerProtocol::ServerCapabilities &capabilities() const;
const DynamicCapabilities &dynamicCapabilities() const;
const BaseClientInterface *clientInterface() const;
signals:
void initialized(LanguageServerProtocol::ServerCapabilities capabilities);

View File

@@ -110,7 +110,7 @@ StdIOClientInterface::~StdIOClientInterface()
Utils::SynchronousProcess::stopProcess(m_process);
}
bool StdIOClientInterface::needsRestart(const StdIOSettings *settings)
bool StdIOClientInterface::needsRestart(const StdIOSettings *settings) const
{
return m_executable != settings->m_executable || m_arguments != settings->m_arguments;
}

View File

@@ -74,7 +74,7 @@ public:
StdIOClientInterface &operator=(const StdIOClientInterface &) = delete;
StdIOClientInterface &operator=(StdIOClientInterface &&) = delete;
bool needsRestart(const StdIOSettings *settings);
bool needsRestart(const StdIOSettings *settings) const;
bool start() override;

View File

@@ -125,7 +125,10 @@ void LanguageClientManager::deleteClient(Client *client)
QTC_ASSERT(client, return);
client->disconnect();
managerInstance->m_clients.removeAll(client);
client->deleteLater();
if (managerInstance->m_shuttingDown)
delete client;
else
client->deleteLater();
}
void LanguageClientManager::shutdown()
@@ -210,6 +213,18 @@ void LanguageClientManager::editorOpened(Core::IEditor *editor)
(const QTextCursor &cursor){
findUsages(filePath, cursor);
});
connect(widget, &TextEditorWidget::cursorPositionChanged, this, [this, widget](){
// TODO This would better be a compressing timer
QTimer::singleShot(50, this,
[this, widget = QPointer<TextEditorWidget>(widget)]() {
if (widget) {
for (Client *client : this->reachableClients()) {
if (client->isSupportedDocument(widget->textDocument()))
client->cursorPositionChanged(widget);
}
}
});
});
}
}
}

View File

@@ -491,7 +491,9 @@ bool StdIOSettings::needsRestart() const
{
if (BaseSettings::needsRestart())
return true;
if (auto stdIOInterface = qobject_cast<StdIOClientInterface *>(m_client))
if (m_client.isNull())
return false;
if (auto stdIOInterface = qobject_cast<const StdIOClientInterface *>(m_client->clientInterface()))
return stdIOInterface->needsRestart(this);
return false;
}

View File

@@ -133,12 +133,10 @@ void updateCodeActionRefactoringMarker(Client *client,
TextDocument* doc = TextDocument::textDocumentForFileName(uri.toFileName());
if (!doc)
return;
BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(doc);
if (!editor)
const QVector<BaseTextEditor *> editors = BaseTextEditor::textEditorsForDocument(doc);
if (editors.isEmpty())
return;
TextEditorWidget *editorWidget = editor->editorWidget();
const QList<Diagnostic> &diagnostics = action.diagnostics().value_or(QList<Diagnostic>());
RefactorMarkers markers;
@@ -181,7 +179,10 @@ void updateCodeActionRefactoringMarker(Client *client,
marker.cursor = endOfLineCursor(diagnostic.range().start().toTextCursor(doc->document()));
markers << marker;
}
editorWidget->setRefactorMarkers(markers + editorWidget->refactorMarkers());
for (BaseTextEditor *editor : editors) {
if (TextEditorWidget *editorWidget = editor->editorWidget())
editorWidget->setRefactorMarkers(markers + editorWidget->refactorMarkers());
}
}
} // namespace LanguageClient

View File

@@ -10,9 +10,6 @@
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox">

View File

@@ -96,7 +96,7 @@ PerfTracePointDialog::~PerfTracePointDialog()
void PerfTracePointDialog::runScript()
{
m_ui->label->setText(tr("Executing script ..."));
m_ui->label->setText(tr("Executing script..."));
m_ui->textEdit->setReadOnly(true);
m_ui->privilegesChooser->setEnabled(false);
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);

View File

@@ -41,6 +41,8 @@ namespace Ui { class PerfTracePointDialog; }
class PerfTracePointDialog : public QDialog
{
Q_OBJECT
public:
PerfTracePointDialog();
~PerfTracePointDialog();

View File

@@ -59,7 +59,6 @@ SUBDIRS = \
languageclient \
cppcheck \
compilationdatabaseprojectmanager \
perfprofiler \
qmlpreview \
studiowelcome
@@ -70,9 +69,9 @@ qtHaveModule(serialport) {
}
qtHaveModule(quick) {
SUBDIRS += qmlprofiler
SUBDIRS += qmlprofiler perfprofiler
} else {
warning("QmlProfiler plugin has been disabled since the Qt Quick module is not available.")
warning("QmlProfiler and PerfProfiler plugins have been disabled since the Qt Quick module is not available.")
}
qtHaveModule(help) {

View File

@@ -32,6 +32,8 @@ namespace Internal {
class DesktopDeviceFactory : public IDeviceFactory
{
Q_OBJECT
public:
DesktopDeviceFactory();
};

View File

@@ -275,11 +275,9 @@ void Kit::fix()
void Kit::setup()
{
KitGuard g(this);
// Process the KitAspects in reverse order: They may only be based on other information
// lower in the stack.
const QList<KitAspect *> aspects = KitManager::kitAspects();
for (int i = aspects.count() - 1; i >= 0; --i)
aspects.at(i)->setup(this);
for (KitAspect * const aspect : aspects)
aspect->setup(this);
}
void Kit::upgrade()

View File

@@ -71,10 +71,12 @@ class KitManagerPrivate
public:
Kit *m_defaultKit = nullptr;
bool m_initialized = false;
std::vector<std::unique_ptr<KitAspect>> m_informationList;
std::vector<std::unique_ptr<Kit>> m_kitList;
std::unique_ptr<PersistentSettingsWriter> m_writer;
QSet<Id> m_irrelevantAspects;
// Sorted by priority, in descending order.
std::vector<std::unique_ptr<KitAspect>> m_informationList;
};
} // namespace Internal

View File

@@ -1027,6 +1027,8 @@ bool static hasFlagEffectOnMacros(const QString &flag)
return false; // Skip include paths
if (f.startsWith("w", Qt::CaseInsensitive))
return false; // Skip warning options
if (f.startsWith("Y") || (f.startsWith("F") && f != "F"))
return false; // Skip pch-related flags
}
return true;
}

View File

@@ -2045,8 +2045,12 @@ void ProjectExplorerPluginPrivate::updateWelcomePage()
void ProjectExplorerPluginPrivate::currentModeChanged(Id mode, Id oldMode)
{
if (oldMode == Constants::MODE_SESSION)
ICore::saveSettings();
if (oldMode == Constants::MODE_SESSION) {
// Saving settings directly in a mode change is not a good idea, since the mode change
// can be part of a bigger change. Save settings after that bigger change had a chance to
// complete.
QTimer::singleShot(0, ICore::instance(), &ICore::saveSettings);
}
if (mode == Core::Constants::MODE_WELCOME)
updateWelcomePage();
}

View File

@@ -363,7 +363,7 @@ static QStringList readLinesJson(const Utils::FileName &projectFile,
// This assumes te project file is formed with only one field called
// 'files' that has a list associated of the files to include in the project.
if (content.isEmpty()) {
*errorMessage = PythonProject::tr("Unable read \"%1\": The file is empty.")
*errorMessage = PythonProject::tr("Unable to read \"%1\": The file is empty.")
.arg(projectFile.toUserOutput());
return lines;
}
@@ -372,7 +372,7 @@ static QStringList readLinesJson(const Utils::FileName &projectFile,
const QJsonDocument doc = QJsonDocument::fromJson(content, &error);
if (doc.isNull()) {
const int line = content.left(error.offset).count('\n') + 1;
*errorMessage = PythonProject::tr("Unable parse %1:%2: %3")
*errorMessage = PythonProject::tr("Unable to parse \"%1\":%2: %3")
.arg(projectFile.toUserOutput()).arg(line)
.arg(error.errorString());
return lines;

View File

@@ -71,10 +71,10 @@ public:
void toogleRecording(bool b) const;
void resetGroupRecording() const;
bool hasKeyframeGroup(const ModelNode &node, const PropertyName &propertyName) const;
private:
void addKeyframeGroupIfNotExists(const ModelNode &node, const PropertyName &propertyName);
bool hasKeyframeGroup(const ModelNode &node, const PropertyName &propertyName) const;
QList<QmlTimelineKeyframeGroup> allKeyframeGroups() const;
};

View File

@@ -63,7 +63,7 @@ void QmlObjectNode::setVariantProperty(const PropertyName &name, const QVariant
timelineFrames.setValue(value, frame);
return;
} else if (modelNode().hasId() && timelineIsActive()) {
} else if (modelNode().hasId() && timelineIsActive() && currentTimeline().hasKeyframeGroup(modelNode(), name)) {
QmlTimelineKeyframeGroup timelineFrames(currentTimeline().keyframeGroup(modelNode(), name));
Q_ASSERT(timelineFrames.isValid());

View File

@@ -65,7 +65,6 @@ const char REFORMAT_UI_QML_FILES[] = "ReformatUiQmlFiles"; /* These setti
const char IGNORE_DEVICE_PIXEL_RATIO[] = "IgnoreDevicePixelRaio"; /* The settings can be used to turn off the feature, if there are serious issues */
const char STANDALONE_MODE[] = "StandAloneMode";
const char ENABLE_TIMELINEVIEW[] = "EnableTimelineView";
const char ENABLE_TIMELINEVIEW_ENVVAR[] = "QTC_ENABLE_QTQUICKTIMELINE_EDITOR";
}
class DesignerSettings : public QHash<QByteArray, QVariant>

View File

@@ -10,14 +10,11 @@
<height>176</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="3">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Loops</string>
<string>Loops:</string>
</property>
</widget>
</item>
@@ -117,7 +114,7 @@
</size>
</property>
<property name="text">
<string>Animation ID</string>
<string>Animation ID:</string>
</property>
</widget>
</item>
@@ -162,14 +159,14 @@
<item row="5" column="1">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Finished</string>
<string>Finished:</string>
</property>
</widget>
</item>
<item row="4" column="7">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Ping Pong</string>
<string>Ping pong</string>
</property>
</widget>
</item>
@@ -205,7 +202,7 @@
</size>
</property>
<property name="text">
<string>Transition to state</string>
<string>Transition to state:</string>
</property>
</widget>
</item>
@@ -222,7 +219,7 @@
<bool>true</bool>
</property>
<property name="text">
<string>Running in Base State</string>
<string>Running in base state</string>
</property>
</widget>
</item>
@@ -257,7 +254,7 @@
<item row="3" column="1">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Start Frame</string>
<string>Start frame:</string>
</property>
</widget>
</item>
@@ -290,14 +287,14 @@
<item row="3" column="7">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Duration</string>
<string>Duration:</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLabel" name="label_13">
<property name="text">
<string>End Frame</string>
<string>End frame:</string>
</property>
</widget>
</item>

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -46,13 +46,13 @@ const int priorityTimelineCategory = 110;
const char timelineCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Timeline");
const char timelineCopyKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
"Copy All Keyframes from item");
"Copy All Keyframes");
const char timelinePasteKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
"Paste Keyframes to item");
"Paste Keyframes");
const char timelineInsertKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
"Insert Keyframes for item");
"Add Keyframes at Current Frame");
const char timelineDeleteKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
"Delete All Keyframes for item");
"Delete All Keyframes");
const char timelineStatusBarFrameNumber[] = QT_TRANSLATE_NOOP("QmlDesignerTimeline", "Frame %1");

View File

@@ -10,9 +10,6 @@
<height>170</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="8" colspan="2">
<spacer name="horizontalSpacer_11">
@@ -84,7 +81,7 @@
<item row="4" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Expression Binding</string>
<string>Expression binding:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
@@ -107,7 +104,7 @@
<item row="2" column="4">
<widget class="QLabel" name="label_7">
<property name="text">
<string>End Frame</string>
<string>End frame:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
@@ -200,7 +197,7 @@
<bool>false</bool>
</property>
<property name="text">
<string>Expression Binding</string>
<string>Expression binding</string>
</property>
</widget>
</item>
@@ -214,7 +211,7 @@
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Timeline ID</string>
<string>Timeline ID:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
@@ -243,7 +240,7 @@
<item row="2" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Start Frame</string>
<string>Start frame:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>

View File

@@ -44,6 +44,8 @@ class TimelineToolButton;
class TimelineKeyframeItem : public TimelineMovableAbstractItem
{
Q_DECLARE_TR_FUNCTIONS(TimelineKeyframeItem)
public:
explicit TimelineKeyframeItem(TimelinePropertyItem *parent, const ModelNode &frame);
~TimelineKeyframeItem() override;
@@ -84,6 +86,8 @@ private:
class TimelinePropertyItem : public TimelineItem
{
Q_OBJECT
public:
enum { Type = TimelineConstants::timelinePropertyItemUserType };

View File

@@ -40,6 +40,8 @@ class TimelineSectionItem;
class TimelineBarItem : public TimelineMovableAbstractItem
{
Q_DECLARE_TR_FUNCTIONS(TimelineBarItem)
enum class Location { Undefined, Center, Left, Right };
public:

View File

@@ -103,7 +103,7 @@ QWidget *TimelineEditorDelegate::createEditor(QWidget *parent,
switch (index.column()) {
case TimelineSettingsModel::TimelineRow: {
QTC_ASSERT(comboBox, return widget);
comboBox->addItem(tr("None"));
comboBox->addItem(TimelineSettingsModel::tr("None"));
for (const auto &timeline : timelineSettingsModel->timelineView()->getTimelines()) {
if (!timeline.modelNode().id().isEmpty())
comboBox->addItem(timeline.modelNode().id());
@@ -111,7 +111,7 @@ QWidget *TimelineEditorDelegate::createEditor(QWidget *parent,
} break;
case TimelineSettingsModel::AnimationRow: {
QTC_ASSERT(comboBox, return widget);
comboBox->addItem(tr("None"));
comboBox->addItem(TimelineSettingsModel::tr("None"));
for (const auto &animation :
timelineSettingsModel->timelineView()->getAnimations(qmlTimeline)) {
if (!animation.id().isEmpty())

View File

@@ -194,8 +194,7 @@ bool QmlDesignerPlugin::delayedInitialize()
d->settings.fromSettings(Core::ICore::settings());
d->viewManager.registerViewTakingOwnership(new QmlDesigner::Internal::ConnectionView);
if (DesignerSettings::getValue(DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool()
|| qEnvironmentVariableIsSet(DesignerSettingsKey::ENABLE_TIMELINEVIEW_ENVVAR))
if (DesignerSettings::getValue(DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool())
d->viewManager.registerViewTakingOwnership(new QmlDesigner::TimelineView);
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::SourceTool);
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::ColorTool);

View File

@@ -159,6 +159,8 @@ DesignerSettings SettingsPageWidget::settings() const
m_ui.showPropertyEditorWarningsCheckBox->isChecked());
settings.insert(DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT,
m_ui.showWarnExceptionsCheckBox->isChecked());
settings.insert(DesignerSettingsKey::ENABLE_TIMELINEVIEW,
m_ui.featureTimelineEditorCheckBox->isChecked());
return settings;
}
@@ -224,9 +226,13 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings)
m_ui.controls2StyleComboBox->setCurrentText(m_ui.styleLineEdit->text());
m_ui.featureTimelineEditorCheckBox->setChecked(settings.value(
DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool());
if (settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool()) {
m_ui.emulationGroupBox->hide();
m_ui.debugGroupBox->hide();
m_ui.featuresGroupBox->hide();
}
}
@@ -262,7 +268,8 @@ void SettingsPage::apply()
<< DesignerSettingsKey::PUPPET_KILL_TIMEOUT
<< DesignerSettingsKey::FORWARD_PUPPET_OUTPUT
<< DesignerSettingsKey::DEBUG_PUPPET
<< DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT;
<< DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT
<< DesignerSettingsKey::ENABLE_TIMELINEVIEW;
foreach (const QByteArray &key, restartNecessaryKeys) {
if (currentSettings.value(key) != newSettings.value(key)) {

View File

@@ -410,6 +410,22 @@
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="featuresGroupBox">
<property name="title">
<string>Features</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QCheckBox" name="featureTimelineEditorCheckBox">
<property name="text">
<string>Enable Timeline editor</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="debugGroupBox">
<property name="title">

View File

@@ -287,10 +287,10 @@ void QmlProfilerTool::updateRunActions()
d->m_startAction->setToolTip(tr("A QML Profiler analysis is still in progress."));
d->m_stopAction->setEnabled(true);
} else {
QString whyNot = tr("Start QML Profiler analysis.");
QString tooltip = tr("Start QML Profiler analysis.");
bool canRun = ProjectExplorerPlugin::canRunStartupProject
(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, &whyNot);
d->m_startAction->setToolTip(whyNot);
(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, &tooltip);
d->m_startAction->setToolTip(tooltip);
d->m_startAction->setEnabled(canRun);
d->m_stopAction->setEnabled(false);
}

View File

@@ -31,6 +31,7 @@
#include <utils/algorithm.h>
#include <utils/ansiescapecodehandler.h>
#include <utils/fileinprojectfinder.h>
#include <utils/hostosinfo.h>
#include <utils/theme/theme.h>
#include <QPlainTextEdit>
@@ -412,16 +413,16 @@ void QtSupportPlugin::testQtOutputFormatter_data()
<< " Loc: [../TestProject/test.cpp(123)]"
<< 9 << 37 << "../TestProject/test.cpp(123)"
<< "../TestProject/test.cpp" << 123 << -1;
QTest::newRow("Windows failed QTest link")
<< "..\\TestProject\\test.cpp(123) : failure location"
<< 0 << 28 << "..\\TestProject\\test.cpp(123)"
<< "..\\TestProject\\test.cpp" << 123 << -1;
QTest::newRow("Windows failed QTest link with carriage return")
<< "..\\TestProject\\test.cpp(123) : failure location\r"
<< 0 << 28 << "..\\TestProject\\test.cpp(123)"
<< "..\\TestProject\\test.cpp" << 123 << -1;
if (HostOsInfo::isWindowsHost()) {
QTest::newRow("Windows failed QTest link")
<< "..\\TestProject\\test.cpp(123) : failure location"
<< 0 << 28 << "..\\TestProject\\test.cpp(123)"
<< "../TestProject/test.cpp" << 123 << -1;
QTest::newRow("Windows failed QTest link with carriage return")
<< "..\\TestProject\\test.cpp(123) : failure location\r"
<< 0 << 28 << "..\\TestProject\\test.cpp(123)"
<< "../TestProject/test.cpp" << 123 << -1;
}
}
void QtSupportPlugin::testQtOutputFormatter()

View File

@@ -203,7 +203,7 @@ void AbstractRemoteLinuxDeployService::handleDeviceSetupDone(bool success)
} else {
connect(d->connection, &SshConnection::connected,
this, &AbstractRemoteLinuxDeployService::handleConnected);
emit progressMessage(tr("Connecting to device '%1' (%2)")
emit progressMessage(tr("Connecting to device \"%1\" (%2).")
.arg(deviceConfiguration()->displayName())
.arg(deviceConfiguration()->sshParameters().host()));
if (d->connection->state() == SshConnection::Unconnected)

View File

@@ -145,7 +145,7 @@ void BaseHoverHandler::decorateToolTip()
if (Qt::mightBeRichText(toolTip()))
setToolTip(toolTip().toHtmlEscaped());
if (lastHelpItemIdentified().isValid()) {
if (lastHelpItemIdentified().isValid() && !lastHelpItemIdentified().isFuzzyMatch()) {
const QString &helpContents = lastHelpItemIdentified().extractContent(false);
if (!helpContents.isEmpty()) {
m_toolTip = toolTip().toHtmlEscaped();

View File

@@ -258,6 +258,16 @@ void Highlighter::handleShutdown()
delete highlightRepository();
}
static bool isOpeningParenthesis(QChar c)
{
return c == QLatin1Char('{') || c == QLatin1Char('[') || c == QLatin1Char('(');
}
static bool isClosingParenthesis(QChar c)
{
return c == QLatin1Char('}') || c == QLatin1Char(']') || c == QLatin1Char(')');
}
void Highlighter::highlightBlock(const QString &text)
{
if (!definition().isValid())
@@ -266,8 +276,21 @@ void Highlighter::highlightBlock(const QString &text)
KSyntaxHighlighting::State state = TextDocumentLayout::userData(block)->syntaxState();
state = highlightLine(text, state);
block = block.next();
Parentheses parentheses;
int pos = 0;
for (const QChar &c : text) {
if (isOpeningParenthesis(c))
parentheses.push_back(Parenthesis(Parenthesis::Opened, c, pos));
else if (isClosingParenthesis(c))
parentheses.push_back(Parenthesis(Parenthesis::Closed, c, pos));
pos++;
}
TextDocumentLayout::setParentheses(currentBlock(), parentheses);
if (block.isValid())
TextDocumentLayout::userData(block)->setSyntaxState(state);
formatSpaces(text);
}
void Highlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format)

View File

@@ -127,6 +127,9 @@
</item>
<item>
<widget class="QPushButton" name="resetCache">
<property name="toolTip">
<string>Reset definitions remembered for files that can be associated with more than one highlighter definition.</string>
</property>
<property name="text">
<string>Reset Remembered Definitions</string>
</property>

View File

@@ -8508,13 +8508,14 @@ BaseTextEditor *BaseTextEditor::currentTextEditor()
return qobject_cast<BaseTextEditor *>(EditorManager::currentEditor());
}
BaseTextEditor *BaseTextEditor::textEditorForDocument(TextDocument *textDocument)
QVector<BaseTextEditor *> BaseTextEditor::textEditorsForDocument(TextDocument *textDocument)
{
QVector<BaseTextEditor *> ret;
for (IEditor *editor : Core::DocumentModel::editorsForDocument(textDocument)) {
if (auto textEditor = qobject_cast<BaseTextEditor *>(editor))
return textEditor;
ret << textEditor;
}
return nullptr;
return ret;
}
TextEditorWidget *BaseTextEditor::editorWidget() const

View File

@@ -111,7 +111,7 @@ public:
virtual void finalizeInitialization() {}
static BaseTextEditor *currentTextEditor();
static BaseTextEditor *textEditorForDocument(TextDocument *textDocument);
static QVector<BaseTextEditor *> textEditorsForDocument(TextDocument *textDocument);
TextEditorWidget *editorWidget() const;
TextDocument *textDocument() const;

View File

@@ -2,7 +2,19 @@ DEFINES += TEXTEDITOR_LIBRARY
QT += gui-private network printsupport xml
CONFIG += exceptions
CONFIG += include_source_dir # For the highlighter autotest.
include(../../shared/syntax/syntax_shared.pri)
isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) | isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) {
QTC_LIB_DEPENDS += syntax-highlighting
} else {
unix:!disable_external_rpath {
!macos: QMAKE_LFLAGS += -Wl,-z,origin
QMAKE_LFLAGS += -Wl,-rpath,$$shell_quote($${KSYNTAXHIGHLIGHTING_LIB_DIR})
}
}
include(../../qtcreatorplugin.pri)
SOURCES += texteditorplugin.cpp \
plaintexteditorfactory.cpp \
textdocument.cpp \

View File

@@ -2,7 +2,21 @@ QTC_PLUGIN_NAME = TextEditor
QTC_LIB_DEPENDS += \
aggregation \
extensionsystem \
utils \
syntax-highlighting
utils
QTC_PLUGIN_DEPENDS += \
coreplugin
# needed for plugins that depend on TextEditor plugin
include(../../shared/syntax/syntax_shared.pri)
!isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR):!isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) {
INCLUDEPATH *= $${KSYNTAXHIGHLIGHTING_INCLUDE_DIR}
LIBS *= -L$$KSYNTAXHIGHLIGHTING_LIB_DIR -lKF5SyntaxHighlighting
linux {
QMAKE_LFLAGS += -Wl,-z,origin
QMAKE_LFLAGS += -Wl,-rpath,$$shell_quote($${KSYNTAXHIGHLIGHTING_LIB_DIR})
}
} else {
QTC_LIB_DEPENDS += syntax-highlighting
}

View File

@@ -96,7 +96,16 @@ defineReplace(splitFlags) {
flag ~= s,-I\S*,,
flag ~= s,/D\S*,,
flag ~= s,/Z\S*,,
result += $$split(flag, " ")
separate_flags = $$split(flag, " ")
for (separate_flag, separate_flags) {
starting_substr = $$str_member($$separate_flag, 0, 0)
win32:equals(starting_substr, "/") {
result += $$separate_flag
}
equals(starting_substr, "-") {
result += $$separate_flag
}
}
} else {
inside_quotes = 0
starting_substr = $$str_member($$flag, 0, 0)

View File

@@ -0,0 +1,21 @@
# KSyntaxHighlighting uses a special folder structure (may contain target arch triple for the lib),
# so expect lib folder to be specified by the user - generate include path based on this
isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR): KSYNTAXHIGHLIGHTING_LIB_DIR=$$(KSYNTAXHIGHLIGHTING_LIB_DIR)
isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR): KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$(KSYNTAXHIGHLIGHTING_INCLUDE_DIR)
!isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) {
!exists($$KSYNTAXHIGHLIGHTING_LIB_DIR) {
unset(KSYNTAXHIGHLIGHTING_LIB_DIR)
unset(KSYNTAXHIGHLIGHTING_INCLUDE_DIR)
} else {
isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) {
!linux: KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$absolute_path('../include/KF5/KSyntaxHighlighting/', $$KSYNTAXHIGHLIGHTING_LIB_DIR)
else: KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$absolute_path('../../include/KF5/KSyntaxHighlighting/', $$KSYNTAXHIGHLIGHTING_LIB_DIR)
}
!exists($$KSYNTAXHIGHLIGHTING_INCLUDE_DIR) {
unset(KSYNTAXHIGHLIGHTING_INCLUDE_DIR)
unset(KSYNTAXHIGHLIGHTING_LIB_DIR)
}
}
}

View File

@@ -181,6 +181,7 @@ void FullTokenInfo::variableKind(const Cursor &cursor)
{
TokenInfo::variableKind(cursor);
m_extraInfo.accessSpecifier = cursor.accessSpecifier();
m_extraInfo.storageClass = cursor.storageClass();
}

View File

@@ -41,7 +41,7 @@
#include <precompiledheaderstorage.h>
#include <processormanager.h>
#include <progresscounter.h>
#include <projectparts.h>
#include <projectpartsmanager.h>
#include <filepathcaching.h>
#include <refactoringdatabaseinitializer.h>
#include <sqlitedatabase.h>
@@ -68,7 +68,7 @@ using ClangBackEnd::PchCreator;
using ClangBackEnd::PchManagerClientProxy;
using ClangBackEnd::PchManagerServer;
using ClangBackEnd::PrecompiledHeaderStorage;
using ClangBackEnd::ProjectParts;
using ClangBackEnd::ProjectPartsManager;
using ClangBackEnd::FilePathCache;
using ClangBackEnd::FilePathView;
using ClangBackEnd::TimeStamp;
@@ -138,12 +138,14 @@ public:
ClangBackEnd::Environment &environment,
Sqlite::Database &database,
PchManagerServer &pchManagerServer,
ClangBackEnd::ClangPathWatcherInterface &pathWatcher)
: ProcessorManager(generatedFiles),
m_environment(environment),
m_database(database),
m_pchManagerServer(pchManagerServer),
m_pathWatcher(pathWatcher)
ClangBackEnd::ClangPathWatcherInterface &pathWatcher,
ClangBackEnd::BuildDependenciesStorageInterface &buildDependenciesStorage)
: ProcessorManager(generatedFiles)
, m_environment(environment)
, m_database(database)
, m_pchManagerServer(pchManagerServer)
, m_pathWatcher(pathWatcher)
, m_buildDependenciesStorage(buildDependenciesStorage)
{}
protected:
@@ -152,7 +154,8 @@ protected:
return std::make_unique<PchCreator>(m_environment,
m_database,
*m_pchManagerServer.client(),
m_pathWatcher);
m_pathWatcher,
m_buildDependenciesStorage);
}
private:
@@ -160,6 +163,7 @@ private:
Sqlite::Database &m_database;
ClangBackEnd::PchManagerServer &m_pchManagerServer;
ClangBackEnd::ClangPathWatcherInterface &m_pathWatcher;
ClangBackEnd::BuildDependenciesStorageInterface &m_buildDependenciesStorage;
};
struct Data // because we have a cycle dependency
@@ -175,13 +179,14 @@ struct Data // because we have a cycle dependency
ClangBackEnd::FilePathCaching filePathCache{database};
ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher{filePathCache};
ApplicationEnvironment environment;
ProjectParts projectParts;
ProjectPartsManager projectParts;
GeneratedFiles generatedFiles;
PchCreatorManager pchCreatorManager{generatedFiles,
environment,
database,
clangPchManagerServer,
includeWatcher};
includeWatcher,
buildDependencyStorage};
PrecompiledHeaderStorage<> preCompiledHeaderStorage{database};
ClangBackEnd::ProgressCounter pchCreationProgressCounter{[&](int progress, int total) {
executeInLoop([&] {

View File

@@ -55,19 +55,19 @@ OutputContainer setUnion(InputContainer1 &&input1,
BuildDependency BuildDependenciesProvider::create(const ProjectPartContainer &projectPart)
{
SourceEntries includes = createSourceEntriesFromStorage(projectPart.sourcePathIds,
projectPart.projectPartId);
auto sourcesAndProjectPart = createSourceEntriesFromStorage(
projectPart.sourcePathIds, projectPart.projectPartId);
if (!m_modifiedTimeChecker.isUpToDate(includes)) {
if (!m_modifiedTimeChecker.isUpToDate(sourcesAndProjectPart.first)) {
BuildDependency buildDependency = m_generator.create(projectPart);
storeBuildDependency(buildDependency);
storeBuildDependency(buildDependency, sourcesAndProjectPart.second);
return buildDependency;
}
return createBuildDependencyFromStorage(std::move(includes));
return createBuildDependencyFromStorage(
std::move(sourcesAndProjectPart.first));
}
BuildDependency BuildDependenciesProvider::createBuildDependencyFromStorage(
@@ -76,7 +76,7 @@ BuildDependency BuildDependenciesProvider::createBuildDependencyFromStorage(
BuildDependency buildDependency;
buildDependency.usedMacros = createUsedMacrosFromStorage(includes);
buildDependency.includes = std::move(includes);
buildDependency.sources = std::move(includes);
return buildDependency;
}
@@ -101,16 +101,19 @@ UsedMacros BuildDependenciesProvider::createUsedMacrosFromStorage(const SourceEn
return usedMacros;
}
SourceEntries BuildDependenciesProvider::createSourceEntriesFromStorage(
const FilePathIds &sourcePathIds, Utils::SmallStringView projectPartId) const
{
std::pair<SourceEntries, int>
BuildDependenciesProvider::createSourceEntriesFromStorage(
const FilePathIds &sourcePathIds,
Utils::SmallStringView projectPartName) const {
SourceEntries includes;
Sqlite::DeferredTransaction transaction(m_transactionBackend);
int projectPartId = m_storage.fetchProjectPartId(projectPartName);
for (FilePathId sourcePathId : sourcePathIds) {
SourceEntries entries = m_storage.fetchDependSources(sourcePathId,
projectPartId);
SourceEntries entries =
m_storage.fetchDependSources(sourcePathId, projectPartId);
SourceEntries mergedEntries = setUnion<SourceEntries>(includes, entries);
includes = std::move(mergedEntries);
@@ -118,15 +121,14 @@ SourceEntries BuildDependenciesProvider::createSourceEntriesFromStorage(
transaction.commit();
return includes;
return {includes, projectPartId};
}
void BuildDependenciesProvider::storeBuildDependency(const BuildDependency &buildDependency)
{
void BuildDependenciesProvider::storeBuildDependency(
const BuildDependency &buildDependency, int projectPartId) {
Sqlite::ImmediateTransaction transaction(m_transactionBackend);
m_storage.updateSources(buildDependency.includes);
m_storage.insertFileStatuses(buildDependency.fileStatuses);
m_storage.insertOrUpdateSources(buildDependency.sources, projectPartId);
m_storage.insertOrUpdateFileStatuses(buildDependency.fileStatuses);
m_storage.insertOrUpdateSourceDependencies(buildDependency.sourceDependencies);
m_storage.insertOrUpdateUsedMacros(buildDependency.usedMacros);

View File

@@ -55,9 +55,9 @@ public:
private:
BuildDependency createBuildDependencyFromStorage(SourceEntries &&includes) const;
UsedMacros createUsedMacrosFromStorage(const SourceEntries &includes) const;
SourceEntries createSourceEntriesFromStorage(const FilePathIds &sourcePathIds,
Utils::SmallStringView projectPartId) const;
void storeBuildDependency(const BuildDependency &buildDependency);
std::pair<SourceEntries, int> createSourceEntriesFromStorage(
const FilePathIds &sourcePathIds, Utils::SmallStringView projectPartName) const;
void storeBuildDependency(const BuildDependency &buildDependency, int projectPartId);
private:
BuildDependenciesStorageInterface &m_storage;

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