Merge remote-tracking branch 'origin/4.8'

Conflicts:
	src/plugins/debugger/debuggeritem.cpp
	tests/unit/unittest/unittest.pro

Change-Id: Id2e4e9c2bc87b2556d7c2845aea3fe2fa11b630b
This commit is contained in:
Eike Ziller
2018-10-22 09:53:54 +02:00
151 changed files with 2927 additions and 1910 deletions
+2 -6
View File
@@ -255,13 +255,9 @@ http://llvm.org/docs/GettingStarted.html#git-mirror:
1. Clone LLVM and checkout a suitable branch
git clone -b release_60-based https://code.qt.io/clang/llvm
git clone -b release_70-based --recursive https://code.qt.io/clang/llvm
2. Clone Clang into llvm/tools/clang and checkout a suitable branch
git clone -b release_60-based https://code.qt.io/clang/clang llvm/tools/clang
3. Build and install LLVM/Clang
2. Build and install LLVM/Clang
mkdir build
cd build
+48
View File
@@ -0,0 +1,48 @@
Qt Creator version 4.7.2 contains bug fixes.
The most important changes are listed in this document. For a complete
list of changes, see the Git log for the Qt Creator sources that
you can check out from the public Git repository. For example:
git clone git://code.qt.io/qt-creator/qt-creator.git
git log --cherry-pick --pretty=oneline origin/v4.7.1..v4.7.2
Editing
* Fixed that collapsed text no longer showed up in tooltip (QTCREATORBUG-21040)
* Fixed crash with generic text completion (QTCREATORBUG-21192)
C++ Support
* Fixed wrong value of `__cplusplus` define (QTCREATORBUG-20884)
* Clang Code Model
* Fixed possible crash in `Follow Symbol Under Cursor`
* Fixed crash when using `Select Block Up/Down` with lambda
(QTCREATORBUG-20994)
Debugging
* CDB
* Fixed pretty printing of `std::vector` without Python (QTCREATORBUG-21074)
Platform Specific
Windows
* Fixed saving of files when another application blocks atomic save operation
(QTCREATORBUG-7668)
Remote Linux
* Fixed superfluous empty lines in application output (QTCREATORBUG-19367)
Credits for these changes go to:
David Schulz
Eike Ziller
Friedemann Kleint
Hannes Domani
Ivan Donchevskii
Jonathan Liu
Kai Köhne
Nikolai Kosjar
Sergey Belyashov
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

+1 -1
View File
@@ -33,7 +33,7 @@
\contentspage index.html
\previouspage creator-heob.html
\page creator-cpu-usage-analyzer.html
\nextpage creator-autotest.html
\nextpage creator-cppcheck.html
\title Analyzing CPU Usage
+5
View File
@@ -81,6 +81,11 @@
desktop applications with the Performance Analyzer (commercial only)
that integrates the Linux Perf tool.
\li \l{Analyzing Code with Cppcheck}
You can use the experimental Cppcheck plugin to detect undefined
behavior and dangerous coding constructs.
\endlist
*/
+85
View File
@@ -0,0 +1,85 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
**
** 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 Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
**
****************************************************************************/
/*!
\contentspage index.html
\previouspage creator-cpu-usage-analyzer.html
\page creator-cppcheck.html
\nextpage creator-autotest.html
\title Analyzing Code with Cppcheck
\l{http://cppcheck.sourceforge.net/}{Cppcheck} is a static analysis tool
that detects errors in C++ code. Static analysis is performed on the source
code without actually executing the application.
The experimental Cppcheck Diagnostics plugin integrates diagnostics
that are generated by the Cppcheck tool into the C++ editor.
To enable running Cppcheck automatically on currently open files:
\list 1
\li Select \uicontrol Help > \uicontrol {About Plugins} >
\uicontrol {Code Analyzer} > \uicontrol Cppcheck to enable the
plugin.
\li Restart \QC to load the plugin.
\li Select \uicontrol Tools > \uicontrol Options > \uicontrol Analyzer
> \uicontrol Cppcheck to specify settings for running Cppcheck.
\image qtcreator-cppcheck-options.png "Cppcheck options"
\li In the \uicontrol Binary field, enter the path to the Cppcheck
executable file.
\li In the \uicontrol Checks group, select the checks to perform on
currently open files.
\note By default, Cppcheck uses multiple threads to perform checks.
Selecting the \uicontrol {Unused functions} option disables the
default behavior.
\li In the \uicontrol {Custom arguments} field, enter additional
arguments for running Cppcheck. The arguments might be shadowed
by automatically generated ones. To avoid possible conflicts in
configuration, select the \uicontrol {Show raw output} check box
to see the final arguments.
\li In the \uicontrol {Ignored file patterns} field, enter a filter
for ignoring files that match the pattern (wildcard). You can enter
multiple patterns separated by commas. Even though Cppcheck is not
run on files that match the provided patterns, they might be
implicitly checked if other files include them.
\li Select the \uicontrol {Inconclusive errors} check box to also
mark possible false positives.
\li Select the \uicontrol {Check all define combinations} check box to
check all define combinations. Enabling this option can significantly
slow down analysis, but might help to find more issues.
\li Select the \uicontrol {Add include paths} check box to pass the
current project's include paths to Cppcheck. Enabling this option
slows down checks on big projects, but can help Cppcheck to find
missing includes.
\li Select the \uicontrol {Calculate additional arguments} check box to
calculate additional arguments based on current project's settings
(such as the language used and standard version) and pass them to
Cppcheck.
\endlist
\QC automatically runs Cppcheck on currently opened documents and displays
results via text marks or annotations.
*/
+9
View File
@@ -41,7 +41,9 @@
\title Coding
\if defined(qtcreator)
\image creator_coding.png
\endif
\list
@@ -89,6 +91,13 @@
\list
\li \l{Using Language Servers}
The experimental language client provides code completion,
highlighting of the symbol under cursor, and jumping to the symbol
definition for other programming languages besides C++. In addition,
it integrates diagnostics from the language server.
\li \l{Editing MIME Types}
\QC uses the MIME type of a file to determine which mode and editor
@@ -27,7 +27,7 @@
\contentspage index.html
\previouspage creator-editor-options-text.html
\page creator-editor-fakevim.html
\nextpage creator-mime-types.html
\nextpage creator-language-servers.html
\title Using FakeVim Mode
@@ -0,0 +1,83 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
**
** 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 Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
**
****************************************************************************/
/*!
\contentspage index.html
\previouspage creator-editor-fakevim.html
\page creator-language-servers.html
\nextpage creator-mime-types.html
\title Using Language Servers
For several programming languages, a \e {language server} is available
that provides information about the code to IDEs as long as they support
communication via the language server protocol (LSP). This enables the
IDE to provide code completion, highlighting of the symbol under cursor,
and jumping to the symbol definition, as well as to integrate diagnostics
from the language server.
By providing a client for the language server protocol, \QC can support
the above features for several other programming languages besides C++.
However, the experimental client does support language servers that
require special handling.
\QC uses the \l{https://www.iana.org/assignments/media-types/media-types.xhtml}
{MIME type} of the file to determine which language server to start when you
open a file for editing. Add new MIME types as filters for language servers.
For more information about how \QC uses MIME types, see
\l {Editing MIME Types}.
The experimental language service client has been mostly tested with Python.
If problems arise when you try some other language, please select
\uicontrol Help > \uicontrol {Report Bug} to report them in the Qt Bug
Tracker. The reports should include \QC console output with the environment
variable \c {QT_LOGGING_RULES=qtc.languageclient.*=true} set.
To use a language server:
\list 1
\li Enable the language server client by selecting \uicontrol Help >
\uicontrol {About Plugins} > \uicontrol {Other Languages} >
\uicontrol {Language Client} (or \uicontrol {Qt Creator} >
\uicontrol {About Plugins} > \uicontrol {Other Languages} >
\uicontrol {Language Client} on \macos).
\li Restart \QC to load the language client plugin.
\li Select \uicontrol Tools > \uicontrol Options >
\uicontrol {Language Client} > \uicontrol Add (or
\uicontrol {Qt Creator} > \uicontrol {Language Client} >
\uicontrol Add on \macos) to add language servers.
\li In the \uicontrol Name field, enter a name for the language server.
\li Select the \uicontrol Enabled check box.
\li In the \uicontrol {MIME Type} field, enter the filter for files that
the lanaguage server will handle. When you start typing the filter
name, a list of predefined filters appears where you can select a
filter.
\li In the \uicontrol Executable field, enter the path to the language
server executable.
\li In the \uicontrol Arguments field, enter any required command line
arguments.
\endlist
*/
@@ -31,16 +31,16 @@
/*!
\contentspage index.html
\previouspage creator-editor-fakevim.html
\previouspage creator-language-servers.html
\page creator-mime-types.html
\nextpage creator-modeling.html
\title Editing MIME Types
\QC uses the \l{http://en.wikipedia.org/wiki/Internet_media_type}
{Internet media type} (MIME type) of the file to determine which mode and
editor to use for opening the file. For example, \QC opens C++ source and
header files in the C++ editor, and Qt widget based UI files (.ui) in \QD.
\QC uses the \l{https://www.iana.org/assignments/media-types/media-types.xhtml}
{MIME type} of the file to determine which mode and editor to use for
opening the file. For example, \QC opens C++ source and header files in
the C++ editor, and Qt widget based UI files (.ui) in \QD.
To identify the MIME type of a file, \QC uses matching by pattern and
matching by contents. First, \QC looks at the filename to check whether it
@@ -25,7 +25,7 @@
/*!
\contentspage index.html
\previouspage creator-cpu-usage-analyzer.html
\previouspage creator-cppcheck.html
\page creator-autotest.html
\nextpage creator-advanced.html
+2
View File
@@ -141,6 +141,7 @@
\li \l{Specifying Text Editor Settings}
\li \l{Using FakeVim Mode}
\endlist
\li \l{Using Language Servers}
\li \l{Editing MIME Types}
\li \l{Modeling}
\li \l{Editing State Charts}
@@ -191,6 +192,7 @@
\li \l{Using Clang Tools}
\li \l{Detecting Memory Leaks with Heob}
\li \l{Analyzing CPU Usage}
\li \l{Analyzing Code with Cppcheck}
\endlist
\li \l{Running Autotests}
\endlist
+7 -7
View File
@@ -107,24 +107,24 @@ function formattingLibs(llvmConfig, qtcFunctions, targetOS)
var libs = []
if (qtcFunctions.versionIsAtLeast(clangVersion, MinimumLLVMVersion)) {
if (qtcFunctions.versionIsAtLeast(clangVersion, "7.0.0")) {
libs.concat([
libs.push(
"clangFormat",
"clangToolingInclusions",
"clangToolingCore",
"clangRewrite",
"clangLex",
"clangBasic",
]);
"clangBasic"
);
} else {
libs.concat([
libs.push(
"clangFormat",
"clangToolingCore",
"clangRewrite",
"clangLex",
"clangBasic",
]);
"clangBasic"
);
}
libs.concat(extraLibraries(llvmConfig, targetOS));
libs = libs.concat(extraLibraries(llvmConfig, targetOS));
}
return libs;
+4 -1
View File
@@ -230,7 +230,10 @@ class Dumper(DumperBase):
return None
def parseAndEvaluate(self, exp):
return self.fromNativeValue(cdbext.parseAndEvaluate(exp))
return self.fromNativeValue(self.nativeParseAndEvaluate(exp))
def nativeParseAndEvaluate(self, exp):
return cdbext.parseAndEvaluate(exp)
def isWindowsTarget(self):
return True
+15
View File
@@ -337,6 +337,10 @@ class DumperBase:
#warn('EXPANDED INAMES: %s' % self.expandedINames)
#warn('WATCHERS: %s' % self.watchers)
def resetPerStepCaches(self):
self.perStepCache = {}
pass
def resetCaches(self):
# This is a cache mapping from 'type name' to 'display alternatives'.
self.qqFormats = { 'QVariant (QVariantMap)' : mapForms() }
@@ -355,6 +359,14 @@ class DumperBase:
# to not be QObject derived, it contains a 0 value.
self.knownStaticMetaObjects = {}
# A dictionary to serve as a per debugging step cache.
# Cleared on each step over / into / continue.
self.perStepCache = {}
# A dictionary to serve as a general cache throughout the whole
# debug session.
self.generalCache = {}
self.counts = {}
self.structPatternCache = {}
self.pretimings = {}
@@ -3670,6 +3682,9 @@ class DumperBase:
error('wrong')
return bytes(struct.pack(self.packCode + self.ptrCode(), address))
def fromPointerData(self, bytes_value):
return struct.unpack(self.packCode + self.ptrCode(), bytes_value)
def createPointerValue(self, targetAddress, targetTypish):
if not isinstance(targetTypish, self.Type) and not isinstance(targetTypish, str):
error('Expected type in createPointerValue(), got %s'
+5 -1
View File
@@ -708,14 +708,18 @@ class Dumper(DumperBase):
self.reportResult(self.output)
def parseAndEvaluate(self, exp):
val = self.nativeParseAndEvaluate(exp)
return None if val is None else self.fromNativeValue(val)
def nativeParseAndEvaluate(self, exp):
#warn('EVALUATE "%s"' % exp)
try:
val = gdb.parse_and_eval(exp)
return val
except RuntimeError as error:
if self.passExceptions:
warn("Cannot evaluate '%s': %s" % (exp, error))
return None
return self.fromNativeValue(val)
def callHelper(self, rettype, value, function, args):
# args is a tuple.
+7
View File
@@ -1127,6 +1127,13 @@ class Dumper(DumperBase):
self.setVariableFetchingOptions(args)
# Reset certain caches whenever a step over / into / continue
# happens.
# FIXME: Caches are currently also cleared if currently
# selected frame is changed, that shouldn't happen.
if not self.partialVariable:
self.resetPerStepCaches()
anyModule = self.target.GetModuleAtIndex(0)
anySymbol = anyModule.GetSymbolAtIndex(0)
self.fakeAddress = int(anySymbol.GetStartAddress())
+166
View File
@@ -24,6 +24,7 @@
############################################################################
from dumper import *
import re
#######################################################################
#
@@ -351,6 +352,171 @@ def qdump__WTF__String(d, value):
d.putCharArrayHelper(bufferPtr, stringLength, charSize)
#######################################################################
#
# Python
#
#######################################################################
def get_python_interpreter_major_version(d):
key = 'python_interpreter_major_version'
if key in d.generalCache:
return d.generalCache[key]
e = "(char*)Py_GetVersion()"
result = d.nativeParseAndEvaluate(e)
result_str = str(result)
matches = re.search(r'(\d+?)\.(\d+?)\.(\d+?)', result_str)
if matches:
result_str = matches.group(1)
d.generalCache[key] = result_str
return result_str
def is_python_3(d):
return get_python_interpreter_major_version(d) == '3'
def repr_cache_decorator(namespace):
def real_decorator(func_to_decorate):
def wrapper(d, address):
if namespace in d.perStepCache and address in d.perStepCache[namespace]:
return d.perStepCache[namespace][address]
if namespace not in d.perStepCache:
d.perStepCache[namespace] = {}
if address == 0:
result_str = d.perStepCache[namespace][address] = "<nullptr>"
return result_str
result = func_to_decorate(d, address)
d.perStepCache[namespace][address] = result
return result
return wrapper
return real_decorator
@repr_cache_decorator('py_object')
def get_py_object_repr_helper(d, address):
# The code below is a long way to evaluate:
# ((PyBytesObject *)PyUnicode_AsEncodedString(PyObject_Repr(
# (PyObject*){}), \"utf-8\", \"backslashreplace\"))->ob_sval"
# But with proper object cleanup.
e_decref = "Py_DecRef((PyObject *){})"
e = "PyObject_Repr((PyObject*){})"
repr_object_value = d.parseAndEvaluate(e.format(address))
repr_object_address = d.fromPointerData(repr_object_value.ldata)[0]
if is_python_3(d):
# Try to get a UTF-8 encoded string from the repr object.
e = "PyUnicode_AsEncodedString((PyObject*){}, \"utf-8\", \"backslashreplace\")"
string_object_value = d.parseAndEvaluate(e.format(repr_object_address))
string_object_address = d.fromPointerData(string_object_value.ldata)[0]
e = "(char*)(((PyBytesObject *){})->ob_sval)"
result = d.nativeParseAndEvaluate(e.format(string_object_address))
# It's important to stringify the result before any other evaluations happen.
result_str = str(result)
# Clean up.
d.nativeParseAndEvaluate(e_decref.format(string_object_address))
else:
# Retrieve non-unicode string.
e = "(char*)(PyString_AsString((PyObject*){}))"
result = d.nativeParseAndEvaluate(e.format(repr_object_address))
# It's important to stringify the result before any other evaluations happen.
result_str = str(result)
# Do some string stripping.
# FIXME when using cdb engine.
matches = re.search(r'.+?"(.+)"$', result_str)
if matches:
result_str = matches.group(1)
# Clean up.
d.nativeParseAndEvaluate(e_decref.format(repr_object_address))
return result_str
@repr_cache_decorator('py_object_type')
def get_py_object_type(d, object_address):
e = "((PyObject *){})->ob_type"
type_value = d.parseAndEvaluate(e.format(object_address))
type_address = d.fromPointerData(type_value.ldata)[0]
type_repr = get_py_object_repr_helper(d, type_address)
return type_repr
@repr_cache_decorator('py_object_meta_type')
def get_py_object_meta_type(d, object_address):
# The python3 object layout has a few more indirections.
if is_python_3(d):
e = "((PyObject *){})->ob_type->ob_base->ob_base->ob_type"
else:
e = "((PyObject *){})->ob_type->ob_type"
type_value = d.parseAndEvaluate(e.format(object_address))
type_address = d.fromPointerData(type_value.ldata)[0]
type_repr = get_py_object_repr_helper(d, type_address)
return type_repr
@repr_cache_decorator('py_object_base_class')
def get_py_object_base_class(d, object_address):
e = "((PyObject *){})->ob_type->tp_base"
base_value = d.parseAndEvaluate(e.format(object_address))
base_address = d.fromPointerData(base_value.ldata)[0]
base_repr = get_py_object_repr_helper(d, base_address)
return base_repr
def get_py_object_repr(d, value):
address = value.address()
repr_available = False
try:
result = get_py_object_repr_helper(d, address)
d.putValue(d.hexencode(result), encoding='utf8')
repr_available = True
except:
d.putEmptyValue()
def sub_item(name, functor, address):
with SubItem(d, '[{}]'.format(name)):
sub_value = functor(d, address)
d.putValue(d.hexencode(sub_value), encoding='utf8')
d.putNumChild(1)
if d.isExpanded():
with Children(d):
if repr_available:
sub_item('class', get_py_object_type, address)
sub_item('super class', get_py_object_base_class, address)
sub_item('meta type', get_py_object_meta_type, address)
d.putFields(value)
def qdump__PyTypeObject(d, value):
get_py_object_repr(d, value)
def qdump___typeobject(d, value):
get_py_object_repr(d, value)
def qdump__PyObject(d, value):
get_py_object_repr(d, value)
def qdump__PyVarObject(d, value):
get_py_object_repr(d, value)
#######################################################################
#
# Internal test
@@ -195,7 +195,7 @@ void QuickItemNodeInstance::doComponentComplete()
QmlPrivateGate::disableTextCursor(quickItem());
DesignerSupport::emitComponentCompleteSignalForAttachedProperty(quickItem());
QmlPrivateGate::emitComponentComplete(quickItem());
QQmlProperty contentItemProperty(quickItem(), "contentItem", engine());
if (contentItemProperty.isValid())
@@ -85,6 +85,7 @@ public:
void setPropertyBinding(QObject *object, QQmlContext *context, const PropertyName &propertyName, const QString &expression);
void keepBindingFromGettingDeleted(QObject *object, QQmlContext *context, const PropertyName &propertyName);
void emitComponentComplete(QObject *item);
void doComponentCompleteRecursive(QObject *object, NodeInstanceServer *nodeInstanceServer);
bool objectWasDeleted(QObject *object);
@@ -44,6 +44,8 @@
#include <private/qquickdesignersupportproperties_p.h>
#include <private/qquickdesignersupportpropertychanges_p.h>
#include <private/qquickdesignersupportstates_p.h>
#include <private/qqmldata_p.h>
#include <private/qqmlcomponentattached_p.h>
namespace QmlDesigner {
@@ -216,6 +218,24 @@ void setPropertyBinding(QObject *object, QQmlContext *context, const PropertyNam
QQuickDesignerSupportProperties::setPropertyBinding(object, context, propertyName, expression);
}
void emitComponentComplete(QObject *item)
{
if (!item)
return;
QQmlData *data = QQmlData::get(item);
if (data && data->context) {
QQmlComponentAttached *componentAttached = data->context->componentAttached;
while (componentAttached) {
if (componentAttached->parent())
if (componentAttached->parent() == item)
emit componentAttached->completed();
componentAttached = componentAttached->next;
}
}
}
void doComponentCompleteRecursive(QObject *object, NodeInstanceServer *nodeInstanceServer)
{
if (object) {
@@ -224,6 +244,8 @@ void doComponentCompleteRecursive(QObject *object, NodeInstanceServer *nodeInsta
if (item && DesignerSupport::isComponentComplete(item))
return;
if (!nodeInstanceServer->hasInstanceForObject(item))
emitComponentComplete(object);
QList<QObject*> childList = object->children();
if (item) {
@@ -77,7 +77,7 @@ static QPair<QByteArray, QByteArray> splitHeaderFieldLine(
return {headerFieldLine.mid(0, assignmentIndex),
headerFieldLine.mid(assignmentIndex + fieldSeparatorLength)};
}
parseError = BaseMessage::tr("Unexpected header line \"%1\"")
parseError = BaseMessage::tr("Unexpected header line \"%1\".")
.arg(QLatin1String(headerFieldLine));
return {};
}
@@ -97,8 +97,8 @@ static void parseContentType(BaseMessage &message, QByteArray contentType, QStri
if (equalindex > 0)
codec = QTextCodec::codecForName(charset);
if (!codec) {
parseError = BaseMessage::tr("Cannot decode content with \"%1\" "
"falling back to \"%2\"")
parseError = BaseMessage::tr("Cannot decode content with \"%1\". "
"Falling back to \"%2\".")
.arg(QLatin1String(charset),
QLatin1String(defaultCharset));
}
@@ -113,7 +113,7 @@ static void parseContentLength(BaseMessage &message, QByteArray contentLength, Q
bool ok = true;
message.contentLength = QString::fromLatin1(contentLength).toInt(&ok);
if (!ok) {
parseError = BaseMessage::tr("Expected an integer in \"%1\", but got \"%2\"")
parseError = BaseMessage::tr("Expected an integer in \"%1\", but got \"%2\".")
.arg(contentLengthFieldName, QLatin1String(contentLength));
}
}
@@ -146,7 +146,7 @@ void BaseMessage::parse(QBuffer *data, QString &parseError, BaseMessage &message
} else if (headerFieldName == contentTypeFieldName) {
parseContentType(message, headerFieldValue, parseError);
} else {
parseError = tr("Unexpected header field \"%1\" in \"%2\"")
parseError = tr("Unexpected header field \"%1\" in \"%2\".")
.arg(QLatin1String(headerFieldName),
QLatin1String(headerFieldLine));
}
@@ -104,7 +104,7 @@ QString JsonObject::valueTypeString(QJsonValue::Type type)
QString JsonObject::errorString(QJsonValue::Type expected, QJsonValue::Type actual)
{
return tr("Expected Type %1 but value contained %2")
return tr("Expected type %1 but value contained %2")
.arg(valueTypeString(expected), valueTypeString(actual));
}
@@ -141,9 +141,9 @@ QJsonObject JsonRpcMessageHandler::toJsonObject(const QByteArray &_content,
if (doc.isObject())
return doc.object();
if (doc.isNull())
parseError = tr("Could not parse Json message '%1'").arg(error.errorString());
parseError = tr("Could not parse JSON message \"%1\".").arg(error.errorString());
else
parseError = tr("Expected Json object, but got a json '%1'").arg(docTypeName(doc));
parseError = tr("Expected a JSON object, but got a JSON \"%1\".").arg(docTypeName(doc));
return QJsonObject();
}
@@ -125,7 +125,7 @@ public:
}
if (errorMessage)
*errorMessage = QCoreApplication::translate("LanguageServerProtocol::Notification",
"No parameters in '%1'").arg(method());
"No parameters in \"%1\".").arg(method());
return false;
}
};
@@ -274,7 +274,7 @@ public:
return true;
if (errorMessage) {
*errorMessage = QCoreApplication::translate("LanguageServerProtocol::Request",
"No id set in '%1'").arg(this->method());
"No ID set in \"%1\".").arg(this->method());
}
return false;
}
@@ -331,7 +331,7 @@ bool MarkedString::isValid(QStringList *errorHierarchy) const
*errorHierarchy << QCoreApplication::translate(
"LanguageServerProtocol::MarkedString",
"MarkedString should be either MarkedLanguageString, "
"MarkupContent or QList<MarkedLanguageString>");
"MarkupContent, or QList<MarkedLanguageString>.");
}
return false;
}
@@ -356,7 +356,7 @@ bool DocumentFormattingProperty::isValid(QStringList *error) const
if (error) {
*error << QCoreApplication::translate(
"LanguageServerProtocol::MarkedString",
"DocumentFormattingProperty should be either bool, double or QString");
"DocumentFormattingProperty should be either bool, double, or QString.");
}
return false;
}
+1 -1
View File
@@ -136,7 +136,7 @@ bool MarkupOrString::isValid(QStringList *error) const
return true;
if (error) {
*error << QCoreApplication::translate("LanguageServerProtocoll::MarkupOrString",
"Expected a string or MarkupContent in MarkupOrString");
"Expected a string or MarkupContent in MarkupOrString.");
}
return false;
}
+15
View File
@@ -140,5 +140,20 @@ QTextCursor wordStartCursor(const QTextCursor &textCursor)
return cursor;
}
int utf8NthLineOffset(const QTextDocument *textDocument, const QByteArray &buffer, int line)
{
if (textDocument->characterCount() == buffer.size() + 1)
return textDocument->findBlockByNumber(line - 1).position();
int pos = 0;
for (int count = 0; count < line - 1; ++count) {
pos = buffer.indexOf('\n', pos);
if (pos == -1)
return -1;
++pos;
}
return pos;
}
} // Text
} // Utils
+4 -38
View File
@@ -29,7 +29,6 @@
#include "utils_global.h"
#include <QString>
#include <QTextCursor>
QT_FORWARD_DECLARE_CLASS(QTextDocument)
QT_FORWARD_DECLARE_CLASS(QTextCursor)
@@ -37,7 +36,7 @@ QT_FORWARD_DECLARE_CLASS(QTextCursor)
namespace Utils {
namespace Text {
// line is 1-based, column is 0-based
// line is 1-based, column is 1-based
QTCREATOR_UTILS_EXPORT bool convertPosition(const QTextDocument *document,
int pos,
int *line, int *column);
@@ -55,42 +54,9 @@ QTCREATOR_UTILS_EXPORT QTextCursor flippedCursor(const QTextCursor &cursor);
QTCREATOR_UTILS_EXPORT QTextCursor wordStartCursor(const QTextCursor &cursor);
template <class CharacterProvider>
void moveToPrevChar(CharacterProvider &provider, QTextCursor &cursor)
{
cursor.movePosition(QTextCursor::PreviousCharacter);
while (provider.characterAt(cursor.position()).isSpace())
cursor.movePosition(QTextCursor::PreviousCharacter);
}
template <class CharacterProvider>
bool matchPreviousWord(CharacterProvider &provider, QTextCursor cursor, QString pattern)
{
cursor.movePosition(QTextCursor::PreviousWord);
while (provider.characterAt(cursor.position()) == ':')
cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 2);
int previousWordStart = cursor.position();
cursor.movePosition(QTextCursor::NextWord);
moveToPrevChar(provider, cursor);
QString toMatch = provider.textAt(previousWordStart, cursor.position() - previousWordStart + 1);
pattern = pattern.simplified();
while (!pattern.isEmpty() && pattern.endsWith(toMatch)) {
pattern.chop(toMatch.length());
if (pattern.endsWith(' '))
pattern.chop(1);
if (!pattern.isEmpty()) {
cursor.movePosition(QTextCursor::StartOfWord);
cursor.movePosition(QTextCursor::PreviousWord);
previousWordStart = cursor.position();
cursor.movePosition(QTextCursor::NextWord);
moveToPrevChar(provider, cursor);
toMatch = provider.textAt(previousWordStart, cursor.position() - previousWordStart + 1);
}
}
return pattern.isEmpty();
}
QTCREATOR_UTILS_EXPORT int utf8NthLineOffset(const QTextDocument *textDocument,
const QByteArray &buffer,
int line);
} // Text
} // Utils
+4 -1
View File
@@ -451,6 +451,8 @@ AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath,
QList<AndroidToolChain *> toolChainBundle;
for (Core::Id lang : {ProjectExplorer::Constants::CXX_LANGUAGE_ID, ProjectExplorer::Constants::C_LANGUAGE_ID}) {
FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, lang, version);
if (!compilerPath.exists())
continue;
AndroidToolChain *tc = findToolChain(compilerPath, lang, alreadyKnown);
if (!tc || tc->originalTargetTriple().isEmpty()) {
@@ -464,7 +466,8 @@ AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath,
toolChainBundle.append(tc);
}
QTC_ASSERT(!toolChainBundle.isEmpty(), continue);
if (toolChainBundle.isEmpty())
continue;
auto it = newestToolChainForArch.constFind(abi);
if (it == newestToolChainForArch.constEnd())
+24 -8
View File
@@ -57,6 +57,7 @@
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <texteditor/texteditor.h>
#include <texteditor/textdocument.h>
#include <utils/textutils.h>
#include <utils/utilsicons.h>
@@ -261,11 +262,22 @@ void AutotestPlugin::onRunFileTriggered()
runner->prepareToRunTests(TestRunMode::Run);
}
static QList<TestConfiguration *> testItemsToTestConfigurations(const QList<TestTreeItem *> &items,
TestRunMode mode)
{
QList<TestConfiguration *> configs;
for (const TestTreeItem * item : items) {
if (TestConfiguration *currentConfig = item->asConfiguration(mode))
configs << currentConfig;
}
return configs;
}
void AutotestPlugin::onRunUnderCursorTriggered(TestRunMode mode)
{
QTextCursor cursor = Utils::Text::wordStartCursor(
TextEditor::BaseTextEditor::currentTextEditor()->editorWidget()->textCursor());
cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
TextEditor::BaseTextEditor *currentEditor = TextEditor::BaseTextEditor::currentTextEditor();
QTextCursor cursor = currentEditor->editorWidget()->textCursor();
cursor.select(QTextCursor::WordUnderCursor);
const QString text = cursor.selectedText();
if (text.isEmpty())
return; // Do not trigger when no name under cursor
@@ -274,11 +286,15 @@ void AutotestPlugin::onRunUnderCursorTriggered(TestRunMode mode)
if (testsItems.isEmpty())
return; // Wrong location triggered
QList<TestConfiguration *> testsToRun;
for (const TestTreeItem * item : testsItems){
if (TestConfiguration *cfg = item->asConfiguration(mode))
testsToRun << cfg;
}
// check whether we have been triggered on a test function definition
const uint line = uint(currentEditor->currentLine());
const QString &filePath = currentEditor->textDocument()->filePath().toString();
const QList<TestTreeItem *> filteredItems = Utils::filtered(testsItems, [&](TestTreeItem *it){
return it->line() == line && it->filePath() == filePath;
});
const QList<TestConfiguration *> testsToRun = testItemsToTestConfigurations(
filteredItems.size() == 1 ? filteredItems : testsItems, mode);
if (testsToRun.isEmpty()) {
MessageManager::write(tr("Selected test was not found (%1).").arg(text), MessageManager::Flash);
@@ -198,9 +198,9 @@ void ClangAssistProposalItem::apply(TextDocumentManipulatorInterface &manipulato
QTextCursor cursor = manipulator.textCursorAt(basePosition);
bool abandonParen = false;
if (::Utils::Text::matchPreviousWord(manipulator, cursor, "&")) {
::Utils::Text::moveToPrevChar(manipulator, cursor);
::Utils::Text::moveToPrevChar(manipulator, cursor);
if (Utils::Text::matchPreviousWord(manipulator, cursor, "&")) {
Utils::Text::moveToPreviousWord(manipulator, cursor);
Utils::Text::moveToPreviousChar(manipulator, cursor);
const QChar prevChar = manipulator.characterAt(cursor.position());
cursor.setPosition(basePosition);
abandonParen = QString("(;,{}").contains(prevChar);
@@ -211,7 +211,7 @@ void ClangAssistProposalItem::apply(TextDocumentManipulatorInterface &manipulato
if (!abandonParen && ccr.completionKind == CodeCompletion::FunctionDefinitionCompletionKind) {
const CodeCompletionChunk resultType = ccr.chunks.first();
if (resultType.kind == CodeCompletionChunk::ResultType) {
if (::Utils::Text::matchPreviousWord(manipulator, cursor, resultType.text.toString())) {
if (Utils::Text::matchPreviousWord(manipulator, cursor, resultType.text.toString())) {
extraCharacters += methodDefinitionParameters(ccr.chunks);
// To skip the next block.
abandonParen = true;
@@ -207,9 +207,26 @@ bool BackendCommunicator::isNotWaitingForCompletion() const
return !m_receiver.isExpectingCompletionsMessage();
}
void BackendCommunicator::setBackendJobsPostponed(bool postponed)
{
if (postponed) {
if (!m_postponeBackendJobs)
documentVisibilityChanged(Utf8String(), {});
++m_postponeBackendJobs;
} else {
if (QTC_GUARD(m_postponeBackendJobs > 0))
--m_postponeBackendJobs;
if (!m_postponeBackendJobs)
documentVisibilityChanged();
}
}
void BackendCommunicator::documentVisibilityChanged(const Utf8String &currentEditorFilePath,
const Utf8StringVector &visibleEditorsFilePaths)
{
if (m_postponeBackendJobs)
return;
const DocumentVisibilityChangedMessage message(currentEditorFilePath, visibleEditorsFilePaths);
m_sender->documentVisibilityChanged(message);
}
@@ -459,9 +476,14 @@ void BackendCommunicator::initializeBackendWithCurrentData()
void BackendCommunicator::documentsOpened(const FileContainers &fileContainers)
{
const DocumentsOpenedMessage message(fileContainers,
currentCppEditorDocumentFilePath(),
visibleCppEditorDocumentsFilePaths());
Utf8String currentDocument;
Utf8StringVector visibleDocuments;
if (!m_postponeBackendJobs) {
currentDocument = currentCppEditorDocumentFilePath();
visibleDocuments = visibleCppEditorDocumentsFilePaths();
}
const DocumentsOpenedMessage message(fileContainers, currentDocument, visibleDocuments);
m_sender->documentsOpened(message);
}
@@ -108,6 +108,8 @@ public:
void updateChangeContentStartPosition(const QString &filePath, int position);
bool isNotWaitingForCompletion() const;
void setBackendJobsPostponed(bool postponed);
private:
void initializeBackend();
void initializeBackendWithCurrentData();
@@ -134,6 +136,7 @@ private:
QTimer m_backendStartTimeOut;
QScopedPointer<ClangBackEnd::ClangCodeModelServerInterface> m_sender;
int m_connectedCount = 0;
int m_postponeBackendJobs = 1; // Initial application state is inactive, so no jobs should be run.
};
} // namespace Internal
@@ -98,9 +98,9 @@ static void addFunctionOverloadAssistProposalItem(QList<AssistProposalItemInterf
cursor.movePosition(QTextCursor::StartOfWord);
const ClangBackEnd::CodeCompletionChunk resultType = codeCompletion.chunks.first();
if (::Utils::Text::matchPreviousWord(*interface->textEditorWidget(),
cursor,
resultType.text.toString())) {
if (Utils::Text::matchPreviousWord(*interface->textEditorWidget(),
cursor,
resultType.text.toString())) {
// Function definition completion - do not merge completions together.
addAssistProposalItem(items, codeCompletion, name);
} else {
@@ -445,6 +445,12 @@ bool ClangCompletionAssistProcessor::completeInclude(const QTextCursor &cursor)
completeIncludePath(realPath, suffixes);
}
auto includesCompare = [](AssistProposalItemInterface *first,
AssistProposalItemInterface *second) {
return first->text() < second->text();
};
std::sort(m_completions.begin(), m_completions.end(), includesCompare);
return !m_completions.isEmpty();
}
@@ -53,7 +53,7 @@
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <QCoreApplication>
#include <QApplication>
#include <QMenu>
#include <QTextBlock>
@@ -75,6 +75,8 @@ ModelManagerSupportClang::ModelManagerSupportClang()
QTC_CHECK(!m_instance);
m_instance = this;
QApplication::instance()->installEventFilter(this);
CppTools::CppModelManager::instance()->setCurrentDocumentFilter(
std::make_unique<ClangCurrentDocumentFilter>());
@@ -138,6 +140,11 @@ std::unique_ptr<CppTools::AbstractOverviewModel> ModelManagerSupportClang::creat
return std::make_unique<OverviewModel>();
}
void ModelManagerSupportClang::setBackendJobsPostponed(bool postponed)
{
m_communicator.setBackendJobsPostponed(postponed);
}
CppTools::BaseEditorDocumentProcessor *ModelManagerSupportClang::createEditorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument)
{
@@ -211,6 +218,20 @@ void ModelManagerSupportClang::connectToWidgetsMarkContextMenuRequested(QWidget
}
}
bool ModelManagerSupportClang::eventFilter(QObject *obj, QEvent *e)
{
if (obj == QApplication::instance() && e->type() == QEvent::ApplicationStateChange) {
switch (QApplication::applicationState()) {
case Qt::ApplicationInactive: setBackendJobsPostponed(true); break;
case Qt::ApplicationActive: setBackendJobsPostponed(false); break;
default:
QTC_CHECK(false && "Unexpected Qt::ApplicationState");
}
}
return false;
}
void ModelManagerSupportClang::onEditorOpened(Core::IEditor *editor)
{
QTC_ASSERT(editor, return);
@@ -72,6 +72,7 @@ public:
CppTools::FollowSymbolInterface &followSymbolInterface() override;
CppTools::RefactoringEngineInterface &refactoringEngineInterface() override;
std::unique_ptr<CppTools::AbstractOverviewModel> createOverviewModel() override;
void setBackendJobsPostponed(bool postponed) override;
BackendCommunicator &communicator();
QString dummyUiHeaderOnDiskDirPath() const;
@@ -82,6 +83,8 @@ public:
static ModelManagerSupportClang *instance();
private:
bool eventFilter(QObject *obj, QEvent *e) override;
void onEditorOpened(Core::IEditor *editor);
void onEditorClosed(const QList<Core::IEditor *> &editors);
void onCurrentEditorChanged(Core::IEditor *newCurrent);
+50
View File
@@ -29,6 +29,8 @@
#include <cpptools/projectpart.h>
#include <QTextCursor>
QT_BEGIN_NAMESPACE
class QTextBlock;
QT_END_NAMESPACE
@@ -66,5 +68,53 @@ QString diagnosticCategoryPrefixRemoved(const QString &text);
void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo);
namespace Text {
template <class CharacterProvider>
void moveToPreviousChar(CharacterProvider &provider, QTextCursor &cursor)
{
cursor.movePosition(QTextCursor::PreviousCharacter);
while (provider.characterAt(cursor.position()).isSpace())
cursor.movePosition(QTextCursor::PreviousCharacter);
}
template <class CharacterProvider>
void moveToPreviousWord(CharacterProvider &provider, QTextCursor &cursor)
{
cursor.movePosition(QTextCursor::PreviousWord);
while (provider.characterAt(cursor.position()) == ':')
cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 2);
}
template <class CharacterProvider>
bool matchPreviousWord(CharacterProvider &provider, QTextCursor cursor, QString pattern)
{
cursor.movePosition(QTextCursor::PreviousWord);
while (provider.characterAt(cursor.position()) == ':')
cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 2);
int previousWordStart = cursor.position();
cursor.movePosition(QTextCursor::NextWord);
moveToPreviousChar(provider, cursor);
QString toMatch = provider.textAt(previousWordStart, cursor.position() - previousWordStart + 1);
pattern = pattern.simplified();
while (!pattern.isEmpty() && pattern.endsWith(toMatch)) {
pattern.chop(toMatch.length());
if (pattern.endsWith(' '))
pattern.chop(1);
if (!pattern.isEmpty()) {
cursor.movePosition(QTextCursor::StartOfWord);
cursor.movePosition(QTextCursor::PreviousWord);
previousWordStart = cursor.position();
cursor.movePosition(QTextCursor::NextWord);
moveToPreviousChar(provider, cursor);
toMatch = provider.textAt(previousWordStart, cursor.position() - previousWordStart + 1);
}
}
return pattern.isEmpty();
}
} // namespace Text
} // namespace Utils
} // namespace Clang
+2 -1
View File
@@ -24,7 +24,8 @@ HEADERS = \
clangformatconfigwidget.h \
clangformatindenter.h \
clangformatplugin.h \
clangformatconstants.h
clangformatconstants.h \
clangformatutils.h
FORMS += \
clangformatconfigwidget.ui
+2 -1
View File
@@ -27,10 +27,11 @@ QtcPlugin {
"clangformatconfigwidget.cpp",
"clangformatconfigwidget.h",
"clangformatconfigwidget.ui",
"clangformatconstants.h",
"clangformatindenter.cpp",
"clangformatindenter.h",
"clangformatplugin.cpp",
"clangformatplugin.h",
"clangformatconstants.h",
"clangformatutils.h",
]
}
@@ -25,6 +25,8 @@
#include "clangformatconfigwidget.h"
#include "clangformatutils.h"
#include "ui_clangformatconfigwidget.h"
#include <clang/Format/Format.h>
@@ -40,23 +42,6 @@
using namespace ProjectExplorer;
namespace ClangFormat {
namespace Internal {
static void createGlobalClangFormatFileIfNeeded(const QString &settingsDir)
{
const QString fileName = settingsDir + "/.clang-format";
if (QFile::exists(fileName))
return;
QFile file(fileName);
if (!file.open(QFile::WriteOnly))
return;
const clang::format::FormatStyle defaultStyle = clang::format::getLLVMStyle();
const std::string configuration = clang::format::configurationAsText(defaultStyle);
file.write(configuration.c_str());
file.close();
}
static void readTable(QTableWidget *table, std::istringstream &stream)
{
@@ -137,50 +122,75 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(ProjectExplorer::Project *proje
{
m_ui->setupUi(this);
std::string testFilePath;
initialize();
}
void ClangFormatConfigWidget::initialize()
{
m_ui->projectHasClangFormat->show();
m_ui->clangFormatOptionsTable->show();
m_ui->applyButton->show();
if (m_project && !m_project->projectDirectory().appendPath(".clang-format").exists()) {
m_ui->projectHasClangFormat->setText("No .clang-format file for the project");
m_ui->projectHasClangFormat->setText(tr("No .clang-format file for the project."));
m_ui->clangFormatOptionsTable->hide();
m_ui->applyButton->hide();
connect(m_ui->createFileButton, &QPushButton::clicked,
this, [this]() {
createStyleFileIfNeeded(m_project->projectDirectory());
initialize();
});
return;
}
m_ui->createFileButton->hide();
std::string testFilePath;
if (m_project) {
m_ui->projectHasClangFormat->hide();
testFilePath = m_project->projectDirectory().appendPath("t.cpp").toString().toStdString();
connect(m_ui->applyButton, &QPushButton::clicked, this, &ClangFormatConfigWidget::apply);
} else {
const Project *currentProject = SessionManager::startupProject();
if (!currentProject
|| !currentProject->projectDirectory().appendPath(".clang-format").exists()) {
m_ui->projectHasClangFormat->hide();
} else {
m_ui->projectHasClangFormat->setText(
tr(" Current project has its own .clang-format file "
"and can be configured in Projects > Clang Format."));
}
const QString settingsDir = Core::ICore::userResourcePath();
createGlobalClangFormatFileIfNeeded(settingsDir);
createStyleFileIfNeeded(Utils::FileName::fromString(settingsDir));
testFilePath = settingsDir.toStdString() + "/t.cpp";
m_ui->applyButton->hide();
}
fillTable(testFilePath);
}
void ClangFormatConfigWidget::fillTable(const std::string &testFilePath)
{
llvm::Expected<clang::format::FormatStyle> formatStyle =
clang::format::getStyle("file", testFilePath, "LLVM", "");
if (!formatStyle)
return;
const std::string configText = clang::format::configurationAsText(*formatStyle);
std::istringstream stream(configText);
readTable(m_ui->clangFormatOptionsTable, stream);
if (m_project) {
m_ui->projectHasClangFormat->hide();
return;
clang::format::getStyle("file", testFilePath, "LLVM");
std::string configText;
bool brokenConfig = false;
if (!formatStyle) {
handleAllErrors(formatStyle.takeError(), [](const llvm::ErrorInfoBase &) {
// do nothing
});
configText = clang::format::configurationAsText(clang::format::getLLVMStyle());
brokenConfig = true;
} else {
configText = clang::format::configurationAsText(*formatStyle);
}
const Project *currentProject = SessionManager::startupProject();
if (!currentProject || !currentProject->projectDirectory().appendPath(".clang-format").exists())
m_ui->projectHasClangFormat->hide();
std::istringstream stream(configText);
readTable(m_ui->clangFormatOptionsTable, stream);
if (brokenConfig)
apply();
connect(SessionManager::instance(), &SessionManager::startupProjectChanged,
this, [this](ProjectExplorer::Project *project) {
if (project && project->projectDirectory().appendPath(".clang-format").exists())
m_ui->projectHasClangFormat->show();
else
m_ui->projectHasClangFormat->hide();
});
}
ClangFormatConfigWidget::~ClangFormatConfigWidget() = default;
@@ -201,5 +211,4 @@ void ClangFormatConfigWidget::apply()
file.close();
}
} // namespace Internal
} // namespace ClangFormat
@@ -32,7 +32,6 @@
namespace ProjectExplorer { class Project; }
namespace ClangFormat {
namespace Internal {
namespace Ui {
class ClangFormatConfigWidget;
@@ -49,9 +48,11 @@ public:
void apply();
private:
void initialize();
void fillTable(const std::string &testFilePath);
ProjectExplorer::Project *m_project;
std::unique_ptr<Ui::ClangFormatConfigWidget> m_ui;
};
} // namespace Internal
} // namespace ClangFormat
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ClangFormat::Internal::ClangFormatConfigWidget</class>
<widget class="QWidget" name="ClangFormat::Internal::ClangFormatConfigWidget">
<class>ClangFormat::ClangFormatConfigWidget</class>
<widget class="QWidget" name="ClangFormat::ClangFormatConfigWidget">
<property name="geometry">
<rect>
<x>0</x>
@@ -29,7 +29,7 @@
<item>
<widget class="QLabel" name="projectHasClangFormat">
<property name="text">
<string> Current project has its own .clang-format file and can be configured in Projects -&gt; ClangFormat.</string>
<string/>
</property>
</widget>
</item>
@@ -38,6 +38,13 @@
</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">
+248 -278
View File
@@ -25,16 +25,21 @@
#include "clangformatindenter.h"
#include "clangformatutils.h"
#include <clang/Format/Format.h>
#include <clang/Tooling/Core/Replacement.h>
#include <coreplugin/icore.h>
#include <cpptools/cppmodelmanager.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include <utils/hostosinfo.h>
#include <utils/textutils.h>
#include <utils/qtcassert.h>
#include <llvm/Config/llvm-config.h>
@@ -42,6 +47,8 @@
#include <QFileInfo>
#include <QTextBlock>
#include <fstream>
using namespace clang;
using namespace format;
using namespace llvm;
@@ -50,67 +57,35 @@ using namespace ProjectExplorer;
using namespace TextEditor;
namespace ClangFormat {
namespace Internal {
namespace {
void adjustFormatStyleForLineBreak(format::FormatStyle &style,
int length,
int prevBlockSize,
bool prevBlockEndsWithPunctuation)
void adjustFormatStyleForLineBreak(format::FormatStyle &style)
{
if (length > 0)
style.ColumnLimit = prevBlockSize;
style.AlwaysBreakBeforeMultilineStrings = true;
#if LLVM_VERSION_MAJOR >= 7
style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes;
#else
style.AlwaysBreakTemplateDeclarations = true;
style.DisableFormat = false;
style.ColumnLimit = 0;
#ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED
style.KeepLineBreaksForNonEmptyLines = true;
#endif
style.AllowAllParametersOfDeclarationOnNextLine = true;
style.AllowShortBlocksOnASingleLine = true;
style.AllowShortCaseLabelsOnASingleLine = true;
style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
style.AllowShortIfStatementsOnASingleLine = true;
style.AllowShortLoopsOnASingleLine = true;
if (prevBlockEndsWithPunctuation) {
style.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
style.BreakBeforeTernaryOperators = false;
style.BreakConstructorInitializers = FormatStyle::BCIS_AfterColon;
} else {
style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
style.BreakBeforeTernaryOperators = true;
style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
}
style.MaxEmptyLinesToKeep = 2;
}
Replacements filteredReplacements(const Replacements &replacements,
unsigned int offset,
unsigned int lengthForFilter,
int extraOffsetToAdd,
int prevBlockLength)
int offset,
int lengthForFilter,
int extraOffsetToAdd)
{
Replacements filtered;
for (const Replacement &replacement : replacements) {
unsigned int replacementOffset = replacement.getOffset();
int replacementOffset = static_cast<int>(replacement.getOffset());
if (replacementOffset > offset + lengthForFilter)
break;
if (offset > static_cast<unsigned int>(prevBlockLength)
&& replacementOffset < offset - static_cast<unsigned int>(prevBlockLength))
continue;
if (lengthForFilter == 0 && replacement.getReplacementText().find('\n') == std::string::npos
&& filtered.empty()) {
continue;
}
if (replacementOffset + 1 >= offset)
replacementOffset += static_cast<unsigned int>(extraOffsetToAdd);
replacementOffset += extraOffsetToAdd;
Error error = filtered.add(Replacement(replacement.getFilePath(),
replacementOffset,
static_cast<unsigned int>(replacementOffset),
replacement.getLength(),
replacement.getReplacementText()));
// Throws if error is not checked.
@@ -120,147 +95,58 @@ Replacements filteredReplacements(const Replacements &replacements,
return filtered;
}
std::string assumedFilePath()
Utils::FileName styleConfigPath()
{
const Project *project = SessionManager::startupProject();
if (project && project->projectDirectory().appendPath(".clang-format").exists())
return project->projectDirectory().appendPath("test.cpp").toString().toStdString();
return project->projectDirectory();
return QString(Core::ICore::userResourcePath() + "/test.cpp").toStdString();
return Utils::FileName::fromString(Core::ICore::userResourcePath());
}
FormatStyle formatStyle()
FormatStyle formatStyle(Utils::FileName styleConfigPath)
{
Expected<FormatStyle> style = format::getStyle("file", assumedFilePath(), "none", "");
createStyleFileIfNeeded(styleConfigPath);
Expected<FormatStyle> style = format::getStyle(
"file", styleConfigPath.appendPath("test.cpp").toString().toStdString(), "LLVM");
if (style)
return *style;
return FormatStyle();
handleAllErrors(style.takeError(), [](const ErrorInfoBase &) {
// do nothing
});
return format::getLLVMStyle();
}
Replacements replacements(const std::string &buffer,
unsigned int offset,
unsigned int length,
bool blockFormatting = false,
const QChar &typedChar = QChar::Null,
int extraOffsetToAdd = 0,
int prevBlockLength = 1,
bool prevBlockEndsWithPunctuation = false)
{
FormatStyle style = formatStyle();
if (blockFormatting && typedChar == QChar::Null)
adjustFormatStyleForLineBreak(style, length, prevBlockLength, prevBlockEndsWithPunctuation);
std::vector<Range> ranges{{offset, length}};
FormattingAttemptStatus status;
Replacements replacements = reformat(style, buffer, ranges, assumedFilePath(), &status);
if (!status.FormatComplete)
Replacements();
unsigned int lengthForFilter = 0;
if (!blockFormatting)
lengthForFilter = length;
return filteredReplacements(replacements,
offset,
lengthForFilter,
extraOffsetToAdd,
prevBlockLength);
}
void applyReplacements(QTextDocument *doc,
const std::string &stdStrBuffer,
const tooling::Replacements &replacements,
int totalShift)
{
if (replacements.empty())
return;
QTextCursor editCursor(doc);
int fullOffsetDiff = 0;
for (const Replacement &replacement : replacements) {
const int utf16Offset
= QString::fromStdString(stdStrBuffer.substr(0, replacement.getOffset())).length()
+ totalShift + fullOffsetDiff;
const int utf16Length = QString::fromStdString(stdStrBuffer.substr(replacement.getOffset(),
replacement.getLength()))
.length();
const QString replacementText = QString::fromStdString(replacement.getReplacementText());
editCursor.beginEditBlock();
editCursor.setPosition(utf16Offset);
editCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, utf16Length);
editCursor.removeSelectedText();
editCursor.insertText(replacementText);
editCursor.endEditBlock();
fullOffsetDiff += replacementText.length() - utf16Length;
}
}
// Returns offset shift.
int modifyToIndentEmptyLines(QString &buffer, int &offset, int &length, const QTextBlock &block)
{
//This extra text works for the most cases.
QString extraText("a;");
const QString blockText = block.text().trimmed();
// Search for previous character
QTextBlock prevBlock = block.previous();
while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty())
prevBlock = prevBlock.previous();
if (prevBlock.text().endsWith(','))
extraText = "int a,";
const bool closingParenBlock = blockText.startsWith(')');
if (closingParenBlock) {
if (prevBlock.text().endsWith(','))
extraText = "int a";
else
extraText = "&& a";
}
if (length == 0 || closingParenBlock) {
length += extraText.length();
buffer.insert(offset, extraText);
}
if (blockText.startsWith('}')) {
buffer.insert(offset - 1, extraText);
offset += extraText.size();
return extraText.size();
}
return 0;
}
// Returns first non-empty block (searches from current block backwards).
QTextBlock clearFirstNonEmptyBlockFromExtraSpaces(const QTextBlock &currentBlock)
void trimFirstNonEmptyBlock(const QTextBlock &currentBlock)
{
QTextBlock prevBlock = currentBlock.previous();
while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty())
prevBlock = prevBlock.previous();
if (prevBlock.text().trimmed().isEmpty())
return prevBlock;
return;
const QString initialText = prevBlock.text();
if (!initialText.at(initialText.length() - 1).isSpace())
return prevBlock;
if (!initialText.at(initialText.size() - 1).isSpace())
return;
int extraSpaceCount = 1;
for (int i = initialText.size() - 2; i >= 0; --i) {
if (!initialText.at(i).isSpace())
break;
++extraSpaceCount;
}
QTextCursor cursor(prevBlock);
cursor.beginEditBlock();
cursor.movePosition(QTextCursor::EndOfBlock);
cursor.movePosition(QTextCursor::Left);
while (cursor.positionInBlock() >= 0 && initialText.at(cursor.positionInBlock()).isSpace())
cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
if (cursor.hasSelection())
cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor,
initialText.size() - extraSpaceCount);
cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, extraSpaceCount);
cursor.removeSelectedText();
cursor.endEditBlock();
return prevBlock;
}
// Returns the total langth of previous lines with pure whitespace.
@@ -276,42 +162,175 @@ int previousEmptyLinesLength(const QTextBlock &currentBlock)
return length;
}
static constexpr const int MinCharactersBeforeCurrentInBuffer = 200;
static constexpr const int MaxCharactersBeforeCurrentInBuffer = 500;
int startOfIndentationBuffer(const QString &buffer, int start)
void modifyToIndentEmptyLines(QByteArray &buffer, int &offset, int &length, const QTextBlock &block)
{
if (start < MaxCharactersBeforeCurrentInBuffer)
return 0;
const QString blockText = block.text().trimmed();
const bool closingParenBlock = blockText.startsWith(')');
if (length != 0 && !closingParenBlock)
return;
auto it = buffer.cbegin() + (start - MinCharactersBeforeCurrentInBuffer);
for (; it != buffer.cbegin() + (start - MaxCharactersBeforeCurrentInBuffer); --it) {
if (*it == '{') {
// Find the start of it's line.
for (auto inner = it;
inner != buffer.cbegin() + (start - MaxCharactersBeforeCurrentInBuffer);
--inner) {
if (*inner == '\n')
return inner + 1 - buffer.cbegin();
}
break;
}
//This extra text works for the most cases.
QByteArray extraText("a;");
// Search for previous character
QTextBlock prevBlock = block.previous();
while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty())
prevBlock = prevBlock.previous();
if (prevBlock.text().endsWith(','))
extraText = "int a,";
if (closingParenBlock) {
if (prevBlock.text().endsWith(','))
extraText = "int a";
else
extraText = "&& a";
}
return it - buffer.cbegin();
length += extraText.length();
buffer.insert(offset, extraText);
}
int nextEndingScopePosition(const QString &buffer, int start)
{
if (start >= buffer.size() - 1)
return buffer.size() - 1;
static const int kMaxLinesFromCurrentBlock = 200;
for (auto it = buffer.cbegin() + (start + 1); it != buffer.cend(); ++it) {
if (*it == '}')
return it - buffer.cbegin();
Replacements replacements(QByteArray buffer,
int utf8Offset,
int utf8Length,
const QTextBlock *block = nullptr,
const QChar &typedChar = QChar::Null)
{
Utils::FileName stylePath = styleConfigPath();
FormatStyle style = formatStyle(stylePath);
int extraOffset = 0;
if (block) {
if (block->blockNumber() > kMaxLinesFromCurrentBlock) {
extraOffset = Utils::Text::utf8NthLineOffset(
block->document(), buffer, block->blockNumber() - kMaxLinesFromCurrentBlock);
}
buffer = buffer.mid(extraOffset,
std::min(buffer.size(), utf8Offset + kMaxLinesFromCurrentBlock)
- extraOffset);
utf8Offset -= extraOffset;
const int emptySpaceLength = previousEmptyLinesLength(*block);
utf8Offset -= emptySpaceLength;
buffer.remove(utf8Offset, emptySpaceLength);
extraOffset += emptySpaceLength;
adjustFormatStyleForLineBreak(style);
if (typedChar == QChar::Null)
modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, *block);
}
return buffer.size() - 1;
std::vector<Range> ranges{{static_cast<unsigned int>(utf8Offset),
static_cast<unsigned int>(utf8Length)}};
FormattingAttemptStatus status;
const std::string assumedFilePath
= stylePath.appendPath("test.cpp").toString().toStdString();
Replacements replacements = reformat(style, buffer.data(), ranges, assumedFilePath, &status);
if (!status.FormatComplete)
Replacements();
int lengthForFilter = 0;
if (block == nullptr)
lengthForFilter = utf8Length;
return filteredReplacements(replacements,
utf8Offset,
lengthForFilter,
extraOffset);
}
Utils::LineColumn utf16LineColumn(const QTextBlock &block,
int blockOffsetUtf8,
const QByteArray &utf8Buffer,
int utf8Offset)
{
if (utf8Offset < blockOffsetUtf8 - 1)
return Utils::LineColumn();
if (utf8Offset == blockOffsetUtf8 - 1) {
const int lineStart = utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1;
const QByteArray lineText = utf8Buffer.mid(lineStart, utf8Offset - lineStart);
return Utils::LineColumn(block.blockNumber(), QString::fromUtf8(lineText).size() + 1);
}
int pos = blockOffsetUtf8;
int prevPos = pos;
int line = block.blockNumber(); // Start with previous line.
while (pos != -1 && pos <= utf8Offset) {
// Find the first pos which comes after offset and take the previous line.
++line;
prevPos = pos;
pos = utf8Buffer.indexOf('\n', pos);
if (pos != -1)
++pos;
}
const QByteArray lineText = utf8Buffer.mid(prevPos, utf8Offset - prevPos);
return Utils::LineColumn(line, QString::fromUtf8(lineText).size() + 1);
}
tooling::Replacements utf16Replacements(const QTextBlock &block,
int blockOffsetUtf8,
const QByteArray &utf8Buffer,
const tooling::Replacements &replacements)
{
tooling::Replacements convertedReplacements;
for (const Replacement &replacement : replacements) {
const Utils::LineColumn lineColUtf16 = utf16LineColumn(
block, blockOffsetUtf8, utf8Buffer, static_cast<int>(replacement.getOffset()));
if (!lineColUtf16.isValid())
continue;
const int utf16Offset = Utils::Text::positionInText(block.document(),
lineColUtf16.line,
lineColUtf16.column);
const int utf16Length = QString::fromUtf8(
utf8Buffer.mid(static_cast<int>(replacement.getOffset()),
static_cast<int>(replacement.getLength()))).size();
Error error = convertedReplacements.add(
Replacement(replacement.getFilePath(),
static_cast<unsigned int>(utf16Offset),
static_cast<unsigned int>(utf16Length),
replacement.getReplacementText()));
// Throws if error is not checked.
if (error)
break;
}
return convertedReplacements;
}
void applyReplacements(const QTextBlock &block,
int blockOffsetUtf8,
const QByteArray &utf8Buffer,
const tooling::Replacements &replacements)
{
if (replacements.empty())
return;
tooling::Replacements convertedReplacements = utf16Replacements(block,
blockOffsetUtf8,
utf8Buffer,
replacements);
int fullOffsetShift = 0;
QTextCursor editCursor(block);
for (const Replacement &replacement : convertedReplacements) {
const QString replacementString = QString::fromStdString(replacement.getReplacementText());
const int replacementLength = static_cast<int>(replacement.getLength());
editCursor.beginEditBlock();
editCursor.setPosition(static_cast<int>(replacement.getOffset()) + fullOffsetShift);
editCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor,
replacementLength);
editCursor.removeSelectedText();
editCursor.insertText(replacementString);
editCursor.endEditBlock();
fullOffsetShift += replacementString.length() - replacementLength;
}
}
} // anonymous namespace
@@ -342,30 +361,34 @@ void ClangFormatIndenter::indent(QTextDocument *doc,
bool autoTriggered)
{
if (typedChar == QChar::Null && (cursor.hasSelection() || !autoTriggered)) {
TextEditorWidget *editor = TextEditorWidget::currentTextEditorWidget();
int offset;
int length;
int utf8Offset;
int utf8Length;
const QByteArray buffer = doc->toPlainText().toUtf8();
if (cursor.hasSelection()) {
const QTextBlock start = doc->findBlock(cursor.selectionStart());
const QTextBlock end = doc->findBlock(cursor.selectionEnd());
offset = start.position();
length = std::max(0, end.position() + end.length() - start.position() - 1);
utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, start.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return;);
utf8Length =
Utils::Text::textAt(
QTextCursor(doc),
start.position(),
std::max(0, end.position() + end.length() - start.position() - 1))
.toUtf8().size();
applyReplacements(start,
utf8Offset,
buffer,
replacements(buffer, utf8Offset, utf8Length));
} else {
const QTextBlock block = cursor.block();
offset = block.position();
length = std::max(0, block.length() - 1);
utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return;);
utf8Length = block.text().toUtf8().size();
applyReplacements(block,
utf8Offset,
buffer,
replacements(buffer, utf8Offset, utf8Length));
}
QString buffer = editor->toPlainText();
const int totalShift = startOfIndentationBuffer(buffer, offset);
const int cutAtPos = nextEndingScopePosition(buffer, offset + length) + 1;
buffer = buffer.mid(totalShift, cutAtPos - totalShift);
offset -= totalShift;
const std::string stdStrBefore = buffer.left(offset).toStdString();
const std::string stdStrBuffer = stdStrBefore + buffer.mid(offset).toStdString();
applyReplacements(doc,
stdStrBuffer,
replacements(stdStrBuffer, stdStrBefore.length(), length),
totalShift);
} else {
indentBlock(doc, cursor.block(), typedChar, tabSettings);
}
@@ -389,46 +412,16 @@ void ClangFormatIndenter::indentBlock(QTextDocument *doc,
if (!editor)
return;
const QTextBlock prevBlock = clearFirstNonEmptyBlockFromExtraSpaces(block);
trimFirstNonEmptyBlock(block);
const QByteArray buffer = doc->toPlainText().toUtf8();
const int utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return;);
const int utf8Length = block.text().toUtf8().size();
int offset = block.position();
int length = std::max(0, block.length() - 1);
QString buffer = editor->toPlainText();
int emptySpaceLength = previousEmptyLinesLength(block);
offset -= emptySpaceLength;
buffer.remove(offset, emptySpaceLength);
int extraPrevBlockLength{0};
int prevBlockTextLength{1};
bool prevBlockEndsWithPunctuation = false;
if (typedChar == QChar::Null) {
extraPrevBlockLength = modifyToIndentEmptyLines(buffer, offset, length, block);
const QString prevBlockText = prevBlock.text();
prevBlockEndsWithPunctuation = prevBlockText.size() > 0
? prevBlockText.at(prevBlockText.size() - 1).isPunct()
: false;
prevBlockTextLength = prevBlockText.size() + 1;
}
const int totalShift = startOfIndentationBuffer(buffer, offset);
const int cutAtPos = nextEndingScopePosition(buffer, offset + length) + 1;
buffer = buffer.mid(totalShift, cutAtPos - totalShift);
offset -= totalShift;
const std::string stdStrBefore = buffer.left(offset).toStdString();
const std::string stdStrBuffer = stdStrBefore + buffer.mid(offset).toStdString();
applyReplacements(doc,
stdStrBuffer,
replacements(stdStrBuffer,
stdStrBefore.length(),
length,
true,
typedChar,
emptySpaceLength - extraPrevBlockLength,
prevBlockTextLength + extraPrevBlockLength,
prevBlockEndsWithPunctuation),
totalShift);
applyReplacements(block,
utf8Offset,
buffer,
replacements(buffer, utf8Offset, utf8Length, &block, typedChar));
}
int ClangFormatIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings &)
@@ -437,36 +430,14 @@ int ClangFormatIndenter::indentFor(const QTextBlock &block, const TextEditor::Ta
if (!editor)
return -1;
const QTextBlock prevBlock = clearFirstNonEmptyBlockFromExtraSpaces(block);
trimFirstNonEmptyBlock(block);
const QTextDocument *doc = block.document();
const QByteArray buffer = doc->toPlainText().toUtf8();
const int utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return 0;);
const int utf8Length = block.text().toUtf8().size();
int offset = block.position();
int length = std::max(0, block.length() - 1);
QString buffer = editor->toPlainText();
int emptySpaceLength = previousEmptyLinesLength(block);
offset -= emptySpaceLength;
buffer.replace(offset, emptySpaceLength, "");
int extraPrevBlockLength = modifyToIndentEmptyLines(buffer, offset, length, block);
const QString prevBlockText = prevBlock.text();
bool prevBlockEndsWithPunctuation = prevBlockText.size() > 0
? prevBlockText.at(prevBlockText.size() - 1).isPunct()
: false;
const int totalShift = startOfIndentationBuffer(buffer, offset);
const int cutAtPos = nextEndingScopePosition(buffer, offset + length) + 1;
buffer = buffer.mid(totalShift, cutAtPos - totalShift);
offset -= totalShift;
const std::string stdStrBefore = buffer.left(offset).toStdString();
const std::string stdStrBuffer = stdStrBefore + buffer.mid(offset).toStdString();
Replacements toReplace = replacements(stdStrBuffer,
stdStrBefore.length(),
length,
true,
QChar::Null,
emptySpaceLength - extraPrevBlockLength,
prevBlockText.size() + extraPrevBlockLength + 1,
prevBlockEndsWithPunctuation);
Replacements toReplace = replacements(buffer, utf8Offset, utf8Length, &block);
if (toReplace.empty())
return -1;
@@ -481,7 +452,7 @@ int ClangFormatIndenter::indentFor(const QTextBlock &block, const TextEditor::Ta
TabSettings ClangFormatIndenter::tabSettings() const
{
FormatStyle style = formatStyle();
FormatStyle style = formatStyle(styleConfigPath());
TabSettings tabSettings;
switch (style.UseTab) {
@@ -495,8 +466,8 @@ TabSettings ClangFormatIndenter::tabSettings() const
tabSettings.m_tabPolicy = TabSettings::MixedTabPolicy;
}
tabSettings.m_tabSize = style.TabWidth;
tabSettings.m_indentSize = style.IndentWidth;
tabSettings.m_tabSize = static_cast<int>(style.TabWidth);
tabSettings.m_indentSize = static_cast<int>(style.IndentWidth);
if (style.AlignAfterOpenBracket)
tabSettings.m_continuationAlignBehavior = TabSettings::ContinuationAlignWithSpaces;
@@ -506,5 +477,4 @@ TabSettings ClangFormatIndenter::tabSettings() const
return tabSettings;
}
} // namespace Internal
} // namespace ClangFormat
@@ -28,7 +28,6 @@
#include <texteditor/indenter.h>
namespace ClangFormat {
namespace Internal {
class ClangFormatIndenter final : public TextEditor::Indenter
{
@@ -42,9 +41,9 @@ public:
const QTextCursor &cursor,
const TextEditor::TabSettings &tabSettings) override;
void indentBlock(QTextDocument *doc,
const QTextBlock &block,
const QChar &typedChar,
const TextEditor::TabSettings &tabSettings) override;
const QTextBlock &block,
const QChar &typedChar,
const TextEditor::TabSettings &tabSettings) override;
int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override;
bool isElectricCharacter(const QChar &ch) const override;
@@ -53,5 +52,4 @@ public:
TextEditor::TabSettings tabSettings() const override;
};
} // namespace Internal
} // namespace ClangFormat
@@ -45,6 +45,8 @@
#include <projectexplorer/projectpanelfactory.h>
#include <projectexplorer/target.h>
#include <clang/Format/Format.h>
#include <QAction>
#include <QDebug>
#include <QMainWindow>
@@ -56,7 +58,6 @@
using namespace ProjectExplorer;
namespace ClangFormat {
namespace Internal {
class ClangFormatOptionsPage : public Core::IOptionsPage
{
@@ -98,7 +99,7 @@ bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorS
{
Q_UNUSED(arguments);
Q_UNUSED(errorString);
#ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED
m_optionsPage = std::make_unique<ClangFormatOptionsPage>();
auto panelFactory = new ProjectPanelFactory();
@@ -112,9 +113,8 @@ bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorS
CppTools::CppModelManager::instance()->setCppIndenterCreator([]() {
return new ClangFormatIndenter();
});
#endif
return true;
}
} // namespace Internal
} // namespace ClangFormat
@@ -30,7 +30,6 @@
#include <memory>
namespace ClangFormat {
namespace Internal {
class ClangFormatOptionsPage;
@@ -50,5 +49,4 @@ private:
std::unique_ptr<ClangFormatOptionsPage> m_optionsPage;
};
} // namespace Internal
} // namespace ClangTools
@@ -0,0 +1,51 @@
/****************************************************************************
**
** Copyright (C) 2018 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.
**
****************************************************************************/
#pragma once
#include <utils/fileutils.h>
#include <clang/Format/Format.h>
#include <QFile>
#include <fstream>
namespace ClangFormat {
inline void createStyleFileIfNeeded(Utils::FileName styleConfigPath)
{
const QString configFile = styleConfigPath.appendPath(".clang-format").toString();
if (QFile::exists(configFile))
return;
clang::format::FormatStyle newStyle = clang::format::getLLVMStyle();
std::fstream newStyleFile(configFile.toStdString(), std::fstream::out);
if (newStyleFile.is_open()) {
newStyleFile << clang::format::configurationAsText(newStyle);
newStyleFile.close();
}
}
}
+1 -1
View File
@@ -71,7 +71,7 @@ public:
variableChooser->addSupportedWidget (m_customArguments);
m_unusedFunction->setToolTip(tr("Disables multithreaded check."));
m_ignorePatterns->setToolTip(tr("Comma-separated wildcards of full file paths."
m_ignorePatterns->setToolTip(tr("Comma-separated wildcards of full file paths. "
"Files still can be checked if others include them."));
m_addIncludePaths->setToolTip(tr("Can find missing includes but makes "
"checking slower. Use only when needed."));
+5
View File
@@ -1326,6 +1326,11 @@ void CppModelManager::renameIncludes(const QString &oldFileName, const QString &
}
}
void CppModelManager::setBackendJobsPostponed(bool postponed)
{
d->m_activeModelManagerSupport->setBackendJobsPostponed(postponed);
}
void CppModelManager::onCoreAboutToClose()
{
Core::ProgressManager::cancelTasks(CppTools::Constants::TASK_INDEX);
+2
View File
@@ -238,6 +238,8 @@ public:
void renameIncludes(const QString &oldFileName, const QString &newFileName);
void setBackendJobsPostponed(bool postponed);
signals:
/// Project data might be locked while this is emitted.
void aboutToRemoveFiles(const QStringList &files);
@@ -60,6 +60,7 @@ public:
virtual FollowSymbolInterface &followSymbolInterface() = 0;
virtual RefactoringEngineInterface &refactoringEngineInterface() = 0;
virtual std::unique_ptr<AbstractOverviewModel> createOverviewModel() = 0;
virtual void setBackendJobsPostponed(bool yesno) = 0;
};
class CPPTOOLS_EXPORT ModelManagerSupportProvider
@@ -47,6 +47,7 @@ public:
FollowSymbolInterface &followSymbolInterface() final;
RefactoringEngineInterface &refactoringEngineInterface() final;
std::unique_ptr<AbstractOverviewModel> createOverviewModel() final;
void setBackendJobsPostponed(bool) final {}
private:
QScopedPointer<CppCompletionAssistProvider> m_completionAssistProvider;
+104 -55
View File
@@ -50,6 +50,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
{
"android-",
{
"tring-find-startswith",
{
"cloexec-",
{
@@ -76,7 +77,8 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"open",
"socket"
}
}
},
"comparison-in-temp-failure-retry"
}
},
{
@@ -93,16 +95,69 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"bool-pointer-implicit-conversion",
"copy-constructor-init",
"dangling-handle",
"exception-escape",
"fold-init-type",
"forward-declaration-namespace",
"forwarding-reference-overload",
"inaccurate-erase",
"incorrect-roundings",
"integer-division",
"misplaced-operator-in-strlen-in-alloc",
"lambda-function-name",
{
"macro-",
{
"parentheses",
"repeated-side-effects"
}
},
{
"misplaced-",
{
"operator-in-strlen-in-alloc",
"widening-cast"
}
},
"move-forwarding-reference",
"multiple-statement-macro",
"string-constructor",
"suspicious-memset-usage",
"narrowing-conversions",
"parent-virtual-call",
{
"sizeof-",
{
"container",
"expression"
}
},
{
"string-",
{
"constructor",
"integer-assignment",
"literal-with-embedded-nul"
}
},
{
"suspicious-",
{
"enum-usage",
"memset-usage",
"missing-comma",
"semicolon",
"string-compare"
}
},
"swapped-arguments",
"terminating-continue",
"throw-keyword-missing",
"undefined-memory-manipulation",
"undelegated-constructor",
{
"unused-",
{
"raii",
"return-value"
}
},
"use-after-move",
"virtual-near-miss"
}
@@ -126,14 +181,22 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"fio38-c",
"flp30-c",
"msc30-c",
"msc32-c",
"msc50-cpp",
"msc51-cpp",
"oop11-cpp"
}
},
{
"clang-analyzer-",
{
"apiModeling.google.GTest",
{
"apiModeling.",
{
"TrustNonnull",
"google.GTest"
}
},
{
"core.",
{
@@ -168,6 +231,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
{
"cplusplus.",
{
"InnerPointer",
"NewDelete",
"NewDeleteLeaks",
"SelfAssignment"
@@ -207,7 +271,13 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
}
}
},
"performance.Padding",
{
"performance.",
{
"GCDAntipattern",
"Padding"
}
},
"portability.UnixAPI"
}
},
@@ -222,6 +292,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"cocoa.",
{
"AtSync",
"AutoreleaseWrite",
"ClassRelease",
"Dealloc",
"IncompatibleMethodTypes",
@@ -233,6 +304,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"NonNilReturnValue",
"ObjCGenerics",
"RetainCount",
"RunLoopAutoreleaseLeak",
"SelfInit",
"SuperDealloc",
"UnusedIvars",
@@ -264,6 +336,9 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"insecureAPI.",
{
"UncheckedReturn",
"bcmp",
"bcopy",
"bzero",
"getpw",
"gets",
"mkstemp",
@@ -306,8 +381,10 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
{
"cppcoreguidelines-",
{
"avoid-goto",
"c-copy-assignment-signature",
"interfaces-global-init",
"narrowing-conversions",
"no-malloc",
"owning-memory",
{
@@ -343,7 +420,12 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"fuchsia-",
{
"default-arguments",
"header-anon-namespaces",
"multiple-inheritance",
"overloaded-operator",
"restrict-system-includes",
"statically-constructed-objects",
"trailing-return",
"virtual-inheritance"
}
},
@@ -375,7 +457,6 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"casting",
"function-size",
"namespace-comments",
"redundant-smartptr-get",
"todo"
}
},
@@ -383,7 +464,6 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"runtime-",
{
"int",
"member-string-references",
"operator",
"references"
}
@@ -393,6 +473,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
{
"hicpp-",
{
"avoid-goto",
"braces-around-statements",
"deprecated-headers",
"exception-baseclass",
@@ -401,6 +482,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"invalid-access-moved",
"member-init",
"move-const-arg",
"multiway-paths-covered",
"named-parameter",
"new-delete-operators",
{
@@ -449,62 +531,19 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"misc-",
{
"definitions-in-headers",
"forwarding-reference-overload",
"incorrect-roundings",
"lambda-function-name",
{
"macro-",
{
"parentheses",
"repeated-side-effects"
}
},
{
"misplaced-",
{
"const",
"widening-cast"
}
},
"misplaced-const",
"new-delete-overloads",
"non-copyable-objects",
"redundant-expression",
{
"sizeof-",
{
"container",
"expression"
}
},
"static-assert",
{
"string-",
{
"compare",
"integer-assignment",
"literal-with-embedded-nul"
}
},
{
"suspicious-",
{
"enum-usage",
"missing-comma",
"semicolon",
"string-compare"
}
},
"swapped-arguments",
"throw-by-value-catch-by-reference",
"unconventional-assign-operator",
"undelegated-constructor",
"uniqueptr-reset-release",
{
"unused-",
{
"alias-decls",
"parameters",
"raii",
"using-decls"
}
}
@@ -554,6 +593,7 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"nullptr",
"override",
"transparent-functors",
"uncaught-exceptions",
"using"
}
}
@@ -609,7 +649,8 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"copy-initialization",
"value-param"
}
}
},
"simd-intrinsics"
}
},
{
@@ -646,7 +687,13 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
}
}
},
"simplify-boolean-expr",
{
"simplify-",
{
"boolean-expr",
"subscript-expr"
}
},
{
"static-",
{
@@ -654,7 +701,9 @@ static const TidyNode CLANG_TIDY_CHECKS_ROOT
"definition-in-anonymous-namespace"
}
},
"uniqueptr-delete-release"
"string-compare",
"uniqueptr-delete-release",
"rary-objects"
}
}
}
+10 -11
View File
@@ -1709,7 +1709,6 @@ void BreakHandler::removeBreakpoint(const Breakpoint &bp)
break;
case BreakpointInserted:
case BreakpointInsertionProceeding:
bp->setState(BreakpointRemoveRequested);
requestBreakpointRemoval(bp);
break;
case BreakpointNew:
@@ -2565,17 +2564,17 @@ bool BreakpointManager::setData(const QModelIndex &idx, const QVariant &value, i
// setCurrentIndex(index(row, 0)); FIXME
return true;
}
// if (kev->key() == Qt::Key_Space) {
// const QModelIndexList selectedIds = ev.selectedRows();
// if (!selectedIds.isEmpty()) {
// const GlobalBreakpoints gbps = findBreakpointsByIndex(selectedIds);
// const bool isEnabled = gbps.isEmpty() || gbps.at(0)->isEnabled();
// for (GlobalBreakpoint gbp : gbps)
// gbp->m_parameters.enabled = isEnabled;
if (kev->key() == Qt::Key_Space) {
const QModelIndexList selectedIds = ev.selectedRows();
if (!selectedIds.isEmpty()) {
const GlobalBreakpoints gbps = findBreakpointsByIndex(selectedIds);
const bool isEnabled = gbps.isEmpty() || gbps.at(0)->isEnabled();
for (GlobalBreakpoint gbp : gbps)
gbp->setEnabled(!isEnabled);
// scheduleSynchronization();
// return true;
// }
// }
return true;
}
}
}
if (ev.as<QMouseEvent>(QEvent::MouseButtonDblClick)) {
+1 -1
View File
@@ -98,7 +98,7 @@ private:
void updateMarker();
void updateMarkerIcon();
void destroyMarker();
void scheduleSynchronization();
// void scheduleSynchronization();
QPointer<DebuggerEngine> usingEngine() const;
bool isEngineRunning() const;
+15 -23
View File
@@ -224,7 +224,7 @@ void CdbEngine::init()
m_stopMode = NoStopRequested;
m_nextCommandToken = 0;
m_currentBuiltinResponseToken = -1;
m_operateByInstruction = true; // Default CDB setting.
m_lastOperateByInstruction = true; // Default CDB setting.
m_hasDebuggee = false;
m_sourceStepInto = false;
m_watchPointX = m_watchPointY = 0;
@@ -266,14 +266,13 @@ void CdbEngine::init()
CdbEngine::~CdbEngine() = default;
void CdbEngine::operateByInstructionTriggered(bool operateByInstruction)
void CdbEngine::adjustOperateByInstruction(bool operateByInstruction)
{
DebuggerEngine::operateByInstructionTriggered(operateByInstruction);
if (m_operateByInstruction == operateByInstruction)
if (m_lastOperateByInstruction == operateByInstruction)
return;
m_operateByInstruction = operateByInstruction;
runCommand({QLatin1String(m_operateByInstruction ? "l-t" : "l+t"), NoFlags});
runCommand({QLatin1String(m_operateByInstruction ? "l-s" : "l+s"), NoFlags});
m_lastOperateByInstruction = operateByInstruction;
runCommand({QLatin1String(m_lastOperateByInstruction ? "l-t" : "l+t"), NoFlags});
runCommand({QLatin1String(m_lastOperateByInstruction ? "l-s" : "l+s"), NoFlags});
}
bool CdbEngine::canHandleToolTip(const DebuggerToolTipContext &context) const
@@ -521,7 +520,7 @@ void CdbEngine::handleInitialSessionIdle()
const DebuggerRunParameters &rp = runParameters();
if (!rp.commandsAfterConnect.isEmpty())
runCommand({rp.commandsAfterConnect, NoFlags});
operateByInstructionTriggered(operatesByInstruction());
//operateByInstructionTriggered(operatesByInstruction());
// QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
// (attemptBreakpointSynchronization() will be directly called then)
if (rp.breakOnMain) {
@@ -758,10 +757,11 @@ bool CdbEngine::hasCapability(unsigned cap) const
|AdditionalQmlStackCapability);
}
void CdbEngine::executeStep()
void CdbEngine::executeStepIn(bool byInstruction)
{
if (!m_operateByInstruction)
if (!m_lastOperateByInstruction)
m_sourceStepInto = true; // See explanation at handleStackTrace().
adjustOperateByInstruction(byInstruction);
runCommand({"t", NoFlags}); // Step into-> t (trace)
STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
notifyInferiorRunRequested();
@@ -774,23 +774,14 @@ void CdbEngine::executeStepOut()
notifyInferiorRunRequested();
}
void CdbEngine::executeNext()
void CdbEngine::executeStepOver(bool byInstruction)
{
adjustOperateByInstruction(byInstruction);
runCommand({"p", NoFlags}); // Step over -> p
STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
notifyInferiorRunRequested();
}
void CdbEngine::executeStepI()
{
executeStep();
}
void CdbEngine::executeNextI()
{
executeNext();
}
void CdbEngine::continueInferior()
{
STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
@@ -1756,8 +1747,9 @@ unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
*message = bp->msgWatchpointByExpressionTriggered(bp->expression(), tid);
else
*message = bp->msgBreakpointTriggered(tid);
rc |= StopReportStatusMessage|StopNotifyStop;
rc |= StopReportStatusMessage;
}
rc |= StopNotifyStop;
return rc;
}
if (reason == "exception") {
@@ -1848,7 +1840,7 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT
if (stack.isValid()) {
switch (parseStackTrace(stack, sourceStepInto)) {
case ParseStackStepInto: // Hit on a frame while step into, see parseStackTrace().
executeStep();
executeStepIn(operatesByInstruction());
return;
case ParseStackStepOut: // Hit on a frame with no source while step into.
executeStepOut();
+5 -7
View File
@@ -41,7 +41,7 @@ class CdbCommand;
struct MemoryViewCookie;
class StringInputStream;
class CdbEngine : public DebuggerEngine
class CdbEngine : public CppDebuggerEngine
{
Q_OBJECT
@@ -64,11 +64,9 @@ public:
void watchPoint(const QPoint &) override;
void setRegisterValue(const QString &name, const QString &value) override;
void executeStep() override;
void executeStepOver(bool byInstruction) override;
void executeStepIn(bool byInstruction) override;
void executeStepOut() override;
void executeNext() override;
void executeStepI() override;
void executeNextI() override;
void continueInferior() override;
void interruptInferior() override;
@@ -113,7 +111,7 @@ private:
void processError();
void processFinished();
void runCommand(const DebuggerCommand &cmd) override;
void operateByInstructionTriggered(bool) override;
void adjustOperateByInstruction(bool);
void createFullBacktrace();
@@ -217,7 +215,7 @@ private:
int m_currentBuiltinResponseToken = -1;
QMap<QString, NormalizedSourceFileName> m_normalizedFileCache;
const QString m_extensionCommandPrefix; //!< Library name used as prefix
bool m_operateByInstruction = true; // Default CDB setting.
bool m_lastOperateByInstruction = true; // Default CDB setting.
bool m_hasDebuggee = false;
enum Wow64State {
wow64Uninitialized,
+3
View File
@@ -37,6 +37,8 @@ const char MODE_DEBUG[] = "Mode.Debug";
const char C_DEBUGMODE[] = "Debugger.DebugMode";
const char C_CPPDEBUGGER[] = "Gdb Debugger";
const char C_QMLDEBUGGER[] = "Qml/JavaScript Debugger";
const char C_DEBUGGER_RUNNING[] = "Debugger.Running";
const char C_DEBUGGER_NOTRUNNING[] = "Debugger.NotRunning";
const char PRESET_PERSPECTIVE_ID[] = "Debugger.Perspective.Preset";
@@ -54,6 +56,7 @@ const char ABORT[] = "Debugger.Abort";
const char STEP[] = "Debugger.StepLine";
const char STEPOUT[] = "Debugger.StepOut";
const char NEXT[] = "Debugger.NextLine";
const char START_AND_BREAK_ON_MAIN[]= "Debugger.StartAndBreakOnMain";
const char REVERSE[] = "Debugger.ReverseDirection";
const char RESET[] = "Debugger.Reset";
const char OPERATE_BY_INSTRUCTION[] = "Debugger.OperateByInstruction";
+19 -35
View File
@@ -488,7 +488,7 @@ public:
QAction m_breakAction{tr("Toggle Breakpoint")};
QAction m_resetAction{tr("Restart Debugging")};
OptionalAction m_operateByInstructionAction{tr("Operate by Instruction")};
QAction m_recordForReverseOperationAction{tr("Record information to allpow reversal of Direction")};
QAction m_recordForReverseOperationAction{tr("Record Information to Allow Reversal of Direction")};
OptionalAction m_operateInReverseDirectionAction{tr("Reverse Direction")};
OptionalAction m_snapshotAction{tr("Take Snapshot of Process State")};
@@ -526,7 +526,7 @@ void DebuggerEnginePrivate::setupViews()
m_operateByInstructionAction.setIcon(Debugger::Icons::SINGLE_INSTRUCTION_MODE.icon());
m_operateByInstructionAction.setCheckable(true);
m_operateByInstructionAction.setChecked(false);
m_operateByInstructionAction.setToolTip("<p>" + tr("This switches the debugger to instruction-wise "
m_operateByInstructionAction.setToolTip("<p>" + tr("Switches the debugger to instruction-wise "
"operation mode. In this mode, stepping operates on single "
"instructions and the source location view also shows the "
"disassembled instructions."));
@@ -684,18 +684,18 @@ void DebuggerEnginePrivate::setupViews()
connect(&m_abortAction, &QAction::triggered,
m_engine, &DebuggerEngine::abortDebugger);
m_resetAction.setToolTip(tr("Restart the debugging session."));
m_resetAction.setToolTip(tr("Restarts the debugging session."));
m_resetAction.setIcon(Icons::RESTART_TOOLBAR.icon());
connect(&m_resetAction, &QAction::triggered,
m_engine, &DebuggerEngine::handleReset);
m_stepOverAction.setIcon(Icons::STEP_OVER_TOOLBAR.icon());
connect(&m_stepOverAction, &QAction::triggered,
m_engine, &DebuggerEngine::handleExecNext);
m_engine, &DebuggerEngine::handleExecStepOver);
m_stepIntoAction.setIcon(Icons::STEP_INTO_TOOLBAR.icon());
connect(&m_stepIntoAction, &QAction::triggered,
m_engine, &DebuggerEngine::handleExecStep);
m_engine, &DebuggerEngine::handleExecStepIn);
m_stepOutAction.setIcon(Icons::STEP_OUT_TOOLBAR.icon());
connect(&m_stepOutAction, &QAction::triggered,
@@ -1111,7 +1111,7 @@ void DebuggerEngine::notifyEngineSetupFailed()
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
setState(EngineSetupFailed);
if (d->m_isPrimaryEngine) {
showMessage(tr("Debugging has failed"), NormalMessageFormat);
showMessage(tr("Debugging has failed."), NormalMessageFormat);
d->m_progress.setProgressValue(900);
d->m_progress.reportCanceled();
d->m_progress.reportFinished();
@@ -1472,7 +1472,7 @@ void DebuggerEnginePrivate::updateReverseActions()
m_operateInReverseDirectionAction.setVisible(canReverse);
m_operateInReverseDirectionAction.setEnabled(canReverse && stopped && doesRecord);
m_operateInReverseDirectionAction.setIcon(Icons::DIRECTION_BACKWARD.icon());
m_operateInReverseDirectionAction.setText(DebuggerEngine::tr("Operate in reverse direction"));
m_operateInReverseDirectionAction.setText(DebuggerEngine::tr("Operate in Reverse Direction"));
}
void DebuggerEnginePrivate::cleanupViews()
@@ -1787,16 +1787,16 @@ DebuggerToolTipManager *DebuggerEngine::toolTipManager()
return &d->m_toolTipManager;
}
bool DebuggerEngine::debuggerActionsEnabled() const
{
return debuggerActionsEnabledHelper(d->m_state);
}
bool DebuggerEngine::operatesByInstruction() const
{
return d->m_operateByInstructionAction.isChecked();
}
bool DebuggerEngine::debuggerActionsEnabled() const
{
return debuggerActionsEnabledHelper(d->m_state);
}
void DebuggerEngine::operateByInstructionTriggered(bool on)
{
// Go to source only if we have the file.
@@ -2212,7 +2212,7 @@ void DebuggerEngine::updateLocalsView(const GdbMi &all)
static int count = 0;
showMessage(QString("<Rebuild Watchmodel %1 @ %2 >")
.arg(++count).arg(LogWindow::logTimeStamp()), LogMiscInput);
showMessage(tr("Finished retrieving data"), 400, StatusBar);
showMessage(tr("Finished retrieving data."), 400, StatusBar);
d->m_toolTipManager.updateToolTips();
@@ -2291,32 +2291,16 @@ void DebuggerEngine::handleReset()
resetInferior();
}
void DebuggerEngine::handleExecStep()
void DebuggerEngine::handleExecStepIn()
{
if (state() == DebuggerNotReady) {
DebuggerRunTool::setBreakOnMainNextTime();
ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE);
} else {
resetLocation();
if (operatesByInstruction())
executeStepI();
else
executeStep();
}
resetLocation();
executeStepIn(operatesByInstruction());
}
void DebuggerEngine::handleExecNext()
void DebuggerEngine::handleExecStepOver()
{
if (state() == DebuggerNotReady) {
DebuggerRunTool::setBreakOnMainNextTime();
ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE);
} else {
resetLocation();
if (operatesByInstruction())
executeNextI();
else
executeNext();
}
resetLocation();
executeStepOver(operatesByInstruction());
}
void DebuggerEngine::handleExecStepOut()
+4 -6
View File
@@ -434,8 +434,8 @@ public:
void handleUserStop();
void handleAbort();
void handleReset();
void handleExecStep();
void handleExecNext();
void handleExecStepIn();
void handleExecStepOver();
void handleExecStepOut();
void handleExecReturn();
void handleExecJumpToLine();
@@ -480,11 +480,9 @@ protected:
virtual void resetInferior() {}
virtual void detachDebugger() {}
virtual void executeStep() {}
virtual void executeStepOver(bool /*byInstruction*/ = false) {}
virtual void executeStepIn(bool /*byInstruction*/ = false) {}
virtual void executeStepOut() {}
virtual void executeNext() {}
virtual void executeStepI() {}
virtual void executeNextI() {}
virtual void executeReturn() {}
virtual void continueInferior() {}
-8
View File
@@ -56,7 +56,6 @@ const char DEBUGGER_INFORMATION_DISPLAYNAME[] = "DisplayName";
const char DEBUGGER_INFORMATION_ID[] = "Id";
const char DEBUGGER_INFORMATION_ENGINETYPE[] = "EngineType";
const char DEBUGGER_INFORMATION_AUTODETECTED[] = "AutoDetected";
const char DEBUGGER_INFORMATION_AUTODETECTION_SOURCE[] = "AutoDetectionSource";
const char DEBUGGER_INFORMATION_VERSION[] = "Version";
const char DEBUGGER_INFORMATION_ABIS[] = "Abis";
const char DEBUGGER_INFORMATION_LASTMODIFIED[] = "LastModified";
@@ -82,7 +81,6 @@ DebuggerItem::DebuggerItem(const QVariantMap &data)
m_workingDirectory = FileName::fromUserInput(data.value(DEBUGGER_INFORMATION_WORKINGDIRECTORY).toString());
m_unexpandedDisplayName = data.value(DEBUGGER_INFORMATION_DISPLAYNAME).toString();
m_isAutoDetected = data.value(DEBUGGER_INFORMATION_AUTODETECTED, false).toBool();
m_autoDetectionSource = data.value(DEBUGGER_INFORMATION_AUTODETECTION_SOURCE).toString();
m_version = data.value(DEBUGGER_INFORMATION_VERSION).toString();
m_engineType = DebuggerEngineType(data.value(DEBUGGER_INFORMATION_ENGINETYPE,
static_cast<int>(NoEngineType)).toInt());
@@ -252,7 +250,6 @@ QVariantMap DebuggerItem::toMap() const
data.insert(DEBUGGER_INFORMATION_WORKINGDIRECTORY, m_workingDirectory.toString());
data.insert(DEBUGGER_INFORMATION_ENGINETYPE, int(m_engineType));
data.insert(DEBUGGER_INFORMATION_AUTODETECTED, m_isAutoDetected);
data.insert(DEBUGGER_INFORMATION_AUTODETECTION_SOURCE, m_autoDetectionSource);
data.insert(DEBUGGER_INFORMATION_VERSION, m_version);
data.insert(DEBUGGER_INFORMATION_ABIS, abiNames());
data.insert(DEBUGGER_INFORMATION_LASTMODIFIED, m_lastModified);
@@ -306,11 +303,6 @@ void DebuggerItem::setVersion(const QString &version)
m_version = version;
}
void DebuggerItem::setAutoDetectionSource(const QString &autoDetectionSource)
{
m_autoDetectionSource = autoDetectionSource;
}
void DebuggerItem::setAbis(const QList<Abi> &abis)
{
m_abis = abis;
-4
View File
@@ -81,9 +81,6 @@ public:
QString version() const;
void setVersion(const QString &version);
QString autoDetectionSource() const { return m_autoDetectionSource; }
void setAutoDetectionSource(const QString &autoDetectionSource);
const QList<ProjectExplorer::Abi> &abis() const { return m_abis; }
void setAbis(const QList<ProjectExplorer::Abi> &abis);
void setAbi(const ProjectExplorer::Abi &abi);
@@ -115,7 +112,6 @@ private:
Utils::FileName m_command;
Utils::FileName m_workingDirectory;
bool m_isAutoDetected = false;
QString m_autoDetectionSource;
QString m_version;
QList<ProjectExplorer::Abi> m_abis;
QDateTime m_lastModified;
+49 -40
View File
@@ -768,7 +768,7 @@ public:
Action m_interruptAction{tr("Interrupt"), interruptIcon(false), &DebuggerEngine::handleExecInterrupt};
Action m_abortAction{tr("Abort Debugging"), {}, &DebuggerEngine::abortDebugger,
tr("Aborts debugging and resets the debugger to the initial state.")};
QAction m_stepAction{tr("Step Into")};
QAction m_stepInAction{tr("Step Into")};
Action m_stepOutAction{tr("Step Out"), Icons::STEP_OUT.icon(), &DebuggerEngine::handleExecStepOut};
Action m_runToLineAction{tr("Run to Line"), {}, &DebuggerEngine::handleExecRunToLine};
@@ -776,7 +776,8 @@ public:
Action m_jumpToLineAction{tr("Jump to Line"), {}, &DebuggerEngine::handleExecJumpToLine};
// In the Debug menu.
Action m_returnFromFunctionAction{tr("Immediately Return From Inner Function"), {}, &DebuggerEngine::executeReturn};
QAction m_nextAction{tr("Step Over")};
QAction m_stepOverAction{tr("Step Over")};
QAction m_startAndBreakOnMain{tr("Start and Break on Main")};
Action m_watchAction{tr("Add Expression Evaluator"), {}, &DebuggerEngine::handleAddToWatchWindow};
Command *m_watchCommand = nullptr;
QAction m_breakAction{tr("Toggle Breakpoint")};
@@ -1012,6 +1013,11 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
QString *errorMessage)
{
Q_UNUSED(errorMessage);
const Context debuggerRunning(C_DEBUGGER_RUNNING);
const Context debuggerNotRunning(C_DEBUGGER_NOTRUNNING);
ICore::addAdditionalContext(debuggerNotRunning);
m_arguments = arguments;
if (!m_arguments.isEmpty())
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::finishedInitialization,
@@ -1225,34 +1231,37 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
debugMenu->addSeparator();
cmd = ActionManager::registerAction(&m_nextAction, Constants::NEXT);
cmd = ActionManager::registerAction(&m_startAndBreakOnMain,
Constants::START_AND_BREAK_ON_MAIN,
debuggerNotRunning);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+Shift+O") : tr("F10")));
cmd->setAttribute(Command::CA_Hide);
cmd->setAttribute(Command::CA_UpdateText);
debugMenu->addAction(cmd);
m_nextAction.setIcon(Icons::STEP_OVER.icon());
connect(&m_nextAction, &QAction::triggered, this, [] {
if (DebuggerEngine *engine = EngineManager::currentEngine()) {
engine->handleExecNext();
} else {
DebuggerRunTool::setBreakOnMainNextTime();
ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, false);
}
connect(&m_startAndBreakOnMain, &QAction::triggered, this, [] {
DebuggerRunTool::setBreakOnMainNextTime();
ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, false);
});
cmd = ActionManager::registerAction(&m_stepAction, Constants::STEP);
cmd = ActionManager::registerAction(&m_stepOverAction, Constants::NEXT, debuggerRunning);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+Shift+O") : tr("F10")));
cmd->setAttribute(Command::CA_Hide);
debugMenu->addAction(cmd);
m_stepOverAction.setIcon(Icons::STEP_OVER.icon());
connect(&m_stepOverAction, &QAction::triggered, this, [] {
DebuggerEngine *engine = EngineManager::currentEngine();
QTC_ASSERT(engine, return);
engine->handleExecStepOver();
});
cmd = ActionManager::registerAction(&m_stepInAction, Constants::STEP, debuggerRunning);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+Shift+I") : tr("F11")));
cmd->setAttribute(Command::CA_Hide);
cmd->setAttribute(Command::CA_UpdateText);
debugMenu->addAction(cmd);
m_stepAction.setIcon(Icons::STEP_OVER.icon());
connect(&m_stepAction, &QAction::triggered, this, [] {
if (DebuggerEngine *engine = EngineManager::currentEngine()) {
engine->handleExecStep();
} else {
DebuggerRunTool::setBreakOnMainNextTime();
ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, false);
}
m_stepInAction.setIcon(Icons::STEP_INTO.icon());
connect(&m_stepInAction, &QAction::triggered, this, [] {
DebuggerEngine *engine = EngineManager::currentEngine();
QTC_ASSERT(engine, return);
engine->handleExecStepIn();
});
@@ -1469,10 +1478,10 @@ void DebuggerPluginPrivate::updatePresetState()
// correspond to the current start up project.
// Step into/next: Start and break at 'main' unless a debugger is running.
QString stepToolTip = canRun ? tr("Start \"%1\" and break at function \"main\"").arg(startupRunConfigName) : whyNot;
m_stepAction.setToolTip(stepToolTip);
m_nextAction.setToolTip(stepToolTip);
m_stepAction.setEnabled(canRun);
m_nextAction.setEnabled(canRun);
m_stepInAction.setEnabled(canRun);
m_stepInAction.setToolTip(stepToolTip);
m_stepOverAction.setEnabled(canRun);
m_stepOverAction.setToolTip(stepToolTip);
m_startAction.setEnabled(canRun);
m_startAction.setIcon(startIcon(false));
m_startAction.setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
@@ -1492,8 +1501,8 @@ void DebuggerPluginPrivate::updatePresetState()
QTC_ASSERT(currentEngine, return);
// We have a current engine, and it belongs to the startup runconfig.
m_stepAction.setToolTip(QString());
m_nextAction.setToolTip(QString());
m_stepInAction.setToolTip(QString());
m_stepOverAction.setToolTip(QString());
// The 'state' bits only affect the fat debug button, not the preset start button.
m_startAction.setIcon(startIcon(false));
@@ -1522,8 +1531,8 @@ void DebuggerPluginPrivate::updatePresetState()
m_debugWithoutDeployAction.setEnabled(false);
m_visibleStartAction.setAction(&m_continueAction);
m_hiddenStopAction.setAction(&m_exitAction);
m_stepAction.setEnabled(!companionPreventsAction);
m_nextAction.setEnabled(!companionPreventsAction);
m_stepInAction.setEnabled(!companionPreventsAction);
m_stepOverAction.setEnabled(!companionPreventsAction);
m_jumpToLineAction.setEnabled(currentEngine->hasCapability(JumpToLineCapability));
m_returnFromFunctionAction.setEnabled(currentEngine->hasCapability(ReturnFromFunctionCapability));
m_detachAction.setEnabled(!isCore);
@@ -1541,8 +1550,8 @@ void DebuggerPluginPrivate::updatePresetState()
m_debugWithoutDeployAction.setEnabled(false);
m_visibleStartAction.setAction(&m_interruptAction);
m_hiddenStopAction.setAction(&m_interruptAction);
m_stepAction.setEnabled(false);
m_nextAction.setEnabled(false);
m_stepInAction.setEnabled(false);
m_stepOverAction.setEnabled(false);
m_jumpToLineAction.setEnabled(false);
m_returnFromFunctionAction.setEnabled(false);
m_detachAction.setEnabled(false);
@@ -1560,8 +1569,8 @@ void DebuggerPluginPrivate::updatePresetState()
m_debugWithoutDeployAction.setEnabled(canRun);
m_visibleStartAction.setAction(&m_startAction);
m_hiddenStopAction.setAction(&m_undisturbableAction);
m_stepAction.setEnabled(false);
m_nextAction.setEnabled(false);
m_stepInAction.setEnabled(false);
m_stepOverAction.setEnabled(false);
m_jumpToLineAction.setEnabled(false);
m_returnFromFunctionAction.setEnabled(false);
m_detachAction.setEnabled(false);
@@ -1579,8 +1588,8 @@ void DebuggerPluginPrivate::updatePresetState()
m_debugWithoutDeployAction.setEnabled(false);
m_visibleStartAction.setAction(&m_exitAction);
m_hiddenStopAction.setAction(&m_exitAction);
m_stepAction.setEnabled(false);
m_nextAction.setEnabled(false);
m_stepInAction.setEnabled(false);
m_stepOverAction.setEnabled(false);
m_jumpToLineAction.setEnabled(false);
m_returnFromFunctionAction.setEnabled(false);
m_detachAction.setEnabled(false);
@@ -1601,8 +1610,8 @@ void DebuggerPluginPrivate::updatePresetState()
m_debugWithoutDeployAction.setEnabled(false);
m_visibleStartAction.setAction(&m_undisturbableAction);
m_hiddenStopAction.setAction(&m_undisturbableAction);
m_stepAction.setEnabled(false);
m_nextAction.setEnabled(false);
m_stepInAction.setEnabled(false);
m_stepOverAction.setEnabled(false);
m_jumpToLineAction.setEnabled(false);
m_returnFromFunctionAction.setEnabled(false);
m_detachAction.setEnabled(false);
@@ -2064,13 +2073,13 @@ void DebuggerPluginPrivate::setInitialState()
m_interruptAction.setEnabled(false);
m_continueAction.setEnabled(false);
m_stepAction.setEnabled(true);
m_stepInAction.setEnabled(true);
m_stepOutAction.setEnabled(false);
m_runToLineAction.setEnabled(false);
m_runToSelectedFunctionAction.setEnabled(true);
m_returnFromFunctionAction.setEnabled(false);
m_jumpToLineAction.setEnabled(false);
m_nextAction.setEnabled(true);
m_stepOverAction.setEnabled(true);
action(AutoDerefPointers)->setEnabled(true);
action(ExpandStack)->setEnabled(false);
@@ -774,11 +774,6 @@ void DebuggerRunTool::setSolibSearchPath(const QStringList &list)
m_runParameters.solibSearchPath = list;
}
void DebuggerRunTool::quitDebugger()
{
initiateStop();
}
bool DebuggerRunTool::fixupParameters()
{
DebuggerRunParameters &rp = m_runParameters;
@@ -59,8 +59,6 @@ public:
void start() override;
void stop() override;
void quitDebugger();
bool isCppDebugging() const;
bool isQmlDebugging() const;
int portsUsedByDebugger() const;
@@ -400,6 +400,7 @@ void DisassemblerAgent::updateBreakpointMarker(const Breakpoint &bp)
auto marker = new DisassemblerBreakpointMarker(bp, lineNumber);
d->breakpointMarks.append(marker);
QTC_ASSERT(d->document, return);
d->document->addMark(marker);
}
+5
View File
@@ -344,8 +344,13 @@ void EngineManagerPrivate::selectUiForCurrentEngine()
int row = 0;
if (m_currentItem && m_currentItem->m_engine) {
ICore::updateAdditionalContexts(Context(Debugger::Constants::C_DEBUGGER_NOTRUNNING),
Context(Debugger::Constants::C_DEBUGGER_RUNNING));
perspective = m_currentItem->m_engine->perspective();
m_currentItem->m_engine->updateState(false);
} else {
ICore::updateAdditionalContexts(Context(Debugger::Constants::C_DEBUGGER_RUNNING),
Context(Debugger::Constants::C_DEBUGGER_NOTRUNNING));
}
if (m_currentItem)
+27 -44
View File
@@ -901,7 +901,7 @@ void GdbEngine::handleResultRecord(DebuggerResponse *response)
// there is no debug information. Divert to "-exec-next-step"
showMessage("APPLYING WORKAROUND #3");
notifyInferiorStopOk();
executeNextI();
executeStepOver(true);
} else if (msg.startsWith("Couldn't get registers: No such process.")) {
// Happens on archer-tromey-python 6.8.50.20090910-cvs
// There might to be a race between a process shutting down
@@ -1324,7 +1324,7 @@ void GdbEngine::handleStop1(const GdbMi &data)
if (isSkippableFunction(funcName, fileName)) {
//showMessage(_("SKIPPING ") + funcName);
++stepCounter;
executeStep();
executeStepIn(false);
return;
}
//if (stepCounter)
@@ -1838,25 +1838,32 @@ void GdbEngine::continueInferior()
continueInferiorInternal();
}
void GdbEngine::executeStep()
void GdbEngine::executeStepIn(bool byInstruction)
{
CHECK_STATE(InferiorStopOk);
setTokenBarrier();
notifyInferiorRunRequested();
showStatusMessage(tr("Step requested..."), 5000);
DebuggerCommand cmd;
if (isNativeMixedActiveFrame()) {
DebuggerCommand cmd("executeStep", RunRequest);
cmd.flags = RunRequest;
cmd.function = "executeStep";
cmd.callback = CB(handleExecuteStep);
runCommand(cmd);
} else if (byInstruction) {
cmd.flags = RunRequest|NeedsFlush;
cmd.function = "-exec-step-instruction";
if (isReverseDebugging())
cmd.function += "--reverse";
cmd.callback = CB(handleExecuteContinue);
} else {
DebuggerCommand cmd;
cmd.flags = RunRequest|NeedsFlush;
cmd.function = "-exec-step";
if (isReverseDebugging())
cmd.function += " --reverse";
cmd.callback = CB(handleExecuteStep);
runCommand(cmd);
}
runCommand(cmd);
}
void GdbEngine::handleExecuteStep(const DebuggerResponse &response)
@@ -1882,7 +1889,7 @@ void GdbEngine::handleExecuteStep(const DebuggerResponse &response)
notifyInferiorRunFailed();
if (isDying())
return;
executeStepI(); // Fall back to instruction-wise stepping.
executeStepIn(true); // Fall back to instruction-wise stepping.
} else if (msg.startsWith("Cannot execute this command while the selected thread is running.")) {
showExecutionError(msg);
notifyInferiorRunFailed();
@@ -1895,21 +1902,6 @@ void GdbEngine::handleExecuteStep(const DebuggerResponse &response)
}
}
void GdbEngine::executeStepI()
{
CHECK_STATE(InferiorStopOk);
setTokenBarrier();
notifyInferiorRunRequested();
showStatusMessage(tr("Step by instruction requested..."), 5000);
DebuggerCommand cmd;
cmd.flags = RunRequest|NeedsFlush;
cmd.function = "-exec-step-instruction";
if (isReverseDebugging())
cmd.function += "--reverse";
cmd.callback = CB(handleExecuteContinue);
runCommand(cmd);
}
void GdbEngine::executeStepOut()
{
CHECK_STATE(InferiorStopOk);
@@ -1928,23 +1920,29 @@ void GdbEngine::executeStepOut()
}
}
void GdbEngine::executeNext()
void GdbEngine::executeStepOver(bool byInstruction)
{
CHECK_STATE(InferiorStopOk);
setTokenBarrier();
notifyInferiorRunRequested();
showStatusMessage(tr("Step next requested..."), 5000);
DebuggerCommand cmd;
cmd.flags = RunRequest;
if (isNativeMixedActiveFrame()) {
runCommand({"executeNext", RunRequest});
cmd.function = "executeNext";
} else if (byInstruction) {
cmd.function = "-exec-next-instruction";
if (isReverseDebugging())
cmd.function += " --reverse";
cmd.callback = CB(handleExecuteContinue);
} else {
DebuggerCommand cmd;
cmd.flags = RunRequest;
cmd.function = "-exec-next";
if (isReverseDebugging())
cmd.function += " --reverse";
cmd.callback = CB(handleExecuteNext);
runCommand(cmd);
}
runCommand(cmd);
}
void GdbEngine::handleExecuteNext(const DebuggerResponse &response)
@@ -1967,7 +1965,7 @@ void GdbEngine::handleExecuteNext(const DebuggerResponse &response)
|| msg.contains("Error accessing memory address ")) {
notifyInferiorRunFailed();
if (!isDying())
executeNextI(); // Fall back to instruction-wise stepping.
executeStepOver(true); // Fall back to instruction-wise stepping.
} else if (msg.startsWith("Cannot execute this command while the selected thread is running.")) {
showExecutionError(msg);
notifyInferiorRunFailed();
@@ -1981,21 +1979,6 @@ void GdbEngine::handleExecuteNext(const DebuggerResponse &response)
}
}
void GdbEngine::executeNextI()
{
CHECK_STATE(InferiorStopOk);
setTokenBarrier();
notifyInferiorRunRequested();
showStatusMessage(tr("Step next instruction requested..."), 5000);
DebuggerCommand cmd;
cmd.flags = RunRequest;
cmd.function = "-exec-next-instruction";
if (isReverseDebugging())
cmd.function += " --reverse";
cmd.callback = CB(handleExecuteContinue);
runCommand(cmd);
}
static QString addressSpec(quint64 address)
{
return "*0x" + QString::number(address, 16);
+2 -4
View File
@@ -192,11 +192,9 @@ private: ////////// General Interface //////////
void updateBreakpoint(const Breakpoint &bp) final;
void enableSubBreakpoint(const SubBreakpoint &sbp, bool on) final;
void executeStep() final;
void executeStepIn(bool byInstruction) final;
void executeStepOut() final;
void executeNext() final;
void executeStepI() final;
void executeNextI() final;
void executeStepOver(bool byInstruction) final;
void continueInferiorInternal();
void continueInferior() final;
+4 -16
View File
@@ -336,16 +336,10 @@ void LldbEngine::interruptInferior()
runCommand({"interruptInferior"});
}
void LldbEngine::executeStep()
void LldbEngine::executeStepIn(bool byInstruction)
{
notifyInferiorRunRequested();
runCommand({"executeStep"});
}
void LldbEngine::executeStepI()
{
notifyInferiorRunRequested();
runCommand({"executeStepI"});
runCommand({QLatin1String(byInstruction ? "executeStepI" : "executeStep")});
}
void LldbEngine::executeStepOut()
@@ -354,16 +348,10 @@ void LldbEngine::executeStepOut()
runCommand({"executeStepOut"});
}
void LldbEngine::executeNext()
void LldbEngine::executeStepOver(bool byInstruction)
{
notifyInferiorRunRequested();
runCommand({"executeNext"});
}
void LldbEngine::executeNextI()
{
notifyInferiorRunRequested();
runCommand({"executeNextI"});
runCommand({QLatin1String(byInstruction ? "executeNextI" : "executeNext")});
}
void LldbEngine::continueInferior()
+2 -4
View File
@@ -60,11 +60,9 @@ signals:
void outputReady(const QString &data);
private:
void executeStep() override;
void executeStepIn(bool byInstruction) override;
void executeStepOut() override;
void executeNext() override;
void executeStepI() override;
void executeNextI() override;
void executeStepOver(bool byInstruction) override;
void setupEngine() override;
void runEngine() override;
+29 -19
View File
@@ -167,14 +167,7 @@ void PdbEngine::interruptInferior()
interruptProcess(m_proc.processId(), GdbEngineType, &error);
}
void PdbEngine::executeStep()
{
notifyInferiorRunRequested();
notifyInferiorRunOk();
postDirectCommand("step");
}
void PdbEngine::executeStepI()
void PdbEngine::executeStepIn(bool)
{
notifyInferiorRunRequested();
notifyInferiorRunOk();
@@ -188,14 +181,7 @@ void PdbEngine::executeStepOut()
postDirectCommand("return");
}
void PdbEngine::executeNext()
{
notifyInferiorRunRequested();
notifyInferiorRunOk();
postDirectCommand("next");
}
void PdbEngine::executeNextI()
void PdbEngine::executeStepOver(bool)
{
notifyInferiorRunRequested();
notifyInferiorRunOk();
@@ -269,8 +255,24 @@ void PdbEngine::insertBreakpoint(const Breakpoint &bp)
void PdbEngine::updateBreakpoint(const Breakpoint &bp)
{
Q_UNUSED(bp);
QTC_CHECK(false);
QTC_ASSERT(bp, return);
const BreakpointState state = bp->state();
if (QTC_GUARD(state == BreakpointUpdateRequested))
notifyBreakpointChangeProceeding(bp);
if (bp->responseId().isEmpty()) // FIXME postpone update somehow (QTimer::singleShot?)
return;
// FIXME figure out what needs to be changed (there might be more than enabled state)
const BreakpointParameters &requested = bp->requestedParameters();
if (requested.enabled != bp->isEnabled()) {
if (bp->isEnabled())
postDirectCommand("disable " + bp->responseId());
else
postDirectCommand("enable " + bp->responseId());
bp->setEnabled(!bp->isEnabled());
}
// Pretend it succeeds without waiting for response.
notifyBreakpointChangeOk(bp);
}
void PdbEngine::removeBreakpoint(const Breakpoint &bp)
@@ -278,6 +280,10 @@ void PdbEngine::removeBreakpoint(const Breakpoint &bp)
QTC_ASSERT(bp, return);
QTC_CHECK(bp->state() == BreakpointRemoveRequested);
notifyBreakpointRemoveProceeding(bp);
if (bp->responseId().isEmpty()) {
notifyBreakpointRemoveFailed(bp);
return;
}
showMessage(QString("DELETING BP %1 IN %2")
.arg(bp->responseId()).arg(bp->fileName()));
postDirectCommand("clear " + bp->responseId());
@@ -504,8 +510,12 @@ void PdbEngine::handleOutput2(const QString &data)
bp->setLineNumber(lineNumber);
bp->adjustMarker();
bp->setPending(false);
QTC_CHECK(!bp->needsChange());
notifyBreakpointInsertOk(bp);
if (bp->needsChange()) {
bp->gotoState(BreakpointUpdateRequested, BreakpointInserted);
updateBreakpoint(bp);
// QTC_CHECK(!bp->needsChange());
}
}
}
}
+2 -5
View File
@@ -47,12 +47,9 @@ public:
PdbEngine();
private:
// DebuggerEngine implementation
void executeStep() override;
void executeStepIn(bool) override;
void executeStepOut() override;
void executeNext() override;
void executeStepI() override;
void executeNextI() override;
void executeStepOver(bool) override;
void setupEngine() override;
void runEngine() override;
+2 -15
View File
@@ -610,15 +610,7 @@ void QmlEngine::interruptInferior()
showStatusMessage(tr("Waiting for JavaScript engine to interrupt on next statement."));
}
void QmlEngine::executeStep()
{
clearExceptionSelection();
d->continueDebugging(StepIn);
notifyInferiorRunRequested();
notifyInferiorRunOk();
}
void QmlEngine::executeStepI()
void QmlEngine::executeStepIn(bool)
{
clearExceptionSelection();
d->continueDebugging(StepIn);
@@ -634,7 +626,7 @@ void QmlEngine::executeStepOut()
notifyInferiorRunOk();
}
void QmlEngine::executeNext()
void QmlEngine::executeStepOver(bool)
{
clearExceptionSelection();
d->continueDebugging(Next);
@@ -642,11 +634,6 @@ void QmlEngine::executeNext()
notifyInferiorRunOk();
}
void QmlEngine::executeNextI()
{
executeNext();
}
void QmlEngine::executeRunToLine(const ContextData &data)
{
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
+2 -4
View File
@@ -72,11 +72,9 @@ private:
void resetLocation() override;
void executeStep() override;
void executeStepOver(bool) override;
void executeStepIn(bool) override;
void executeStepOut() override;
void executeNext() override;
void executeStepI() override;
void executeNextI() override;
void setupEngine() override;
void runEngine() override;
-17
View File
@@ -1,17 +0,0 @@
Commands:
- P3:
- allow to use external viewer instead of greenhouse one
as these have more functionality usually
GUI:
- Better diff view
- Commit action View
- Able to add further files to commit (list of modified/untracked files)
- use List for Log (and allow 10+ entries)
Backend:
- Don't use forked processes, instead find a library connection like libgit-thin
- http://repo.or.cz/w/git/libgit-gsoc.git
- apply to SCM Manager in Greenhouse, currently it's mostly independent
Suggestions:
- Bjorn: Use a "Summary" Lineedit in the commit dialog to make commits look nicer on gitweb or such.
-2
View File
@@ -123,8 +123,6 @@ public:
QStringList fullName(bool includePrefix = false) const
{
QTC_ASSERT(isLeaf(), return QStringList());
QStringList fn;
QList<const BranchNode *> nodes;
const BranchNode *current = this;
+36 -8
View File
@@ -37,6 +37,7 @@
#include <coreplugin/documentmanager.h>
#include <coreplugin/inavigationwidgetfactory.h>
#include <utils/elidinglabel.h>
#include <utils/fancylineedit.h>
#include <utils/navigationtreeview.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
@@ -48,6 +49,7 @@
#include <QMenu>
#include <QMessageBox>
#include <QPoint>
#include <QSortFilterProxyModel>
#include <QTreeView>
#include <QToolButton>
#include <QVBoxLayout>
@@ -57,6 +59,21 @@ using namespace Core;
namespace Git {
namespace Internal {
class BranchFilterModel : public QSortFilterProxyModel
{
public:
BranchFilterModel(QObject *parent) : QSortFilterProxyModel(parent) {}
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
{
QAbstractItemModel *m = sourceModel();
// Filter leaves only. The root node and all intermediate nodes should always be visible
if (!sourceParent.isValid() || m->rowCount(m->index(sourceRow, 0, sourceParent)) > 0)
return true;
return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
}
};
BranchView::BranchView() :
m_includeOldEntriesAction(new QAction(tr("Include Old Entries"), this)),
m_includeTagsAction(new QAction(tr("Include Tags"), this)),
@@ -64,7 +81,8 @@ BranchView::BranchView() :
m_refreshButton(new QToolButton(this)),
m_repositoryLabel(new Utils::ElidingLabel(this)),
m_branchView(new Utils::NavigationTreeView(this)),
m_model(new BranchModel(GitPlugin::client(), this))
m_model(new BranchModel(GitPlugin::client(), this)),
m_filterModel(new BranchFilterModel(this))
{
m_addButton->setIcon(Utils::Icons::PLUS_TOOLBAR.icon());
m_addButton->setProperty("noArrow", true);
@@ -75,12 +93,21 @@ BranchView::BranchView() :
m_refreshButton->setProperty("noArrow", true);
connect(m_refreshButton, &QToolButton::clicked, this, &BranchView::refreshCurrentRepository);
m_branchView->setModel(m_model);
m_branchView->setHeaderHidden(true);
setFocus();
m_repositoryLabel->setElideMode(Qt::ElideLeft);
m_filterModel->setSourceModel(m_model);
m_filterModel->setFilterRole(Qt::EditRole);
m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_branchView->setModel(m_filterModel);
auto filterEdit = new Utils::FancyLineEdit(this);
filterEdit->setFiltering(true);
connect(filterEdit, &Utils::FancyLineEdit::textChanged,
m_filterModel, QOverload<const QString &>::of(&BranchFilterModel::setFilterRegExp));
auto layout = new QVBoxLayout(this);
layout->addWidget(filterEdit);
layout->addWidget(m_repositoryLabel);
layout->addWidget(m_branchView);
layout->setContentsMargins(0, 2, 0, 0);
@@ -100,7 +127,7 @@ BranchView::BranchView() :
m_branchView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_branchView, &QAbstractItemView::doubleClicked,
this, &BranchView::log);
this, [this](const QModelIndex &idx) { log(m_filterModel->mapToSource(idx)); });
connect(m_branchView, &QWidget::customContextMenuRequested,
this, &BranchView::slotCustomContextMenu);
connect(m_model, &QAbstractItemModel::modelReset,
@@ -161,10 +188,11 @@ void BranchView::resizeColumns()
void BranchView::slotCustomContextMenu(const QPoint &point)
{
const QModelIndex index = m_branchView->indexAt(point);
if (!index.isValid())
const QModelIndex filteredIndex = m_branchView->indexAt(point);
if (!filteredIndex.isValid())
return;
const QModelIndex index = m_filterModel->mapToSource(filteredIndex);
const QModelIndex currentBranch = m_model->currentBranch();
const bool currentSelected = index.row() == currentBranch.row();
const bool isLocal = m_model->isLocal(index);
@@ -185,9 +213,9 @@ void BranchView::slotCustomContextMenu(const QPoint &point)
}
if (hasActions) {
if (!currentSelected && (isLocal || isTag))
contextMenu.addAction(tr("Remove"), this, &BranchView::remove);
contextMenu.addAction(tr("Remove..."), this, &BranchView::remove);
if (isLocal || isTag)
contextMenu.addAction(tr("Rename"), this, &BranchView::rename);
contextMenu.addAction(tr("Rename..."), this, &BranchView::rename);
if (!currentSelected)
contextMenu.addAction(tr("Checkout"), this, &BranchView::checkout);
contextMenu.addSeparator();
@@ -246,7 +274,7 @@ QModelIndex BranchView::selectedIndex()
QModelIndexList selected = m_branchView->selectionModel()->selectedIndexes();
if (selected.isEmpty())
return QModelIndex();
return selected.at(0);
return m_filterModel->mapToSource(selected.at(0));
}
bool BranchView::add()
+2
View File
@@ -46,6 +46,7 @@ namespace Git {
namespace Internal {
class BranchModel;
class BranchFilterModel;
class BranchView : public QWidget
{
@@ -87,6 +88,7 @@ private:
Utils::ElidingLabel *m_repositoryLabel = nullptr;
Utils::NavigationTreeView *m_branchView = nullptr;
BranchModel *m_model = nullptr;
BranchFilterModel *m_filterModel = nullptr;
QString m_repository;
};
+1 -1
View File
@@ -274,7 +274,7 @@ HelpPluginPrivate::HelpPluginPrivate()
textEditorContextMenu->addAction(cmd, Core::Constants::G_HELP);
}
action = new QAction(HelpPlugin::tr("Technical Support"), this);
action = new QAction(HelpPlugin::tr("Technical Support..."), this);
cmd = ActionManager::registerAction(action, "Help.TechSupport");
ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT);
connect(action, &QAction::triggered, this, [this] {
+28 -10
View File
@@ -24,7 +24,6 @@
****************************************************************************/
#include "baseclient.h"
#include "languageclientcodeassist.h"
#include "languageclientmanager.h"
#include <coreplugin/icore.h>
@@ -63,6 +62,7 @@ static Q_LOGGING_CATEGORY(LOGLSPCLIENTV, "qtc.languageclient.messages", QtWarnin
BaseClient::BaseClient()
: m_id(Core::Id::fromString(QUuid::createUuid().toString()))
, m_completionProvider(this)
{
m_buffer.open(QIODevice::ReadWrite | QIODevice::Append);
m_contentHandler.insert(JsonRpcMessageHandler::jsonRpcMimeType(),
@@ -72,6 +72,10 @@ BaseClient::BaseClient()
BaseClient::~BaseClient()
{
m_buffer.close();
// FIXME: instead of replacing the completion provider in the text document store the
// completion provider as a prioritised list in the text document
for (TextEditor::TextDocument *document : m_resetCompletionProvider)
document->setCompletionAssistProvider(nullptr);
}
void BaseClient::initialize()
@@ -117,7 +121,7 @@ BaseClient::State BaseClient::state() const
void BaseClient::openDocument(Core::IDocument *document)
{
using namespace TextEditor;
if (!isSupportedMimeType(document->mimeType()))
if (!isSupportedDocument(document))
return;
const FileName &filePath = document->filePath();
const QString method(DidOpenTextDocumentNotification::methodName);
@@ -149,7 +153,11 @@ void BaseClient::openDocument(Core::IDocument *document)
documentContentsChanged(document);
});
if (textDocument) {
textDocument->setCompletionAssistProvider(new LanguageClientCompletionAssistProvider(this));
m_resetCompletionProvider << textDocument;
textDocument->setCompletionAssistProvider(&m_completionProvider);
connect(textDocument, &QObject::destroyed, this, [this, textDocument]{
m_resetCompletionProvider.remove(textDocument);
});
if (BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(textDocument)) {
if (QPointer<TextEditorWidget> widget = editor->editorWidget()) {
connect(widget, &TextEditorWidget::cursorPositionChanged, this, [this, widget](){
@@ -489,19 +497,29 @@ void BaseClient::projectClosed(ProjectExplorer::Project *project)
sendContent(change);
}
void BaseClient::setSupportedMimeType(const QStringList &supportedMimeTypes)
void BaseClient::setSupportedLanguage(const LanguageFilter &filter)
{
m_supportedMimeTypes = supportedMimeTypes;
m_languagFilter = filter;
}
bool BaseClient::isSupportedMimeType(const QString &mimeType) const
bool BaseClient::isSupportedDocument(const Core::IDocument *document) const
{
return m_supportedMimeTypes.isEmpty() || m_supportedMimeTypes.contains(mimeType);
QTC_ASSERT(document, return false);
if (m_languagFilter.mimeTypes.isEmpty() || m_languagFilter.mimeTypes.contains(document->mimeType()))
return true;
auto regexps = Utils::transform(m_languagFilter.filePattern, [](const QString &pattern){
return QRegExp(pattern, Utils::HostOsInfo::fileNameCaseSensitivity(), QRegExp::Wildcard);
});
return Utils::anyOf(regexps, [filePath = document->filePath()](const QRegExp &reg){
return reg.exactMatch(filePath.toString()) || reg.exactMatch(filePath.fileName());
});
}
bool BaseClient::needsRestart(const BaseSettings *) const
bool BaseClient::needsRestart(const BaseSettings *settings) const
{
return false;
QTC_ASSERT(settings, return false);
return m_languagFilter.mimeTypes != settings->m_languageFilter.mimeTypes
|| m_languagFilter.filePattern != settings->m_languageFilter.filePattern;
}
bool BaseClient::reset()
@@ -640,7 +658,7 @@ void BaseClient::intializeCallback(const InitializeResponse &initResponse)
if (optional<ResponseError<InitializeError>> error = initResponse.error()) {
if (error.value().data().has_value()
&& error.value().data().value().retry().value_or(false)) {
const QString title(tr("Language Server \"%1\" initialize error"));
const QString title(tr("Language Server \"%1\" Initialize Error"));
auto result = QMessageBox::warning(Core::ICore::dialogParent(),
title,
error.value().message(),
+6 -3
View File
@@ -26,6 +26,7 @@
#pragma once
#include "dynamiccapabilities.h"
#include "languageclientcodeassist.h"
#include "languageclientsettings.h"
#include <coreplugin/id.h>
@@ -104,8 +105,8 @@ public:
const LanguageServerProtocol::IContent &content);
void cancelRequest(const LanguageServerProtocol::MessageId &id);
void setSupportedMimeType(const QStringList &supportedMimeTypes);
bool isSupportedMimeType(const QString &mimeType) const;
void setSupportedLanguage(const LanguageFilter &filter);
bool isSupportedDocument(const Core::IDocument *document) const;
void setName(const QString &name) { m_displayName = name; }
QString name() const { return m_displayName; }
@@ -153,11 +154,13 @@ private:
QHash<QByteArray, ContentHandler> m_contentHandler;
QBuffer m_buffer;
QString m_displayName;
QStringList m_supportedMimeTypes;
LanguageFilter m_languagFilter;
QList<Utils::FileName> m_openedDocument;
Core::Id m_id;
LanguageServerProtocol::ServerCapabilities m_serverCapabilities;
DynamicCapabilities m_dynamicCapabilities;
LanguageClientCompletionAssistProvider m_completionProvider;
QSet<TextEditor::TextDocument *> m_resetCompletionProvider;
LanguageServerProtocol::BaseMessage m_currentMessage;
QHash<LanguageServerProtocol::DocumentUri, LanguageServerProtocol::MessageId> m_highlightRequests;
int m_restartsLeft = 5;
@@ -69,6 +69,8 @@ public:
bool operator <(const LanguageClientCompletionItem &other) const;
bool isPerfectMatch(int pos, QTextDocument *doc) const;
private:
CompletionItem m_item;
mutable QString m_sortText;
@@ -194,6 +196,26 @@ bool LanguageClientCompletionItem::operator <(const LanguageClientCompletionItem
return sortText() < other.sortText();
}
bool LanguageClientCompletionItem::isPerfectMatch(int pos, QTextDocument *doc) const
{
QTC_ASSERT(doc, return false);
using namespace Utils::Text;
if (auto additionalEdits = m_item.additionalTextEdits()) {
if (!additionalEdits.value().isEmpty())
return false;
}
if (auto edit = m_item.textEdit()) {
auto range = edit->range();
const int start = positionInText(doc, range.start().line() + 1, range.start().character() + 1);
const int end = positionInText(doc, range.end().line() + 1, range.end().character() + 1);
auto text = textAt(QTextCursor(doc), start, end - start);
return text == edit->newText();
}
const QString textToInsert(m_item.insertText().value_or(text()));
const int length = textToInsert.length();
return textToInsert == textAt(QTextCursor(doc), pos - length, length);
}
class LanguageClientCompletionModel : public TextEditor::GenericProposalModel
{
public:
@@ -201,6 +223,9 @@ public:
bool isSortable(const QString &/*prefix*/) const override { return true; }
void sort(const QString &/*prefix*/) override;
bool supportsPrefixExpansion() const override { return false; }
QList<LanguageClientCompletionItem *> items() const
{ return Utils::static_container_cast<LanguageClientCompletionItem *>(m_currentItems); }
};
void LanguageClientCompletionModel::sort(const QString &/*prefix*/)
@@ -213,16 +238,44 @@ void LanguageClientCompletionModel::sort(const QString &/*prefix*/)
});
}
class LanguageClientCompletionProposal : public TextEditor::GenericProposal
{
public:
LanguageClientCompletionProposal(int cursorPos, LanguageClientCompletionModel *model)
: TextEditor::GenericProposal(cursorPos, TextEditor::GenericProposalModelPtr(model))
, m_model(model)
{ }
// IAssistProposal interface
bool hasItemsToPropose(const QString &/*text*/, TextEditor::AssistReason reason) const override
{
if (m_model->size() <= 0 || m_document.isNull())
return false;
return m_model->keepPerfectMatch(reason)
|| !Utils::anyOf(m_model->items(), [this](LanguageClientCompletionItem *item){
return item->isPerfectMatch(m_pos, m_document);
});
}
LanguageClientCompletionModel *m_model;
QPointer<QTextDocument> m_document;
int m_pos = -1;
};
class LanguageClientCompletionAssistProcessor : public TextEditor::IAssistProcessor
{
public:
LanguageClientCompletionAssistProcessor(BaseClient *client);
TextEditor::IAssistProposal *perform(const TextEditor::AssistInterface *interface) override;
bool running() override;
bool needsRestart() const override { return true; }
private:
void handleCompletionResponse(const Response<CompletionResult, LanguageClientNull> &response);
QPointer<QTextDocument> m_document;
QPointer<BaseClient> m_client;
bool m_running = false;
int m_pos = -1;
@@ -247,11 +300,15 @@ TextEditor::IAssistProposal *LanguageClientCompletionAssistProcessor::perform(
{
QTC_ASSERT(m_client, return nullptr);
m_pos = interface->position();
// const QRegExp regexp("[_a-zA-Z][_a-zA-Z0-9]*"); // FIXME
// int delta = 0;
// while (m_pos - delta > 0 && regexp.exactMatch(interface->textAt(m_pos - delta - 1, delta + 1)))
// ++delta;
// m_pos -= delta;
if (interface->reason() == TextEditor::IdleEditor) {
// Trigger an automatic completion request only when we are on a word with more than 2 "identifier" character
const QRegExp regexp("[_a-zA-Z0-9]*");
int delta = 0;
while (m_pos - delta > 0 && regexp.exactMatch(interface->textAt(m_pos - delta - 1, delta + 1)))
++delta;
if (delta < 3)
return nullptr;
}
CompletionRequest completionRequest;
CompletionParams::CompletionContext context;
context.setTriggerKind(interface->reason() == TextEditor::ActivationCharacter
@@ -263,6 +320,7 @@ TextEditor::IAssistProposal *LanguageClientCompletionAssistProcessor::perform(
if (!Utils::Text::convertPosition(interface->textDocument(), m_pos, &line, &column))
return nullptr;
--line; // line is 0 based in the protocol
--column; // column is 0 based in the protocol
params.setPosition({line, column});
params.setTextDocument(
DocumentUri::fromFileName(Utils::FileName::fromString(interface->fileName())));
@@ -272,6 +330,7 @@ TextEditor::IAssistProposal *LanguageClientCompletionAssistProcessor::perform(
completionRequest.setParams(params);
m_client->sendContent(completionRequest);
m_running = true;
m_document = interface->textDocument();
qCDebug(LOGLSPCOMPLETION) << QTime::currentTime()
<< " : request completions at " << m_pos
<< " by " << assistReasonString(interface->reason());
@@ -309,7 +368,9 @@ void LanguageClientCompletionAssistProcessor::handleCompletionResponse(
model->loadContent(Utils::transform(items, [](const CompletionItem &item){
return static_cast<AssistProposalItemInterface *>(new LanguageClientCompletionItem(item));
}));
auto proposal = new GenericProposal(m_pos, GenericProposalModelPtr(model));
auto proposal = new LanguageClientCompletionProposal(m_pos, model);
proposal->m_document = m_document;
proposal->m_pos = m_pos;
proposal->setFragile(true);
setAsyncProposalAvailable(proposal);
qCDebug(LOGLSPCOMPLETION) << QTime::currentTime() << " : "
@@ -32,24 +32,33 @@
#include <coreplugin/icore.h>
#include <utils/algorithm.h>
#include <utils/delegates.h>
#include <utils/fancylineedit.h>
#include <utils/qtcprocess.h>
#include <utils/mimetypes/mimedatabase.h>
#include <languageserverprotocol/lsptypes.h>
#include <QBoxLayout>
#include <QCheckBox>
#include <QComboBox>
#include <QCompleter>
#include <QCoreApplication>
#include <QDialog>
#include <QDialogButtonBox>
#include <QDir>
#include <QFileInfo>
#include <QHeaderView>
#include <QLabel>
#include <QListView>
#include <QPushButton>
#include <QSettings>
#include <QStyledItemDelegate>
#include <QSortFilterProxyModel>
#include <QStringListModel>
#include <QTreeView>
constexpr char nameKey[] = "name";
constexpr char enabledKey[] = "enabled";
constexpr char mimeTypeKey[] = "mimeType";
constexpr char filePatternKey[] = "filePattern";
constexpr char executableKey[] = "executable";
constexpr char argumentsKey[] = "arguments";
constexpr char settingsGroupKey[] = "LanguageClient";
@@ -57,34 +66,25 @@ constexpr char clientsKey[] = "clients";
namespace LanguageClient {
class LanguageClientSettingsModel : public QAbstractTableModel
class LanguageClientSettingsModel : public QAbstractListModel
{
public:
LanguageClientSettingsModel() = default;
~LanguageClientSettingsModel();
// QAbstractItemModel interface
int rowCount(const QModelIndex &/*parent*/ = QModelIndex()) const override { return m_settings.count(); }
int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const override { return ColumnCount; }
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
bool removeRows(int row, int count = 1, const QModelIndex &parent = QModelIndex()) override;
bool insertRows(int row, int count = 1, const QModelIndex &parent = QModelIndex()) override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
int rowCount(const QModelIndex &/*parent*/ = QModelIndex()) const final { return m_settings.count(); }
QVariant data(const QModelIndex &index, int role) const final;
bool removeRows(int row, int count = 1, const QModelIndex &parent = QModelIndex()) final;
bool insertRows(int row, int count = 1, const QModelIndex &parent = QModelIndex()) final;
bool setData(const QModelIndex &index, const QVariant &value, int role) final;
Qt::ItemFlags flags(const QModelIndex &index) const final;
void reset(const QList<StdIOSettings *> &settings);
QList<StdIOSettings *> settings() const { return m_settings; }
QList<StdIOSettings *> removed() const { return m_removed; }
enum Columns {
DisplayNameColumn = 0,
EnabledColumn,
MimeTypeColumn,
ExecutableColumn,
ArgumentsColumn,
ColumnCount
};
StdIOSettings *settingForIndex(const QModelIndex &index) const;
QModelIndex indexForSetting(StdIOSettings *setting) const;
private:
QList<StdIOSettings *> m_settings; // owned
@@ -95,10 +95,18 @@ class LanguageClientSettingsPageWidget : public QWidget
{
public:
LanguageClientSettingsPageWidget(LanguageClientSettingsModel &settings);
void currentChanged(const QModelIndex &index);
int currentRow() const;
void resetCurrentSettings(int row);
void applyCurrentSettings();
private:
LanguageClientSettingsModel &m_settings;
QTreeView *m_view;
QTreeView *m_view = nullptr;
struct CurrentSettings {
StdIOSettings *setting = nullptr;
QWidget *widget = nullptr;
} m_currentSettings;
void addItem();
void deleteItem();
@@ -123,61 +131,29 @@ private:
QPointer<LanguageClientSettingsPageWidget> m_widget;
};
class LanguageChooseDelegate : public QStyledItemDelegate
{
public:
QWidget *createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
};
QWidget *LanguageChooseDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
Q_UNUSED(option);
Q_UNUSED(index);
auto editor = new QComboBox(parent);
editor->addItem(noLanguageFilter);
editor->addItems(LanguageServerProtocol::languageIds().values());
return editor;
}
void LanguageChooseDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if (auto comboBox = qobject_cast<QComboBox*>(editor))
comboBox->setCurrentText(index.data().toString());
}
LanguageClientSettingsPageWidget::LanguageClientSettingsPageWidget(LanguageClientSettingsModel &settings)
: m_settings(settings)
, m_view(new QTreeView())
{
auto mainLayout = new QVBoxLayout();
auto layout = new QHBoxLayout();
m_view->setModel(&m_settings);
m_view->header()->setStretchLastSection(true);
m_view->setRootIsDecorated(false);
m_view->setItemsExpandable(false);
m_view->setHeaderHidden(true);
m_view->setSelectionMode(QAbstractItemView::SingleSelection);
m_view->setSelectionBehavior(QAbstractItemView::SelectItems);
connect(m_view->selectionModel(), &QItemSelectionModel::currentChanged,
this, &LanguageClientSettingsPageWidget::currentChanged);
auto mimeTypes = Utils::transform(Utils::allMimeTypes(), [](const Utils::MimeType &mimeType){
return mimeType.name();
});
auto mimeTypeCompleter = new QCompleter(mimeTypes);
mimeTypeCompleter->setCaseSensitivity(Qt::CaseInsensitive);
mimeTypeCompleter->setFilterMode(Qt::MatchContains);
m_view->setItemDelegateForColumn(LanguageClientSettingsModel::MimeTypeColumn,
new Utils::CompleterDelegate(mimeTypeCompleter));
auto executableDelegate = new Utils::PathChooserDelegate();
executableDelegate->setExpectedKind(Utils::PathChooser::File);
executableDelegate->setHistoryCompleter("LanguageClient.ServerPathHistory");
m_view->setItemDelegateForColumn(LanguageClientSettingsModel::ExecutableColumn, executableDelegate);
auto buttonLayout = new QVBoxLayout();
auto addButton = new QPushButton(tr("&Add"));
connect(addButton, &QPushButton::pressed, this, &LanguageClientSettingsPageWidget::addItem);
auto deleteButton = new QPushButton(tr("&Delete"));
connect(deleteButton, &QPushButton::pressed, this, &LanguageClientSettingsPageWidget::deleteItem);
setLayout(layout);
mainLayout->addLayout(layout);
setLayout(mainLayout);
layout->addWidget(m_view);
layout->addLayout(buttonLayout);
buttonLayout->addWidget(addButton);
@@ -185,6 +161,51 @@ LanguageClientSettingsPageWidget::LanguageClientSettingsPageWidget(LanguageClien
buttonLayout->addStretch(10);
}
void LanguageClientSettingsPageWidget::currentChanged(const QModelIndex &index)
{
if (m_currentSettings.widget) {
applyCurrentSettings();
layout()->removeWidget(m_currentSettings.widget);
delete m_currentSettings.widget;
}
if (index.isValid()) {
m_currentSettings.setting = m_settings.settingForIndex(index);
m_currentSettings.widget = m_currentSettings.setting->createSettingsWidget(this);
layout()->addWidget(m_currentSettings.widget);
} else {
m_currentSettings.setting = nullptr;
m_currentSettings.widget = nullptr;
}
}
int LanguageClientSettingsPageWidget::currentRow() const
{
return m_settings.indexForSetting(m_currentSettings.setting).row();
}
void LanguageClientSettingsPageWidget::resetCurrentSettings(int row)
{
if (m_currentSettings.widget) {
layout()->removeWidget(m_currentSettings.widget);
delete m_currentSettings.widget;
}
m_currentSettings.setting = nullptr;
m_currentSettings.widget = nullptr;
m_view->setCurrentIndex(m_settings.index(row));
}
void LanguageClientSettingsPageWidget::applyCurrentSettings()
{
if (!m_currentSettings.setting)
return;
m_currentSettings.setting->applyFromSettingsWidget(m_currentSettings.widget);
auto index = m_settings.indexForSetting(m_currentSettings.setting);
m_settings.dataChanged(index, index);
}
void LanguageClientSettingsPageWidget::addItem()
{
const int row = m_settings.rowCount();
@@ -233,6 +254,8 @@ QWidget *LanguageClientSettingsPage::widget()
void LanguageClientSettingsPage::apply()
{
qDeleteAll(m_settings);
if (m_widget)
m_widget->applyCurrentSettings();
m_settings = Utils::transform(m_model.settings(), [](const StdIOSettings *other){
return dynamic_cast<StdIOSettings *>(other->copy());
});
@@ -255,11 +278,19 @@ void LanguageClientSettingsPage::apply()
}
}
}
m_model.reset(m_settings);
if (m_widget) {
int row = m_widget->currentRow();
m_model.reset(m_settings);
m_widget->resetCurrentSettings(row);
} else {
m_model.reset(m_settings);
}
}
void LanguageClientSettingsPage::finish()
{
m_model.reset(m_settings);
}
LanguageClientSettingsModel::~LanguageClientSettingsModel()
@@ -269,35 +300,13 @@ LanguageClientSettingsModel::~LanguageClientSettingsModel()
QVariant LanguageClientSettingsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
StdIOSettings *setting = settingForIndex(index);
if (!setting)
return QVariant();
StdIOSettings *setting = m_settings[index.row()];
QTC_ASSERT(setting, return false);
if (role == Qt::DisplayRole || role == Qt::EditRole) {
switch (index.column()) {
case DisplayNameColumn: return setting->m_name;
case MimeTypeColumn: return setting->m_mimeType;
case ExecutableColumn: return setting->m_executable;
case ArgumentsColumn: return setting->m_arguments;
}
} else if (role == Qt::CheckStateRole && index.column() == EnabledColumn) {
if (role == Qt::DisplayRole)
return setting->m_name;
else if (role == Qt::CheckStateRole)
return setting->m_enabled ? Qt::Checked : Qt::Unchecked;
}
return QVariant();
}
QVariant LanguageClientSettingsModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
return QVariant();
switch (section) {
case DisplayNameColumn: return tr("Name");
case EnabledColumn: return tr("Enabled");
case MimeTypeColumn: return tr("Mime Type");
case ExecutableColumn: return tr("Executable");
case ArgumentsColumn: return tr("Arguments");
}
return QVariant();
}
@@ -326,44 +335,20 @@ bool LanguageClientSettingsModel::insertRows(int row, int count, const QModelInd
bool LanguageClientSettingsModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
StdIOSettings *setting = settingForIndex(index);
if (!setting || role != Qt::CheckStateRole)
return false;
StdIOSettings *setting = m_settings[index.row()];
QTC_ASSERT(setting, return false);
if (role == Qt::DisplayRole || role == Qt::EditRole) {
const QString strVal(value.toString());
QString *settingsValue = nullptr;
switch (index.column()) {
case DisplayNameColumn: settingsValue = &setting->m_name; break;
case MimeTypeColumn: settingsValue = &setting->m_mimeType; break;
case ExecutableColumn: settingsValue = &setting->m_executable; break;
case ArgumentsColumn: settingsValue = &setting->m_arguments; break;
}
if (settingsValue) {
if (strVal != *settingsValue) {
*settingsValue = value.toString();
emit dataChanged(index, index, { Qt::EditRole, Qt::DisplayRole });
}
return true;
}
}
if (role == Qt::CheckStateRole && index.column() == EnabledColumn) {
if (setting->m_enabled != value.toBool()) {
setting->m_enabled = !setting->m_enabled;
emit dataChanged(index, index, { Qt::CheckStateRole });
}
return true;
if (setting->m_enabled != value.toBool()) {
setting->m_enabled = !setting->m_enabled;
emit dataChanged(index, index, { Qt::CheckStateRole });
}
return false;
return true;
}
Qt::ItemFlags LanguageClientSettingsModel::flags(const QModelIndex &index) const
Qt::ItemFlags LanguageClientSettingsModel::flags(const QModelIndex &/*index*/) const
{
const auto defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
if (index.column() == EnabledColumn)
return defaultFlags | Qt::ItemIsUserCheckable;
return defaultFlags;
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
}
void LanguageClientSettingsModel::reset(const QList<StdIOSettings *> &settings)
@@ -378,6 +363,32 @@ void LanguageClientSettingsModel::reset(const QList<StdIOSettings *> &settings)
endResetModel();
}
StdIOSettings *LanguageClientSettingsModel::settingForIndex(const QModelIndex &index) const
{
if (!index.isValid() || index.row() >= m_settings.size())
return nullptr;
return m_settings[index.row()];
}
QModelIndex LanguageClientSettingsModel::indexForSetting(StdIOSettings *setting) const
{
const int index = m_settings.indexOf(setting);
return index < 0 ? QModelIndex() : createIndex(index, 0, setting);
}
void BaseSettings::applyFromSettingsWidget(QWidget *widget)
{
if (auto settingsWidget = qobject_cast<BaseSettingsWidget *>(widget)) {
m_name = settingsWidget->name();
m_languageFilter = settingsWidget->filter();
}
}
QWidget *BaseSettings::createSettingsWidget(QWidget *parent) const
{
return new BaseSettingsWidget(this, parent);
}
bool BaseSettings::needsRestart() const
{
return m_client ? !m_enabled || m_client->needsRestart(this) : m_enabled;
@@ -398,7 +409,8 @@ QVariantMap BaseSettings::toMap() const
QVariantMap map;
map.insert(nameKey, m_name);
map.insert(enabledKey, m_enabled);
map.insert(mimeTypeKey, m_mimeType);
map.insert(mimeTypeKey, m_languageFilter.mimeTypes);
map.insert(filePatternKey, m_languageFilter.filePattern);
return map;
}
@@ -406,7 +418,8 @@ void BaseSettings::fromMap(const QVariantMap &map)
{
m_name = map[nameKey].toString();
m_enabled = map[enabledKey].toBool();
m_mimeType = map[mimeTypeKey].toString();
m_languageFilter.mimeTypes = map[mimeTypeKey].toStringList();
m_languageFilter.filePattern = map[filePatternKey].toStringList();
}
void LanguageClientSettings::init()
@@ -438,6 +451,20 @@ void LanguageClientSettings::toSettings(QSettings *settings, const QList<StdIOSe
settings->endGroup();
}
void StdIOSettings::applyFromSettingsWidget(QWidget *widget)
{
if (auto settingsWidget = qobject_cast<StdIOSettingsWidget *>(widget)) {
BaseSettings::applyFromSettingsWidget(settingsWidget);
m_executable = settingsWidget->executable();
m_arguments = settingsWidget->arguments();
}
}
QWidget *StdIOSettings::createSettingsWidget(QWidget *parent) const
{
return new StdIOSettingsWidget(this, parent);
}
bool StdIOSettings::needsRestart() const
{
if (BaseSettings::needsRestart())
@@ -456,8 +483,7 @@ BaseClient *StdIOSettings::createClient() const
{
auto client = new StdIOClient(m_executable, m_arguments);
client->setName(m_name);
if (m_mimeType != noLanguageFilter)
client->setSupportedMimeType({m_mimeType});
client->setSupportedLanguage(m_languageFilter);
return client;
}
@@ -476,4 +502,160 @@ void StdIOSettings::fromMap(const QVariantMap &map)
m_arguments = map[argumentsKey].toString();
}
BaseSettingsWidget::BaseSettingsWidget(const BaseSettings *settings, QWidget *parent)
: QWidget(parent)
, m_name(new QLineEdit(settings->m_name, this))
, m_mimeTypes(new QLabel(settings->m_languageFilter.mimeTypes.join(filterSeparator), this))
, m_filePattern(new QLineEdit(settings->m_languageFilter.filePattern.join(filterSeparator), this))
{
int row = 0;
auto *mainLayout = new QGridLayout;
mainLayout->addWidget(new QLabel(tr("Name:")), row, 0);
mainLayout->addWidget(m_name, row, 1);
mainLayout->addWidget(new QLabel(tr("Language:")), ++row, 0);
auto mimeLayout = new QHBoxLayout;
mimeLayout->addWidget(m_mimeTypes);
mimeLayout->addStretch();
auto addMimeTypeButton = new QPushButton(tr("Set MIME Types..."), this);
mimeLayout->addWidget(addMimeTypeButton);
mainLayout->addLayout(mimeLayout, row, 1);
m_filePattern->setPlaceholderText(tr("File pattern"));
mainLayout->addWidget(m_filePattern, ++row, 1);
connect(addMimeTypeButton, &QPushButton::pressed,
this, &BaseSettingsWidget::showAddMimeTypeDialog);
setLayout(mainLayout);
}
QString BaseSettingsWidget::name() const
{
return m_name->text();
}
LanguageFilter BaseSettingsWidget::filter() const
{
return {m_mimeTypes->text().split(filterSeparator),
m_filePattern->text().split(filterSeparator)};
}
class MimeTypeModel : public QStringListModel
{
public:
using QStringListModel::QStringListModel;
QVariant data(const QModelIndex &index, int role) const final
{
if (index.isValid() && role == Qt::CheckStateRole)
return m_selectedMimeTypes.contains(index.data().toString()) ? Qt::Checked : Qt::Unchecked;
return QStringListModel::data(index, role);
}
bool setData(const QModelIndex &index, const QVariant &value, int role) final
{
if (index.isValid() && role == Qt::CheckStateRole) {
QString mimeType = index.data().toString();
if (value.toInt() == Qt::Checked) {
if (!m_selectedMimeTypes.contains(mimeType))
m_selectedMimeTypes.append(index.data().toString());
} else {
m_selectedMimeTypes.removeAll(index.data().toString());
}
return true;
}
return QStringListModel::setData(index, value, role);
}
Qt::ItemFlags flags(const QModelIndex &index) const final
{
if (!index.isValid())
return Qt::NoItemFlags;
return (QStringListModel::flags(index)
& ~(Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled))
| Qt::ItemIsUserCheckable;
}
QStringList m_selectedMimeTypes;
};
class MimeTypeDialog : public QDialog
{
public:
explicit MimeTypeDialog(const QStringList &selectedMimeTypes, QWidget *parent = nullptr)
: QDialog(parent)
{
setWindowTitle(tr("Select MIME Types"));
auto mainLayout = new QVBoxLayout;
auto filter = new Utils::FancyLineEdit(this);
filter->setFiltering(true);
mainLayout->addWidget(filter);
auto listView = new QListView(this);
mainLayout->addWidget(listView);
auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
mainLayout->addWidget(buttons);
setLayout(mainLayout);
filter->setPlaceholderText(tr("Filter"));
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
auto proxy = new QSortFilterProxyModel(this);
m_mimeTypeModel = new MimeTypeModel(Utils::transform(Utils::allMimeTypes(),
&Utils::MimeType::name), this);
m_mimeTypeModel->m_selectedMimeTypes = selectedMimeTypes;
proxy->setSourceModel(m_mimeTypeModel);
proxy->sort(0);
connect(filter, &QLineEdit::textChanged, proxy, &QSortFilterProxyModel::setFilterWildcard);
listView->setModel(proxy);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setModal(true);
}
MimeTypeDialog(const MimeTypeDialog &other) = delete;
MimeTypeDialog(MimeTypeDialog &&other) = delete;
MimeTypeDialog operator=(const MimeTypeDialog &other) = delete;
MimeTypeDialog operator=(MimeTypeDialog &&other) = delete;
QStringList mimeTypes() const
{
return m_mimeTypeModel->m_selectedMimeTypes;
}
private:
MimeTypeModel *m_mimeTypeModel = nullptr;
};
void BaseSettingsWidget::showAddMimeTypeDialog()
{
MimeTypeDialog dialog(m_mimeTypes->text().split(filterSeparator, QString::SkipEmptyParts),
Core::ICore::dialogParent());
if (dialog.exec() == QDialog::Rejected)
return;
m_mimeTypes->setText(dialog.mimeTypes().join(filterSeparator));
}
StdIOSettingsWidget::StdIOSettingsWidget(const StdIOSettings *settings, QWidget *parent)
: BaseSettingsWidget(settings, parent)
, m_executable(new Utils::PathChooser(this))
, m_arguments(new QLineEdit(settings->m_arguments, this))
{
auto mainLayout = qobject_cast<QGridLayout *>(layout());
QTC_ASSERT(mainLayout, return);
const int baseRows = mainLayout->rowCount();
mainLayout->addWidget(new QLabel(tr("Executable:")), baseRows, 0);
mainLayout->addWidget(m_executable, baseRows, 1);
mainLayout->addWidget(new QLabel(tr("Arguments:")), baseRows + 1, 0);
m_executable->setExpectedKind(Utils::PathChooser::ExistingCommand);
m_executable->setPath(QDir::toNativeSeparators(settings->m_executable));
mainLayout->addWidget(m_arguments, baseRows + 1, 1);
}
QString StdIOSettingsWidget::executable() const
{
return m_executable->path();
}
QString StdIOSettingsWidget::arguments() const
{
return m_arguments->text();
}
} // namespace LanguageClient
@@ -28,32 +28,48 @@
#include <coreplugin/dialogs/ioptionspage.h>
#include <QAbstractItemModel>
#include <QLabel>
#include <QPointer>
#include <QWidget>
QT_BEGIN_NAMESPACE
class QCheckBox;
class QLineEdit;
QT_END_NAMESPACE
namespace Utils { class PathChooser; }
namespace LanguageClient {
constexpr char noLanguageFilter[] = "No Filter";
class BaseClient;
struct LanguageFilter
{
QStringList mimeTypes;
QStringList filePattern;
};
class BaseSettings
{
public:
BaseSettings() = default;
BaseSettings(const QString &name, bool enabled, const QString &mimeTypeName)
BaseSettings(const QString &name, bool enabled, const LanguageFilter &filter)
: m_name(name)
, m_enabled(enabled)
, m_mimeType(mimeTypeName)
, m_languageFilter(filter)
{}
virtual ~BaseSettings() = default;
QString m_name = QString("New Language Server");
bool m_enabled = true;
QString m_mimeType = QLatin1String(noLanguageFilter);
LanguageFilter m_languageFilter;
QPointer<BaseClient> m_client; // not owned
virtual void applyFromSettingsWidget(QWidget *widget);
virtual QWidget *createSettingsWidget(QWidget *parent = nullptr) const;
virtual BaseSettings *copy() const { return new BaseSettings(*this); }
virtual bool needsRestart() const;
virtual bool isValid() const ;
@@ -72,9 +88,9 @@ class StdIOSettings : public BaseSettings
{
public:
StdIOSettings() = default;
StdIOSettings(const QString &name, bool enabled, const QString &mimeTypeName,
StdIOSettings(const QString &name, bool enabled, const LanguageFilter &filter,
const QString &executable, const QString &arguments)
: BaseSettings(name, enabled, mimeTypeName)
: BaseSettings(name, enabled, filter)
, m_executable(executable)
, m_arguments(arguments)
{}
@@ -84,6 +100,8 @@ public:
QString m_executable;
QString m_arguments;
void applyFromSettingsWidget(QWidget *widget) override;
QWidget *createSettingsWidget(QWidget *parent = nullptr) const override;
BaseSettings *copy() const override { return new StdIOSettings(*this); }
bool needsRestart() const override;
bool isValid() const override;
@@ -106,4 +124,39 @@ public:
static void toSettings(QSettings *settings, const QList<StdIOSettings *> &languageClientSettings);
};
class BaseSettingsWidget : public QWidget
{
Q_OBJECT
public:
explicit BaseSettingsWidget(const BaseSettings* settings, QWidget *parent = nullptr);
~BaseSettingsWidget() = default;
QString name() const;
LanguageFilter filter() const;
private:
void showAddMimeTypeDialog();
QLineEdit *m_name = nullptr;
QLabel *m_mimeTypes = nullptr;
QLineEdit *m_filePattern = nullptr;
static constexpr char filterSeparator = ';';
};
class StdIOSettingsWidget : public BaseSettingsWidget
{
Q_OBJECT
public:
explicit StdIOSettingsWidget(const StdIOSettings* settings, QWidget *parent = nullptr);
~StdIOSettingsWidget() = default;
QString executable() const;
QString arguments() const;
private:
Utils::PathChooser *m_executable = nullptr;
QLineEdit *m_arguments = nullptr;
};
} // namespace LanguageClient
@@ -278,11 +278,6 @@ QString CustomExecutableRunConfiguration::defaultDisplayName() const
return tr("Run %1").arg(QDir::toNativeSeparators(rawExecutable()));
}
Abi CustomExecutableRunConfiguration::abi() const
{
return Abi(); // return an invalid ABI: We do not know what we will end up running!
}
// Factory
CustomExecutableRunConfigurationFactory::CustomExecutableRunConfigurationFactory() :
@@ -45,7 +45,6 @@ public:
/** Returns whether this runconfiguration ever was configured with an executable
*/
bool isConfigured() const override;
Abi abi() const override;
ConfigurationState ensureConfigured(QString *errorMessage) override;
QString defaultDisplayName() const;
+1 -1
View File
@@ -489,7 +489,7 @@ LanguageExtensions GccToolChain::languageExtensions(const QStringList &cxxflags)
else
extensions &= ~LanguageExtensions(LanguageExtension::Gnu);
} else if (flag == "-fopenmp") {
extensions |= LanguageExtension::Gnu;
extensions |= LanguageExtension::OpenMP;
} else if (flag == "-fms-extensions") {
extensions |= LanguageExtension::Microsoft;
}
@@ -31,6 +31,7 @@
#include "../project.h"
#include "../projectexplorer.h"
#include "../projectexplorerconstants.h"
#include "../projecttree.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/messagemanager.h>
@@ -290,7 +291,7 @@ void JsonWizard::accept()
openFiles(m_files);
auto node = static_cast<ProjectExplorer::Node*>(value(ProjectExplorer::Constants::PREFERRED_PROJECT_NODE).value<void*>());
if (node) // PREFERRED_PROJECT_NODE is not set for newly created projects
if (node && ProjectTree::hasNode(node)) // PREFERRED_PROJECT_NODE is not set for newly created projects
openProjectForNode(node);
}
@@ -1296,6 +1296,11 @@ bool MsvcToolChain::operator ==(const ToolChain &other) const
return m_varsBatArg == msvcTc->m_varsBatArg;
}
void MsvcToolChain::cancelMsvcToolChainDetection()
{
envModThreadPool()->clear();
}
bool MsvcToolChainFactory::canRestore(const QVariantMap &data)
{
const Core::Id id = typeIdFromMap(data);
@@ -82,6 +82,8 @@ public:
bool operator == (const ToolChain &) const override;
static void cancelMsvcToolChainDetection();
protected:
explicit MsvcToolChain(Core::Id typeId, const QString &name, const Abi &abi,
const QString &varsBat, const QString &varsBatArg,
@@ -1739,6 +1739,7 @@ ExtensionSystem::IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown()
disconnect(ModeManager::instance(), &ModeManager::currentModeChanged,
dd, &ProjectExplorerPluginPrivate::currentModeChanged);
ProjectTree::aboutToShutDown();
ToolChainManager::aboutToShutdown();
SessionManager::closeAllProjects();
dd->m_shuttingDown = true;
@@ -127,12 +127,18 @@ ProjectWelcomePage::ProjectWelcomePage()
auto act = new QAction(tr("Open Session #%1").arg(i), this);
Command *cmd = ActionManager::registerAction(act, sessionBase.withSuffix(i), welcomeContext);
cmd->setDefaultKeySequence(QKeySequence((useMacShortcuts ? tr("Ctrl+Meta+%1") : tr("Ctrl+Alt+%1")).arg(i)));
connect(act, &QAction::triggered, this, [this, i] { openSessionAt(i - 1); });
connect(act, &QAction::triggered, this, [this, i] {
if (i <= m_sessionModel->rowCount())
openSessionAt(i - 1);
});
act = new QAction(tr("Open Recent Project #%1").arg(i), this);
cmd = ActionManager::registerAction(act, projectBase.withSuffix(i), welcomeContext);
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+%1").arg(i)));
connect(act, &QAction::triggered, this, [this, i] { openProjectAt(i - 1); });
connect(act, &QAction::triggered, this, [this, i] {
if (i <= m_projectModel->rowCount(QModelIndex()))
openProjectAt(i - 1);
});
}
}
@@ -456,10 +456,11 @@ void ProjectWizardPage::initializeProjectTree(Node *context, const QStringList &
}
root->prependChild(createNoneNode(&selector));
// Set combobox to context node:
// Set combobox to context node if that appears in the tree:
auto predicate = [context](TreeItem *ti) { return static_cast<AddNewTree*>(ti)->node() == context; };
TreeItem *contextItem = root->findAnyChild(predicate);
m_ui->projectComboBox->setCurrentIndex(m_model.indexForItem(contextItem));
if (contextItem)
m_ui->projectComboBox->setCurrentIndex(m_model.indexForItem(contextItem));
setAdditionalInfo(selector.deployingProjects());
setBestNode(selector.bestChoice());
@@ -310,17 +310,6 @@ QVariantMap RunConfiguration::toMap() const
return map;
}
Abi RunConfiguration::abi() const
{
BuildConfiguration *bc = target()->activeBuildConfiguration();
if (!bc)
return Abi::hostAbi();
ToolChain *tc = ToolChainKitInformation::toolChain(target()->kit(), Constants::CXX_LANGUAGE_ID);
if (!tc)
return Abi::hostAbi();
return tc->targetAbi();
}
BuildTargetInfo RunConfiguration::buildTargetInfo() const
{
return target()->applicationTargets().buildTargetInfo(m_buildKey);
@@ -1334,13 +1323,6 @@ Utils::Icon RunControl::icon() const
return d->icon;
}
Abi RunControl::abi() const
{
if (const RunConfiguration *rc = d->runConfiguration.data())
return rc->abi();
return Abi();
}
IDevice::ConstPtr RunControl::device() const
{
return d->device;
@@ -46,7 +46,6 @@
namespace Utils { class OutputFormatter; }
namespace ProjectExplorer {
class Abi;
class BuildConfiguration;
class GlobalOrProjectAspect;
class Node;
@@ -172,7 +171,6 @@ public:
QVariantMap toMap() const override;
virtual Runnable runnable() const;
virtual Abi abi() const;
// Return a handle to the build system target that created this run configuration.
// May return an empty string if no target built the executable!
@@ -439,7 +437,6 @@ public:
Utils::ProcessHandle applicationProcessHandle() const;
void setApplicationProcessHandle(const Utils::ProcessHandle &handle);
Abi abi() const;
IDevice::ConstPtr device() const;
RunConfiguration *runConfiguration() const;
@@ -27,6 +27,7 @@
#include "abi.h"
#include "kitinformation.h"
#include "msvctoolchain.h"
#include "toolchain.h"
#include "toolchainsettingsaccessor.h"
@@ -249,4 +250,11 @@ bool ToolChainManager::isLanguageSupported(const Core::Id &id)
return Utils::contains(d->m_languages, Utils::equal(&LanguageDisplayPair::id, id));
}
void ToolChainManager::aboutToShutdown()
{
#ifdef Q_OS_WIN
MsvcToolChain::cancelMsvcToolChainDetection();
#endif
}
} // namespace ProjectExplorer
@@ -74,6 +74,8 @@ public:
static QString displayNameOfLanguageId(const Core::Id &id);
static bool isLanguageSupported(const Core::Id &id);
static void aboutToShutdown();
void saveToolChains();
signals:
@@ -177,6 +177,8 @@ void WinDebugInterface::dispatchDebugOutput()
m_outputMutex.lock();
for (auto &entry : m_debugOutput) {
std::vector<QString> &src = entry.second;
if (src.empty())
continue;
QString dst;
size_t n = std::min(maxMessagesToSend, src.size());
for (size_t i = 0; i < n; ++i)

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