提交 a3e4cc1b 编写于 作者: J Johannes Rieken

Merge pull request #870 from Microsoft/joh/commands

Joh/commands
......@@ -29,7 +29,7 @@ var currentDynamicContrib:IMarshallingContribution = null;
export function canSerialize(obj: any): boolean {
for (let contrib of marshallingContributions) {
if (contrib.canDeserialize(obj)) {
if (contrib.canSerialize(obj)) {
return true;
}
}
......
......@@ -54,7 +54,7 @@ export class Position implements EditorCommon.IEditorPosition {
return new Position(pos.lineNumber, pos.column);
}
public static isIPosition(obj: any): boolean {
public static isIPosition(obj: any): obj is EditorCommon.IPosition {
return (
obj
&& (typeof obj.lineNumber === 'number')
......
......@@ -90,7 +90,7 @@ export class Range implements EditorCommon.IEditorRange {
return new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
}
public static isIRange(obj: any): boolean {
public static isIRange(obj: any): obj is EditorCommon.IRange {
return (
obj
&& (typeof obj.startLineNumber === 'number')
......
......@@ -5,10 +5,13 @@
'use strict';
import EditorCommon = require('vs/editor/common/editorCommon');
import {onUnexpectedError, illegalArgument} from 'vs/base/common/errors';
import URI from 'vs/base/common/uri';
import {Position} from 'vs/editor/common/core/position';
import {ServicesAccessor} from 'vs/platform/instantiation/common/instantiation';
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {IModelService} from 'vs/editor/common/services/modelService';
import {Registry} from 'vs/platform/platform';
import Errors = require('vs/base/common/errors');
import {KeybindingsRegistry,ICommandDescriptor} from 'vs/platform/keybinding/common/keybindingsRegistry';
import config = require('vs/editor/common/config/config');
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
......@@ -84,6 +87,38 @@ export module CommonEditorRegistry {
KeybindingsRegistry.registerCommandDesc(commandDesc);
}
export function registerLanguageCommand(id: string, handler: (accessor: ServicesAccessor, args: { [n: string]: any }) => any) {
KeybindingsRegistry.registerCommandDesc({
id,
handler(accessor, args: any[]) {
if (args && args.length > 1 || typeof args[0] !== 'object') {
throw illegalArgument();
}
return handler(accessor, args && args[0]);
},
weight: KeybindingsRegistry.WEIGHT.editorContrib(),
primary: undefined,
context: undefined,
});
}
export function registerDefaultLanguageCommand(id: string, handler: (model: EditorCommon.IModel, position: EditorCommon.IPosition, args: { [n: string]: any }) => any) {
registerLanguageCommand(id, function(accessor, args) {
const {resource, position} = args;
if (!URI.isURI(resource) || !Position.isIPosition(position)) {
throw illegalArgument();
}
const model = accessor.get(IModelService).getModel(resource);
if (!model) {
throw illegalArgument();
}
return handler(model, position, args);
});
}
}
class SimpleEditorContributionDescriptor implements EditorCommon.ICommonEditorContributionDescriptor {
......@@ -193,7 +228,7 @@ function triggerEditorActionGlobal(actionId: string, accessor: ServicesAccessor,
var action = activeEditor.getAction(actionId);
if (action) {
accessor.get(ITelemetryService).publicLog('editorActionInvoked', {name: action.label} );
action.run().done(null, Errors.onUnexpectedError);
action.run().done(null, onUnexpectedError);
}
return;
}
......
......@@ -808,8 +808,7 @@ export interface ICommand {
export interface ICodeLensSymbol {
range: EditorCommon.IRange;
id?: string;
kind?: string;
name?: string;
command?: ICommand;
}
/**
......@@ -817,7 +816,7 @@ export interface ICodeLensSymbol {
*/
export interface ICodeLensSupport {
findCodeLensSymbols(resource: URI): TPromise<ICodeLensSymbol[]>;
resolveCodeLensSymbol(resource: URI, symbol: ICodeLensSymbol): TPromise<ICommand>;
resolveCodeLensSymbol(resource: URI, symbol: ICodeLensSymbol): TPromise<ICodeLensSymbol>;
}
export interface ITaskSummary {
......
......@@ -103,16 +103,16 @@ class CodeLensContentWidget implements EditorBrowser.IContentWidget {
}
}
public withCommands(commands: Modes.ICommand[]): void {
public withCommands(symbols: Modes.ICodeLensSymbol[]): void {
this._commands = Object.create(null);
if (!commands || !commands.length) {
if (!symbols || !symbols.length) {
this._domNode.innerHTML = 'no commands';
return;
}
let html: string[] = [];
for (let i = 0; i < commands.length; i++) {
let command = commands[i];
for (let i = 0; i < symbols.length; i++) {
let command = symbols[i].command;
let part: string;
if (command.id) {
part = format('<a id={0}>{1}</a>', i, command.title);
......@@ -303,8 +303,8 @@ class CodeLens {
return this._data;
}
public updateCommands(commands: Modes.ICommand[], currentModelsVersionId: number): void {
this._contentWidget.withCommands(commands);
public updateCommands(symbols: Modes.ICodeLensSymbol[], currentModelsVersionId: number): void {
this._contentWidget.withCommands(symbols);
this._lastUpdateModelsVersionId = currentModelsVersionId;
}
......@@ -616,17 +616,15 @@ export class CodeLensContribution implements EditorCommon.IEditorContribution {
var resource = model.getAssociatedResource();
var promises = toResolve.map((request, i) => {
let commands = new Array<Modes.ICommand>(request.length);
let resolvedSymbols = new Array<Modes.ICodeLensSymbol>(request.length);
let promises = request.map((request, i) => {
return request.support.resolveCodeLensSymbol(resource, request.symbol).then(command => {
if (command) {
commands[i] = command;
}
return request.support.resolveCodeLensSymbol(resource, request.symbol).then(symbol => {
resolvedSymbols[i] = symbol;
});
});
return TPromise.join(promises).then(() => {
lenses[i].updateCommands(commands, currentModelsVersionId);
lenses[i].updateCommands(resolvedSymbols, currentModelsVersionId);
})
});
......
......@@ -5,13 +5,15 @@
'use strict';
import {onUnexpectedError} from 'vs/base/common/errors';
import {onUnexpectedError, illegalArgument} from 'vs/base/common/errors';
import URI from 'vs/base/common/uri';
import {IAction, Action} from 'vs/base/common/actions';
import {IModelService} from 'vs/editor/common/services/modelService';
import {TPromise} from 'vs/base/common/winjs.base';
import {IModel, IRange, IPosition} from 'vs/editor/common/editorCommon';
import {Range} from 'vs/editor/common/core/range';
import {ICodeLensSupport, ICodeLensSymbol, ICommand} from 'vs/editor/common/modes';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
export const CodeLensRegistry = new LanguageFeatureRegistry<ICodeLensSupport>('codeLensSupport');
......@@ -21,7 +23,7 @@ export interface ICodeLensData {
support: ICodeLensSupport;
}
export function getCodeLensData(model: IModel) {
export function getCodeLensData(model: IModel):TPromise<ICodeLensData[]> {
const symbols: ICodeLensData[] = [];
const promises = CodeLensRegistry.all(model).map(support => {
......@@ -38,4 +40,19 @@ export function getCodeLensData(model: IModel) {
});
return TPromise.join(promises).then(() => symbols);
}
\ No newline at end of file
}
CommonEditorRegistry.registerLanguageCommand('_executeCodeLensProvider', function(accessor, args) {
const {resource} = args;
if (!URI.isURI(resource)) {
throw illegalArgument();
}
const model = accessor.get(IModelService).getModel(resource);
if (!model) {
throw illegalArgument();
}
return getCodeLensData(model);
});
\ No newline at end of file
......@@ -5,10 +5,86 @@
'use strict';
import {IFormattingSupport} from 'vs/editor/common/modes';
import {IFormattingSupport, IFormattingOptions} from 'vs/editor/common/modes';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
import {onUnexpectedError, illegalArgument} from 'vs/base/common/errors';
import URI from 'vs/base/common/uri';
import {IAction, Action} from 'vs/base/common/actions';
import {IModelService} from 'vs/editor/common/services/modelService';
import {TPromise} from 'vs/base/common/winjs.base';
import {IModel, IRange, IPosition, ISingleEditOperation} from 'vs/editor/common/editorCommon';
import {Range} from 'vs/editor/common/core/range';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
export const FormatRegistry = new LanguageFeatureRegistry<IFormattingSupport>('formattingSupport');
export const FormatOnTypeRegistry = new LanguageFeatureRegistry<IFormattingSupport>('formattingSupport');
export {IFormattingSupport};
\ No newline at end of file
export {IFormattingSupport};
export function formatRange(model: IModel, range: IRange, options: IFormattingOptions): TPromise<ISingleEditOperation[]> {
const [support] = FormatRegistry.ordered(model);
if (!support) {
return TPromise.as(undefined);
}
return support.formatRange(model.getAssociatedResource(), range, options);
}
export function formatDocument(model: IModel, options: IFormattingOptions): TPromise<ISingleEditOperation[]> {
const [support] = FormatRegistry.ordered(model);
if (!support) {
return TPromise.as(undefined);
}
if (typeof support.formatDocument !== 'function') {
if (typeof support.formatRange === 'function') {
return formatRange(model, model.getFullModelRange(), options);
} else {
return TPromise.as(undefined);
}
}
return support.formatDocument(model.getAssociatedResource(), options);
}
export function formatAfterKeystroke(model: IModel, position: IPosition, ch: string, options: IFormattingOptions): TPromise<ISingleEditOperation[]> {
const [support] = FormatOnTypeRegistry.ordered(model);
if (!support) {
return TPromise.as(undefined);
}
if (support.autoFormatTriggerCharacters.indexOf(ch) < 0) {
return TPromise.as(undefined);
}
return support.formatAfterKeystroke(model.getAssociatedResource(), position, ch, options);
}
CommonEditorRegistry.registerLanguageCommand('_executeFormatRangeProvider', function(accessor, args) {
const {resource, range, options} = args;
if (!URI.isURI(resource) || !Range.isIRange(range)) {
throw illegalArgument();
}
const model = accessor.get(IModelService).getModel(resource);
if (!model) {
throw illegalArgument('resource');
}
return formatRange(model, range, options);
});
CommonEditorRegistry.registerLanguageCommand('_executeFormatDocumentProvider', function(accessor, args) {
const {resource, options} = args;
if (!URI.isURI(resource)) {
throw illegalArgument('resource');
}
const model = accessor.get(IModelService).getModel(resource);
if (!model) {
throw illegalArgument('resource');
}
return formatDocument(model, options)
});
CommonEditorRegistry.registerDefaultLanguageCommand('_executeFormatOnTypeProvider', function(model, position, args) {
const {ch, options } = args;
if (typeof ch !== 'string') {
throw illegalArgument('ch');
}
return formatAfterKeystroke(model, position, ch, options);
});
......@@ -15,7 +15,7 @@ import formatCommand = require('./formatCommand');
import {Range} from 'vs/editor/common/core/range';
import {INullService} from 'vs/platform/instantiation/common/instantiation';
import {KeyMod, KeyCode} from 'vs/base/common/keyCodes';
import {FormatOnTypeRegistry, FormatRegistry, IFormattingSupport} from '../common/format';
import {FormatOnTypeRegistry, FormatRegistry, IFormattingSupport, formatRange, formatDocument, formatAfterKeystroke} from '../common/format';
interface IFormatOnTypeResult {
range: EditorCommon.IEditorRange;
......@@ -66,7 +66,7 @@ class FormatOnType implements EditorCommon.IEditorContribution {
var model = this.editor.getModel();
// no support
var support = FormatOnTypeRegistry.ordered(model)[0];
var [support] = FormatOnTypeRegistry.ordered(model);
if (!support || !support.autoFormatTriggerCharacters) {
return;
}
......@@ -75,12 +75,12 @@ class FormatOnType implements EditorCommon.IEditorContribution {
this.formattingOptions = this.editor.getIndentationOptions();
// register typing listeners that will trigger the format
support.autoFormatTriggerCharacters.forEach(char => {
this.callOnModel.push(this.editor.addTypingListener(char, this.trigger.bind(this, support, char)));
support.autoFormatTriggerCharacters.forEach(ch => {
this.callOnModel.push(this.editor.addTypingListener(ch, this.trigger.bind(this, ch)));
});
}
private trigger(support: IFormattingSupport, char: string): void {
private trigger(ch: string): void {
if (this.editor.getSelections().length > 1) {
return;
......@@ -116,7 +116,7 @@ class FormatOnType implements EditorCommon.IEditorContribution {
}
});
support.formatAfterKeystroke(model.getAssociatedResource(), position, char, this.formattingOptions).then((edits) => {
formatAfterKeystroke(model, position, ch, this.formattingOptions).then(edits => {
unbind();
......@@ -170,31 +170,19 @@ export class FormatAction extends EditorAction {
public run(): TPromise<boolean> {
var model = this.editor.getModel(),
formattingSupport = FormatRegistry.ordered(model)[0],
canFormatRange = typeof formattingSupport.formatRange === 'function',
canFormatDocument = typeof formattingSupport.formatDocument === 'function',
editorSelection = this.editor.getSelection();
var options = this.editor.getIndentationOptions(),
formattingPromise: TPromise<EditorCommon.ISingleEditOperation[]>;
if(canFormatRange) {
// format a selection/range
var formatRange: EditorCommon.IEditorRange = editorSelection;
if(!formatRange.isEmpty()) {
// Fix the selection to include the entire line to improve formatting results
formatRange.startColumn = 1;
} else {
formatRange = model.getFullModelRange();
}
formattingPromise = formattingSupport.formatRange(model.getAssociatedResource(), formatRange, options);
const model = this.editor.getModel(),
editorSelection = this.editor.getSelection(),
options = this.editor.getIndentationOptions();
let formattingPromise: TPromise<EditorCommon.ISingleEditOperation[]>;
} else if(canFormatDocument) {
// format the whole document
formattingPromise = formattingSupport.formatDocument(model.getAssociatedResource(), options);
if (editorSelection.isEmpty()) {
formattingPromise = formatDocument(model, options);
} else {
// broken support?
formattingPromise = formatRange(model, editorSelection, options);
}
if (!formattingPromise) {
return TPromise.as(false);
}
......
......@@ -12,6 +12,7 @@ import {IModel, IPosition} from 'vs/editor/common/editorCommon';
import {IDeclarationSupport} from 'vs/editor/common/modes';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
import {IReference} from 'vs/editor/common/modes';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
export const DeclarationRegistry = new LanguageFeatureRegistry<IDeclarationSupport>('declarationSupport');
......@@ -40,4 +41,6 @@ export function getDeclarationsAtPosition(model: IModel, position: IPosition): T
}
return result;
});
}
\ No newline at end of file
}
CommonEditorRegistry.registerDefaultLanguageCommand('_executeDefinitionProvider', getDeclarationsAtPosition)
\ No newline at end of file
......@@ -5,13 +5,13 @@
'use strict';
import URI from 'vs/base/common/uri';
import {IExtraInfoSupport, IComputeExtraInfoResult} from 'vs/editor/common/modes';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
import {TPromise} from 'vs/base/common/winjs.base';
import {coalesce} from 'vs/base/common/arrays';
import {onUnexpectedError} from 'vs/base/common/errors';
import {IPosition, IModel} from 'vs/editor/common/editorCommon';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
export const ExtraInfoRegistry = new LanguageFeatureRegistry<IExtraInfoSupport>('extraInfoSupport');
......@@ -37,4 +37,6 @@ export function getExtraInfoAtPosition(model: IModel, position: IPosition): TPro
});
return TPromise.join(promises).then(() => coalesce(values));
}
\ No newline at end of file
}
CommonEditorRegistry.registerDefaultLanguageCommand('_executeHoverProvider', getExtraInfoAtPosition);
\ No newline at end of file
......@@ -8,8 +8,9 @@
import {IParameterHintsSupport, IParameterHints} from 'vs/editor/common/modes';
import {IModel, IPosition} from 'vs/editor/common/editorCommon';
import {TPromise} from 'vs/base/common/winjs.base';
import {onUnexpectedError} from 'vs/base/common/errors';
import {onUnexpectedError, illegalArgument} from 'vs/base/common/errors';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
export const ParameterHintsRegistry = new LanguageFeatureRegistry<IParameterHintsSupport>('parameterHintsSupport');
......@@ -21,4 +22,12 @@ export function getParameterHints(model:IModel, position:IPosition, triggerChara
}
return support.getParameterHints(model.getAssociatedResource(), position, triggerCharacter);
}
\ No newline at end of file
}
CommonEditorRegistry.registerDefaultLanguageCommand('_executeSignatureHelpProvider', function(model, position, args) {
let {triggerCharacter} = args;
if (triggerCharacter && typeof triggerCharacter !== 'string') {
throw illegalArgument('triggerCharacter');
}
return getParameterHints(model, position, triggerCharacter);
});
\ No newline at end of file
......@@ -5,10 +5,14 @@
'use strict';
import URI from 'vs/base/common/uri';
import {Range} from 'vs/editor/common/core/range';
import {IModel, IRange} from 'vs/editor/common/editorCommon';
import {TPromise} from 'vs/base/common/winjs.base';
import {onUnexpectedError} from 'vs/base/common/errors';
import {onUnexpectedError, illegalArgument} from 'vs/base/common/errors';
import {IQuickFixSupport, IQuickFix} from 'vs/editor/common/modes';
import {IModelService} from 'vs/editor/common/services/modelService';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
export const QuickFixRegistry = new LanguageFeatureRegistry<IQuickFixSupport>('quickFixSupport');
......@@ -40,4 +44,19 @@ export function getQuickFixes(model: IModel, range: IRange): TPromise<IQuickFix2
});
return TPromise.join(promises).then(() => quickFixes);
}
\ No newline at end of file
}
CommonEditorRegistry.registerLanguageCommand('_executeCodeActionProvider', function(accessor, args) {
const {resource, range} = args;
if (!URI.isURI(resource) || !Range.isIRange(range)) {
throw illegalArgument();
}
const model = accessor.get(IModelService).getModel(resource);
if (!model) {
throw illegalArgument();
}
return getQuickFixes(model, range);
});
\ No newline at end of file
......@@ -5,12 +5,15 @@
'use strict';
import {onUnexpectedError} from 'vs/base/common/errors';
import URI from 'vs/base/common/uri';
import {onUnexpectedError, illegalArgument} from 'vs/base/common/errors';
import {TPromise} from 'vs/base/common/winjs.base';
import {Range} from 'vs/editor/common/core/range';
import {IModel} from 'vs/editor/common/editorCommon';
import {IOutlineEntry, IOutlineSupport} from 'vs/editor/common/modes';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
import {IModelService} from 'vs/editor/common/services/modelService';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
const OutlineRegistry = new LanguageFeatureRegistry<IOutlineSupport>('outlineSupport');
......@@ -20,7 +23,12 @@ export {
IOutlineSupport
}
export function getOutlineEntries(model: IModel): TPromise<{ entries: IOutlineEntry[], outlineGroupLabel: { [n: string]: string;} }> {
export interface IOutline {
entries: IOutlineEntry[];
outlineGroupLabel: { [n: string]: string; };
}
export function getOutlineEntries(model: IModel): TPromise<IOutline> {
let groupLabels: { [n: string]: string } = Object.create(null);
let entries: IOutlineEntry[] = [];
......@@ -74,3 +82,16 @@ function flatten(bucket: IOutlineEntry[], entries: IOutlineEntry[], overrideCont
}
}
}
CommonEditorRegistry.registerLanguageCommand('_executeDocumentSymbolProvider', function(accessor, args) {
const {resource} = args;
if (!URI.isURI(resource)) {
throw illegalArgument('resource');
}
const model = accessor.get(IModelService).getModel(resource);
if (!model) {
throw illegalArgument('resource');
}
return getOutlineEntries(model);
});
\ No newline at end of file
......@@ -10,12 +10,12 @@ import {IModel, IPosition} from 'vs/editor/common/editorCommon';
import {TPromise} from 'vs/base/common/winjs.base';
import {onUnexpectedError} from 'vs/base/common/errors';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
export const ReferenceRegistry = new LanguageFeatureRegistry<IReferenceSupport>('referenceSupport');
export function findReferences(model: IModel, position: IPosition): TPromise<IReference[]> {
// collect references from all providers
const promises = ReferenceRegistry.ordered(model).map(provider => {
return provider.findReferences(model.getAssociatedResource(), position, true).then(result => {
......@@ -37,3 +37,5 @@ export function findReferences(model: IModel, position: IPosition): TPromise<IRe
return result;
});
}
CommonEditorRegistry.registerDefaultLanguageCommand('_executeReferenceProvider', findReferences);
\ No newline at end of file
......@@ -10,8 +10,9 @@ import {IModel, IPosition} from 'vs/editor/common/editorCommon';
import {TPromise} from 'vs/base/common/winjs.base';
import {localize} from 'vs/nls';
import {sequence} from 'vs/base/common/async';
import {onUnexpectedError} from 'vs/base/common/errors';
import {onUnexpectedError, illegalArgument} from 'vs/base/common/errors';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
export const RenameRegistry = new LanguageFeatureRegistry<IRenameSupport>('renameSupport');
......@@ -57,4 +58,12 @@ export function rename(model: IModel, position: IPosition, newName: string): TPr
return result;
}
});
}
\ No newline at end of file
}
CommonEditorRegistry.registerDefaultLanguageCommand('_executeDocumentRenameProvider', function(model, position, args) {
let {newName} = args;
if (typeof newName !== 'string') {
throw illegalArgument('newName');
}
return rename(model, position, newName);
});
\ No newline at end of file
......@@ -18,7 +18,7 @@ import { ISuggestSupport, ISuggestions, ISuggestion, ISorter } from 'vs/editor/c
import {DefaultFilter} from 'vs/editor/common/modes/modesFilters';
import { CodeSnippet } from 'vs/editor/contrib/snippet/common/snippet';
import { IDisposable, disposeAll } from 'vs/base/common/lifecycle';
import {SuggestRegistry} from '../common/suggest';
import {SuggestRegistry, ISuggestions2, suggest} from '../common/suggest';
enum SuggestState {
NOT_ACTIVE = 0,
......@@ -77,13 +77,13 @@ class RawModel {
public size: number = 0;
public incomplete: boolean = false;
insertSuggestions(rank: number, suggestions: ISuggestions[], support: ISuggestSupport): boolean {
insertSuggestions(rank: number, suggestions: ISuggestions2[]): boolean {
if (suggestions) {
let items: CompletionItem[] = [];
for (let _suggestions of suggestions) {
for (let suggestionItem of _suggestions.suggestions) {
items.push(new CompletionItem(support, suggestionItem, _suggestions));
items.push(new CompletionItem(_suggestions.support, suggestionItem, _suggestions));
}
this.size += _suggestions.suggestions.length;
......@@ -385,35 +385,17 @@ export class SuggestModel extends EventEmitter {
// Send mode request
var $tRequest = timer.start(timer.Topic.EDITOR, 'suggest/REQUEST');
var position = this.editor.getPosition();
var resource = model.getAssociatedResource();
let raw = new RawModel();
let rank = 0;
let factory = groups.map((supports, index) => {
return () => {
// stop as soon as a group produced a result
if (raw.size !== 0) {
return;
this.requestPromise = suggest(model, position, triggerCharacter, groups).then(all => {
for (let suggestions of all) {
if (raw.insertSuggestions(rank, suggestions)) {
rank++;
}
// for each support in the group as for suggestions
let promises = supports.map(support => {
return support.suggest(resource, position, triggerCharacter).then(value => {
if (raw.insertSuggestions(rank, value, support)) {
rank++;
}
}, err => {
onUnexpectedError(err);
});
});
return TPromise.join(promises);
};
}
});
this.requestPromise = sequence(factory).then(() => { });
this.requestPromise.then(() => {
$tRequest.stop();
this.requestPromise = null;
......@@ -424,7 +406,7 @@ export class SuggestModel extends EventEmitter {
var snippets = getSnippets(model, position);
if (snippets && snippets.suggestions && snippets.suggestions.length > 0) {
raw.insertSuggestions(rank, [snippets], undefined);
raw.insertSuggestions(rank, [snippets]);
}
if(raw.size > 0) {
......
......@@ -4,11 +4,94 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {ISuggestSupport} from 'vs/editor/common/modes';
import {sequence} from 'vs/base/common/async';
import {IModel, IPosition} from 'vs/editor/common/editorCommon';
import {TPromise} from 'vs/base/common/winjs.base';
import {mixin} from 'vs/base/common/objects';
import {onUnexpectedError, illegalArgument} from 'vs/base/common/errors';
import {ISuggestSupport, ISuggestions} from 'vs/editor/common/modes';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
export var CONTEXT_SUGGEST_WIDGET_VISIBLE = 'suggestWidgetVisible';
export var CONTEXT_SUGGESTION_SUPPORTS_ACCEPT_ON_KEY = 'suggestionSupportsAcceptOnKey';
export var ACCEPT_SELECTED_SUGGESTION_CMD = 'acceptSelectedSuggestion';
export var SuggestRegistry = new LanguageFeatureRegistry<ISuggestSupport>('suggestSupport');
export interface ISuggestions2 extends ISuggestions {
support?: ISuggestSupport;
}
export function suggest(model: IModel, position: IPosition, triggerCharacter: string, groups?: ISuggestSupport[][]): TPromise<ISuggestions2[][]> {
if (!groups) {
groups = SuggestRegistry.orderedGroups(model);
}
const resource = model.getAssociatedResource();
const suggestions: ISuggestions[][] = [];
const factory = groups.map((supports, index) => {
return () => {
// stop as soon as a group produced a result
if (suggestions.length > 0) {
return;
}
// for each support in the group ask for suggestions
let promises = supports.map(support => {
return support.suggest(resource, position, triggerCharacter).then(value => {
let result: ISuggestions2[] = [];
for (let suggestions of value) {
if (!suggestions
|| !Array.isArray(suggestions.suggestions)
|| suggestions.suggestions.length === 0) {
continue;
}
const suggestions2: ISuggestions2 = {
support,
currentWord: suggestions.currentWord,
incomplete: suggestions.incomplete,
overwriteAfter: suggestions.overwriteAfter,
overwriteBefore: suggestions.overwriteBefore,
suggestions: suggestions.suggestions
}
// add additional properties
mixin(suggestions2, suggestions, false);
result.push(suggestions2);
}
return result;
}, onUnexpectedError);
});
return TPromise.join(promises).then(values => {
for (let value of values) {
if (Array.isArray(value) && value.length > 0) {
suggestions.push(value);
}
}
});
};
});
return sequence(factory).then(() => suggestions);
}
CommonEditorRegistry.registerDefaultLanguageCommand('_executeCompletionItemProvider', (model, position, args) => {
let triggerCharacter = args['triggerCharacter'];
if (typeof triggerCharacter !== 'undefined' && typeof triggerCharacter !== 'string') {
throw illegalArgument('triggerCharacter');
}
return suggest(model, position, triggerCharacter);
});
\ No newline at end of file
......@@ -10,9 +10,10 @@ import * as EditorCommon from 'vs/editor/common/editorCommon';
import {IOccurrencesSupport, IOccurence} from 'vs/editor/common/modes';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
import {Range} from 'vs/editor/common/core/range';
import {onUnexpectedError} from 'vs/base/common/errors';
import {onUnexpectedError, illegalArgument} from 'vs/base/common/errors';
import {INullService} from 'vs/platform/instantiation/common/instantiation';
import {sequence} from 'vs/base/common/async';
import {IModelService} from 'vs/editor/common/services/modelService';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
export const OccurrencesRegistry = new LanguageFeatureRegistry<IOccurrencesSupport>('occurrencesSupport');
......@@ -44,6 +45,8 @@ export function getOccurrencesAtPosition(model: EditorCommon.IModel, position: E
});
}
CommonEditorRegistry.registerDefaultLanguageCommand('_executeDocumentHighlights', getOccurrencesAtPosition);
class WordHighlighter {
private editor: EditorCommon.ICommonCodeEditor;
......
......@@ -22,6 +22,7 @@ import {PluginHostTelemetryService} from 'vs/workbench/api/common/pluginHostTele
import {PluginHostEditors} from 'vs/workbench/api/common/pluginHostEditors';
import {ExtHostLanguages} from 'vs/workbench/api/common/extHostLanguages';
import {ExtHostLanguageFeatures} from 'vs/workbench/api/common/extHostLanguageFeatures';
import {ExtHostLanguageFeatureCommands} from 'vs/workbench/api/common/extHostLanguageFeatureCommands';
import * as extHostTypes from 'vs/workbench/api/common/pluginHostTypes';
import 'vs/workbench/api/common/pluginHostTypes.marshalling';
import {wrapAsWinJSPromise} from 'vs/base/common/async';
......@@ -251,6 +252,7 @@ export class PluginHostAPIImplementation {
const languages = new ExtHostLanguages(this._threadService);
const pluginHostDiagnostics = new PluginHostDiagnostics(this._threadService);
const languageFeatures = threadService.getRemotable(ExtHostLanguageFeatures);
const languageFeatureCommand = new ExtHostLanguageFeatureCommands(threadService.getRemotable(PluginHostCommands));
this.languages = {
createDiagnosticCollection(name?: string): vscode.DiagnosticCollection {
......
/*---------------------------------------------------------------------------------------------
* 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 URI from 'vs/base/common/uri';
import Event, {Emitter} from 'vs/base/common/event';
import Severity from 'vs/base/common/severity';
import {DefaultFilter} from 'vs/editor/common/modes/modesFilters';
import {TPromise} from 'vs/base/common/winjs.base';
import {onUnexpectedError} from 'vs/base/common/errors';
import {sequence} from 'vs/base/common/async';
import {Range as EditorRange} from 'vs/editor/common/core/range';
import {IDisposable} from 'vs/base/common/lifecycle';
import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService';
import {Remotable, IThreadService} from 'vs/platform/thread/common/thread';
import * as vscode from 'vscode';
import * as typeConverters from 'vs/workbench/api/common/pluginHostTypeConverters';
import * as types from 'vs/workbench/api/common/pluginHostTypes';
import {IPosition, IRange, ISingleEditOperation} from 'vs/editor/common/editorCommon';
import * as modes from 'vs/editor/common/modes';
import {CancellationTokenSource} from 'vs/base/common/cancellation';
import {PluginHostModelService} from 'vs/workbench/api/common/pluginHostDocuments';
import {IMarkerService, IMarker} from 'vs/platform/markers/common/markers';
import {PluginHostCommands, MainThreadCommands} from 'vs/workbench/api/common/pluginHostCommands';
import {DeclarationRegistry} from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration';
import {ExtraInfoRegistry} from 'vs/editor/contrib/hover/common/hover';
import {OccurrencesRegistry} from 'vs/editor/contrib/wordHighlighter/common/wordHighlighter';
import {ReferenceRegistry} from 'vs/editor/contrib/referenceSearch/common/referenceSearch';
import {IQuickFix2, QuickFixRegistry, getQuickFixes} from 'vs/editor/contrib/quickFix/common/quickFix';
import {IOutline} from 'vs/editor/contrib/quickOpen/common/quickOpen';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
import {NavigateTypesSupportRegistry, INavigateTypesSupport, ITypeBearing} from 'vs/workbench/parts/search/common/search'
import {RenameRegistry} from 'vs/editor/contrib/rename/common/rename';
import {FormatRegistry, FormatOnTypeRegistry} from 'vs/editor/contrib/format/common/format';
import {ICodeLensData} from 'vs/editor/contrib/codelens/common/codelens';
export class ExtHostLanguageFeatureCommands {
private _commands: PluginHostCommands;
private _disposables: IDisposable[] = [];
constructor(commands: PluginHostCommands) {
this._commands = commands;
this._register('vscode.executeWorkspaceSymbolProvider', this._executeWorkspaceSymbolProvider);
this._register('vscode.executeDefinitionProvider', this._executeDefinitionProvider);
this._register('vscode.executeHoverProvider', this._executeHoverProvider);
this._register('vscode.executeDocumentHighlights', this._executeDocumentHighlights);
this._register('vscode.executeReferenceProvider', this._executeReferenceProvider);
this._register('vscode.executeDocumentRenameProvider', this._executeDocumentRenameProvider);
this._register('vscode.executeSignatureHelpProvider', this._executeSignatureHelpProvider);
this._register('vscode.executeDocumentSymbolProvider', this._executeDocumentSymbolProvider);
this._register('vscode.executeCompletionItemProvider', this._executeCompletionItemProvider);
this._register('vscode.executeCodeActionProvider', this._executeCodeActionProvider);
this._register('vscode.executeCodeLensProvider', this._executeCodeLensProvider);
this._register('vscode.executeFormatDocumentProvider', this._executeFormatDocumentProvider);
this._register('vscode.executeFormatRangeProvider', this._executeFormatRangeProvider);
this._register('vscode.executeFormatOnTypeProvider', this._executeFormatOnTypeProvider);
}
private _register(id: string, callback: (...args: any[]) => any): void {
this._disposables.push(this._commands.registerCommand(id, callback, this));
}
// --- command impl
private _executeWorkspaceSymbolProvider(query: string): Thenable<types.SymbolInformation[]> {
return this._commands.executeCommand<ITypeBearing[]>('_executeWorkspaceSymbolProvider', { query }).then(value => {
if (Array.isArray(value)) {
return value.map(typeConverters.toSymbolInformation);
}
});
}
private _executeDefinitionProvider(resource: URI, position: types.Position): Thenable<types.Location[]> {
const args = {
resource,
position: position && typeConverters.fromPosition(position)
};
return this._commands.executeCommand<modes.IReference[]>('_executeDefinitionProvider', args).then(value => {
if (Array.isArray(value)) {
return value.map(typeConverters.toLocation)
}
});
}
private _executeHoverProvider(resource: URI, position: types.Position): Thenable<types.Hover[]> {
const args = {
resource,
position: position && typeConverters.fromPosition(position)
};
return this._commands.executeCommand<modes.IComputeExtraInfoResult[]>('_executeHoverProvider', args).then(value => {
if (Array.isArray(value)) {
return value.map(typeConverters.toHover)
}
});
}
private _executeDocumentHighlights(resource: URI, position: types.Position): Thenable<types.DocumentHighlight[]> {
const args = {
resource,
position: position && typeConverters.fromPosition(position)
};
return this._commands.executeCommand<modes.IOccurence[]>('_executeDocumentHighlights', args).then(value => {
if (Array.isArray(value)) {
return value.map(typeConverters.toDocumentHighlight)
}
});
}
private _executeReferenceProvider(resource: URI, position: types.Position): Thenable<types.Location[]> {
const args = {
resource,
position: position && typeConverters.fromPosition(position)
};
return this._commands.executeCommand<modes.IReference[]>('_executeDocumentHighlights', args).then(value => {
if (Array.isArray(value)) {
return value.map(typeConverters.toLocation)
}
});
}
private _executeDocumentRenameProvider(resource: URI, position: types.Position, newName: string): Thenable<types.WorkspaceEdit> {
const args = {
resource,
position: position && typeConverters.fromPosition(position),
newName
};
return this._commands.executeCommand<modes.IRenameResult>('_executeDocumentRenameProvider', args).then(value => {
if (!value) {
return;
}
if (value.rejectReason) {
return TPromise.wrapError(value.rejectReason);
}
let workspaceEdit = new types.WorkspaceEdit();
for (let edit of value.edits) {
workspaceEdit.replace(edit.resource, typeConverters.toRange(edit.range), edit.newText);
}
return workspaceEdit;
});
}
private _executeSignatureHelpProvider(resource: URI, position: types.Position, triggerCharacter: string): Thenable<types.SignatureHelp> {
const args = {
resource,
position: position && typeConverters.fromPosition(position),
triggerCharacter
};
return this._commands.executeCommand<modes.IParameterHints>('_executeSignatureHelpProvider', args).then(value => {
if (value) {
return typeConverters.SignatureHelp.to(value);
}
});
}
private _executeCompletionItemProvider(resource: URI, position: types.Position, triggerCharacter: string): Thenable<types.CompletionItem[]> {
const args = {
resource,
position: position && typeConverters.fromPosition(position),
triggerCharacter
};
return this._commands.executeCommand<modes.ISuggestions[][]>('_executeCompletionItemProvider', args).then(value => {
if (value) {
let items: types.CompletionItem[] = [];
for (let group of value) {
for (let suggestions of group) {
for (let suggestion of suggestions.suggestions) {
const item = typeConverters.Suggest.to(suggestion, suggestions);
items.push(item);
}
}
}
return items;
}
});
}
private _executeDocumentSymbolProvider(resource: URI): Thenable<types.SymbolInformation[]> {
const args = {
resource
};
return this._commands.executeCommand<IOutline>('_executeDocumentSymbolProvider', args).then(value => {
if (value && Array.isArray(value.entries)) {
return value.entries.map(typeConverters.SymbolInformation.fromOutlineEntry);
}
});
}
private _executeCodeActionProvider(resource: URI, range: types.Range): Thenable<vscode.Command[]> {
const args = {
resource,
range: typeConverters.fromRange(range)
};
return this._commands.executeCommand<IQuickFix2[]>('_executeCodeActionProvider', args).then(value => {
if (Array.isArray(value)) {
// TODO@joh this isn't proper!
return value.map(quickFix => ({ title: quickFix.label }));
}
});
}
private _executeCodeLensProvider(resource: URI): Thenable<vscode.CodeLens[]>{
const args = { resource };
return this._commands.executeCommand<ICodeLensData[]>('_executeCodeLensProvider', args).then(value => {
if (Array.isArray(value)) {
return value.map(item => {
return new types.CodeLens(typeConverters.toRange(item.symbol.range),
typeConverters.Command.to(item.symbol.command));
});
}
});
}
private _executeFormatDocumentProvider(resource: URI, options: vscode.FormattingOptions): Thenable<vscode.TextEdit[]> {
const args = {
resource,
options
};
return this._commands.executeCommand<ISingleEditOperation[]>('_executeFormatDocumentProvider', args).then(value => {
if (Array.isArray(value)) {
return value.map(edit => new types.TextEdit(typeConverters.toRange(edit.range), edit.text));
}
});
}
private _executeFormatRangeProvider(resource: URI, range: types.Range, options: vscode.FormattingOptions): Thenable<vscode.TextEdit[]> {
const args = {
resource,
range: typeConverters.fromRange(range),
options
};
return this._commands.executeCommand<ISingleEditOperation[]>('_executeFormatRangeProvider', args).then(value => {
if (Array.isArray(value)) {
return value.map(edit => new types.TextEdit(typeConverters.toRange(edit.range), edit.text));
}
});
}
private _executeFormatOnTypeProvider(resource: URI, position: types.Position, ch:string, options: vscode.FormattingOptions): Thenable<vscode.TextEdit[]> {
const args = {
resource,
position: typeConverters.fromPosition(position),
ch,
options
};
return this._commands.executeCommand<ISingleEditOperation[]>('_executeFormatOnTypeProvider', args).then(value => {
if (Array.isArray(value)) {
return value.map(edit => new types.TextEdit(typeConverters.toRange(edit.range), edit.text));
}
});
}
}
\ No newline at end of file
......@@ -72,20 +72,10 @@ class OutlineAdapter implements IOutlineSupport {
let doc = this._documents.getDocument(resource);
return asWinJsPromise(token => this._provider.provideDocumentSymbols(doc, token)).then(value => {
if (Array.isArray(value)) {
return value.map(OutlineAdapter._convertSymbolInfo);
return value.map(TypeConverters.SymbolInformation.toOutlineEntry);
}
});
}
private static _convertSymbolInfo(symbol: vscode.SymbolInformation): IOutlineEntry {
return <IOutlineEntry>{
type: TypeConverters.fromSymbolKind(symbol.kind),
range: TypeConverters.fromRange(symbol.location.range),
containerLabel: symbol.containerName,
label: symbol.name,
icon: undefined,
};
}
}
class CodeLensAdapter implements modes.ICodeLensSupport {
......@@ -116,13 +106,14 @@ class CodeLensAdapter implements modes.ICodeLensSupport {
return value.map((lens, i) => {
return <modes.ICodeLensSymbol>{
id: String(i),
range: TypeConverters.fromRange(lens.range)
range: TypeConverters.fromRange(lens.range),
command: TypeConverters.Command.from(lens.command)
}
});
});
}
resolveCodeLensSymbol(resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICommand> {
resolveCodeLensSymbol(resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> {
let lenses = this._cache[resource.toString()];
if (!lenses) {
......@@ -150,11 +141,9 @@ class CodeLensAdapter implements modes.ICodeLensSupport {
command: 'missing',
}
}
return {
id: command.command,
title: command.title,
arguments: command.arguments
}
symbol.command = TypeConverters.Command.from(command);
return symbol;
});
}
}
......@@ -215,20 +204,14 @@ class ExtraInfoAdapter implements modes.IExtraInfoSupport {
if (!value) {
return;
}
let {range, contents} = value;
if (!range) {
range = doc.getWordRangeAtPosition(pos);
if (!value.range) {
value.range = doc.getWordRangeAtPosition(pos);
}
if (!range) {
range = new Range(pos, pos);
if (!value.range) {
value.range = new Range(pos, pos);
}
return <modes.IComputeExtraInfoResult>{
range: TypeConverters.fromRange(range),
htmlContent: contents && contents.map(TypeConverters.fromFormattedString)
}
return TypeConverters.fromHover(value);
});
}
}
......@@ -438,21 +421,10 @@ class NavigateTypeAdapter implements INavigateTypesSupport {
getNavigateToItems(search: string): TPromise<ITypeBearing[]> {
return asWinJsPromise(token => this._provider.provideWorkspaceSymbols(search, token)).then(value => {
if (Array.isArray(value)) {
return value.map(NavigateTypeAdapter._fromSymbolInformation);
return value.map(TypeConverters.fromSymbolInformation);
}
});
}
private static _fromSymbolInformation(info: vscode.SymbolInformation): ITypeBearing {
return <ITypeBearing>{
name: info.name,
type: SymbolKind[info.kind || SymbolKind.Property].toLowerCase(),
range: TypeConverters.fromRange(info.location.range),
resourceUri: info.location.uri,
containerName: info.containerName,
parameters: '',
};
}
}
class RenameAdapter implements modes.IRenameSupport {
......@@ -536,7 +508,7 @@ class SuggestAdapter implements modes.ISuggestSupport {
for (let i = 0; i < value.length; i++) {
const item = value[i];
const suggestion = SuggestAdapter._convertCompletionItem(item);
const [suggestion] = TypeConverters.Suggest.from(item, defaultSuggestions); SuggestAdapter._convertCompletionItem(item);
if (item.textEdit) {
......@@ -634,51 +606,11 @@ class ParameterHintsAdapter implements modes.IParameterHintsSupport {
return asWinJsPromise(token => this._provider.provideSignatureHelp(doc, pos, token)).then(value => {
if (value instanceof SignatureHelp) {
return ParameterHintsAdapter._convertSignatureHelp(value);
return TypeConverters.SignatureHelp.from(value);
}
});
}
private static _convertSignatureHelp(signatureHelp: SignatureHelp): modes.IParameterHints {
let result: modes.IParameterHints = {
currentSignature: signatureHelp.activeSignature,
currentParameter: signatureHelp.activeParameter,
signatures: []
}
for (let signature of signatureHelp.signatures) {
let signatureItem: modes.ISignature = {
label: signature.label,
documentation: signature.documentation,
parameters: []
};
let idx = 0;
for (let parameter of signature.parameters) {
let parameterItem: modes.IParameter = {
label: parameter.label,
documentation: parameter.documentation,
};
signatureItem.parameters.push(parameterItem);
idx = signature.label.indexOf(parameter.label, idx);
if (idx >= 0) {
parameterItem.signatureLabelOffset = idx;
idx += parameter.label.length;
parameterItem.signatureLabelEnd = idx;
}
}
result.signatures.push(signatureItem);
}
return result;
}
getParameterHintsTriggerCharacters(): string[] {
throw new Error('illegal state');
}
......@@ -754,7 +686,7 @@ export class ExtHostLanguageFeatures {
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.findCodeLensSymbols(resource));
}
$resolveCodeLensSymbol(handle:number, resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICommand> {
$resolveCodeLensSymbol(handle:number, resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> {
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLensSymbol(resource, symbol));
}
......@@ -958,7 +890,7 @@ export class MainThreadLanguageFeatures {
findCodeLensSymbols: (resource: URI): TPromise<modes.ICodeLensSymbol[]> => {
return this._proxy.$findCodeLensSymbols(handle, resource);
},
resolveCodeLensSymbol: (resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICommand> => {
resolveCodeLensSymbol: (resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> => {
return this._proxy.$resolveCodeLensSymbol(handle, resource, symbol);
}
});
......
......@@ -78,13 +78,13 @@ export class PluginHostCommands {
return this._executeContributedCommand(id, ...args);
} else {
// check that we can get all parameters over to
// the other side
for (let i = 0; i < args.length; i++) {
if (typeof args[i] === 'object' && !canSerialize(args[i])) {
throw new Error('illegal argument - can not serialize argument number: ' + i)
}
}
// // check that we can get all parameters over to
// // the other side
// for (let i = 0; i < args.length; i++) {
// if (args[i] !== null && typeof args[i] === 'object' && !canSerialize(args[i])) {
// throw new Error('illegal argument - can not serialize argument number: ' + i)
// }
// }
return this._proxy._executeCommand(id, args);
}
......
......@@ -6,10 +6,13 @@
import Severity from 'vs/base/common/severity';
import * as objects from 'vs/base/common/objects';
import * as modes from 'vs/editor/common/modes';
import * as types from './pluginHostTypes';
import {Position as EditorPosition} from 'vs/platform/editor/common/editor';
import {Selection, Range, Position, SymbolKind, DiagnosticSeverity, ViewColumn} from './pluginHostTypes';
import {IPosition, ISelection, IRange, IRangeWithMessage, ISingleEditOperation} from 'vs/editor/common/editorCommon';
import {IHTMLContentElement} from 'vs/base/common/htmlContent';
import {ITypeBearing} from 'vs/workbench/parts/search/common/search';
import * as vscode from 'vscode';
export interface PositionLike {
line: number;
......@@ -26,11 +29,11 @@ export interface SelectionLike extends RangeLike {
active: PositionLike;
}
export function toSelection(selection: ISelection): Selection {
export function toSelection(selection: ISelection): types.Selection {
let {selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn} = selection;
let start = new Position(selectionStartLineNumber - 1, selectionStartColumn - 1);
let end = new Position(positionLineNumber - 1, positionColumn - 1);
return new Selection(start, end);
let start = new types.Position(selectionStartLineNumber - 1, selectionStartColumn - 1);
let end = new types.Position(positionLineNumber - 1, positionColumn - 1);
return new types.Selection(start, end);
}
export function fromSelection(selection: SelectionLike): ISelection {
......@@ -53,87 +56,54 @@ export function fromRange(range: RangeLike): IRange {
};
}
export function toRange(range: IRange): Range {
export function toRange(range: IRange): types.Range {
let {startLineNumber, startColumn, endLineNumber, endColumn} = range;
return new Range(startLineNumber - 1, startColumn - 1, endLineNumber - 1, endColumn - 1);
}
export function toPosition(position: IPosition): Position {
return new Position(position.lineNumber - 1, position.column - 1);
}
export function fromSymbolKind(kind: number | SymbolKind): string {
switch (kind) {
case SymbolKind.Method:
return 'method';
case SymbolKind.Function:
return 'function';
case SymbolKind.Constructor:
return 'constructor';
case SymbolKind.Variable:
return 'variable';
case SymbolKind.Class:
return 'class';
case SymbolKind.Interface:
return 'interface';
case SymbolKind.Module:
case SymbolKind.Namespace:
case SymbolKind.Package:
return 'module';
case SymbolKind.Property:
return 'property';
case SymbolKind.Enum:
return 'enum';
case SymbolKind.String:
return 'string';
case SymbolKind.File:
return 'file';
case SymbolKind.Array:
return 'array';
case SymbolKind.Number:
return 'number';
case SymbolKind.Boolean:
return 'boolean';
}
return 'property';
return new types.Range(startLineNumber - 1, startColumn - 1, endLineNumber - 1, endColumn - 1);
}
export function toPosition(position: IPosition): types.Position {
return new types.Position(position.lineNumber - 1, position.column - 1);
}
export function fromPosition(position: types.Position):IPosition {
return { lineNumber: position.line + 1, column: position.character + 1};
}
export function fromDiagnosticSeverity(value: number): Severity {
switch (value) {
case DiagnosticSeverity.Error:
case types.DiagnosticSeverity.Error:
return Severity.Error;
case DiagnosticSeverity.Warning:
case types.DiagnosticSeverity.Warning:
return Severity.Warning;
case DiagnosticSeverity.Information:
case types.DiagnosticSeverity.Information:
return Severity.Info;
case DiagnosticSeverity.Hint:
case types.DiagnosticSeverity.Hint:
return Severity.Ignore;
}
return Severity.Error;
}
export function toDiagnosticSeverty(value: Severity): DiagnosticSeverity {
export function toDiagnosticSeverty(value: Severity): types.DiagnosticSeverity {
switch (value) {
case Severity.Info:
return DiagnosticSeverity.Information;
return types.DiagnosticSeverity.Information;
case Severity.Warning:
return DiagnosticSeverity.Warning;
return types.DiagnosticSeverity.Warning;
case Severity.Error:
return DiagnosticSeverity.Error;
return types.DiagnosticSeverity.Error;
case Severity.Ignore:
return DiagnosticSeverity.Hint;
return types.DiagnosticSeverity.Hint;
}
return DiagnosticSeverity.Error;
return types.DiagnosticSeverity.Error;
}
export function fromViewColumn(column?: vscode.ViewColumn): EditorPosition {
let editorColumn = EditorPosition.LEFT;
if (typeof column !== 'number') {
// stick with LEFT
} else if (column === <number>ViewColumn.Two) {
} else if (column === <number>types.ViewColumn.Two) {
editorColumn = EditorPosition.CENTER;
} else if (column === <number>ViewColumn.Three) {
} else if (column === <number>types.ViewColumn.Three) {
editorColumn = EditorPosition.RIGHT;
}
return editorColumn;
......@@ -148,6 +118,14 @@ export function fromFormattedString(value: vscode.MarkedString): IHTMLContentEle
}
}
export function toFormattedString(value: IHTMLContentElement): vscode.MarkedString {
if (typeof value.code === 'string') {
return value.code;
}
let {formattedText, text} = value;
return formattedText || text || '<???>';
}
function isMarkedStringArr(something: vscode.MarkedString | vscode.MarkedString[]): something is vscode.MarkedString[] {
return Array.isArray(something);
}
......@@ -195,4 +173,261 @@ export function fromTextEdit(edit: vscode.TextEdit) {
text: edit.newText,
range: fromRange(edit.range)
}
}
export namespace SymbolKind {
export function from(kind: number | types.SymbolKind): string {
switch (kind) {
case types.SymbolKind.Method:
return 'method';
case types.SymbolKind.Function:
return 'function';
case types.SymbolKind.Constructor:
return 'constructor';
case types.SymbolKind.Variable:
return 'variable';
case types.SymbolKind.Class:
return 'class';
case types.SymbolKind.Interface:
return 'interface';
case types.SymbolKind.Module:
case types.SymbolKind.Namespace:
case types.SymbolKind.Package:
return 'module';
case types.SymbolKind.Property:
return 'property';
case types.SymbolKind.Enum:
return 'enum';
case types.SymbolKind.String:
return 'string';
case types.SymbolKind.File:
return 'file';
case types.SymbolKind.Array:
return 'array';
case types.SymbolKind.Number:
return 'number';
case types.SymbolKind.Boolean:
return 'boolean';
}
return 'property';
}
export function to(type: string): types.SymbolKind {
switch (type) {
case 'method':
return types.SymbolKind.Method;
case 'function':
return types.SymbolKind.Function;
case 'constructor':
return types.SymbolKind.Constructor;
case 'variable':
return types.SymbolKind.Variable;
case 'class':
return types.SymbolKind.Class;
case 'interface':
return types.SymbolKind.Interface;
case 'module':
// case types.SymbolKind.Namespace:
// case types.SymbolKind.Package:
return types.SymbolKind.Module;
case 'property':
return types.SymbolKind.Property;
case 'enum':
return types.SymbolKind.Enum;
case 'string':
return types.SymbolKind.String;
case 'file':
return types.SymbolKind.File;
case 'array':
return types.SymbolKind.Array;
case 'number':
return types.SymbolKind.Number;
case 'boolean':
return types.SymbolKind.Boolean;
}
return types.SymbolKind.Property
}
}
export namespace SymbolInformation {
export function fromOutlineEntry(entry: modes.IOutlineEntry): types.SymbolInformation {
return new types.SymbolInformation(entry.label,
SymbolKind.to(entry.type),
toRange(entry.range),
undefined,
entry.containerLabel)
}
export function toOutlineEntry(symbol: vscode.SymbolInformation): modes.IOutlineEntry {
return <modes.IOutlineEntry>{
type: SymbolKind.from(symbol.kind),
range: fromRange(symbol.location.range),
containerLabel: symbol.containerName,
label: symbol.name,
icon: undefined,
};
}
}
export function fromSymbolInformation(info: vscode.SymbolInformation): ITypeBearing {
return <ITypeBearing>{
name: info.name,
type: types.SymbolKind[info.kind || types.SymbolKind.Property].toLowerCase(),
range: fromRange(info.location.range),
resourceUri: info.location.uri,
containerName: info.containerName,
parameters: '',
};
}
export function toSymbolInformation(bearing: ITypeBearing): types.SymbolInformation {
return new types.SymbolInformation(bearing.name,
types.SymbolKind[bearing.type.charAt(0).toUpperCase() + bearing.type.substr(1)],
toRange(bearing.range),
bearing.resourceUri,
bearing.containerName);
}
export function toLocation(reference: modes.IReference): types.Location {
return new types.Location(reference.resource, toRange(reference.range));
}
export function fromHover(hover: vscode.Hover): modes.IComputeExtraInfoResult {
return <modes.IComputeExtraInfoResult>{
range: fromRange(hover.range),
htmlContent: hover.contents.map(fromFormattedString)
}
}
export function toHover(info: modes.IComputeExtraInfoResult): types.Hover {
return new types.Hover(info.htmlContent.map(toFormattedString), toRange(info.range));
}
export function toDocumentHighlight(occurrence: modes.IOccurence): types.DocumentHighlight {
return new types.DocumentHighlight(toRange(occurrence.range),
types.DocumentHighlightKind[occurrence.kind.charAt(0).toUpperCase() + occurrence.kind.substr(1)]);
}
export const Suggest = {
from(item: vscode.CompletionItem, defaultContainer: modes.ISuggestions): [modes.ISuggestion, modes.ISuggestions] {
const suggestion: modes.ISuggestion = {
label: item.label,
codeSnippet: item.insertText || item.label,
type: types.CompletionItemKind[item.kind || types.CompletionItemKind.Text].toString().toLowerCase(),
typeLabel: item.detail,
documentationLabel: item.documentation,
sortText: item.sortText,
filterText: item.filterText
};
if (item.textEdit) {
// TODO@joh
}
return [suggestion, defaultContainer];
},
to(suggestion: modes.ISuggestion, container: modes.ISuggestions): types.CompletionItem {
const result = new types.CompletionItem(suggestion.label);
result.insertText = suggestion.codeSnippet;
result.kind = types.CompletionItemKind[suggestion.type.charAt(0).toUpperCase() + suggestion.type.substr(1)];
result.detail = suggestion.typeLabel;
result.documentation = suggestion.documentationLabel;
result.sortText = suggestion.sortText;
result.filterText = suggestion.filterText;
// todo@joh edit range!
return result;
}
}
export namespace SignatureHelp {
export function from(signatureHelp: types.SignatureHelp): modes.IParameterHints {
let result: modes.IParameterHints = {
currentSignature: signatureHelp.activeSignature,
currentParameter: signatureHelp.activeParameter,
signatures: []
}
for (let signature of signatureHelp.signatures) {
let signatureItem: modes.ISignature = {
label: signature.label,
documentation: signature.documentation,
parameters: []
};
let idx = 0;
for (let parameter of signature.parameters) {
let parameterItem: modes.IParameter = {
label: parameter.label,
documentation: parameter.documentation,
};
signatureItem.parameters.push(parameterItem);
idx = signature.label.indexOf(parameter.label, idx);
if (idx >= 0) {
parameterItem.signatureLabelOffset = idx;
idx += parameter.label.length;
parameterItem.signatureLabelEnd = idx;
}
}
result.signatures.push(signatureItem);
}
return result;
}
export function to(hints: modes.IParameterHints): types.SignatureHelp {
const result = new types.SignatureHelp();
result.activeSignature = hints.currentSignature;
result.activeParameter = hints.currentParameter;
for (let signature of hints.signatures) {
const signatureItem = new types.SignatureInformation(signature.label, signature.documentation);
result.signatures.push(signatureItem);
for (let parameter of signature.parameters) {
const parameterItem = new types.ParameterInformation(parameter.label, parameter.documentation);
signatureItem.parameters.push(parameterItem);
}
}
return result;
}
}
export const Command = {
from(command: vscode.Command): modes.ICommand {
if (command) {
return <modes.ICommand>{
id: command.command,
title: command.title,
arguments: command.arguments
};
}
},
to(command: modes.ICommand): vscode.Command {
if (command) {
return <vscode.Command>{
command: command.id,
title: command.title,
arguments: command.arguments
};
}
}
}
\ No newline at end of file
......@@ -6,9 +6,10 @@
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import {onUnexpectedError} from 'vs/base/common/errors';
import {onUnexpectedError, illegalArgument} from 'vs/base/common/errors';
import {IDisposable} from 'vs/base/common/lifecycle';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
import {IRange} from 'vs/editor/common/editorCommon';
import URI from 'vs/base/common/uri';
......@@ -72,4 +73,12 @@ export function getNavigateToItems(query: string): TPromise<ITypeBearing[]> {
}
return result;
});
}
\ No newline at end of file
}
CommonEditorRegistry.registerLanguageCommand('_executeWorkspaceSymbolProvider', function(accessor, args: { query: string;}) {
let {query} = args;
if (typeof query !== 'string') {
throw illegalArgument();
}
return getNavigateToItems(query);
});
/*---------------------------------------------------------------------------------------------
* 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 * as assert from 'assert';
import {setUnexpectedErrorHandler, errorHandler} from 'vs/base/common/errors';
import {create} from 'vs/base/common/types';
import URI from 'vs/base/common/uri';
import {URL} from 'vs/base/common/network';
import {TPromise} from 'vs/base/common/winjs.base';
import {PluginHostDocument} from 'vs/workbench/api/common/pluginHostDocuments';
import * as types from 'vs/workbench/api/common/pluginHostTypes';
import {Range as CodeEditorRange} from 'vs/editor/common/core/range';
import * as EditorCommon from 'vs/editor/common/editorCommon';
import {Model as EditorModel} from 'vs/editor/common/model/model';
import threadService from './testThreadService'
import {create as createInstantiationService} from 'vs/platform/instantiation/common/instantiationService';
import {MarkerService} from 'vs/platform/markers/common/markerService';
import {IMarkerService} from 'vs/platform/markers/common/markers';
import {IThreadService} from 'vs/platform/thread/common/thread';
import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService';
import {KeybindingsRegistry} from 'vs/platform/keybinding/common/keybindingsRegistry';
import {IModelService} from 'vs/editor/common/services/modelService';
import {ExtHostLanguageFeatures, MainThreadLanguageFeatures} from 'vs/workbench/api/common/extHostLanguageFeatures';
import {ExtHostLanguageFeatureCommands} from 'vs/workbench/api/common/extHostLanguageFeatureCommands';
import {PluginHostCommands, MainThreadCommands} from 'vs/workbench/api/common/pluginHostCommands';
import {PluginHostModelService} from 'vs/workbench/api/common/pluginHostDocuments';
import {SyncDescriptor0} from 'vs/platform/instantiation/common/descriptors';
import {LanguageSelector, ModelLike} from 'vs/editor/common/modes/languageSelector';
import {OutlineRegistry, getOutlineEntries} from 'vs/editor/contrib/quickOpen/common/quickOpen';
import {CodeLensRegistry, getCodeLensData} from 'vs/editor/contrib/codelens/common/codelens';
import {DeclarationRegistry, getDeclarationsAtPosition} from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration';
import {ExtraInfoRegistry, getExtraInfoAtPosition} from 'vs/editor/contrib/hover/common/hover';
import {OccurrencesRegistry, getOccurrencesAtPosition} from 'vs/editor/contrib/wordHighlighter/common/wordHighlighter';
import {ReferenceRegistry, findReferences} from 'vs/editor/contrib/referenceSearch/common/referenceSearch';
import {getQuickFixes} from 'vs/editor/contrib/quickFix/common/quickFix';
import {getNavigateToItems} from 'vs/workbench/parts/search/common/search';
import {rename} from 'vs/editor/contrib/rename/common/rename';
import {getParameterHints} from 'vs/editor/contrib/parameterHints/common/parameterHints';
const defaultSelector = { scheme: 'far' };
const model: EditorCommon.IModel = new EditorModel(
[
'This is the first line',
'This is the second line',
'This is the third line',
].join('\n'),
undefined,
URL.fromUri(URI.parse('far://testing/file.b')));
let extHost: ExtHostLanguageFeatures;
let mainThread: MainThreadLanguageFeatures;
let commands: PluginHostCommands;
let disposables: vscode.Disposable[] = [];
suite('ExtHostLanguageFeatureCommands', function() {
suiteSetup(() => {
let instantiationService = createInstantiationService();
threadService.setInstantiationService(instantiationService);
instantiationService.addSingleton(IMarkerService, new MarkerService(threadService));
instantiationService.addSingleton(IThreadService, threadService);
instantiationService.addSingleton(IModelService, <IModelService> {
serviceId: IModelService,
getModel():any { return model; },
createModel():any { throw new Error(); },
destroyModel():any { throw new Error(); },
getModels():any { throw new Error(); },
onModelAdded: undefined,
onModelModeChanged: undefined,
onModelRemoved: undefined
});
instantiationService.addSingleton(IKeybindingService, <IKeybindingService>{
executeCommand(id, args):any {
let handler = KeybindingsRegistry.getCommands()[id];
return TPromise.as(instantiationService.invokeFunction(handler, args));
}
})
threadService.getRemotable(PluginHostModelService)._acceptModelAdd({
isDirty: false,
versionId: model.getVersionId(),
modeId: model.getModeId(),
url: model.getAssociatedResource(),
value: {
EOL: model.getEOL(),
lines: model.getValue().split(model.getEOL()),
BOM: '',
length: -1
},
});
threadService.getRemotable(MainThreadCommands);
commands = threadService.getRemotable(PluginHostCommands);
new ExtHostLanguageFeatureCommands(commands);
mainThread = threadService.getRemotable(MainThreadLanguageFeatures);
extHost = threadService.getRemotable(ExtHostLanguageFeatures);
});
suiteTeardown(() => {
model.dispose();
});
teardown(function(done) {
while (disposables.length) {
disposables.pop().dispose();
}
threadService.sync()
.then(() => done(), err => done(err));
});
// --- workspace symbols
test('WorkspaceSymbols, invalid arguments', function(done) {
let promises = [
commands.executeCommand('vscode.executeWorkspaceSymbolProvider'),
commands.executeCommand('vscode.executeWorkspaceSymbolProvider', null),
commands.executeCommand('vscode.executeWorkspaceSymbolProvider', undefined),
commands.executeCommand('vscode.executeWorkspaceSymbolProvider', true)
];
threadService.sync().then(() => {
TPromise.join(<any[]>promises).then(undefined, (err: any[]) => {
assert.equal(err.length, 4);
done();
return [];
});
});
});
test('WorkspaceSymbols, ⇔ back and forth', function(done) {
disposables.push(extHost.registerWorkspaceSymbolProvider(<vscode.WorkspaceSymbolProvider>{
provideWorkspaceSymbols(query): any {
return [
new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/first')),
new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/second'))
]
}
}));
disposables.push(extHost.registerWorkspaceSymbolProvider(<vscode.WorkspaceSymbolProvider>{
provideWorkspaceSymbols(query): any {
return [
new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/first'))
]
}
}));
threadService.sync().then(() => {
commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeWorkspaceSymbolProvider', 'testing').then(value => {
for (let info of value) {
assert.ok(info instanceof types.SymbolInformation);
assert.equal(info.name, 'testing');
assert.equal(info.kind, types.SymbolKind.Array);
}
assert.equal(value.length, 3);
done();
});
});
});
// --- definition
test('Definition, invalid arguments', function(done) {
let promises = [
commands.executeCommand('vscode.executeDefinitionProvider'),
commands.executeCommand('vscode.executeDefinitionProvider', null),
commands.executeCommand('vscode.executeDefinitionProvider', undefined),
commands.executeCommand('vscode.executeDefinitionProvider', true, false)
];
threadService.sync().then(() => {
TPromise.join(<any[]>promises).then(undefined, (err: any[]) => {
assert.equal(err.length, 4);
done();
return [];
});
});
});
test('Definition, ⇔ back and forth', function(done) {
disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
provideDefinition(doc: any): any {
return new types.Location(doc.uri, new types.Range(0, 0, 0, 0));
}
}));
disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
provideDefinition(doc: any): any {
return [
new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
]
}
}));
threadService.sync().then(() => {
commands.executeCommand<vscode.Location[]>('vscode.executeDefinitionProvider', model.getAssociatedResource(), new types.Position(0, 0)).then(values => {
assert.equal(values.length, 4);
done();
});
});
});
// --- outline
test('Outline, back and forth', function(done) {
disposables.push(extHost.registerDocumentSymbolProvider(defaultSelector, <vscode.DocumentSymbolProvider>{
provideDocumentSymbols(): any {
return [
new types.SymbolInformation('testing1', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0)),
new types.SymbolInformation('testing2', types.SymbolKind.Enum, new types.Range(0, 1, 0, 3)),
]
}
}));
threadService.sync().then(() => {
commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeDocumentSymbolProvider', model.getAssociatedResource()).then(values => {
assert.equal(values.length, 2);
let [first, second] = values;
assert.equal(first.name, 'testing2');
assert.equal(second.name, 'testing1');
done();
});
});
});
// --- suggest
test('Suggest, back and forth', function(done) {
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return [
new types.CompletionItem('item1'),
new types.CompletionItem('item2')
];
}
}, []));
threadService.sync().then(() => {
commands.executeCommand<vscode.CompletionItem[]>('vscode.executeCompletionItemProvider', model.getAssociatedResource(), new types.Position(0, 0)).then(values => {
assert.equal(values.length, 2);
let [first, second] = values;
assert.equal(first.label, 'item1');
assert.equal(second.label, 'item2');
done();
});
});
});
// --- quickfix
test('QuickFix, back and forth', function(done) {
disposables.push(extHost.registerCodeActionProvider(defaultSelector, <vscode.CodeActionProvider>{
provideCodeActions(): any {
return [{ command: 'testing', title: 'Title', arguments: [1, 2, true] }];
}
}));
threadService.sync().then(() => {
commands.executeCommand<vscode.Command[]>('vscode.executeCodeActionProvider', model.getAssociatedResource(), new types.Range(0, 0, 1, 1)).then(value => {
assert.equal(value.length, 1);
let [first] = value;
assert.equal(first.title, 'Title');
// assert.equal(first.command, 'testing');
// assert.deepEqual(first.arguments, [1, 2, true]);
done();
});
});
});
// --- code lens
test('CodeLens, back and forth', function(done) {
disposables.push(extHost.registerCodeLensProvider(defaultSelector, <vscode.CodeLensProvider>{
provideCodeLenses(): any {
return [new types.CodeLens(new types.Range(0, 0, 1, 1), { title: 'Title', command: 'cmd', arguments: [1, 2, true] })];
}
}));
threadService.sync().then(() => {
commands.executeCommand<vscode.CodeLens[]>('vscode.executeCodeLensProvider', model.getAssociatedResource()).then(value => {
assert.equal(value.length, 1);
let [first] = value;
assert.equal(first.command.title, 'Title');
assert.equal(first.command.command, 'cmd');
assert.deepEqual(first.command.arguments, [1, 2, true]);
done();
});
});
});
});
\ No newline at end of file
......@@ -36,6 +36,8 @@ import {getQuickFixes} from 'vs/editor/contrib/quickFix/common/quickFix';
import {getNavigateToItems} from 'vs/workbench/parts/search/common/search';
import {rename} from 'vs/editor/contrib/rename/common/rename';
import {getParameterHints} from 'vs/editor/contrib/parameterHints/common/parameterHints';
import {suggest} from 'vs/editor/contrib/suggest/common/suggest';
import {formatDocument, formatRange, formatAfterKeystroke} from 'vs/editor/contrib/format/common/format';
const defaultSelector = { scheme: 'far' };
const model: EditorCommon.IModel = new EditorModel(
......@@ -85,6 +87,7 @@ suite('ExtHostLanguageFeatures', function() {
suiteTeardown(() => {
setUnexpectedErrorHandler(originalErrorHandler);
model.dispose();
});
teardown(function(done) {
......@@ -203,9 +206,9 @@ suite('ExtHostLanguageFeatures', function() {
assert.equal(value.length, 1);
let data = value[0];
data.support.resolveCodeLensSymbol(model.getAssociatedResource(), data.symbol).then(command => {
assert.equal(command.id, 'id');
assert.equal(command.title, 'Title');
data.support.resolveCodeLensSymbol(model.getAssociatedResource(), data.symbol).then(symbol => {
assert.equal(symbol.command.id, 'id');
assert.equal(symbol.command.title, 'Title');
done();
});
});
......@@ -226,10 +229,10 @@ suite('ExtHostLanguageFeatures', function() {
assert.equal(value.length, 1);
let data = value[0];
data.support.resolveCodeLensSymbol(model.getAssociatedResource(), data.symbol).then(command => {
data.support.resolveCodeLensSymbol(model.getAssociatedResource(), data.symbol).then(symbol => {
assert.equal(command.id, 'missing');
assert.equal(command.title, '<<MISSING COMMAND>>');
assert.equal(symbol.command.id, 'missing');
assert.equal(symbol.command.title, '<<MISSING COMMAND>>');
done();
});
});
......@@ -800,5 +803,191 @@ suite('ExtHostLanguageFeatures', function() {
done();
})
});
});
// --- suggestions
test('Suggest, order 1/3', function(done) {
disposables.push(extHost.registerCompletionItemProvider('*', <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return [new types.CompletionItem('testing1')];
}
}, []));
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return [new types.CompletionItem('testing2')];
}
}, []));
threadService.sync().then(() => {
suggest(model, { lineNumber: 1, column: 1 }, ',').then(value => {
assert.equal(value.length, 1);
let [[first]] = value;
assert.equal(first.suggestions.length, 1)
assert.equal(first.suggestions[0].codeSnippet, 'testing2')
done();
});
});
});
test('Suggest, order 2/3', function(done) {
disposables.push(extHost.registerCompletionItemProvider('*', <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return [new types.CompletionItem('weak-selector')]; // weaker selector but result
}
}, []));
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return []; // stronger selector but not a good result;
}
}, []));
threadService.sync().then(() => {
suggest(model, { lineNumber: 1, column: 1 }, ',').then(value => {
assert.equal(value.length, 1);
let [[first]] = value;
assert.equal(first.suggestions.length, 1)
assert.equal(first.suggestions[0].codeSnippet, 'weak-selector')
done();
});
});
})
test('Suggest, order 2/3', function(done) {
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return [new types.CompletionItem('strong-1')];
}
}, []));
setTimeout(function() {
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return [new types.CompletionItem('strong-2')];
}
}, []));
threadService.sync().then(() => {
suggest(model, { lineNumber: 1, column: 1 }, ',').then(value => {
assert.equal(value.length, 2);
let [[first], [second]] = value;
assert.equal(first.suggestions.length, 1)
assert.equal(first.suggestions[0].codeSnippet, 'strong-2') // last wins
assert.equal(second.suggestions[0].codeSnippet, 'strong-1')
done();
});
});
}, 5);
})
test('Suggest, evil provider', function(done) {
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
throw new Error('evil');
}
}, []));
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return [new types.CompletionItem('testing')];
}
}, []));
threadService.sync().then(() => {
suggest(model, { lineNumber: 1, column: 1 }, ',').then(value => {
assert.equal(value.length, 1);
done();
});
});
});
// --- format
test('Format Doc, data conversion', function(done) {
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultSelector, <vscode.DocumentFormattingEditProvider>{
provideDocumentFormattingEdits(): any {
return [new types.TextEdit(new types.Range(0, 0, 1, 1), 'testing')];
}
}));
threadService.sync().then(() => {
formatDocument(model, { insertSpaces: true, tabSize: 4 }).then(value => {
assert.equal(value.length, 1);
let [first] = value;
assert.equal(first.text, 'testing');
assert.deepEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 2, endColumn: 2 });
done();
});
});
});
test('Format Doc, evil provider', function(done) {
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultSelector, <vscode.DocumentFormattingEditProvider>{
provideDocumentFormattingEdits(): any {
throw new Error('evil');
}
}));
threadService.sync().then(() => {
formatDocument(model, { insertSpaces: true, tabSize: 4 }).then(undefined, err => done());
});
});
test('Format Range, data conversion', function(done) {
disposables.push(extHost.registerDocumentRangeFormattingEditProvider(defaultSelector, <vscode.DocumentRangeFormattingEditProvider>{
provideDocumentRangeFormattingEdits(): any {
return [new types.TextEdit(new types.Range(0, 0, 1, 1), 'testing')];
}
}));
threadService.sync().then(() => {
formatRange(model, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }, { insertSpaces: true, tabSize: 4 }).then(value => {
assert.equal(value.length, 1);
let [first] = value;
assert.equal(first.text, 'testing');
assert.deepEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 2, endColumn: 2 });
done();
});
});
})
test('Format Range, evil provider', function(done) {
disposables.push(extHost.registerDocumentRangeFormattingEditProvider(defaultSelector, <vscode.DocumentRangeFormattingEditProvider>{
provideDocumentRangeFormattingEdits(): any {
throw new Error('evil');
}
}));
threadService.sync().then(() => {
formatRange(model, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }, { insertSpaces: true, tabSize: 4 }).then(undefined, err => done());
});
})
test('Format on Type, data conversion', function(done) {
disposables.push(extHost.registerOnTypeFormattingEditProvider(defaultSelector, <vscode.OnTypeFormattingEditProvider>{
provideOnTypeFormattingEdits(): any {
return [new types.TextEdit(new types.Range(0, 0, 0, 0), arguments[2])];
}
}, [';']));
threadService.sync().then(() => {
formatAfterKeystroke(model, { lineNumber: 1, column: 1 }, ';', { insertSpaces: true, tabSize: 2 }).then(value => {
assert.equal(value.length, 1);
let [first] = value;
assert.equal(first.text, ';');
assert.deepEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 });
done();
});
});
});
});
\ No newline at end of file
......@@ -24,7 +24,7 @@ export class TestThreadService extends NullThreadService {
private set _callCount(value:number) {
this._callCountValue = value;
if (this._callCountValue === 0) {
this._completeIdle();
this._completeIdle && this._completeIdle();
this._idle = undefined;
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册