| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | |
| 5 /** | 4 /** |
| 6 * @constructor | |
| 7 * @implements {WebInspector.ProjectSearchConfig} | 5 * @implements {WebInspector.ProjectSearchConfig} |
| 8 * @param {string} query | 6 * @unrestricted |
| 9 * @param {boolean} ignoreCase | |
| 10 * @param {boolean} isRegex | |
| 11 */ | 7 */ |
| 12 WebInspector.SearchConfig = function(query, ignoreCase, isRegex) | 8 WebInspector.SearchConfig = class { |
| 13 { | 9 /** |
| 10 * @param {string} query |
| 11 * @param {boolean} ignoreCase |
| 12 * @param {boolean} isRegex |
| 13 */ |
| 14 constructor(query, ignoreCase, isRegex) { |
| 14 this._query = query; | 15 this._query = query; |
| 15 this._ignoreCase = ignoreCase; | 16 this._ignoreCase = ignoreCase; |
| 16 this._isRegex = isRegex; | 17 this._isRegex = isRegex; |
| 17 this._parse(); | 18 this._parse(); |
| 19 } |
| 20 |
| 21 /** |
| 22 * @param {{query: string, ignoreCase: boolean, isRegex: boolean}} object |
| 23 * @return {!WebInspector.SearchConfig} |
| 24 */ |
| 25 static fromPlainObject(object) { |
| 26 return new WebInspector.SearchConfig(object.query, object.ignoreCase, object
.isRegex); |
| 27 } |
| 28 |
| 29 /** |
| 30 * @override |
| 31 * @return {string} |
| 32 */ |
| 33 query() { |
| 34 return this._query; |
| 35 } |
| 36 |
| 37 /** |
| 38 * @override |
| 39 * @return {boolean} |
| 40 */ |
| 41 ignoreCase() { |
| 42 return this._ignoreCase; |
| 43 } |
| 44 |
| 45 /** |
| 46 * @override |
| 47 * @return {boolean} |
| 48 */ |
| 49 isRegex() { |
| 50 return this._isRegex; |
| 51 } |
| 52 |
| 53 /** |
| 54 * @return {{query: string, ignoreCase: boolean, isRegex: boolean}} |
| 55 */ |
| 56 toPlainObject() { |
| 57 return {query: this.query(), ignoreCase: this.ignoreCase(), isRegex: this.is
Regex()}; |
| 58 } |
| 59 |
| 60 _parse() { |
| 61 var filePattern = |
| 62 '-?f(ile)?:(([^\\\\ ]|\\\\.)+)'; // After file: prefix: any symbol exce
pt space and backslash or any symbol escaped with a backslash. |
| 63 var quotedPattern = |
| 64 '"(([^\\\\"]|\\\\.)+)"'; // Inside double quotes: any symbol except dou
ble quote and backslash or any symbol escaped with a backslash. |
| 65 |
| 66 // A word is a sequence of any symbols except space and backslash or any sym
bols escaped with a backslash, that does not start with file:. |
| 67 var unquotedWordPattern = '(\\s*(?!-?f(ile)?:)[^\\\\ ]|\\\\.)+'; |
| 68 var unquotedPattern = |
| 69 unquotedWordPattern + '( +' + unquotedWordPattern + ')*'; // A word or
several words separated by space(s). |
| 70 |
| 71 var pattern = '(' + filePattern + ')|(' + quotedPattern + ')|(' + unquotedPa
ttern + ')'; |
| 72 var regexp = new RegExp(pattern, 'g'); |
| 73 var queryParts = this._query.match(regexp) || []; |
| 74 |
| 75 /** |
| 76 * @type {!Array.<!WebInspector.SearchConfig.QueryTerm>} |
| 77 */ |
| 78 this._fileQueries = []; |
| 79 |
| 80 /** |
| 81 * @type {!Array.<string>} |
| 82 */ |
| 83 this._queries = []; |
| 84 |
| 85 for (var i = 0; i < queryParts.length; ++i) { |
| 86 var queryPart = queryParts[i]; |
| 87 if (!queryPart) |
| 88 continue; |
| 89 var fileQuery = this._parseFileQuery(queryPart); |
| 90 if (fileQuery) { |
| 91 this._fileQueries.push(fileQuery); |
| 92 /** @type {!Array.<!WebInspector.SearchConfig.RegexQuery>} */ |
| 93 this._fileRegexQueries = this._fileRegexQueries || []; |
| 94 this._fileRegexQueries.push( |
| 95 {regex: new RegExp(fileQuery.text, this.ignoreCase ? 'i' : ''), isNe
gative: fileQuery.isNegative}); |
| 96 continue; |
| 97 } |
| 98 if (this._isRegex) { |
| 99 this._queries.push(queryPart); |
| 100 continue; |
| 101 } |
| 102 if (queryPart.startsWith('"')) { |
| 103 if (!queryPart.endsWith('"')) |
| 104 continue; |
| 105 this._queries.push(this._parseQuotedQuery(queryPart)); |
| 106 continue; |
| 107 } |
| 108 this._queries.push(this._parseUnquotedQuery(queryPart)); |
| 109 } |
| 110 } |
| 111 |
| 112 /** |
| 113 * @override |
| 114 * @param {string} filePath |
| 115 * @return {boolean} |
| 116 */ |
| 117 filePathMatchesFileQuery(filePath) { |
| 118 if (!this._fileRegexQueries) |
| 119 return true; |
| 120 for (var i = 0; i < this._fileRegexQueries.length; ++i) { |
| 121 if (!!filePath.match(this._fileRegexQueries[i].regex) === this._fileRegexQ
ueries[i].isNegative) |
| 122 return false; |
| 123 } |
| 124 return true; |
| 125 } |
| 126 |
| 127 /** |
| 128 * @override |
| 129 * @return {!Array.<string>} |
| 130 */ |
| 131 queries() { |
| 132 return this._queries; |
| 133 } |
| 134 |
| 135 _parseUnquotedQuery(query) { |
| 136 return query.replace(/\\(.)/g, '$1'); |
| 137 } |
| 138 |
| 139 _parseQuotedQuery(query) { |
| 140 return query.substring(1, query.length - 1).replace(/\\(.)/g, '$1'); |
| 141 } |
| 142 |
| 143 /** |
| 144 * @param {string} query |
| 145 * @return {?WebInspector.SearchConfig.QueryTerm} |
| 146 */ |
| 147 _parseFileQuery(query) { |
| 148 var match = query.match(/^(-)?f(ile)?:/); |
| 149 if (!match) |
| 150 return null; |
| 151 var isNegative = !!match[1]; |
| 152 query = query.substr(match[0].length); |
| 153 var result = ''; |
| 154 for (var i = 0; i < query.length; ++i) { |
| 155 var char = query[i]; |
| 156 if (char === '*') { |
| 157 result += '.*'; |
| 158 } else if (char === '\\') { |
| 159 ++i; |
| 160 var nextChar = query[i]; |
| 161 if (nextChar === ' ') |
| 162 result += ' '; |
| 163 } else { |
| 164 if (String.regexSpecialCharacters().indexOf(query.charAt(i)) !== -1) |
| 165 result += '\\'; |
| 166 result += query.charAt(i); |
| 167 } |
| 168 } |
| 169 return new WebInspector.SearchConfig.QueryTerm(result, isNegative); |
| 170 } |
| 18 }; | 171 }; |
| 19 | 172 |
| 20 /** @typedef {!{regex: !RegExp, isNegative: boolean}} */ | 173 /** @typedef {!{regex: !RegExp, isNegative: boolean}} */ |
| 21 WebInspector.SearchConfig.RegexQuery; | 174 WebInspector.SearchConfig.RegexQuery; |
| 22 | 175 |
| 23 /** | |
| 24 * @param {{query: string, ignoreCase: boolean, isRegex: boolean}} object | |
| 25 * @return {!WebInspector.SearchConfig} | |
| 26 */ | |
| 27 WebInspector.SearchConfig.fromPlainObject = function(object) | |
| 28 { | |
| 29 return new WebInspector.SearchConfig(object.query, object.ignoreCase, object
.isRegex); | |
| 30 }; | |
| 31 | |
| 32 WebInspector.SearchConfig.prototype = { | |
| 33 /** | |
| 34 * @override | |
| 35 * @return {string} | |
| 36 */ | |
| 37 query: function() | |
| 38 { | |
| 39 return this._query; | |
| 40 }, | |
| 41 | |
| 42 /** | |
| 43 * @override | |
| 44 * @return {boolean} | |
| 45 */ | |
| 46 ignoreCase: function() | |
| 47 { | |
| 48 return this._ignoreCase; | |
| 49 }, | |
| 50 | |
| 51 /** | |
| 52 * @override | |
| 53 * @return {boolean} | |
| 54 */ | |
| 55 isRegex: function() | |
| 56 { | |
| 57 return this._isRegex; | |
| 58 }, | |
| 59 | |
| 60 /** | |
| 61 * @return {{query: string, ignoreCase: boolean, isRegex: boolean}} | |
| 62 */ | |
| 63 toPlainObject: function() | |
| 64 { | |
| 65 return { query: this.query(), ignoreCase: this.ignoreCase(), isRegex: th
is.isRegex() }; | |
| 66 }, | |
| 67 | |
| 68 _parse: function() | |
| 69 { | |
| 70 var filePattern = "-?f(ile)?:(([^\\\\ ]|\\\\.)+)"; // After file: prefix
: any symbol except space and backslash or any symbol escaped with a backslash. | |
| 71 var quotedPattern = "\"(([^\\\\\"]|\\\\.)+)\""; // Inside double quotes:
any symbol except double quote and backslash or any symbol escaped with a backs
lash. | |
| 72 | |
| 73 // A word is a sequence of any symbols except space and backslash or any
symbols escaped with a backslash, that does not start with file:. | |
| 74 var unquotedWordPattern = "(\\s*(?!-?f(ile)?:)[^\\\\ ]|\\\\.)+"; | |
| 75 var unquotedPattern = unquotedWordPattern + "( +" + unquotedWordPattern
+ ")*"; // A word or several words separated by space(s). | |
| 76 | |
| 77 var pattern = "(" + filePattern + ")|(" + quotedPattern + ")|(" + unquot
edPattern + ")"; | |
| 78 var regexp = new RegExp(pattern, "g"); | |
| 79 var queryParts = this._query.match(regexp) || []; | |
| 80 | |
| 81 /** | |
| 82 * @type {!Array.<!WebInspector.SearchConfig.QueryTerm>} | |
| 83 */ | |
| 84 this._fileQueries = []; | |
| 85 | |
| 86 /** | |
| 87 * @type {!Array.<string>} | |
| 88 */ | |
| 89 this._queries = []; | |
| 90 | |
| 91 for (var i = 0; i < queryParts.length; ++i) { | |
| 92 var queryPart = queryParts[i]; | |
| 93 if (!queryPart) | |
| 94 continue; | |
| 95 var fileQuery = this._parseFileQuery(queryPart); | |
| 96 if (fileQuery) { | |
| 97 this._fileQueries.push(fileQuery); | |
| 98 /** @type {!Array.<!WebInspector.SearchConfig.RegexQuery>} */ | |
| 99 this._fileRegexQueries = this._fileRegexQueries || []; | |
| 100 this._fileRegexQueries.push({ regex: new RegExp(fileQuery.text,
this.ignoreCase ? "i" : ""), isNegative: fileQuery.isNegative }); | |
| 101 continue; | |
| 102 } | |
| 103 if (this._isRegex) { | |
| 104 this._queries.push(queryPart); | |
| 105 continue; | |
| 106 } | |
| 107 if (queryPart.startsWith("\"")) { | |
| 108 if (!queryPart.endsWith("\"")) | |
| 109 continue; | |
| 110 this._queries.push(this._parseQuotedQuery(queryPart)); | |
| 111 continue; | |
| 112 } | |
| 113 this._queries.push(this._parseUnquotedQuery(queryPart)); | |
| 114 } | |
| 115 }, | |
| 116 | |
| 117 /** | |
| 118 * @override | |
| 119 * @param {string} filePath | |
| 120 * @return {boolean} | |
| 121 */ | |
| 122 filePathMatchesFileQuery: function(filePath) | |
| 123 { | |
| 124 if (!this._fileRegexQueries) | |
| 125 return true; | |
| 126 for (var i = 0; i < this._fileRegexQueries.length; ++i) { | |
| 127 if (!!filePath.match(this._fileRegexQueries[i].regex) === this._file
RegexQueries[i].isNegative) | |
| 128 return false; | |
| 129 } | |
| 130 return true; | |
| 131 }, | |
| 132 | |
| 133 /** | |
| 134 * @override | |
| 135 * @return {!Array.<string>} | |
| 136 */ | |
| 137 queries: function() | |
| 138 { | |
| 139 return this._queries; | |
| 140 }, | |
| 141 | |
| 142 _parseUnquotedQuery: function(query) | |
| 143 { | |
| 144 return query.replace(/\\(.)/g, "$1"); | |
| 145 }, | |
| 146 | |
| 147 _parseQuotedQuery: function(query) | |
| 148 { | |
| 149 return query.substring(1, query.length - 1).replace(/\\(.)/g, "$1"); | |
| 150 }, | |
| 151 | |
| 152 /** | |
| 153 * @param {string} query | |
| 154 * @return {?WebInspector.SearchConfig.QueryTerm} | |
| 155 */ | |
| 156 _parseFileQuery: function(query) | |
| 157 { | |
| 158 var match = query.match(/^(-)?f(ile)?:/); | |
| 159 if (!match) | |
| 160 return null; | |
| 161 var isNegative = !!match[1]; | |
| 162 query = query.substr(match[0].length); | |
| 163 var result = ""; | |
| 164 for (var i = 0; i < query.length; ++i) { | |
| 165 var char = query[i]; | |
| 166 if (char === "*") { | |
| 167 result += ".*"; | |
| 168 } else if (char === "\\") { | |
| 169 ++i; | |
| 170 var nextChar = query[i]; | |
| 171 if (nextChar === " ") | |
| 172 result += " "; | |
| 173 } else { | |
| 174 if (String.regexSpecialCharacters().indexOf(query.charAt(i)) !==
-1) | |
| 175 result += "\\"; | |
| 176 result += query.charAt(i); | |
| 177 } | |
| 178 } | |
| 179 return new WebInspector.SearchConfig.QueryTerm(result, isNegative); | |
| 180 } | |
| 181 }; | |
| 182 | 176 |
| 183 /** | 177 /** |
| 184 * @constructor | 178 * @unrestricted |
| 185 * @param {string} text | |
| 186 * @param {boolean} isNegative | |
| 187 */ | 179 */ |
| 188 WebInspector.SearchConfig.QueryTerm = function(text, isNegative) | 180 WebInspector.SearchConfig.QueryTerm = class { |
| 189 { | 181 /** |
| 182 * @param {string} text |
| 183 * @param {boolean} isNegative |
| 184 */ |
| 185 constructor(text, isNegative) { |
| 190 this.text = text; | 186 this.text = text; |
| 191 this.isNegative = isNegative; | 187 this.isNegative = isNegative; |
| 188 } |
| 192 }; | 189 }; |
| OLD | NEW |