Skip to content

Commit

Permalink
Merge pull request #35740 from Krzysztof-Cieslak/navigate_highlighter
Browse files Browse the repository at this point in the history
Navigate to next/previous symbolic match in file
  • Loading branch information
alexdima authored Oct 24, 2017
2 parents 83f8225 + 9f632d5 commit 1ba59fa
Showing 1 changed file with 127 additions and 5 deletions.
132 changes: 127 additions & 5 deletions src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,28 @@ import { onUnexpectedExternalError } from 'vs/base/common/errors';
import { TPromise } from 'vs/base/common/winjs.base';
import { Range } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { CommonEditorRegistry, commonEditorContribution } from 'vs/editor/common/editorCommonExtensions';
import { CommonEditorRegistry, commonEditorContribution, EditorAction, IActionOptions, editorAction } from 'vs/editor/common/editorCommonExtensions';
import { DocumentHighlight, DocumentHighlightKind, DocumentHighlightProviderRegistry } from 'vs/editor/common/modes';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Position } from 'vs/editor/common/core/position';
import { registerColor, editorSelectionHighlight, activeContrastBorder, overviewRulerSelectionHighlightForeground } from 'vs/platform/theme/common/colorRegistry';
import { registerThemingParticipant, themeColorFromId } from 'vs/platform/theme/common/themeService';
import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations';
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { firstIndex } from 'vs/base/common/arrays';

export const editorWordHighlight = registerColor('editor.wordHighlightBackground', { dark: '#575757B8', light: '#57575740', hc: null }, nls.localize('wordHighlight', 'Background color of a symbol during read-access, like reading a variable.'));
export const editorWordHighlightStrong = registerColor('editor.wordHighlightStrongBackground', { dark: '#004972B8', light: '#0e639c40', hc: null }, nls.localize('wordHighlightStrong', 'Background color of a symbol during write-access, like writing to a variable.'));

export const overviewRulerWordHighlightForeground = registerColor('editorOverviewRuler.wordHighlightForeground', { dark: '#A0A0A0', light: '#A0A0A0', hc: '#A0A0A0' }, nls.localize('overviewRulerWordHighlightForeground', 'Overview ruler marker color for symbol highlights.'));
export const overviewRulerWordHighlightStrongForeground = registerColor('editorOverviewRuler.wordHighlightStrongForeground', { dark: '#C0A0C0', light: '#C0A0C0', hc: '#C0A0C0' }, nls.localize('overviewRulerWordHighlightStrongForeground', 'Overview ruler marker color for write-access symbol highlights.'));

export const ctxHasWordHighlights = new RawContextKey<boolean>('hasWordHighlights', false);

export function getOccurrencesAtPosition(model: editorCommon.IReadOnlyModel, position: Position): TPromise<DocumentHighlight[]> {

const orderedByScore = DocumentHighlightProviderRegistry.ordered(model);
Expand Down Expand Up @@ -76,13 +83,23 @@ class WordHighlighter {
private lastCursorPositionChangeTime: number = 0;
private renderDecorationsTimer: number = -1;

constructor(editor: editorCommon.ICommonCodeEditor) {
private _hasWordHighlights: IContextKey<boolean>;
private _ignorePositionChangeEvent: boolean;

constructor(editor: editorCommon.ICommonCodeEditor, contextKeyService: IContextKeyService) {
this.editor = editor;
this._hasWordHighlights = ctxHasWordHighlights.bindTo(contextKeyService);
this._ignorePositionChangeEvent = false;
this.occurrencesHighlight = this.editor.getConfiguration().contribInfo.occurrencesHighlight;
this.model = this.editor.getModel();
this.toUnhook = [];
this.toUnhook.push(editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => {

if (this._ignorePositionChangeEvent) {
// We are changing the position => ignore this event
return;
}

if (!this.occurrencesHighlight) {
// Early exit if nothing needs to be done!
// Leave some form of early exit check here if you wish to continue being a cursor position change listener ;)
Expand Down Expand Up @@ -127,10 +144,45 @@ class WordHighlighter {
this._run();
}

private _getSortedHighlights(): Range[] {
return this._decorationIds
.map((id) => this.model.getDecorationRange(id))
.sort(Range.compareRangesUsingStarts);
}

public moveNext() {
let highlights = this._getSortedHighlights();
let index = firstIndex(highlights, (range) => range.containsPosition(this.editor.getPosition()));
let newIndex = ((index + 1) % highlights.length);
let dest = highlights[newIndex];
try {
this._ignorePositionChangeEvent = true;
this.editor.setPosition(dest.getStartPosition());
this.editor.revealRangeInCenter(dest);
} finally {
this._ignorePositionChangeEvent = false;
}
}

public moveBack() {
let highlights = this._getSortedHighlights();
let index = firstIndex(highlights, (range) => range.containsPosition(this.editor.getPosition()));
let newIndex = ((index - 1 + highlights.length) % highlights.length);
let dest = highlights[newIndex];
try {
this._ignorePositionChangeEvent = true;
this.editor.setPosition(dest.getStartPosition());
this.editor.revealRangeInCenter(dest);
} finally {
this._ignorePositionChangeEvent = false;
}
}

private _removeDecorations(): void {
if (this._decorationIds.length > 0) {
// remove decorations
this._decorationIds = this.editor.deltaDecorations(this._decorationIds, []);
this._hasWordHighlights.set(false);
}
}

Expand Down Expand Up @@ -296,6 +348,7 @@ class WordHighlighter {
}

this._decorationIds = this.editor.deltaDecorations(this._decorationIds, decorations);
this._hasWordHighlights.set(this.hasDecorations());
}

private static _getDecorationOptions(kind: DocumentHighlightKind): ModelDecorationOptions {
Expand Down Expand Up @@ -344,15 +397,21 @@ class WordHighlighter {
}
}



@commonEditorContribution
class WordHighlighterContribution implements editorCommon.IEditorContribution {

private static ID = 'editor.contrib.wordHighlighter';

public static get(editor: editorCommon.ICommonCodeEditor): WordHighlighterContribution {
return editor.getContribution<WordHighlighterContribution>(WordHighlighterContribution.ID);
}

private wordHighligher: WordHighlighter;

constructor(editor: editorCommon.ICommonCodeEditor) {
this.wordHighligher = new WordHighlighter(editor);
constructor(editor: editorCommon.ICommonCodeEditor, @IContextKeyService contextKeyService: IContextKeyService) {
this.wordHighligher = new WordHighlighter(editor, contextKeyService);
}

public getId(): string {
Expand All @@ -366,6 +425,14 @@ class WordHighlighterContribution implements editorCommon.IEditorContribution {
return false;
}

public moveNext() {
this.wordHighligher.moveNext();
}

public moveBack() {
this.wordHighligher.moveBack();
}

public restoreViewState(state: boolean | undefined): void {
if (state) {
this.wordHighligher.restore();
Expand Down Expand Up @@ -398,4 +465,59 @@ registerThemingParticipant((theme, collector) => {
collector.addRule(`.monaco-editor .wordHighlightStrong { border: 1px dashed ${hcOutline}; box-sizing: border-box; }`);
}

});
});

class WordHighlightNavigationAction extends EditorAction {

private _isNext: boolean;

constructor(next: boolean, opts: IActionOptions) {
super(opts);
this._isNext = next;
}

public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void {
const controller = WordHighlighterContribution.get(editor);
if (!controller) {
return;
}

if (this._isNext) {
controller.moveNext();
} else {
controller.moveBack();
}
}
}

@editorAction
class NextWordHighlightAction extends WordHighlightNavigationAction {
constructor() {
super(true, {
id: 'editor.action.wordHighlight.next',
label: nls.localize('wordHighlight.next.label', "Go to Next Symbol Highlight"),
alias: 'Go to Next Symbol Highlight',
precondition: ctxHasWordHighlights,
kbOpts: {
kbExpr: EditorContextKeys.textFocus,
primary: KeyCode.F7
}
});
}
}

@editorAction
class PrevWordHighlightAction extends WordHighlightNavigationAction {
constructor() {
super(false, {
id: 'editor.action.wordHighlight.prev',
label: nls.localize('wordHighlight.previous.label', "Go to Previous Symbol Highlight"),
alias: 'Go to Previous Symbol Highlight',
precondition: ctxHasWordHighlights,
kbOpts: {
kbExpr: EditorContextKeys.textFocus,
primary: KeyMod.Shift | KeyCode.F7
}
});
}
}

0 comments on commit 1ba59fa

Please sign in to comment.