diff --git a/src/vs/editor/contrib/multicursor/multicursor.ts b/src/vs/editor/contrib/multicursor/multicursor.ts index a5341c5896b25..b23cc0c09f8c4 100644 --- a/src/vs/editor/contrib/multicursor/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/multicursor.ts @@ -631,6 +631,12 @@ export class MultiCursorSelectionController extends Disposable implements IEdito this._setSelections(matches.map(m => new Selection(m.range.startLineNumber, m.range.startColumn, m.range.endLineNumber, m.range.endColumn))); } } + + public selectAllUsingSelections(selections: Selection[]): void { + if (selections.length > 0) { + this._setSelections(selections); + } + } } export abstract class MultiCursorSelectionControllerAction extends EditorAction { diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 55fe302365ca7..5851978e65d76 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -617,9 +617,22 @@ KeybindingsRegistry.registerCommandAndKeybindingRule(objects.assign({ handler: toggleRegexCommand }, ToggleRegexKeybinding)); +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: Constants.AddCursorsAtSearchResults, + weight: KeybindingWeight.WorkbenchContrib, + when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.FileMatchOrMatchFocusKey), + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_L, + handler: (accessor, args: any) => { + const searchView = getSearchView(accessor.get(IViewletService), accessor.get(IPanelService)); + if (searchView) { + const tree: WorkbenchObjectTree = searchView.getControl(); + searchView.openEditorWithMultiCursor(tree.getFocus()[0]); + } + } +}); + registry.registerWorkbenchAction(SyncActionDescriptor.create(CollapseDeepestExpandedLevelAction, CollapseDeepestExpandedLevelAction.ID, CollapseDeepestExpandedLevelAction.LABEL), 'Search: Collapse All', category); registry.registerWorkbenchAction(SyncActionDescriptor.create(ShowAllSymbolsAction, ShowAllSymbolsAction.ID, ShowAllSymbolsAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_T }), 'Go to Symbol in Workspace...'); - registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleSearchOnTypeAction, ToggleSearchOnTypeAction.ID, ToggleSearchOnTypeAction.LABEL), 'Search: Toggle Search on Type', category); registry.registerWorkbenchAction(SyncActionDescriptor.create(RefreshAction, RefreshAction.ID, RefreshAction.LABEL), 'Search: Refresh', category); registry.registerWorkbenchAction(SyncActionDescriptor.create(ClearSearchResultsAction, ClearSearchResultsAction.ID, ClearSearchResultsAction.LABEL), 'Search: Clear Search Results', category); diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index cb734ff0e657e..c8c623f35219b 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -20,7 +20,7 @@ import * as env from 'vs/base/common/platform'; import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import 'vs/css!./media/searchview'; -import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, isCodeEditor, isDiffEditor, getCodeEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import * as nls from 'vs/nls'; import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; @@ -61,6 +61,8 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Memento, MementoObject } from 'vs/workbench/common/memento'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { MultiCursorSelectionController } from 'vs/editor/contrib/multicursor/multicursor'; +import { Selection } from 'vs/editor/common/core/selection'; import { SIDE_BAR_BACKGROUND, PANEL_BACKGROUND } from 'vs/workbench/common/theme'; import { createEditorFromSearchResult } from 'vs/workbench/contrib/search/browser/searchEditor'; import { ILabelService } from 'vs/platform/label/common/label'; @@ -1601,6 +1603,38 @@ export class SearchView extends ViewletPane { }, errors.onUnexpectedError); } + openEditorWithMultiCursor(element: FileMatchOrMatch): Promise { + const resource = element instanceof Match ? element.parent().resource : (element).resource; + return this.editorService.openEditor({ + resource: resource, + options: { + preserveFocus: false, + pinned: true, + revealIfVisible: true + } + }).then(editor => { + if (editor) { + let fileMatch = null; + if (element instanceof FileMatch) { + fileMatch = element; + } + else if (element instanceof Match) { + fileMatch = element.parent(); + } + + if (fileMatch) { + const selections = fileMatch.matches().map(m => new Selection(m.range().startLineNumber, m.range().startColumn, m.range().endLineNumber, m.range().endColumn)); + const codeEditor = getCodeEditor(editor.getControl()); + if (codeEditor) { + let multiCursorController = MultiCursorSelectionController.get(codeEditor); + multiCursorController.selectAllUsingSelections(selections); + } + } + } + this.viewModel.searchResult.rangeHighlightDecorations.removeHighlightRange(); + }, errors.onUnexpectedError); + } + private getSelectionFrom(element: FileMatchOrMatch): any { let match: Match | null = null; if (element instanceof Match) { diff --git a/src/vs/workbench/contrib/search/common/constants.ts b/src/vs/workbench/contrib/search/common/constants.ts index 589eeafc83726..483190b64988c 100644 --- a/src/vs/workbench/contrib/search/common/constants.ts +++ b/src/vs/workbench/contrib/search/common/constants.ts @@ -26,6 +26,7 @@ export const CloseReplaceWidgetActionId = 'closeReplaceInFilesWidget'; export const ToggleCaseSensitiveCommandId = 'toggleSearchCaseSensitive'; export const ToggleWholeWordCommandId = 'toggleSearchWholeWord'; export const ToggleRegexCommandId = 'toggleSearchRegex'; +export const AddCursorsAtSearchResults = 'addCursorsAtSearchResults'; export const RevealInSideBarForSearchResults = 'search.action.revealInSideBar'; export const ToggleSearchViewPositionCommandId = 'search.action.toggleSearchViewPosition';