CppEditor: Rework showing/switching parse configurations

* Move the combox box for switching the parse configurations out of the
  "Additional Preprocessor Directives" dialog ('#'-button) to make it
  better visible/accessible. Also, decouple the extra preprocessor
  directives from the concrete parse context since this is not anymore
  in same dialog.
* The combo box appears only if multiple parse configurations are
  available for a file.
* The first time multiple parse configurations are detected, an info bar
  is shown that points the user to the combox box. A "Do Not Show Again"
  button is provided.
* Upon selecting an entry, the preferred parse configuration is saved as
  part of the session. The setting can be cleared with the context menu
  entry on the combo box.

Follow-up changes need to ensure that the display name and/or tooltip is
unambiguous, e.g. for qbs and cmake projects.

Change-Id: I9e9773704187291524ad7b605bfdddd83ef5b19d
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Nikolai Kosjar
2017-01-18 15:05:46 +01:00
parent 9ac96339ff
commit 38ba61ec4f
18 changed files with 538 additions and 208 deletions

View File

@@ -87,6 +87,12 @@ void BaseEditorDocumentProcessor::editorDocumentTimerRestarted()
{
}
void BaseEditorDocumentProcessor::setParserConfig(
const BaseEditorDocumentParser::Configuration config)
{
parser()->setConfiguration(config);
}
void BaseEditorDocumentProcessor::runParser(QFutureInterface<void> &future,
BaseEditorDocumentParser::Ptr parser,
BaseEditorDocumentParser::UpdateParams updateParams)

View File

@@ -70,6 +70,8 @@ public:
virtual void editorDocumentTimerRestarted();
virtual void setParserConfig(const BaseEditorDocumentParser::Configuration config);
public:
using HeaderErrorDiagnosticWidgetCreator = std::function<QWidget*()>;

View File

@@ -37,7 +37,7 @@ public:
struct PrioritizedProjectPart
{
PrioritizedProjectPart(const ProjectPart::Ptr &projectPart, int priority)
: projectPart(projectPart) , priority(priority) {}
: projectPart(projectPart), priority(priority) {}
ProjectPart::Ptr projectPart;
int priority = 0;
@@ -46,38 +46,42 @@ public:
ProjectPartPrioritizer(const QList<ProjectPart::Ptr> &projectParts,
const QString &preferredProjectPartId,
const ProjectExplorer::Project *activeProject,
Language languagePreference)
: m_projectParts(projectParts)
, m_preferredProjectPartId(preferredProjectPartId)
Language languagePreference,
bool areProjectPartsFromDependencies)
: m_preferredProjectPartId(preferredProjectPartId)
, m_activeProject(activeProject)
, m_languagePreference(languagePreference)
{
// Determine best project part
const QList<PrioritizedProjectPart> prioritized = prioritize();
m_projectPart = prioritized.first().projectPart;
// Prioritize
const QList<PrioritizedProjectPart> prioritized = prioritize(projectParts);
for (const PrioritizedProjectPart &ppp : prioritized)
m_info.projectParts << ppp.projectPart;
// Determine ambiguity
m_isAmbiguous = prioritized.size() > 1
? prioritized[0].priority == prioritized[1].priority
: false;
// Best project part
m_info.projectPart = m_info.projectParts.first();
// Hints
if (m_info.projectParts.size() > 1)
m_info.hints |= ProjectPartInfo::IsAmbiguousMatch;
if (prioritized.first().priority > 1000)
m_info.hints |= ProjectPartInfo::IsPreferredMatch;
if (areProjectPartsFromDependencies)
m_info.hints |= ProjectPartInfo::IsFromDependenciesMatch;
else
m_info.hints |= ProjectPartInfo::IsFromProjectMatch;
}
ProjectPart::Ptr projectPart()
ProjectPartInfo info() const
{
return m_projectPart;
}
bool isAmbiguous() const
{
return m_isAmbiguous;
return m_info;
}
private:
QList<PrioritizedProjectPart> prioritize()
QList<PrioritizedProjectPart> prioritize(const QList<ProjectPart::Ptr> &projectParts)
{
// Prioritize
QList<PrioritizedProjectPart> prioritized = Utils::transform(m_projectParts,
[&](const ProjectPart::Ptr &projectPart) {
QList<PrioritizedProjectPart> prioritized = Utils::transform(projectParts,
[&](const ProjectPart::Ptr &projectPart) {
return PrioritizedProjectPart{projectPart, priority(*projectPart)};
});
@@ -118,14 +122,12 @@ private:
}
private:
const QList<ProjectPart::Ptr> m_projectParts;
const QString m_preferredProjectPartId;
const ProjectExplorer::Project *m_activeProject = nullptr;
Language m_languagePreference = Language::Cxx;
// Results
ProjectPart::Ptr m_projectPart;
bool m_isAmbiguous = false;
ProjectPartInfo m_info;
};
ProjectPartInfo ProjectPartChooser::choose(
@@ -141,40 +143,30 @@ ProjectPartInfo ProjectPartChooser::choose(
QTC_CHECK(m_fallbackProjectPart);
ProjectPart::Ptr projectPart = currentProjectPartInfo.projectPart;
ProjectPartInfo::Hint hint = ProjectPartInfo::NoHint;
QList<ProjectPart::Ptr> projectParts = m_projectPartsForFile(filePath);
bool areProjectPartsFromDependencies = false;
if (projectParts.isEmpty()) {
if (!projectsUpdated && projectPart
&& currentProjectPartInfo.hint == ProjectPartInfo::IsFallbackMatch)
&& currentProjectPartInfo.hints & ProjectPartInfo::IsFallbackMatch)
// Avoid re-calculating the expensive dependency table for non-project files.
return {projectPart, ProjectPartInfo::IsFallbackMatch};
return ProjectPartInfo(projectPart, {projectPart}, ProjectPartInfo::IsFallbackMatch);
// Fall-back step 1: Get some parts through the dependency table:
projectParts = m_projectPartsFromDependenciesForFile(filePath);
if (projectParts.isEmpty()) {
// Fall-back step 2: Use fall-back part from the model manager:
projectPart = m_fallbackProjectPart();
hint = ProjectPartInfo::IsFallbackMatch;
} else {
ProjectPartPrioritizer prioritizer(projectParts,
preferredProjectPartId,
activeProject,
languagePreference);
projectPart = prioritizer.projectPart();
return ProjectPartInfo(projectPart, {projectPart}, ProjectPartInfo::IsFallbackMatch);
}
} else {
ProjectPartPrioritizer prioritizer(projectParts,
preferredProjectPartId,
activeProject,
languagePreference);
projectPart = prioritizer.projectPart();
hint = prioritizer.isAmbiguous()
? ProjectPartInfo::IsAmbiguousMatch
: ProjectPartInfo::NoHint;
areProjectPartsFromDependencies = true;
}
return {projectPart, hint};
return ProjectPartPrioritizer(projectParts,
preferredProjectPartId,
activeProject,
languagePreference,
areProjectPartsFromDependencies).info();
}
void ProjectPartChooser::setFallbackProjectPart(const FallBackProjectPart &getter)

View File

@@ -34,14 +34,29 @@ enum class Language { C, Cxx };
class ProjectPartInfo {
public:
enum Hint {
NoHint,
IsFallbackMatch,
IsAmbiguousMatch
NoHint = 0,
IsFallbackMatch = 1 << 0,
IsAmbiguousMatch = 1 << 1,
IsPreferredMatch = 1 << 2,
IsFromProjectMatch = 1 << 3,
IsFromDependenciesMatch = 1 << 4,
};
Q_DECLARE_FLAGS(Hints, Hint)
ProjectPartInfo() = default;
ProjectPartInfo(const ProjectPart::Ptr &projectPart,
const QList<ProjectPart::Ptr> &projectParts,
Hints hints)
: projectPart(projectPart)
, projectParts(projectParts)
, hints(hints)
{
}
public:
ProjectPart::Ptr projectPart;
Hint hint;
QList<ProjectPart::Ptr> projectParts; // The one above as first plus alternatives.
Hints hints = NoHint;
};
} // namespace CppTools