2
// ProjectSearchCategory.cs
5
// Mike KrĆ¼ger <mkrueger@xamarin.com>
7
// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com)
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
using System.Threading;
28
using System.Threading.Tasks;
29
using MonoDevelop.Core;
30
using System.Collections.Generic;
31
using MonoDevelop.Core.Instrumentation;
32
using MonoDevelop.Projects;
33
using MonoDevelop.Ide.Gui;
34
using MonoDevelop.Ide;
35
using ICSharpCode.NRefactory.TypeSystem;
36
using MonoDevelop.Ide.TypeSystem;
37
using MonoDevelop.Core.Text;
41
namespace MonoDevelop.Components.MainToolbar
43
class ProjectSearchCategory : SearchCategory
45
SearchPopupWindow widget;
47
public ProjectSearchCategory (SearchPopupWindow widget) : base (GettextCatalog.GetString("Solution"))
50
this.lastResult = new WorkerResult (widget);
53
static TimerCounter getMembersTimer = InstrumentationService.CreateTimerCounter ("Time to get all members", "NavigateToDialog");
56
static TimerCounter getTypesTimer = InstrumentationService.CreateTimerCounter ("Time to get all types", "NavigateToDialog");
58
IEnumerable<ITypeDefinition> types {
60
getTypesTimer.BeginTiming ();
62
foreach (Document doc in IdeApp.Workbench.Documents) {
63
// We only want to check it here if it's not part
64
// of the open combine. Otherwise, it will get
65
// checked down below.
66
if (doc.Project == null && doc.IsFile) {
67
var info = doc.ParsedDocument;
69
var ctx = doc.Compilation;
70
foreach (var type in ctx.MainAssembly.GetAllTypeDefinitions ()) {
77
var projects = IdeApp.Workspace.GetAllProjects ();
79
foreach (Project p in projects) {
80
var pctx = TypeSystemService.GetCompilation (p);
81
foreach (var type in pctx.MainAssembly.GetAllTypeDefinitions ())
85
getTypesTimer.EndTiming ();
90
WorkerResult lastResult;
91
string[] typeTags = new [] { "type", "c", "s", "i", "e", "d"};
92
string[] memberTags = new [] { "member", "m", "p", "f", "evt"};
94
public override bool IsValidTag (string tag)
96
return typeTags.Any (t => t == tag) || memberTags.Any (t => t == tag);
99
public override Task<ISearchDataSource> GetResults (SearchPopupSearchPattern searchPattern, int resultsCount, CancellationToken token)
101
return Task.Factory.StartNew (delegate {
102
if (searchPattern.Tag != null && !(typeTags.Contains (searchPattern.Tag) || memberTags.Contains (searchPattern.Tag)) || searchPattern.HasLineNumber)
105
var newResult = new WorkerResult (widget);
106
newResult.pattern = searchPattern.Pattern;
107
newResult.IncludeFiles = true;
108
newResult.Tag = searchPattern.Tag;
109
newResult.IncludeTypes = searchPattern.Tag == null || typeTags.Contains (searchPattern.Tag) ;
110
newResult.IncludeMembers = searchPattern.Tag == null || memberTags.Contains (searchPattern.Tag);
111
var firstType = types.FirstOrDefault ();
112
newResult.ambience = firstType != null ? AmbienceService.GetAmbienceForFile (firstType.Region.FileName) : AmbienceService.DefaultAmbience;
114
string toMatch = searchPattern.Pattern;
115
newResult.matcher = StringMatcher.GetMatcher (toMatch, false);
116
newResult.FullSearch = toMatch.IndexOf ('.') > 0;
117
var oldLastResult = lastResult;
118
if (newResult.FullSearch && oldLastResult != null && !oldLastResult.FullSearch)
119
oldLastResult = new WorkerResult (widget);
120
// var now = DateTime.Now;
122
AllResults (oldLastResult, newResult, token);
123
newResult.results.SortUpToN (new DataItemComparer (token), resultsCount);
124
lastResult = newResult;
125
// Console.WriteLine ((now - DateTime.Now).TotalMilliseconds);
126
return (ISearchDataSource)newResult.results;
128
token.ThrowIfCancellationRequested ();
134
void AllResults (WorkerResult lastResult, WorkerResult newResult, CancellationToken token)
136
if (newResult.isGotoFilePattern)
140
if (newResult.IncludeTypes && (newResult.Tag == null || typeTags.Any (t => t == newResult.Tag))) {
141
newResult.filteredTypes = new List<ITypeDefinition> ();
142
bool startsWithLastFilter = lastResult.pattern != null && newResult.pattern.StartsWith (lastResult.pattern, StringComparison.Ordinal) && lastResult.filteredTypes != null;
143
var allTypes = startsWithLastFilter ? lastResult.filteredTypes : types;
144
foreach (var type in allTypes) {
145
if (unchecked(x++) % 100 == 0 && token.IsCancellationRequested)
148
if (newResult.Tag != null) {
149
if (newResult.Tag == "c" && type.Kind != TypeKind.Class)
151
if (newResult.Tag == "s" && type.Kind != TypeKind.Struct)
153
if (newResult.Tag == "i" && type.Kind != TypeKind.Interface)
155
if (newResult.Tag == "e" && type.Kind != TypeKind.Enum)
157
if (newResult.Tag == "d" && type.Kind != TypeKind.Delegate)
160
SearchResult curResult = newResult.CheckType (type);
161
if (curResult != null) {
162
newResult.filteredTypes.Add (type);
163
newResult.results.AddResult (curResult);
169
if (newResult.IncludeMembers && (newResult.Tag == null || memberTags.Any (t => t == newResult.Tag))) {
170
newResult.filteredMembers = new List<Tuple<ITypeDefinition, IUnresolvedMember>> ();
171
bool startsWithLastFilter = lastResult.pattern != null && newResult.pattern.StartsWith (lastResult.pattern, StringComparison.Ordinal) && lastResult.filteredMembers != null;
172
if (startsWithLastFilter) {
173
foreach (var t in lastResult.filteredMembers) {
174
if (unchecked(x++) % 100 == 0 && token.IsCancellationRequested)
176
var member = t.Item2;
177
if (newResult.Tag != null) {
178
if (newResult.Tag == "m" && member.EntityType != EntityType.Method)
180
if (newResult.Tag == "p" && member.EntityType != EntityType.Property)
182
if (newResult.Tag == "f" && member.EntityType != EntityType.Field)
184
if (newResult.Tag == "evt" && member.EntityType != EntityType.Event)
187
SearchResult curResult = newResult.CheckMember (t.Item1, member);
188
if (curResult != null) {
189
newResult.filteredMembers.Add (t);
190
newResult.results.AddResult (curResult);
194
Func<IUnresolvedMember, bool> mPred = member => {
195
if (newResult.Tag != null) {
196
if (newResult.Tag == "m" && member.EntityType != EntityType.Method)
198
if (newResult.Tag == "p" && member.EntityType != EntityType.Property)
200
if (newResult.Tag == "f" && member.EntityType != EntityType.Field)
202
if (newResult.Tag == "evt" && member.EntityType != EntityType.Event)
205
return newResult.IsMatchingMember (member);
208
getMembersTimer.BeginTiming ();
210
foreach (var type in types) {
211
if (type.Kind == TypeKind.Delegate)
213
foreach (var p in type.Parts) {
214
foreach (var member in p.Members.Where (mPred)) {
215
if (unchecked(x++) % 100 == 0 && token.IsCancellationRequested)
217
SearchResult curResult = newResult.CheckMember (type, member);
218
if (curResult != null) {
219
newResult.filteredMembers.Add (Tuple.Create (type, member));
220
newResult.results.AddResult (curResult);
226
getMembersTimer.EndTiming ();
239
public List<ProjectFile> filteredFiles;
240
public List<ITypeDefinition> filteredTypes;
241
public List<Tuple<ITypeDefinition, IUnresolvedMember>> filteredMembers;
245
public string pattern {
251
if (pattern2.Length == 1) {
252
firstChar = pattern2[0];
253
firstChars = new [] { char.ToUpper (firstChar), char.ToLower (firstChar) };
259
public bool isGotoFilePattern;
260
public ResultsDataSource results;
261
public bool FullSearch;
262
public bool IncludeFiles, IncludeTypes, IncludeMembers;
263
public Ambience ambience;
264
public StringMatcher matcher;
266
public WorkerResult (Widget widget)
268
results = new ResultsDataSource (widget);
271
internal SearchResult CheckFile (ProjectFile file)
274
string matchString = System.IO.Path.GetFileName (file.FilePath);
275
if (MatchName (matchString, out rank))
276
return new FileSearchResult (pattern, matchString, rank, file, true);
280
matchString = FileSearchResult.GetRelProjectPath (file);
281
if (MatchName (matchString, out rank))
282
return new FileSearchResult (pattern, matchString, rank, file, false);
287
internal SearchResult CheckType (ITypeDefinition type)
290
if (MatchName (TypeSearchResult.GetPlainText (type, false), out rank))
291
return new TypeSearchResult (pattern, TypeSearchResult.GetPlainText (type, false), rank, type, false) { Ambience = ambience };
294
if (MatchName (TypeSearchResult.GetPlainText (type, true), out rank))
295
return new TypeSearchResult (pattern, TypeSearchResult.GetPlainText (type, true), rank, type, true) { Ambience = ambience };
299
internal SearchResult CheckMember (ITypeDefinition declaringType, IUnresolvedMember member)
302
bool useDeclaringTypeName = member is IUnresolvedMethod && (((IUnresolvedMethod)member).IsConstructor || ((IUnresolvedMethod)member).IsDestructor);
303
string memberName = useDeclaringTypeName ? member.DeclaringTypeDefinition.Name : member.Name;
304
if (MatchName (memberName, out rank))
305
return new MemberSearchResult (pattern, memberName, rank, declaringType, member, false) { Ambience = ambience };
309
internal bool IsMatchingMember (IUnresolvedMember member)
312
bool useDeclaringTypeName = member is IUnresolvedMethod && (((IUnresolvedMethod)member).IsConstructor || ((IUnresolvedMethod)member).IsDestructor);
313
string memberName = useDeclaringTypeName ? member.DeclaringTypeDefinition.Name : member.Name;
314
return MatchName (memberName, out rank);
317
Dictionary<string, MatchResult> savedMatches = new Dictionary<string, MatchResult> (StringComparer.Ordinal);
319
bool MatchName (string name, out int matchRank)
327
if (firstChars != null) {
328
int idx = name.IndexOfAny (firstChars);
329
doesMatch = idx >= 0;
331
matchRank = int.MaxValue - (name.Length - 1) * 10 - idx;
332
if (name[idx] != firstChar)
340
MatchResult savedMatch;
341
if (!savedMatches.TryGetValue (name, out savedMatch)) {
342
doesMatch = matcher.CalcMatchRank (name, out matchRank);
343
savedMatches [name] = savedMatch = new MatchResult (doesMatch, matchRank);
346
matchRank = savedMatch.Rank;
347
return savedMatch.Match;