diff --git a/package.json b/package.json index d362ad36c35..a15624d0548 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "vscode-chokidar": "1.6.4", "vscode-debugprotocol": "1.32.0", "vscode-nsfw": "1.1.1", - "vscode-ripgrep": "^1.2.2", + "vscode-ripgrep": "^1.2.4", "vscode-sqlite3": "4.0.2", "vscode-textmate": "^4.0.1", "vscode-xterm": "3.9.0-beta9", diff --git a/src/vs/platform/search/common/search.ts b/src/vs/platform/search/common/search.ts index 12cc9fbdb18..288f124c21e 100644 --- a/src/vs/platform/search/common/search.ts +++ b/src/vs/platform/search/common/search.ts @@ -106,6 +106,7 @@ export interface ITextQueryProps extends ICommonQueryPr previewOptions?: ITextSearchPreviewOptions; fileEncoding?: string; maxFileSize?: number; + usePCRE2?: boolean; } export type IFileQuery = IFileQueryProps; @@ -120,6 +121,7 @@ export const enum QueryType { File = 1, Text = 2 } + /* __GDPR__FRAGMENT__ "IPatternInfo" : { "pattern" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, @@ -141,6 +143,10 @@ export interface IPatternInfo { isSmartCase?: boolean; } +export interface IExtendedExtensionSearchOptions { + usePCRE2?: boolean; +} + export interface IFileMatch { resource?: U; matches?: ITextSearchResult[]; @@ -305,6 +311,7 @@ export interface ISearchConfigurationProperties { location: 'sidebar' | 'panel'; useReplacePreview: boolean; showLineNumbers: boolean; + usePCRE2: boolean; } export interface ISearchConfiguration extends IFilesConfiguration { diff --git a/src/vs/workbench/parts/search/browser/searchWidget.ts b/src/vs/workbench/parts/search/browser/searchWidget.ts index b56f1a72fae..e038970faf3 100644 --- a/src/vs/workbench/parts/search/browser/searchWidget.ts +++ b/src/vs/workbench/parts/search/browser/searchWidget.ts @@ -307,7 +307,7 @@ export class SearchWidget extends Widget { this._register(this.searchInputFocusTracker.onDidFocus(() => { this.searchInputBoxFocused.set(true); - const useGlobalFindBuffer = this.configurationService.getValue('search').globalFindClipboard; + const useGlobalFindBuffer = this.searchConfiguration.globalFindClipboard; if (!this.ignoreGlobalFindBufferOnNextFocus && useGlobalFindBuffer) { const globalBufferText = this.clipboardServce.readFindText(); if (this.previousGlobalFindBufferValue !== globalBufferText) { @@ -398,7 +398,9 @@ export class SearchWidget extends Widget { } if (strings.regExpContainsBackreference(value)) { - return { content: nls.localize('regexp.backreferenceValidationFailure', "Backreferences are not supported") }; + if (!this.searchConfiguration.usePCRE2) { + return { content: nls.localize('regexp.backreferenceValidationFailure', "Backreferences are not supported") }; + } } return null; @@ -475,8 +477,13 @@ export class SearchWidget extends Widget { } private submitSearch(): void { + this.searchInput.validate(); + if (!this.searchInput.inputBox.isInputValid()) { + return; + } + const value = this.searchInput.getValue(); - const useGlobalFindBuffer = this.configurationService.getValue('search').globalFindClipboard; + const useGlobalFindBuffer = this.searchConfiguration.globalFindClipboard; if (value) { if (useGlobalFindBuffer) { this.clipboardServce.writeFindText(value); @@ -492,6 +499,10 @@ export class SearchWidget extends Widget { this.replaceActionBar = null; super.dispose(); } + + private get searchConfiguration(): ISearchConfigurationProperties { + return this.configurationService.getValue('search'); + } } export function registerContributions() { diff --git a/src/vs/workbench/parts/search/common/queryBuilder.ts b/src/vs/workbench/parts/search/common/queryBuilder.ts index d379cee892c..a5555d4a033 100644 --- a/src/vs/workbench/parts/search/common/queryBuilder.ts +++ b/src/vs/workbench/parts/search/common/queryBuilder.ts @@ -66,7 +66,8 @@ export class QueryBuilder { text(contentPattern: IPatternInfo, folderResources?: uri[], options?: ITextQueryBuilderOptions): ITextQuery { contentPattern.isCaseSensitive = this.isCaseSensitive(contentPattern); contentPattern.isMultiline = this.isMultiline(contentPattern); - contentPattern.wordSeparators = this.configurationService.getValue().editor.wordSeparators; + const searchConfig = this.configurationService.getValue(); + contentPattern.wordSeparators = searchConfig.editor.wordSeparators; const commonQuery = this.commonQuery(folderResources, options); return { @@ -75,7 +76,8 @@ export class QueryBuilder { contentPattern, previewOptions: options && options.previewOptions, fileEncoding: options && options.fileEncoding, - maxFileSize: options && options.maxFileSize + maxFileSize: options && options.maxFileSize, + usePCRE2: searchConfig.search.usePCRE2 }; } diff --git a/src/vs/workbench/parts/search/electron-browser/search.contribution.ts b/src/vs/workbench/parts/search/electron-browser/search.contribution.ts index 62af8ecc289..4e68c2bc01e 100644 --- a/src/vs/workbench/parts/search/electron-browser/search.contribution.ts +++ b/src/vs/workbench/parts/search/electron-browser/search.contribution.ts @@ -664,6 +664,11 @@ configurationRegistry.registerConfiguration({ type: 'boolean', default: false, description: nls.localize('search.searchRipgrepEnable', "Whether to run search in the extension host") + }, + 'search.usePCRE2': { + type: 'boolean', + default: false, + description: nls.localize('search.usePCRE2', "Whether to use the PCRE2 regex engine in text search. This enables using some advaned regex features like lookbehind and backreferences.") } } }); diff --git a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts index 888c11cb980..6e158ae79d7 100644 --- a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts +++ b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts @@ -12,6 +12,7 @@ import { URI } from 'vs/base/common/uri'; import * as vscode from 'vscode'; import { rgPath } from 'vscode-ripgrep'; import { anchorGlob, createTextSearchResult, IOutputChannel, Maybe, Range } from './ripgrepSearchUtils'; +import { IExtendedExtensionSearchOptions } from 'vs/platform/search/common/search'; // If vscode-ripgrep is in an .asar file, then the binary is unpacked. const rgDiskPath = rgPath.replace(/\bnode_modules\.asar\b/, 'node_modules.asar.unpacked'); @@ -315,6 +316,10 @@ function getRgArgs(query: vscode.TextSearchQuery, options: vscode.TextSearchOpti args.push('--multiline'); } + if ((options).usePCRE2) { + args.push('--pcre2'); + } + // Folder to search args.push('--'); diff --git a/src/vs/workbench/services/search/node/textSearchManager.ts b/src/vs/workbench/services/search/node/textSearchManager.ts index 20dc143411e..ccc65af00a5 100644 --- a/src/vs/workbench/services/search/node/textSearchManager.ts +++ b/src/vs/workbench/services/search/node/textSearchManager.ts @@ -11,7 +11,7 @@ import * as resources from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import * as extfs from 'vs/base/node/extfs'; -import { IFileMatch, IFolderQuery, IPatternInfo, ISearchCompleteStats, ITextQuery, ITextSearchResult } from 'vs/platform/search/common/search'; +import { IFileMatch, IFolderQuery, IPatternInfo, ISearchCompleteStats, ITextQuery, ITextSearchResult, IExtendedExtensionSearchOptions } from 'vs/platform/search/common/search'; import { QueryGlobTester, resolvePatternsForProvider } from 'vs/workbench/services/search/node/search'; import * as vscode from 'vscode'; @@ -121,7 +121,7 @@ export class TextSearchManager { const includes = resolvePatternsForProvider(this.query.includePattern, fq.includePattern); const excludes = resolvePatternsForProvider(this.query.excludePattern, fq.excludePattern); - return { + const options = { folder: URI.from(fq.folder), excludes, includes, @@ -133,6 +133,8 @@ export class TextSearchManager { maxResults: this.query.maxResults, previewOptions: this.query.previewOptions }; + (options).usePCRE2 = this.query.usePCRE2; + return options; } } diff --git a/yarn.lock b/yarn.lock index e39e168182b..e34dc6f3350 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9325,10 +9325,10 @@ vscode-nsfw@1.1.1: lodash.isundefined "^3.0.1" nan "^2.10.0" -vscode-ripgrep@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.2.2.tgz#c21b91bb558638a7124fe3d9719b2666b12dbfdc" - integrity sha512-rPbCj4LUnPzivezk3pC94G5sB17HbayjV9mSvNTDYFg5llHN/XozAmkoDOC0KG9UveuQ71MADX1//CeHtUTmZw== +vscode-ripgrep@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.2.4.tgz#b3cfbe08ed13f6cf6b134147ea4d982970ab4f70" + integrity sha512-TysaK20aCSfsFIQGd0DfMshjkHof0fG6zx7DoO0tdWNAZgsvoqLtOWdqHcocICRZ3RSpdiMiEJRaMK+iOzx16w== vscode-sqlite3@4.0.2: version "4.0.2"