2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * @param {string} query
35 WebInspector.FilePathScoreFunction = function(query)
38 this._queryUpperCase = query.toUpperCase();
40 this._sequence = null;
41 this._dataUpperCase = "";
42 this._fileNameIndex = 0;
46 * @param {string} query
49 WebInspector.FilePathScoreFunction.filterRegex = function(query)
51 const toEscape = String.regexSpecialCharacters();
53 for (var i = 0; i < query.length; ++i) {
54 var c = query.charAt(i);
55 if (toEscape.indexOf(c) !== -1)
58 regexString += "[^" + c + "]*";
61 return new RegExp(regexString, "i");
64 WebInspector.FilePathScoreFunction.prototype = {
66 * @param {string} data
67 * @param {?Array.<!Number>} matchIndexes
70 score: function(data, matchIndexes)
72 if (!data || !this._query)
74 var n = this._query.length;
76 if (!this._score || this._score.length < n * m) {
77 this._score = new Int32Array(n * m * 2);
78 this._sequence = new Int32Array(n * m * 2);
80 var score = this._score;
81 var sequence = /** @type {!Int32Array} */ (this._sequence);
82 this._dataUpperCase = data.toUpperCase();
83 this._fileNameIndex = data.lastIndexOf("/");
84 for (var i = 0; i < n; ++i) {
85 for (var j = 0; j < m; ++j) {
86 var skipCharScore = j === 0 ? 0 : score[i * m + j - 1];
87 var prevCharScore = i === 0 || j === 0 ? 0 : score[(i - 1) * m + j - 1];
88 var consecutiveMatch = i === 0 || j === 0 ? 0 : sequence[(i - 1) * m + j - 1];
89 var pickCharScore = this._match(this._query, data, i, j, consecutiveMatch);
90 if (pickCharScore && prevCharScore + pickCharScore >= skipCharScore) {
91 sequence[i * m + j] = consecutiveMatch + 1;
92 score[i * m + j] = (prevCharScore + pickCharScore);
94 sequence[i * m + j] = 0;
95 score[i * m + j] = skipCharScore;
100 this._restoreMatchIndexes(sequence, n, m, matchIndexes);
101 return score[n * m - 1];
105 * @param {string} data
109 _testWordStart: function(data, j)
111 var prevChar = data.charAt(j - 1);
112 return j === 0 || prevChar === "_" || prevChar === "-" || prevChar === "/" ||
113 (data[j - 1] !== this._dataUpperCase[j - 1] && data[j] === this._dataUpperCase[j]);
117 * @param {!Int32Array} sequence
120 * @param {!Array.<!Number>} out
122 _restoreMatchIndexes: function(sequence, n, m, out)
124 var i = n - 1, j = m - 1;
125 while (i >= 0 && j >= 0) {
126 switch (sequence[i * m + j]) {
141 * @param {string} query
142 * @param {string} data
147 _singleCharScore: function(query, data, i, j)
149 var isWordStart = this._testWordStart(data, j);
150 var isFileName = j > this._fileNameIndex;
151 var isPathTokenStart = j === 0 || data[j - 1] === "/";
152 var isCapsMatch = query[i] === data[j] && query[i] == this._queryUpperCase[i];
154 if (isPathTokenStart)
162 // promote the case of making the whole match in the filename
163 if (j === this._fileNameIndex + 1 && i === 0)
165 if (isFileName && isWordStart)
171 * @param {string} query
172 * @param {string} data
175 * @param {number} sequenceLength
178 _sequenceCharScore: function(query, data, i, j, sequenceLength)
180 var isFileName = j > this._fileNameIndex;
181 var isPathTokenStart = j === 0 || data[j - 1] === "/";
185 if (isPathTokenStart)
187 score += sequenceLength * 4;
192 * @param {string} query
193 * @param {string} data
196 * @param {number} consecutiveMatch
199 _match: function(query, data, i, j, consecutiveMatch)
201 if (this._queryUpperCase[i] !== this._dataUpperCase[j])
204 if (!consecutiveMatch)
205 return this._singleCharScore(query, data, i, j);
207 return this._sequenceCharScore(query, data, i, j - consecutiveMatch, consecutiveMatch);