• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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