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