From 83b7762ee523be63846eb04109112798701b2439 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 6 Jan 2016 09:19:41 +0100 Subject: [PATCH] Fixes #1171: Change All Occurences gets the same implementation as Select All Occurences of Find Match --- src/vs/editor/browser/editor.all.js | 1 - src/vs/editor/common/modes/abstractMode.ts | 7 - .../editor/common/modes/abstractModeWorker.ts | 24 -- src/vs/editor/contrib/find/browser/find.ts | 31 +- .../editor/contrib/rename/browser/rename.css | 2 - .../editor/contrib/rename/browser/rename.ts | 328 ------------------ src/vs/languages/css/common/css.ts | 7 + src/vs/languages/html/common/html.ts | 2 + .../typescript/common/typescriptMode.ts | 2 + 9 files changed, 35 insertions(+), 369 deletions(-) delete mode 100644 src/vs/editor/contrib/rename/browser/rename.ts diff --git a/src/vs/editor/browser/editor.all.js b/src/vs/editor/browser/editor.all.js index 71f01907ab0..16cc2cf7728 100644 --- a/src/vs/editor/browser/editor.all.js +++ b/src/vs/editor/browser/editor.all.js @@ -26,7 +26,6 @@ define([ 'vs/editor/contrib/parameterHints/browser/parameterHints', 'vs/editor/contrib/quickFix/browser/quickFix', 'vs/editor/contrib/referenceSearch/browser/referenceSearch', - 'vs/editor/contrib/rename/browser/rename', 'vs/editor/contrib/rename/browser/rename2', 'vs/editor/contrib/smartSelect/common/smartSelect', 'vs/editor/contrib/smartSelect/common/jumpToBracket', diff --git a/src/vs/editor/common/modes/abstractMode.ts b/src/vs/editor/common/modes/abstractMode.ts index 040fac79b3f..ae408097b42 100644 --- a/src/vs/editor/common/modes/abstractMode.ts +++ b/src/vs/editor/common/modes/abstractMode.ts @@ -35,7 +35,6 @@ export class AbstractMode implements Modes.IMode { // adapters start public autoValidateDelay:number; - public occurrencesSupport:Modes.IOccurrencesSupport; public suggestSupport:Modes.ISuggestSupport; public inplaceReplaceSupport:Modes.IInplaceReplaceSupport; public diffSupport:Modes.IDiffSupport; @@ -63,7 +62,6 @@ export class AbstractMode implements Modes.IMode { this._options = null; this.autoValidateDelay = 500; - this.occurrencesSupport = this; this.suggestSupport = this; this.inplaceReplaceSupport = this; this.diffSupport = this; @@ -194,11 +192,6 @@ export class AbstractMode implements Modes.IMode { return true; } - static $findOccurrences = OneWorkerAttr(AbstractMode, AbstractMode.prototype.findOccurrences); - public findOccurrences(resource:URI, position:EditorCommon.IPosition, strict:boolean = false): TPromise { - return this._worker((w) => w.findOccurrences(resource, position, strict)); - } - static $navigateValueSet = OneWorkerAttr(AbstractMode, AbstractMode.prototype.navigateValueSet); public navigateValueSet(resource:URI, position:EditorCommon.IRange, up:boolean):TPromise { return this._worker((w) => w.inplaceReplaceSupport.navigateValueSet(resource, position, up)); diff --git a/src/vs/editor/common/modes/abstractModeWorker.ts b/src/vs/editor/common/modes/abstractModeWorker.ts index fac48c40364..70cc19a98bf 100644 --- a/src/vs/editor/common/modes/abstractModeWorker.ts +++ b/src/vs/editor/common/modes/abstractModeWorker.ts @@ -177,30 +177,6 @@ export class AbstractModeWorker { return AbstractModeWorker.filter; } - // ---- occurrences --------------------------------------------------------------- - - public findOccurrences(resource:URI, position:EditorCommon.IPosition, strict?:boolean):TPromise { - - var model = this.resourceService.get(resource), - wordAtPosition = model.getWordAtPosition(position), - currentWord = (wordAtPosition ? wordAtPosition.word : ''), - result:Modes.IOccurence[] = []; - - var words = model.getAllWordsWithRange(), - upperBound = Math.min(1000, words.length); // Limit find occurences to 1000 occurences - - for(var i = 0; i < upperBound; i++) { - if(words[i].text === currentWord) { - result.push({ - range: words[i].range, - kind: 'text' - }); - } - } - - return TPromise.as(result); - } - // ---- diff -------------------------------------------------------------------------- public computeDiff(original:URI, modified:URI, ignoreTrimWhitespace:boolean):TPromise { diff --git a/src/vs/editor/contrib/find/browser/find.ts b/src/vs/editor/contrib/find/browser/find.ts index ac0ba00ea20..e1f248e76ec 100644 --- a/src/vs/editor/contrib/find/browser/find.ts +++ b/src/vs/editor/contrib/find/browser/find.ts @@ -22,6 +22,7 @@ import {IContextViewService} from 'vs/platform/contextview/browser/contextView'; import {INullService} from 'vs/platform/instantiation/common/instantiation'; import {KeyMod, KeyCode} from 'vs/base/common/keyCodes'; import {Range} from 'vs/editor/common/core/range'; +import {OccurrencesRegistry} from 'vs/editor/contrib/wordHighlighter/common/wordHighlighter'; /** * The Find controller will survive an editor.setModel(..) call @@ -459,9 +460,18 @@ class MoveSelectionToNextFindMatchAction extends SelectNextFindMatchAction { class SelectHighlightsAction extends EditorAction { static ID = 'editor.action.selectHighlights'; + static COMPAT_ID = 'editor.action.changeAll'; constructor(descriptor:EditorCommon.IEditorActionDescriptorData, editor:EditorCommon.ICommonCodeEditor, @INullService ns) { - super(descriptor, editor, Behaviour.WidgetFocus); + let behaviour = Behaviour.WidgetFocus; + if (descriptor.id === SelectHighlightsAction.COMPAT_ID) { + behaviour |= Behaviour.ShowInContextMenu; + } + super(descriptor, editor, behaviour); + } + + public getGroupId(): string { + return '2_change/1_changeAll'; } public run(): TPromise { @@ -484,20 +494,17 @@ export class SelectionHighlighter implements EditorCommon.IEditorContribution { static ID = 'editor.contrib.selectionHighlighter'; private editor:EditorCommon.ICommonCodeEditor; - private model:EditorCommon.IModel; private decorations:string[]; private toDispose:Lifecycle.IDisposable[]; constructor(editor:EditorCommon.ICommonCodeEditor, @INullService ns) { this.editor = editor; - this.model = this.editor.getModel(); this.decorations = []; this.toDispose = []; this.toDispose.push(editor.addListener2(EditorCommon.EventType.CursorPositionChanged, _ => this._update())); this.toDispose.push(editor.addListener2(EditorCommon.EventType.ModelChanged, (e) => { this.removeDecorations(); - this.model = this.editor.getModel(); })); this.toDispose.push(FindController.getFindController(editor).onStateChanged(() => this._update())); } @@ -522,10 +529,15 @@ export class SelectionHighlighter implements EditorCommon.IEditorContribution { this.removeDecorations(); return; } + + let model = this.editor.getModel(); if (r.nextMatch) { // This is an empty selection - this.removeDecorations(); - return; + if (OccurrencesRegistry.has(model)) { + // Do not interfere with semantic word highlighting in the no selection case + this.removeDecorations(); + return; + } } if (/^[ \t]+$/.test(r.searchText)) { // whitespace only selection @@ -538,7 +550,7 @@ export class SelectionHighlighter implements EditorCommon.IEditorContribution { return; } - let allMatches = this.editor.getModel().findMatches(r.searchText, true, r.isRegex, r.matchCase, r.wholeWord); + let allMatches = model.findMatches(r.searchText, true, r.isRegex, r.matchCase, r.wholeWord); allMatches.sort(Range.compareRangesUsingStarts); let selections = this.editor.getSelections(); @@ -594,6 +606,11 @@ CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(SelectHighl context: ContextKey.EditorFocus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_L })); +// register SelectHighlightsAction again to replace the now removed Change All action +CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(SelectHighlightsAction, SelectHighlightsAction.COMPAT_ID, nls.localize('changeAll.label', "Change All Occurrences"), { + context: ContextKey.EditorTextFocus, + primary: KeyMod.CtrlCmd | KeyCode.F2 +})); var CONTEXT_FIND_WIDGET_VISIBLE = 'findWidgetVisible'; diff --git a/src/vs/editor/contrib/rename/browser/rename.css b/src/vs/editor/contrib/rename/browser/rename.css index edd02c549e9..441fff1414f 100644 --- a/src/vs/editor/contrib/rename/browser/rename.css +++ b/src/vs/editor/contrib/rename/browser/rename.css @@ -2,8 +2,6 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-editor .linked-editing-placeholder { -} .monaco-editor .word-level-progress { font-style: italic; diff --git a/src/vs/editor/contrib/rename/browser/rename.ts b/src/vs/editor/contrib/rename/browser/rename.ts deleted file mode 100644 index 3b2ba539efe..00000000000 --- a/src/vs/editor/contrib/rename/browser/rename.ts +++ /dev/null @@ -1,328 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 'vs/css!./rename'; -import {TPromise} from 'vs/base/common/winjs.base'; -import nls = require('vs/nls'); -import {CommonEditorRegistry, ContextKey, EditorActionDescriptor} from 'vs/editor/common/editorCommonExtensions'; -import {EditorAction, Behaviour} from 'vs/editor/common/editorAction'; -import EditorCommon = require('vs/editor/common/editorCommon'); -import Modes = require('vs/editor/common/modes'); -import Severity from 'vs/base/common/severity'; -import EventEmitter = require('vs/base/common/eventEmitter'); -import {Range} from 'vs/editor/common/core/range'; -import {IMessageService} from 'vs/platform/message/common/message'; -import {IProgressService, IProgressRunner} from 'vs/platform/progress/common/progress'; -import {IKeybindingService, IKeybindingContextKey} from 'vs/platform/keybinding/common/keybindingService'; -import {KeyMod, KeyCode} from 'vs/base/common/keyCodes'; - -class LinkedEditingController { - - private editor: EditorCommon.ICommonCodeEditor; - private listenersToRemove:EventEmitter.ListenerUnbind[]; - private decorations:string[]; - private isDisposed: boolean; - private _onDispose: () => void; - - constructor(editor: EditorCommon.ICommonCodeEditor, selections: EditorCommon.ISelection[], ranges: EditorCommon.IRange[], onDispose: () => void) { - this._onDispose = onDispose; - this.editor = editor; - this.isDisposed = false; - - // Decorate editing ranges - this.editor.changeDecorations((changeAccessor:EditorCommon.IModelDecorationsChangeAccessor) => { - var newDecorations: EditorCommon.IModelDeltaDecoration[] = []; - for (var i = 0, len = selections.length; i < len; i++) { - var className = 'linked-editing-placeholder'; - newDecorations.push({ - range: ranges[i], - options: { - className: className - } - }); - } - - this.decorations = changeAccessor.deltaDecorations([], newDecorations); - }); - - // Begin linked editing (multi-cursor) - this.editor.setSelections(selections); - - this.listenersToRemove = []; - this.listenersToRemove.push(this.editor.addListener(EditorCommon.EventType.CursorPositionChanged, (e:EditorCommon.ICursorPositionChangedEvent) => { - if (this.isDisposed) { - return; - } - var cursorCount = 1 + e.secondaryPositions.length; - if (cursorCount !== this.decorations.length) { - this.dispose(); - } - })); - } - - public onEnterOrEscape(): boolean { - if (this.isDisposed) { - return; - } - // Basically cancel multi-cursor - this.editor.setSelection(this.editor.getSelection()); - this.dispose(); - return true; - } - - public dispose(): void { - if (this.isDisposed) { - return; - } - this.isDisposed = true; - this._onDispose(); - - this.decorations = this.editor.deltaDecorations(this.decorations, []); - - this.listenersToRemove.forEach((element) => { - element(); - }); - this.listenersToRemove = []; - } - -} - -class LocalProgressService implements IProgressService { - public serviceId = IProgressService; - - constructor(private _editor:EditorCommon.ICommonCodeEditor) { - // - } - - showWhile(promise:TPromise, delay?:number):TPromise { - - var decoration: string, - delayHandle: number; - - delayHandle = setTimeout(() => { - decoration = this._addDecoration(); - }, delay || 0); - - return promise.then((value) => { - clearTimeout(delayHandle); - this._removeDecoration(decoration); - return value; - }, (err) => { - clearTimeout(delayHandle); - this._removeDecoration(decoration); - throw err; - }); - } - - private _addDecoration():string { - - var position = this._editor.getPosition(), - word = this._editor.getModel().getWordAtPosition(position), - decorationId:string; - - var decorations = this._editor.deltaDecorations([], [{ - range: { - startLineNumber: position.lineNumber, - startColumn: word.startColumn, - endLineNumber: position.lineNumber, - endColumn: word.endColumn - }, - options: { - inlineClassName: 'word-level-progress' - } - }]); - - return decorations[0]; - } - - private _removeDecoration(decorationId:string):void { - if(decorationId) { - this._editor.changeDecorations((accessor) => { - accessor.deltaDecorations([decorationId], []); - }); - } - } - - public show(...args:any[]):IProgressRunner { - throw new Error('not implemented'); - } -} - -export class ChangeAllAction extends EditorAction { - - public static ID = 'editor.action.changeAll'; - - private _idPool:number; - private _messageService:IMessageService; - private _progressService: IProgressService; - private _currentController: LinkedEditingController; - private _changeAllMode: IKeybindingContextKey; - - constructor(descriptor:EditorCommon.IEditorActionDescriptorData, editor:EditorCommon.ICommonCodeEditor, @IMessageService messageService: IMessageService, @IKeybindingService keybindingService: IKeybindingService) { - super(descriptor, editor, Behaviour.WidgetFocus | Behaviour.Writeable | Behaviour.ShowInContextMenu | Behaviour.UpdateOnCursorPositionChange); - this._idPool = 0; - this._messageService = messageService; - this._progressService = new LocalProgressService(this.editor); - this._currentController = null; - this._changeAllMode = keybindingService.createKey(CONTEXT_CHANGE_ALL_MODE, false); - } - - public getGroupId(): string { - return '2_change/1_changeAll'; - } - - public isSupported():boolean { - var mode = this.editor.getModel().getMode(); - - return !!mode && !!mode.occurrencesSupport && super.isSupported(); - } - - public computeInfos(editor:EditorCommon.ICommonCodeEditor):TPromise { - var selection = editor.getSelection(); - var position = selection.getStartPosition(); - var model = editor.getModel(); - - return this.editor.getModel().getMode().occurrencesSupport.findOccurrences(model.getAssociatedResource(), position); - } - - public run():TPromise { - - var myId = ++this._idPool, - state = this.editor.captureState(EditorCommon.CodeEditorStateFlag.Position, EditorCommon.CodeEditorStateFlag.Value), - capturedSelection = this.editor.getSelection(), - infoPromise = this.computeInfos(this.editor); - - if(this._progressService) { - this._progressService.showWhile(infoPromise, 500); - } - - return infoPromise.then((infos:Modes.IOccurence[]) => { - - if(myId !== this._idPool) { - return; - } - - if(!state.validate(this.editor)) { - return; - } - - if(infos.length === 0) { - return; - } - - var ranges = infos.map((info) => { - return info.range; - }); - - this._beginLinkedEditing(ranges, capturedSelection); - - return true; - }, (e) => { - this._messageService.show(Severity.Info, e); - }); - } - - private _indexOf(ranges:EditorCommon.IRange[], lineNumber: number, column: number): number { - var pos = { - lineNumber: lineNumber, - column: column - }; - for (var i = 0; i < ranges.length; i++) { - if (ranges[i].startLineNumber !== lineNumber) { - // Only consider ranges that start on the same line as position - continue; - } - if (Range.containsPosition(ranges[i], pos)) { - return i; - } - } - return -1; - } - - private _beginLinkedEditing(ranges: EditorCommon.IRange[], capturedSelection: EditorCommon.IEditorSelection): void { - if (this._currentController) { - this._currentController.dispose(); - this._currentController = null; - } - var editorSelection = this.editor.getSelection(); - - // Try to find a suitable range for the current editor position - var foundRangeIndex = this._indexOf(ranges, editorSelection.positionLineNumber, editorSelection.positionColumn); - - if (foundRangeIndex === -1) { - // Current editor position is outside of one of these ranges, try again with the original editor position - editorSelection = capturedSelection; - foundRangeIndex = this._indexOf(ranges, editorSelection.positionLineNumber, editorSelection.positionColumn); - - if (foundRangeIndex === -1) { - // These ranges are bogus! - return; - } - } - - var hasSelectionInFoundRange = false; - if (!editorSelection.isEmpty()) { - if (Range.containsPosition(ranges[foundRangeIndex], { lineNumber: editorSelection.selectionStartLineNumber, column: editorSelection.selectionStartColumn})) { - hasSelectionInFoundRange = true; - } - } - - var deltaColumnForPosition: number, deltaColumnForStartSelection: number; - if (hasSelectionInFoundRange) { - deltaColumnForPosition = editorSelection.positionColumn - ranges[foundRangeIndex].startColumn; - deltaColumnForStartSelection = editorSelection.selectionStartColumn - ranges[foundRangeIndex].startColumn; - } else { - deltaColumnForPosition = ranges[foundRangeIndex].endColumn - ranges[foundRangeIndex].startColumn; - deltaColumnForStartSelection = 0; - } - - var newEditorSelections: EditorCommon.ISelection[] = []; - newEditorSelections.push({ - selectionStartLineNumber: ranges[foundRangeIndex].startLineNumber, - selectionStartColumn: ranges[foundRangeIndex].startColumn + deltaColumnForStartSelection, - positionLineNumber: ranges[foundRangeIndex].startLineNumber, - positionColumn: ranges[foundRangeIndex].startColumn + deltaColumnForPosition, - }); - - for (var i = 0; i < ranges.length; i++) { - if (i !== foundRangeIndex) { - newEditorSelections.push({ - selectionStartLineNumber: ranges[i].startLineNumber, - selectionStartColumn: ranges[i].startColumn + deltaColumnForStartSelection, - positionLineNumber: ranges[i].startLineNumber, - positionColumn: ranges[i].startColumn + deltaColumnForPosition, - }); - } - } - - this._changeAllMode.set(true); - this._currentController = new LinkedEditingController(this.editor, newEditorSelections, ranges, () => { - this._changeAllMode.reset(); - }); - } - - public leaveChangeAllMode(): void { - if (this._currentController) { - this._currentController.onEnterOrEscape(); - this._currentController = null; - } - } -} - -var CONTEXT_CHANGE_ALL_MODE = 'inChangeAllMode'; - -var weight = CommonEditorRegistry.commandWeight(30); - -// register actions -CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(ChangeAllAction, ChangeAllAction.ID, nls.localize('changeAll.label', "Change All Occurrences"), { - context: ContextKey.EditorTextFocus, - primary: KeyMod.CtrlCmd | KeyCode.F2 -})); -CommonEditorRegistry.registerEditorCommand('leaveChangeAllMode', weight, { primary: KeyCode.Enter, secondary: [KeyCode.Escape] }, true, CONTEXT_CHANGE_ALL_MODE,(ctx, editor, args) => { - var action = editor.getAction(ChangeAllAction.ID); - action.leaveChangeAllMode(); -}); \ No newline at end of file diff --git a/src/vs/languages/css/common/css.ts b/src/vs/languages/css/common/css.ts index 00e31d1ae45..cc7d1047f58 100644 --- a/src/vs/languages/css/common/css.ts +++ b/src/vs/languages/css/common/css.ts @@ -285,6 +285,7 @@ export class CSSMode extends AbstractMode { public referenceSupport: Modes.IReferenceSupport; public logicalSelectionSupport: Modes.ILogicalSelectionSupport; public extraInfoSupport:Modes.IExtraInfoSupport; + public occurrencesSupport:Modes.IOccurrencesSupport; public outlineSupport: Modes.IOutlineSupport; public declarationSupport: Modes.IDeclarationSupport; public suggestSupport: Modes.ISuggestSupport; @@ -305,6 +306,7 @@ export class CSSMode extends AbstractMode { { tokenType: 'punctuation.bracket.css', open: '{', close: '}', isElectric: true } ] }); + this.occurrencesSupport = this; this.extraInfoSupport = this; this.referenceSupport = new supports.ReferenceSupport(this, { tokens: [cssTokenTypes.TOKEN_PROPERTY + '.css', cssTokenTypes.TOKEN_VALUE + '.css', cssTokenTypes.TOKEN_SELECTOR_TAG + '.css'], @@ -344,6 +346,11 @@ export class CSSMode extends AbstractMode { return createAsyncDescriptor2('vs/languages/css/common/cssWorker', 'CSSWorker'); } + static $findOccurrences = OneWorkerAttr(CSSMode, CSSMode.prototype.findOccurrences); + public findOccurrences(resource:URI, position:EditorCommon.IPosition, strict:boolean = false): WinJS.TPromise { + return this._worker((w) => w.findOccurrences(resource, position, strict)); + } + static $findDeclaration = OneWorkerAttr(CSSMode, CSSMode.prototype.findDeclaration); public findDeclaration(resource:URI, position:EditorCommon.IPosition):WinJS.TPromise { return this._worker((w) => w.findDeclaration(resource, position)); diff --git a/src/vs/languages/html/common/html.ts b/src/vs/languages/html/common/html.ts index ba29d1b44e4..bcfdf9f816f 100644 --- a/src/vs/languages/html/common/html.ts +++ b/src/vs/languages/html/common/html.ts @@ -277,6 +277,7 @@ export class HTMLMode extends AbstractMode i public characterPairSupport: Modes.ICharacterPairSupport; public extraInfoSupport:Modes.IExtraInfoSupport; + public occurrencesSupport:Modes.IOccurrencesSupport; public referenceSupport: Modes.IReferenceSupport; public logicalSelectionSupport: Modes.ILogicalSelectionSupport; public formattingSupport: Modes.IFormattingSupport; @@ -311,6 +312,7 @@ export class HTMLMode extends AbstractMode i this.formattingSupport = this; this.extraInfoSupport = this; + this.occurrencesSupport = this; this.referenceSupport = new supports.ReferenceSupport(this, { tokens: ['invalid'], findReferences: (resource, position, includeDeclaration) => this.findReferences(resource, position, includeDeclaration)}); diff --git a/src/vs/languages/typescript/common/typescriptMode.ts b/src/vs/languages/typescript/common/typescriptMode.ts index 51df468c30a..4cfa4cff3da 100644 --- a/src/vs/languages/typescript/common/typescriptMode.ts +++ b/src/vs/languages/typescript/common/typescriptMode.ts @@ -132,6 +132,7 @@ export class TypeScriptMode extend public characterPairSupport: Modes.ICharacterPairSupport; public referenceSupport: Modes.IReferenceSupport; public extraInfoSupport:Modes.IExtraInfoSupport; + public occurrencesSupport:Modes.IOccurrencesSupport; public quickFixSupport:Modes.IQuickFixSupport; public logicalSelectionSupport:Modes.ILogicalSelectionSupport; public parameterHintsSupport:Modes.IParameterHintsSupport; @@ -185,6 +186,7 @@ export class TypeScriptMode extend } this.extraInfoSupport = this; + this.occurrencesSupport = this; this.formattingSupport = this; this.quickFixSupport = this; this.logicalSelectionSupport = this; -- GitLab