UNPKG

chrome-devtools-frontend

Version:
191 lines (163 loc) • 5.71 kB
// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import type * as Common from '../../core/common/common.js'; import * as Platform from '../../core/platform/platform.js'; import type * as Workspace from '../../models/workspace/workspace.js'; export class SearchConfig implements Workspace.Workspace.ProjectSearchConfig { private readonly queryInternal: string; private readonly ignoreCaseInternal: boolean; private readonly isRegexInternal: boolean; private fileQueries?: QueryTerm[]; private queriesInternal?: string[]; private fileRegexQueries?: RegexQuery[]; constructor(query: string, ignoreCase: boolean, isRegex: boolean) { this.queryInternal = query; this.ignoreCaseInternal = ignoreCase; this.isRegexInternal = isRegex; this.parse(); } static fromPlainObject(object: { query: string, ignoreCase: boolean, isRegex: boolean, }): SearchConfig { return new SearchConfig(object.query, object.ignoreCase, object.isRegex); } query(): string { return this.queryInternal; } ignoreCase(): boolean { return this.ignoreCaseInternal; } isRegex(): boolean { return this.isRegexInternal; } toPlainObject(): { query: string, ignoreCase: boolean, isRegex: boolean, } { return {query: this.query(), ignoreCase: this.ignoreCase(), isRegex: this.isRegex()}; } private parse(): void { // Inside double quotes: any symbol except double quote and backslash or any symbol escaped with a backslash. const quotedPattern = /"([^\\"]|\\.)+"/; // 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:. const unquotedWordPattern = /(\s*(?!-?f(ile)?:)[^\\ ]|\\.)+/; const unquotedPattern = unquotedWordPattern.source + '(\\s+' + unquotedWordPattern.source + ')*'; const pattern = [ '(\\s*' + FilePatternRegex.source + '\\s*)', '(' + quotedPattern.source + ')', '(' + unquotedPattern + ')', ].join('|'); const regexp = new RegExp(pattern, 'g'); const queryParts = this.queryInternal.match(regexp) || []; this.fileQueries = []; this.queriesInternal = []; for (let i = 0; i < queryParts.length; ++i) { const queryPart = queryParts[i]; if (!queryPart) { continue; } const fileQuery = this.parseFileQuery(queryPart); if (fileQuery) { this.fileQueries.push(fileQuery); this.fileRegexQueries = this.fileRegexQueries || []; this.fileRegexQueries.push( {regex: new RegExp(fileQuery.text, this.ignoreCase() ? 'i' : ''), isNegative: fileQuery.isNegative}); continue; } if (this.isRegexInternal) { this.queriesInternal.push(queryPart); continue; } if (queryPart.startsWith('"')) { if (!queryPart.endsWith('"')) { continue; } this.queriesInternal.push(this.parseQuotedQuery(queryPart)); continue; } this.queriesInternal.push(this.parseUnquotedQuery(queryPart)); } } filePathMatchesFileQuery(filePath: Platform.DevToolsPath.RawPathString| Platform.DevToolsPath.EncodedPathString|Platform.DevToolsPath.UrlString): boolean { if (!this.fileRegexQueries) { return true; } for (let i = 0; i < this.fileRegexQueries.length; ++i) { if (Boolean(filePath.match(this.fileRegexQueries[i].regex)) === this.fileRegexQueries[i].isNegative) { return false; } } return true; } queries(): string[] { return this.queriesInternal || []; } private parseUnquotedQuery(query: string): string { return query.replace(/\\(.)/g, '$1'); } private parseQuotedQuery(query: string): string { return query.substring(1, query.length - 1).replace(/\\(.)/g, '$1'); } private parseFileQuery(query: string): QueryTerm|null { const match = query.match(FilePatternRegex); if (!match) { return null; } const isNegative = Boolean(match[1]); query = match[3]; let result = ''; for (let i = 0; i < query.length; ++i) { const char = query[i]; if (char === '*') { result += '.*'; } else if (char === '\\') { ++i; const nextChar = query[i]; if (nextChar === ' ') { result += ' '; } } else { if (Platform.StringUtilities.regexSpecialCharacters().indexOf(query.charAt(i)) !== -1) { result += '\\'; } result += query.charAt(i); } } return new QueryTerm(result, isNegative); } } // After file: prefix: any symbol except space and backslash or any symbol escaped with a backslash. export const FilePatternRegex = /(-)?f(ile)?:((?:[^\\ ]|\\.)+)/; export class QueryTerm { text: string; isNegative: boolean; constructor(text: string, isNegative: boolean) { this.text = text; this.isNegative = isNegative; } } export interface SearchResult { label(): string; description(): string; matchesCount(): number; matchLabel(index: number): string; matchLineContent(index: number): string; matchRevealable(index: number): Object; } export interface SearchScope { performSearch( searchConfig: SearchConfig, progress: Common.Progress.Progress, searchResultCallback: (arg0: SearchResult) => void, searchFinishedCallback: (arg0: boolean) => void): void|Promise<void>; performIndexing(progress: Common.Progress.Progress): void; stopSearch(): void; } export interface RegexQuery { regex: RegExp; isNegative: boolean; }