1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "cppcurrentdocumentfilter.h"
27
28 #include "cppmodelmanager.h"
29 #include "cpptoolsconstants.h"
30
31 #include <coreplugin/editormanager/editormanager.h>
32 #include <coreplugin/editormanager/ieditor.h>
33 #include <coreplugin/idocument.h>
34
35 #include <QRegularExpression>
36
37 using namespace CppTools::Internal;
38 using namespace CPlusPlus;
39
CppCurrentDocumentFilter(CppTools::CppModelManager * manager)40 CppCurrentDocumentFilter::CppCurrentDocumentFilter(CppTools::CppModelManager *manager)
41 : m_modelManager(manager)
42 {
43 setId(Constants::CURRENT_DOCUMENT_FILTER_ID);
44 setDisplayName(Constants::CURRENT_DOCUMENT_FILTER_DISPLAY_NAME);
45 setDefaultShortcutString(".");
46 setPriority(High);
47 setDefaultIncludedByDefault(false);
48
49 search.setSymbolsToSearchFor(SymbolSearcher::Declarations |
50 SymbolSearcher::Enums |
51 SymbolSearcher::Functions |
52 SymbolSearcher::Classes);
53
54 connect(manager, &CppModelManager::documentUpdated,
55 this, &CppCurrentDocumentFilter::onDocumentUpdated);
56 connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
57 this, &CppCurrentDocumentFilter::onCurrentEditorChanged);
58 connect(Core::EditorManager::instance(), &Core::EditorManager::editorAboutToClose,
59 this, &CppCurrentDocumentFilter::onEditorAboutToClose);
60 }
61
matchesFor(QFutureInterface<Core::LocatorFilterEntry> & future,const QString & entry)62 QList<Core::LocatorFilterEntry> CppCurrentDocumentFilter::matchesFor(
63 QFutureInterface<Core::LocatorFilterEntry> &future, const QString & entry)
64 {
65 QList<Core::LocatorFilterEntry> goodEntries;
66 QList<Core::LocatorFilterEntry> betterEntries;
67
68 const QRegularExpression regexp = createRegExp(entry);
69 if (!regexp.isValid())
70 return goodEntries;
71
72 const QList<IndexItem::Ptr> items = itemsOfCurrentDocument();
73 for (const IndexItem::Ptr &info : items) {
74 if (future.isCanceled())
75 break;
76
77 QString matchString = info->symbolName();
78 if (info->type() == IndexItem::Declaration)
79 matchString = info->representDeclaration();
80 else if (info->type() == IndexItem::Function)
81 matchString += info->symbolType();
82
83 QRegularExpressionMatch match = regexp.match(matchString);
84 if (match.hasMatch()) {
85 const bool betterMatch = match.capturedStart() == 0;
86 QVariant id = QVariant::fromValue(info);
87 QString name = matchString;
88 QString extraInfo = info->symbolScope();
89 if (info->type() == IndexItem::Function) {
90 if (info->unqualifiedNameAndScope(matchString, &name, &extraInfo)) {
91 name += info->symbolType();
92 match = regexp.match(name);
93 }
94 }
95
96 Core::LocatorFilterEntry filterEntry(this, name, id, info->icon());
97 filterEntry.extraInfo = extraInfo;
98 if (match.hasMatch()) {
99 filterEntry.highlightInfo = highlightInfo(match);
100 } else {
101 match = regexp.match(extraInfo);
102 filterEntry.highlightInfo =
103 highlightInfo(match, Core::LocatorFilterEntry::HighlightInfo::ExtraInfo);
104 }
105
106 if (betterMatch)
107 betterEntries.append(filterEntry);
108 else
109 goodEntries.append(filterEntry);
110 }
111 }
112
113 // entries are unsorted by design!
114
115 betterEntries += goodEntries;
116 return betterEntries;
117 }
118
accept(Core::LocatorFilterEntry selection,QString * newText,int * selectionStart,int * selectionLength) const119 void CppCurrentDocumentFilter::accept(Core::LocatorFilterEntry selection,
120 QString *newText, int *selectionStart,
121 int *selectionLength) const
122 {
123 Q_UNUSED(newText)
124 Q_UNUSED(selectionStart)
125 Q_UNUSED(selectionLength)
126 IndexItem::Ptr info = qvariant_cast<CppTools::IndexItem::Ptr>(selection.internalData);
127 Core::EditorManager::openEditorAt(info->fileName(), info->line(), info->column());
128 }
129
onDocumentUpdated(Document::Ptr doc)130 void CppCurrentDocumentFilter::onDocumentUpdated(Document::Ptr doc)
131 {
132 QMutexLocker locker(&m_mutex);
133 if (m_currentFileName == doc->fileName())
134 m_itemsOfCurrentDoc.clear();
135 }
136
onCurrentEditorChanged(Core::IEditor * currentEditor)137 void CppCurrentDocumentFilter::onCurrentEditorChanged(Core::IEditor *currentEditor)
138 {
139 QMutexLocker locker(&m_mutex);
140 if (currentEditor)
141 m_currentFileName = currentEditor->document()->filePath().toString();
142 else
143 m_currentFileName.clear();
144 m_itemsOfCurrentDoc.clear();
145 }
146
onEditorAboutToClose(Core::IEditor * editorAboutToClose)147 void CppCurrentDocumentFilter::onEditorAboutToClose(Core::IEditor *editorAboutToClose)
148 {
149 if (!editorAboutToClose)
150 return;
151
152 QMutexLocker locker(&m_mutex);
153 if (m_currentFileName == editorAboutToClose->document()->filePath().toString()) {
154 m_currentFileName.clear();
155 m_itemsOfCurrentDoc.clear();
156 }
157 }
158
itemsOfCurrentDocument()159 QList<CppTools::IndexItem::Ptr> CppCurrentDocumentFilter::itemsOfCurrentDocument()
160 {
161 QMutexLocker locker(&m_mutex);
162
163 if (m_currentFileName.isEmpty())
164 return QList<CppTools::IndexItem::Ptr>();
165
166 if (m_itemsOfCurrentDoc.isEmpty()) {
167 const Snapshot snapshot = m_modelManager->snapshot();
168 if (const Document::Ptr thisDocument = snapshot.document(m_currentFileName)) {
169 IndexItem::Ptr rootNode = search(thisDocument);
170 rootNode->visitAllChildren([&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult {
171 m_itemsOfCurrentDoc.append(info);
172 return IndexItem::Recurse;
173 });
174 }
175 }
176
177 return m_itemsOfCurrentDoc;
178 }
179