OLD | NEW |
1 /** | 1 /** |
2 * A library for searching and filtering documentation. | 2 * A library for searching and filtering documentation. |
3 * | 3 * |
4 * Given a search query, a set of ranked results is created to determine the | 4 * Given a search query, a set of ranked results is created to determine the |
5 * best member to match that query. Priority is given in the following order: | 5 * best member to match that query. Priority is given in the following order: |
6 * library, class, typedef, and class member or top-level library member. | 6 * library, class, typedef, and class member or top-level library member. |
7 * Results with matches in the last section of their qualified names are | 7 * Results with matches in the last section of their qualified names are |
8 * given a higher rank than those with matches in inner members of the | 8 * given a higher rank than those with matches in inner members of the |
9 * qualified name. | 9 * qualified name. |
10 */ | 10 */ |
11 library search; | 11 library search; |
12 | 12 |
| 13 import 'dart:async'; |
| 14 import 'package:web_ui/web_ui.dart'; |
| 15 |
13 /** Search Index */ | 16 /** Search Index */ |
14 Map<String, String> index = {}; | 17 Map<String, String> index = {}; |
15 | 18 |
| 19 /** Search query. */ |
| 20 @observable String searchQuery = ""; |
| 21 |
16 class SearchResult implements Comparable { | 22 class SearchResult implements Comparable { |
17 | 23 |
18 /** Qualified name of this search result references. */ | 24 /** Qualified name of this search result references. */ |
19 String element; | 25 String element; |
20 | 26 |
21 /** This element's member type. */ | 27 /** This element's member type. */ |
22 String type; | 28 String type; |
23 | 29 |
24 /** Score of the search result match. Higher is better. */ | 30 /** Score of the search result match. Higher is better. */ |
25 int score; | 31 int score; |
(...skipping 22 matching lines...) Expand all Loading... |
48 'constructor' : 4 | 54 'constructor' : 4 |
49 }; | 55 }; |
50 | 56 |
51 /** | 57 /** |
52 * Returns a list of up to [maxResults] number of [SearchResult]s based off the | 58 * Returns a list of up to [maxResults] number of [SearchResult]s based off the |
53 * searchQuery. | 59 * searchQuery. |
54 * | 60 * |
55 * A score is given to each potential search result based off how likely it is | 61 * A score is given to each potential search result based off how likely it is |
56 * the appropriate qualified name to return for the search query. | 62 * the appropriate qualified name to return for the search query. |
57 */ | 63 */ |
58 List<SearchResult> lookupSearchResults(String searchQuery, int maxResults) { | 64 List<SearchResult> lookupSearchResults(String query, int maxResults) { |
59 | 65 |
| 66 var stopwatch = new Stopwatch()..start(); |
| 67 |
60 var scoredResults = <SearchResult>[]; | 68 var scoredResults = <SearchResult>[]; |
61 var resultSet = new Set<String>(); | 69 var resultSet = new Set<String>(); |
62 var queryList = searchQuery.trim().toLowerCase().split(' '); | 70 var queryList = query.trim().toLowerCase().split(' '); |
63 queryList.forEach((q) => resultSet.addAll(index.keys.where((e) => | 71 queryList.forEach((q) => resultSet.addAll(index.keys.where((e) => |
64 e.toLowerCase().contains(q)))); | 72 e.toLowerCase().contains(q)))); |
65 | 73 |
66 for (var r in resultSet) { | 74 for (var r in resultSet) { |
| 75 /// If it is taking too long to compute the search results, time out and |
| 76 /// return an empty list of results. |
| 77 if (stopwatch.elapsedMilliseconds > 500) { |
| 78 return []; |
| 79 } |
67 int score = 0; | 80 int score = 0; |
68 var lowerCaseResult = r.toLowerCase(); | 81 var lowerCaseResult = r.toLowerCase(); |
69 var type = index[r]; | 82 var type = index[r]; |
70 | 83 |
71 var splitDotQueries = []; | 84 var splitDotQueries = []; |
72 // If the search was for a named constructor (Map.fromIterable), give it a | 85 // If the search was for a named constructor (Map.fromIterable), give it a |
73 // score boost of 200. | 86 // score boost of 200. |
74 queryList.forEach((q) { | 87 queryList.forEach((q) { |
75 if (q.contains('.') && lowerCaseResult.endsWith(q)) { | 88 if (q.contains('.') && lowerCaseResult.endsWith(q)) { |
76 score += 100; | 89 score += 100; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 } | 129 } |
117 | 130 |
118 // If the result item is part of the dart library, give it a small boost. | 131 // If the result item is part of the dart library, give it a small boost. |
119 if (qualifiedNameParts.first == 'dart') { | 132 if (qualifiedNameParts.first == 'dart') { |
120 score += 50; | 133 score += 50; |
121 } | 134 } |
122 }); | 135 }); |
123 scoredResults.add(new SearchResult(r, type, score)); | 136 scoredResults.add(new SearchResult(r, type, score)); |
124 } | 137 } |
125 | 138 |
| 139 /// If it is taking too long to compute the search results, time out and |
| 140 /// return an empty list of results. |
| 141 if (stopwatch.elapsedMilliseconds > 500) { |
| 142 return []; |
| 143 } |
126 scoredResults.sort(); | 144 scoredResults.sort(); |
127 updatePositions(scoredResults); | 145 updatePositions(scoredResults); |
128 if (scoredResults.length > maxResults) { | 146 if (scoredResults.length > maxResults) { |
129 return scoredResults.take(maxResults).toList(); | 147 return scoredResults.take(maxResults).toList(); |
130 } else { | 148 } else { |
131 return scoredResults; | 149 return scoredResults; |
132 } | 150 } |
133 } | 151 } |
134 | 152 |
135 void updatePositions(List<SearchResult> list) { | 153 void updatePositions(List<SearchResult> list) { |
136 for(int i = 0; i < list.length; i++) { | 154 for(int i = 0; i < list.length; i++) { |
137 list[i].position = i; | 155 list[i].position = i; |
138 } | 156 } |
139 } | 157 } |
OLD | NEW |