diff --git a/src/vs/platform/search/common/search.ts b/src/vs/platform/search/common/search.ts index e10e1656ea5ed7dd2eebb2f1c03f31448438c78d..ded634a58a4b76a0e3685c0e038be447f4525554 100644 --- a/src/vs/platform/search/common/search.ts +++ b/src/vs/platform/search/common/search.ts @@ -4,19 +4,20 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { PPromise, TPromise } from 'vs/base/common/winjs.base'; -import uri, { UriComponents } from 'vs/base/common/uri'; +import { Event } from 'vs/base/common/event'; +import * as glob from 'vs/base/common/glob'; +import { IDisposable } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; import * as paths from 'vs/base/common/paths'; -import * as glob from 'vs/base/common/glob'; +import uri, { UriComponents } from 'vs/base/common/uri'; +import { PPromise, TPromise } from 'vs/base/common/winjs.base'; import { IFilesConfiguration } from 'vs/platform/files/common/files'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IDisposable } from 'vs/base/common/lifecycle'; -export const ID = 'searchService'; export const VIEW_ID = 'workbench.view.search'; -export const ISearchService = createDecorator(ID); +export const ISearchHistoryService = createDecorator('searchHistoryService'); +export const ISearchService = createDecorator('searchService'); /** * A service that enables to search for files or with in files. @@ -29,6 +30,21 @@ export interface ISearchService { registerSearchResultProvider(provider: ISearchResultProvider): IDisposable; } +export interface ISearchHistoryValues { + search?: string[]; + replace?: string[]; + include?: string[]; + exclude?: string[]; +} + +export interface ISearchHistoryService { + _serviceBrand: any; + onDidClearHistory: Event; + clearHistory(): void; + load(): ISearchHistoryValues; + save(history: ISearchHistoryValues): void; +} + export interface ISearchResultProvider { search(query: ISearchQuery): PPromise; } diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 3b3a799f75bee2f3bce60178a66167b1695a6516..975def9b4623e8d259ff590e43438fbc67c77f76 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -51,7 +51,7 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView import { ILifecycleService, LifecyclePhase, ShutdownReason, StartupKind } from 'vs/platform/lifecycle/common/lifecycle'; import { IMarkerService } from 'vs/platform/markers/common/markers'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ISearchService } from 'vs/platform/search/common/search'; +import { ISearchService, ISearchHistoryService } from 'vs/platform/search/common/search'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { CommandService } from 'vs/workbench/services/commands/common/commandService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; @@ -96,6 +96,7 @@ import { DialogChannel } from 'vs/platform/dialogs/common/dialogIpc'; import { EventType, addDisposableListener, addClass, getClientArea } from 'vs/base/browser/dom'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { OpenerService } from 'vs/editor/browser/services/openerService'; +import { SearchHistoryService } from 'vs/workbench/services/search/node/searchHistoryService'; /** * Services that we require for the Shell @@ -446,6 +447,8 @@ export class WorkbenchShell { serviceCollection.set(ISearchService, new SyncDescriptor(SearchService)); + serviceCollection.set(ISearchHistoryService, new SyncDescriptor(SearchHistoryService)); + serviceCollection.set(IWorkbenchIssueService, new SyncDescriptor(WorkbenchIssueService)); serviceCollection.set(ICodeEditorService, new SyncDescriptor(CodeEditorService)); diff --git a/src/vs/workbench/parts/search/browser/searchActions.ts b/src/vs/workbench/parts/search/browser/searchActions.ts index 42cbcc20231711caf9f4ba9aa6b884281970d48f..6e5abe0ab8bfbc5a85af8db8c464f8ed26b6f011 100644 --- a/src/vs/workbench/parts/search/browser/searchActions.ts +++ b/src/vs/workbench/parts/search/browser/searchActions.ts @@ -3,30 +3,30 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; import * as DOM from 'vs/base/browser/dom'; -import { TPromise } from 'vs/base/common/winjs.base'; import { Action } from 'vs/base/common/actions'; -import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { ITree } from 'vs/base/parts/tree/browser/tree'; import { INavigator } from 'vs/base/common/iterator'; +import { createKeybinding, ResolvedKeybinding } from 'vs/base/common/keyCodes'; +import { getPathLabel } from 'vs/base/common/labels'; +import { Schemas } from 'vs/base/common/network'; +import { isWindows, OS } from 'vs/base/common/platform'; +import URI from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { ITree } from 'vs/base/parts/tree/browser/tree'; +import * as nls from 'vs/nls'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { ICommandHandler } from 'vs/platform/commands/common/commands'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { ISearchHistoryService, VIEW_ID } from 'vs/platform/search/common/search'; import { SearchView } from 'vs/workbench/parts/search/browser/searchView'; -import { Match, FileMatch, FileMatchOrMatch, FolderMatch, RenderableMatch, SearchResult, searchMatchComparer } from 'vs/workbench/parts/search/common/searchModel'; -import { IReplaceService } from 'vs/workbench/parts/search/common/replace'; import * as Constants from 'vs/workbench/parts/search/common/constants'; +import { IReplaceService } from 'vs/workbench/parts/search/common/replace'; +import { FileMatch, FileMatchOrMatch, FolderMatch, Match, RenderableMatch, searchMatchComparer, SearchResult } from 'vs/workbench/parts/search/common/searchModel'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { ResolvedKeybinding, createKeybinding } from 'vs/base/common/keyCodes'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { OS, isWindows } from 'vs/base/common/platform'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; -import { VIEW_ID } from 'vs/platform/search/common/search'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { ICommandHandler } from 'vs/platform/commands/common/commands'; -import { Schemas } from 'vs/base/common/network'; -import { getPathLabel } from 'vs/base/common/labels'; -import URI from 'vs/base/common/uri'; +import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; export function isSearchViewFocused(viewletService: IViewletService, panelService: IPanelService): boolean { let searchView = getSearchView(viewletService, panelService); @@ -830,9 +830,6 @@ export const copyAllCommand: ICommandHandler = accessor => { }; export const clearHistoryCommand: ICommandHandler = accessor => { - const viewletService = accessor.get(IViewletService); - const panelService = accessor.get(IPanelService); - const searchView = getSearchView(viewletService, panelService); - - searchView.clearHistory(); -}; \ No newline at end of file + const searchHistoryService = accessor.get(ISearchHistoryService); + searchHistoryService.clearHistory(); +}; diff --git a/src/vs/workbench/parts/search/browser/searchView.ts b/src/vs/workbench/parts/search/browser/searchView.ts index b85f05524b56cf06b3264a22675d7544eec7f0c0..1e2434a7cd11b711ee25492087f9b90b99df2c00 100644 --- a/src/vs/workbench/parts/search/browser/searchView.ts +++ b/src/vs/workbench/parts/search/browser/searchView.ts @@ -5,62 +5,62 @@ 'use strict'; -import 'vs/css!./media/searchview'; -import * as nls from 'vs/nls'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { Emitter, debounceEvent } from 'vs/base/common/event'; -import * as errors from 'vs/base/common/errors'; -import * as aria from 'vs/base/browser/ui/aria/aria'; -import * as env from 'vs/base/common/platform'; -import { Delayer } from 'vs/base/common/async'; -import URI from 'vs/base/common/uri'; -import * as strings from 'vs/base/common/strings'; -import * as paths from 'vs/base/common/paths'; +import { $, Builder } from 'vs/base/browser/builder'; import * as dom from 'vs/base/browser/dom'; -import { IAction } from 'vs/base/common/actions'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { Builder, $ } from 'vs/base/browser/builder'; +import * as aria from 'vs/base/browser/ui/aria/aria'; import { FindInput } from 'vs/base/browser/ui/findinput/findInput'; -import { ITree, IFocusEvent } from 'vs/base/parts/tree/browser/tree'; -import { Scope } from 'vs/workbench/common/memento'; -import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; -import { FileChangeType, FileChangesEvent, IFileService } from 'vs/platform/files/common/files'; -import { Match, FileMatch, SearchModel, FileMatchOrMatch, IChangeEvent, ISearchWorkbenchService, FolderMatch } from 'vs/workbench/parts/search/common/searchModel'; -import { QueryBuilder } from 'vs/workbench/parts/search/common/queryBuilder'; import { MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; -import { ISearchProgressItem, ISearchComplete, ISearchQuery, IQueryOptions, ISearchConfiguration, IPatternInfo, VIEW_ID } from 'vs/platform/search/common/search'; -import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { IAction } from 'vs/base/common/actions'; +import { Delayer } from 'vs/base/common/async'; +import * as errors from 'vs/base/common/errors'; +import { debounceEvent, Emitter } from 'vs/base/common/event'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import * as paths from 'vs/base/common/paths'; +import * as env from 'vs/base/common/platform'; +import * as strings from 'vs/base/common/strings'; +import URI from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { IFocusEvent, ITree } from 'vs/base/parts/tree/browser/tree'; +import 'vs/css!./media/searchview'; +import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; +import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import * as nls from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; +import { IConfirmation, IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { FileChangesEvent, FileChangeType, IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { TreeResourceNavigator, WorkbenchTree } from 'vs/platform/list/browser/listService'; +import { INotificationService } from 'vs/platform/notification/common/notification'; import { IProgressService } from 'vs/platform/progress/common/progress'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IPatternInfo, IQueryOptions, ISearchComplete, ISearchConfiguration, ISearchHistoryService, ISearchProgressItem, ISearchQuery, VIEW_ID } from 'vs/platform/search/common/search'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import { PatternInputWidget, ExcludePatternInputWidget } from 'vs/workbench/parts/search/browser/patternInputWidget'; -import { SearchRenderer, SearchDataSource, SearchAccessibilityProvider, SearchFilter, SearchTreeController, SearchSorter } from 'vs/workbench/parts/search/browser/searchResultsView'; -import { SearchWidget, ISearchWidgetOptions } from 'vs/workbench/parts/search/browser/searchWidget'; -import { RefreshAction, CollapseDeepestExpandedLevelAction, ClearSearchResultsAction, CancelSearchAction } from 'vs/workbench/parts/search/browser/searchActions'; -import { IReplaceService } from 'vs/workbench/parts/search/common/replace'; -import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { OpenFolderAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; -import * as Constants from 'vs/workbench/parts/search/common/constants'; -import { IThemeService, ITheme, ICssStyleCollector, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { editorFindMatchHighlight, diffInserted, diffRemoved, diffInsertedOutline, diffRemovedOutline, editorFindMatchHighlightBorder } from 'vs/platform/theme/common/colorRegistry'; -import { getOutOfWorkspaceEditorResources } from 'vs/workbench/parts/search/common/search'; -import { PreferencesEditor } from 'vs/workbench/parts/preferences/browser/preferencesEditor'; -import { isDiffEditor, isCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { TreeResourceNavigator, WorkbenchTree } from 'vs/platform/list/browser/listService'; -import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { diffInserted, diffInsertedOutline, diffRemoved, diffRemovedOutline, editorFindMatchHighlight, editorFindMatchHighlightBorder } from 'vs/platform/theme/common/colorRegistry'; +import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { OpenFileFolderAction, OpenFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; import { SimpleFileResourceDragAndDrop } from 'vs/workbench/browser/dnd'; -import { IConfirmation, IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import { Viewlet } from 'vs/workbench/browser/viewlet'; +import { Scope } from 'vs/workbench/common/memento'; import { IPanel } from 'vs/workbench/common/panel'; import { IViewlet } from 'vs/workbench/common/viewlet'; -import { Viewlet } from 'vs/workbench/browser/viewlet'; +import { PreferencesEditor } from 'vs/workbench/parts/preferences/browser/preferencesEditor'; +import { ExcludePatternInputWidget, PatternInputWidget } from 'vs/workbench/parts/search/browser/patternInputWidget'; +import { CancelSearchAction, ClearSearchResultsAction, CollapseDeepestExpandedLevelAction, RefreshAction } from 'vs/workbench/parts/search/browser/searchActions'; +import { SearchAccessibilityProvider, SearchDataSource, SearchFilter, SearchRenderer, SearchSorter, SearchTreeController } from 'vs/workbench/parts/search/browser/searchResultsView'; +import { ISearchWidgetOptions, SearchWidget } from 'vs/workbench/parts/search/browser/searchWidget'; +import * as Constants from 'vs/workbench/parts/search/common/constants'; +import { QueryBuilder } from 'vs/workbench/parts/search/common/queryBuilder'; +import { IReplaceService } from 'vs/workbench/parts/search/common/replace'; +import { getOutOfWorkspaceEditorResources } from 'vs/workbench/parts/search/common/search'; +import { FileMatch, FileMatchOrMatch, FolderMatch, IChangeEvent, ISearchWorkbenchService, Match, SearchModel } from 'vs/workbench/parts/search/common/searchModel'; +import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; +import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; +import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; export class SearchView extends Viewlet implements IViewlet, IPanel { @@ -130,7 +130,8 @@ export class SearchView extends Viewlet implements IViewlet, IPanel { @IReplaceService private replaceService: IReplaceService, @IUntitledEditorService private untitledEditorService: IUntitledEditorService, @IPreferencesService private preferencesService: IPreferencesService, - @IThemeService protected themeService: IThemeService + @IThemeService protected themeService: IThemeService, + @ISearchHistoryService private searchHistoryService: ISearchHistoryService ) { super(VIEW_ID, partService, telemetryService, themeService); @@ -152,6 +153,7 @@ export class SearchView extends Viewlet implements IViewlet, IPanel { this.toUnbind.push(this.fileService.onFileChanges(e => this.onFilesChanged(e))); this.toUnbind.push(this.untitledEditorService.onDidChangeDirty(e => this.onUntitledDidChangeDirty(e))); this.toUnbind.push(this.contextService.onDidChangeWorkbenchState(() => this.onDidChangeWorkbenchState())); + this._register(this.searchHistoryService.onDidClearHistory(() => this.clearHistory())); this.selectCurrentMatchEmitter = new Emitter(); debounceEvent(this.selectCurrentMatchEmitter.event, (l, e) => e, 100, /*leading=*/true) @@ -182,11 +184,12 @@ export class SearchView extends Viewlet implements IViewlet, IPanel { }); this.createSearchWidget(this.searchWidgetsContainer); + const history = this.searchHistoryService.load(); const filePatterns = this.viewletSettings['query.filePatterns'] || ''; let patternExclusions = this.viewletSettings['query.folderExclusions'] || ''; - const patternExclusionsHistory: string[] = this.viewletSettings['query.folderExclusionsHistory'] || []; + const patternExclusionsHistory: string[] = history.exclude || []; let patternIncludes = this.viewletSettings['query.folderIncludes'] || ''; - let patternIncludesHistory: string[] = this.viewletSettings['query.folderIncludesHistory'] || []; + let patternIncludesHistory: string[] = history.include || []; const queryDetailsExpanded = this.viewletSettings['query.queryDetailsExpanded'] || ''; const useExcludesAndIgnoreFiles = typeof this.viewletSettings['query.useExcludesAndIgnoreFiles'] === 'boolean' ? this.viewletSettings['query.useExcludesAndIgnoreFiles'] : true; @@ -328,8 +331,9 @@ export class SearchView extends Viewlet implements IViewlet, IPanel { let isRegex = this.viewletSettings['query.regex'] === true; let isWholeWords = this.viewletSettings['query.wholeWords'] === true; let isCaseSensitive = this.viewletSettings['query.caseSensitive'] === true; - let searchHistory = this.viewletSettings['query.searchHistory'] || []; - let replaceHistory = this.viewletSettings['query.replaceHistory'] || []; + const history = this.searchHistoryService.load(); + let searchHistory = history.search || []; + let replaceHistory = history.replace || []; this.searchWidget = this.instantiationService.createInstance(SearchWidget, builder, { value: contentPattern, @@ -1509,7 +1513,7 @@ export class SearchView extends Viewlet implements IViewlet, IPanel { this.updateTitleArea(); } - public clearHistory(): void { + private clearHistory(): void { this.searchWidget.clearHistory(); this.inputPatternExcludes.clearHistory(); this.inputPatternIncludes.clearHistory(); @@ -1523,24 +1527,23 @@ export class SearchView extends Viewlet implements IViewlet, IPanel { const patternExcludes = this.inputPatternExcludes.getValue().trim(); const patternIncludes = this.inputPatternIncludes.getValue().trim(); const useExcludesAndIgnoreFiles = this.inputPatternExcludes.useExcludesAndIgnoreFiles(); - const searchHistory = this.searchWidget.getSearchHistory(); - const replaceHistory = this.searchWidget.getReplaceHistory(); - const patternExcludesHistory = this.inputPatternExcludes.getHistory(); - const patternIncludesHistory = this.inputPatternIncludes.getHistory(); // store memento this.viewletSettings['query.contentPattern'] = contentPattern; - this.viewletSettings['query.searchHistory'] = searchHistory; - this.viewletSettings['query.replaceHistory'] = replaceHistory; this.viewletSettings['query.regex'] = isRegex; this.viewletSettings['query.wholeWords'] = isWholeWords; this.viewletSettings['query.caseSensitive'] = isCaseSensitive; this.viewletSettings['query.folderExclusions'] = patternExcludes; this.viewletSettings['query.folderIncludes'] = patternIncludes; - this.viewletSettings['query.folderExclusionsHistory'] = patternExcludesHistory; - this.viewletSettings['query.folderIncludesHistory'] = patternIncludesHistory; this.viewletSettings['query.useExcludesAndIgnoreFiles'] = useExcludesAndIgnoreFiles; + this.searchHistoryService.save({ + search: this.searchWidget.getSearchHistory(), + replace: this.searchWidget.getReplaceHistory(), + exclude: this.inputPatternExcludes.getHistory(), + include: this.inputPatternIncludes.getHistory() + }); + super.shutdown(); } diff --git a/src/vs/workbench/services/search/node/searchHistoryService.ts b/src/vs/workbench/services/search/node/searchHistoryService.ts new file mode 100644 index 0000000000000000000000000000000000000000..b12ed92a9a8a838a583b2f778bbd19a7fefebfed --- /dev/null +++ b/src/vs/workbench/services/search/node/searchHistoryService.ts @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { Emitter, Event } from 'vs/base/common/event'; +import { ISearchHistoryValues, ISearchHistoryService } from 'vs/platform/search/common/search'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; + +export class SearchHistoryService implements ISearchHistoryService { + public _serviceBrand: any; + + private static readonly SEARCH_HISTORY_KEY = 'workbench.search.history'; + + private readonly _onDidClearHistory: Emitter = new Emitter(); + public readonly onDidClearHistory: Event = this._onDidClearHistory.event; + + constructor( + @IStorageService private storageService: IStorageService + ) { } + + public clearHistory(): void { + this.storageService.remove(SearchHistoryService.SEARCH_HISTORY_KEY, StorageScope.WORKSPACE); + this._onDidClearHistory.fire(); + } + + public load(): ISearchHistoryValues { + let result: ISearchHistoryValues; + const raw = this.storageService.get(SearchHistoryService.SEARCH_HISTORY_KEY, StorageScope.WORKSPACE); + + if (raw) { + try { + result = JSON.parse(raw); + } catch (e) { + // Invalid data + } + } + + return result || {}; + } + + public save(history: ISearchHistoryValues): void { + this.storageService.store(SearchHistoryService.SEARCH_HISTORY_KEY, JSON.stringify(history), StorageScope.WORKSPACE); + } +} \ No newline at end of file