Adopting EditorAction2 in editor/contrib/quickOpen

This commit is contained in:
Alex Dima 2016-08-04 14:47:51 +02:00
parent 663ba127d9
commit 952405e9df
7 changed files with 181 additions and 216 deletions

View file

@ -4,22 +4,19 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import {QuickOpenModel} from 'vs/base/parts/quickopen/browser/quickOpenModel';
import {IAutoFocus} from 'vs/base/parts/quickopen/common/quickOpen';
import {EditorAction} from 'vs/editor/common/editorAction';
import {Behaviour} from 'vs/editor/common/editorActionEnablement';
import * as editorCommon from 'vs/editor/common/editorCommon';
import {ICodeEditor} from 'vs/editor/browser/editorBrowser';
import {EditorBrowserRegistry} from 'vs/editor/browser/editorBrowserExtensions';
import {QuickOpenEditorWidget} from './quickOpenEditorWidget';
import {Selection} from 'vs/editor/common/core/selection';
import {EditorAction2} from 'vs/editor/common/editorCommonExtensions';
export interface IQuickOpenControllerOpts {
inputAriaLabel: string;
getModel(value:string):QuickOpenModel;
getAutoFocus(searchValue:string):IAutoFocus;
onClose(canceled:boolean):void;
}
export class QuickOpenController implements editorCommon.IEditorContribution {
@ -56,43 +53,41 @@ export class QuickOpenController implements editorCommon.IEditorContribution {
this.widget.destroy();
this.widget = null;
}
// Create goto line widget
if (!this.widget) {
let onClose = (canceled:boolean) => {
// Clear Highlight Decorations if present
this.clearDecorations();
let onClose = (canceled:boolean) => {
// Clear Highlight Decorations if present
this.clearDecorations();
// Restore selection if canceled
if (canceled && this.lastKnownEditorSelection) {
this.editor.setSelection(this.lastKnownEditorSelection);
this.editor.revealRangeInCenterIfOutsideViewport(this.lastKnownEditorSelection);
}
// Restore selection if canceled
if (canceled && this.lastKnownEditorSelection) {
this.editor.setSelection(this.lastKnownEditorSelection);
this.editor.revealRangeInCenterIfOutsideViewport(this.lastKnownEditorSelection);
}
this.lastKnownEditorSelection = null;
this.editor.focus();
this.lastKnownEditorSelection = null;
this.editor.focus();
};
opts.onClose(canceled);
};
this.widget = new QuickOpenEditorWidget(
this.editor,
() => onClose(false),
() => onClose(true),
(value:string)=>{
this.widget.setInput(opts.getModel(value), opts.getAutoFocus(value));
},
{
inputAriaLabel: opts.inputAriaLabel
}
);
// Show
this.widget.show('');
}
this.widget = new QuickOpenEditorWidget(
this.editor,
() => onClose(false),
() => onClose(true),
(value:string)=>{
this.widget.setInput(opts.getModel(value), opts.getAutoFocus(value));
},
{
inputAriaLabel: opts.inputAriaLabel
}
);
// Remember selection to be able to restore on cancel
if (!this.lastKnownEditorSelection) {
this.lastKnownEditorSelection = this.editor.getSelection();
}
// Show
this.widget.show('');
}
public decorateLine(range:editorCommon.IRange, editor:ICodeEditor):void {
@ -128,55 +123,40 @@ export class QuickOpenController implements editorCommon.IEditorContribution {
}
}
// export abstract class
export interface IQuickOpenOpts {
/**
* provide the quick open model for the given search value.
*/
getModel(value:string):QuickOpenModel;
/**
* provide the quick open auto focus mode for the given search value.
*/
getAutoFocus(searchValue:string):IAutoFocus;
}
/**
* Base class for providing quick open in the editor.
*/
export class BaseEditorQuickOpenAction extends EditorAction {
export abstract class BaseEditorQuickOpenAction extends EditorAction2 {
protected controller:QuickOpenController;
private _inputAriaLabel:string;
constructor(descriptor:editorCommon.IEditorActionDescriptorData, editor:editorCommon.ICommonCodeEditor, label:string, condition:Behaviour = Behaviour.WidgetFocus) {
super(descriptor, editor, condition);
this.label = label;
this.controller = QuickOpenController.get(this.editor);
constructor(id:string, label:string, alias:string, inputAriaLabel:string) {
super(id, label, alias, false);
this._inputAriaLabel = inputAriaLabel;
}
public run():TPromise<boolean> {
QuickOpenController.get(this.editor).run({
inputAriaLabel: this._getInputAriaLabel(),
getModel: (value:string):QuickOpenModel => this._getModel(value),
getAutoFocus: (searchValue:string):IAutoFocus => this._getAutoFocus(searchValue),
onClose: (canceled) => this._onClose(canceled)
protected getController(editor:editorCommon.ICommonCodeEditor): QuickOpenController {
return QuickOpenController.get(editor);
}
protected _show(controller:QuickOpenController, opts:IQuickOpenOpts): void {
controller.run({
inputAriaLabel: this._inputAriaLabel,
getModel: (value:string):QuickOpenModel => opts.getModel(value),
getAutoFocus: (searchValue:string):IAutoFocus => opts.getAutoFocus(searchValue)
});
return TPromise.as(true);
}
/**
* Subclasses to override to provide the quick open model for the given search value.
*/
_getModel(value:string):QuickOpenModel {
throw new Error('Subclasses to implement');
}
/**
* Subclasses to override to provide the quick open auto focus mode for the given search value.
*/
_getAutoFocus(searchValue:string):IAutoFocus {
throw new Error('Subclasses to implement');
}
_getInputAriaLabel(): string {
throw new Error('Subclasses to implement');
}
/**
* Subclasses can override this to participate in the close of quick open.
*/
_onClose(canceled:boolean):void {
}
}

View file

@ -4,14 +4,8 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as nls from 'vs/nls';
import {KeyCode, KeyMod} from 'vs/base/common/keyCodes';
import {CommonEditorRegistry, ContextKey, EditorActionDescriptor} from 'vs/editor/common/editorCommonExtensions';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
import {GotoLineAction} from './gotoLine';
// Contribute Ctrl+G to "Go to line" using quick open
CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(GotoLineAction, GotoLineAction.ID, nls.localize('label', "Go to Line..."), {
context: ContextKey.EditorFocus,
primary: KeyMod.CtrlCmd | KeyCode.KEY_G,
mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_G }
}, 'Go to Line...'));
CommonEditorRegistry.registerEditorAction2(new GotoLineAction());

View file

@ -12,6 +12,8 @@ import {IAutoFocus, Mode} from 'vs/base/parts/quickopen/common/quickOpen';
import * as editorCommon from 'vs/editor/common/editorCommon';
import {ICodeEditor, IDiffEditor} from 'vs/editor/browser/editorBrowser';
import {BaseEditorQuickOpenAction, IDecorator} from './editorQuickOpen';
import {EditorKbExpr, ServicesAccessor} from 'vs/editor/common/editorCommonExtensions';
import {KeyCode, KeyMod} from 'vs/base/common/keyCodes';
interface ParseResult {
position: editorCommon.IPosition;
@ -147,23 +149,32 @@ export class GotoLineEntry extends QuickOpenEntry {
export class GotoLineAction extends BaseEditorQuickOpenAction {
public static ID = 'editor.action.gotoLine';
constructor() {
super(
'editor.action.gotoLine',
nls.localize('GotoLineAction.label', "Go to Line..."),
'Go to Line...',
nls.localize('gotoLineActionInput', "Type a line number, followed by an optional colon and a column number to navigate to")
);
constructor(descriptor: editorCommon.IEditorActionDescriptorData, editor: editorCommon.ICommonCodeEditor) {
super(descriptor, editor, nls.localize('GotoLineAction.label', "Go to Line..."));
}
_getModel(value: string): QuickOpenModel {
return new QuickOpenModel([new GotoLineEntry(value, this.editor, this.controller)]);
}
_getAutoFocus(searchValue: string): IAutoFocus {
return {
autoFocusFirstEntry: searchValue.length > 0
this.kbOpts = {
kbExpr: EditorKbExpr.Focus,
primary: KeyMod.CtrlCmd | KeyCode.KEY_G,
mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_G }
};
}
_getInputAriaLabel(): string {
return nls.localize('gotoLineActionInput', "Type a line number, followed by an optional colon and a column number to navigate to");
public run(accessor:ServicesAccessor, editor:editorCommon.ICommonCodeEditor): void {
this._show(this.getController(editor), {
getModel: (value:string):QuickOpenModel => {
return new QuickOpenModel([new GotoLineEntry(value, editor, this.getController(editor))]);
},
getAutoFocus: (searchValue:string):IAutoFocus => {
return {
autoFocusFirstEntry: searchValue.length > 0
};
}
});
}
}
}

View file

@ -4,25 +4,8 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as nls from 'vs/nls';
import {KeyCode, KeyMod} from 'vs/base/common/keyCodes';
import * as browser from 'vs/base/browser/browser';
import {KbExpr} from 'vs/platform/keybinding/common/keybinding';
import {KEYBINDING_CONTEXT_EDITOR_FOCUS} from 'vs/editor/common/editorCommon';
import {CommonEditorRegistry, ContextKey} from 'vs/editor/common/editorCommonExtensions';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
import {QuickCommandAction} from './quickCommand';
// Contribute "Quick Command" to context menu
CommonEditorRegistry.registerEditorAction({
ctor: QuickCommandAction,
id: QuickCommandAction.ID,
label: nls.localize('label', "Command Palette"),
alias: 'Command Palette',
kbOpts: {
context: ContextKey.EditorFocus,
primary: (browser.isIE11orEarlier ? KeyMod.Alt | KeyCode.F1 : KeyCode.F1)
},
menuOpts: {
kbExpr: KbExpr.has(KEYBINDING_CONTEXT_EDITOR_FOCUS)
}
});
CommonEditorRegistry.registerEditorAction2(new QuickCommandAction());

View file

@ -12,8 +12,11 @@ import {TPromise} from 'vs/base/common/winjs.base';
import {IContext, IHighlight, QuickOpenEntryGroup, QuickOpenModel} from 'vs/base/parts/quickopen/browser/quickOpenModel';
import {IAutoFocus, Mode} from 'vs/base/parts/quickopen/common/quickOpen';
import {IKeybindingService} from 'vs/platform/keybinding/common/keybinding';
import {ICommonCodeEditor, IEditor, IEditorActionDescriptorData} from 'vs/editor/common/editorCommon';
import {ICommonCodeEditor, IEditor} from 'vs/editor/common/editorCommon';
import {BaseEditorQuickOpenAction} from './editorQuickOpen';
import {EditorKbExpr, ServicesAccessor} from 'vs/editor/common/editorCommonExtensions';
import {KeyCode, KeyMod} from 'vs/base/common/keyCodes';
import * as browser from 'vs/base/browser/browser';
export class EditorActionCommandEntry extends QuickOpenEntryGroup {
private key: string;
@ -69,38 +72,61 @@ export class EditorActionCommandEntry extends QuickOpenEntryGroup {
export class QuickCommandAction extends BaseEditorQuickOpenAction {
public static ID = 'editor.action.quickCommand';
constructor() {
super(
'editor.action.quickCommand',
nls.localize('QuickCommandAction.label', "Command Palette"),
'Command Palette',
nls.localize('quickCommandActionInput', "Type the name of an action you want to execute")
);
private _keybindingService: IKeybindingService;
this.kbOpts = {
kbExpr: EditorKbExpr.Focus,
primary: (browser.isIE11orEarlier ? KeyMod.Alt | KeyCode.F1 : KeyCode.F1)
};
constructor(descriptor: IEditorActionDescriptorData, editor: ICommonCodeEditor, @IKeybindingService keybindingService: IKeybindingService) {
super(descriptor, editor, nls.localize('QuickCommandAction.label', "Command Palette"));
this._keybindingService = keybindingService;
this.menuOpts = {
kbExpr: EditorKbExpr.Focus
};
}
_getModel(value: string): QuickOpenModel {
return new QuickOpenModel(this._editorActionsToEntries(this.editor.getSupportedActions(), value));
public run(accessor:ServicesAccessor, editor:ICommonCodeEditor): void {
const keybindingService = accessor.get(IKeybindingService);
this._show(this.getController(editor), {
getModel: (value:string):QuickOpenModel => {
return new QuickOpenModel(this._editorActionsToEntries(keybindingService, editor, value));
},
getAutoFocus: (searchValue:string):IAutoFocus => {
return {
autoFocusFirstEntry: true,
autoFocusPrefixMatch: searchValue
};
}
});
}
_sort(elementA: QuickOpenEntryGroup, elementB: QuickOpenEntryGroup): number {
private _sort(elementA: QuickOpenEntryGroup, elementB: QuickOpenEntryGroup): number {
let elementAName = elementA.getLabel().toLowerCase();
let elementBName = elementB.getLabel().toLowerCase();
return elementAName.localeCompare(elementBName);
}
_editorActionsToEntries(actions: IAction[], searchValue: string): EditorActionCommandEntry[] {
private _editorActionsToEntries(keybindingService:IKeybindingService, editor:ICommonCodeEditor, searchValue: string): EditorActionCommandEntry[] {
let actions: IAction[] = editor.getSupportedActions();
let entries: EditorActionCommandEntry[] = [];
for (let i = 0; i < actions.length; i++) {
let action = actions[i];
let keys = this._keybindingService.lookupKeybindings(action.id).map(k => this._keybindingService.getLabelFor(k));
let keys = keybindingService.lookupKeybindings(action.id).map(k => keybindingService.getLabelFor(k));
if (action.label) {
let highlights = matchesFuzzy(searchValue, action.label);
if (highlights) {
entries.push(new EditorActionCommandEntry(keys.length > 0 ? keys.join(', ') : '', highlights, action, this.editor));
entries.push(new EditorActionCommandEntry(keys.length > 0 ? keys.join(', ') : '', highlights, action, editor));
}
}
}
@ -110,15 +136,4 @@ export class QuickCommandAction extends BaseEditorQuickOpenAction {
return entries;
}
_getAutoFocus(searchValue: string): IAutoFocus {
return {
autoFocusFirstEntry: true,
autoFocusPrefixMatch: searchValue
};
}
_getInputAriaLabel(): string {
return nls.localize('quickCommandActionInput', "Type the name of an action you want to execute");
}
}
}

View file

@ -4,26 +4,8 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as nls from 'vs/nls';
import {KeyCode, KeyMod} from 'vs/base/common/keyCodes';
import {KbExpr} from 'vs/platform/keybinding/common/keybinding';
import {ModeContextKeys} from 'vs/editor/common/editorCommon';
import {CommonEditorRegistry, ContextKey} from 'vs/editor/common/editorCommonExtensions';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
import {QuickOutlineAction} from './quickOutline';
// Contribute "Quick Outline" to context menu
CommonEditorRegistry.registerEditorAction({
ctor: QuickOutlineAction,
id: QuickOutlineAction.ID,
label: nls.localize('label', "Go to Symbol..."),
alias: 'Go to Symbol...',
kbOpts: {
context: ContextKey.EditorFocus,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_O
},
menuOpts: {
group: 'navigation',
order: 3,
kbExpr: KbExpr.and(KbExpr.has(ModeContextKeys.hasDocumentSymbolProvider))
}
});
CommonEditorRegistry.registerEditorAction2(new QuickOutlineAction());

View file

@ -8,16 +8,19 @@
import 'vs/css!./quickOutline';
import * as nls from 'vs/nls';
import {onUnexpectedError} from 'vs/base/common/errors';
import {matchesFuzzy} from 'vs/base/common/filters';
import * as strings from 'vs/base/common/strings';
import {TPromise} from 'vs/base/common/winjs.base';
import {IContext, IHighlight, QuickOpenEntryGroup, QuickOpenModel} from 'vs/base/parts/quickopen/browser/quickOpenModel';
import {IAutoFocus, Mode} from 'vs/base/parts/quickopen/common/quickOpen';
import {ICommonCodeEditor, IEditorActionDescriptorData, IRange} from 'vs/editor/common/editorCommon';
import {ICommonCodeEditor, IRange} from 'vs/editor/common/editorCommon';
import {SymbolInformation, SymbolKind, DocumentSymbolProviderRegistry} from 'vs/editor/common/modes';
import {BaseEditorQuickOpenAction, IDecorator} from './editorQuickOpen';
import {getDocumentSymbols, IOutline} from 'vs/editor/contrib/quickOpen/common/quickOpen';
import {EditorKbExpr, ServicesAccessor} from 'vs/editor/common/editorCommonExtensions';
import {KeyCode, KeyMod} from 'vs/base/common/keyCodes';
import {KbExpr} from 'vs/platform/keybinding/common/keybinding';
import {ModeContextKeys} from 'vs/editor/common/editorCommon';
let SCOPE_PREFIX = ':';
@ -108,64 +111,75 @@ class SymbolEntry extends QuickOpenEntryGroup {
export class QuickOutlineAction extends BaseEditorQuickOpenAction {
public static ID = 'editor.action.quickOutline';
constructor() {
super(
'editor.action.quickOutline',
nls.localize('QuickOutlineAction.label', "Go to Symbol..."),
'Go to Symbol...',
nls.localize('quickOutlineActionInput', "Type the name of an identifier you wish to navigate to")
);
private cachedResult: SymbolInformation[];
this.kbOpts = {
kbExpr: EditorKbExpr.Focus,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_O
};
constructor(descriptor: IEditorActionDescriptorData, editor: ICommonCodeEditor) {
super(descriptor, editor, nls.localize('QuickOutlineAction.label', "Go to Symbol..."));
}
public isSupported(): boolean {
return DocumentSymbolProviderRegistry.has(this.editor.getModel()) && super.isSupported();
this.menuOpts = {
group: 'navigation',
order: 3,
kbExpr: KbExpr.and(KbExpr.has(ModeContextKeys.hasDocumentSymbolProvider))
};
}
public run(): TPromise<boolean> {
let model = this.editor.getModel();
public supported(accessor:ServicesAccessor, editor:ICommonCodeEditor): boolean {
if (!super.supported(accessor, editor)) {
return false;
}
return DocumentSymbolProviderRegistry.has(editor.getModel());
}
public run(accessor:ServicesAccessor, editor:ICommonCodeEditor): TPromise<void> {
let model = editor.getModel();
if (!DocumentSymbolProviderRegistry.has(model)) {
return null;
}
// Resolve outline
let promise = getDocumentSymbols(model);
return promise.then((result: IOutline) => {
if (result.entries.length > 0) {
// Cache result
this.cachedResult = result.entries;
return super.run();
return getDocumentSymbols(model).then((result: IOutline) => {
if (result.entries.length === 0) {
return;
}
return TPromise.as(true);
}, (err) => {
onUnexpectedError(err);
return false;
this._run(editor, result.entries);
});
}
_getModel(value: string): QuickOpenModel {
return new QuickOpenModel(this.toQuickOpenEntries(this.cachedResult, value));
private _run(editor:ICommonCodeEditor, result:SymbolInformation[]): void {
this._show(this.getController(editor), {
getModel: (value:string):QuickOpenModel => {
return new QuickOpenModel(this.toQuickOpenEntries(editor, result, value));
},
getAutoFocus: (searchValue:string):IAutoFocus => {
// Remove any type pattern (:) from search value as needed
if (searchValue.indexOf(SCOPE_PREFIX) === 0) {
searchValue = searchValue.substr(SCOPE_PREFIX.length);
}
return {
autoFocusPrefixMatch: searchValue,
autoFocusFirstEntry: !!searchValue
};
}
});
}
_getAutoFocus(searchValue: string): IAutoFocus {
private toQuickOpenEntries(editor:ICommonCodeEditor, flattened: SymbolInformation[], searchValue: string): SymbolEntry[] {
const controller = this.getController(editor);
// Remove any type pattern (:) from search value as needed
if (searchValue.indexOf(SCOPE_PREFIX) === 0) {
searchValue = searchValue.substr(SCOPE_PREFIX.length);
}
return {
autoFocusPrefixMatch: searchValue,
autoFocusFirstEntry: !!searchValue
};
}
_getInputAriaLabel(): string {
return nls.localize('quickOutlineActionInput', "Type the name of an identifier you wish to navigate to");
}
private toQuickOpenEntries(flattened: SymbolInformation[], searchValue: string): SymbolEntry[] {
let results: SymbolEntry[] = [];
// Convert to Entries
@ -189,7 +203,7 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction {
}
// Add
results.push(new SymbolEntry(label, SymbolKind.from(element.kind), description, element.location.range, highlights, this.editor, this.controller));
results.push(new SymbolEntry(label, SymbolKind.from(element.kind), description, element.location.range, highlights, editor, controller));
}
}
@ -309,18 +323,4 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction {
let elementBRange = elementB.getRange();
return elementARange.startLineNumber - elementBRange.startLineNumber;
}
_onClose(canceled: boolean): void {
super._onClose(canceled);
// Clear Cache
this.cachedResult = null;
}
public dispose(): void {
super.dispose();
// Clear Cache
this.cachedResult = null;
}
}
}