提交 9a97cb10 编写于 作者: J Johannes Rieken

make SnippetRegistry a service, move things to workbench layer, preps #20764

上级 2fe6ff47
......@@ -13,9 +13,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { IModel, IPosition } from 'vs/editor/common/editorCommon';
import { CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions';
import { ISuggestResult, ISuggestSupport, ISuggestion, SuggestRegistry } from 'vs/editor/common/modes';
import { ISnippetsRegistry, Extensions } from 'vs/editor/common/modes/snippetsRegistry';
import { Position } from 'vs/editor/common/core/position';
import { Registry } from 'vs/platform/platform';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { DefaultConfig } from 'vs/editor/common/config/defaultConfig';
......@@ -36,20 +34,13 @@ export interface ISuggestionItem {
export type SnippetConfig = 'top' | 'bottom' | 'inline' | 'none';
let _snippetSuggestSupport: ISuggestSupport;
// add suggestions from snippet registry.
export const snippetSuggestSupport: ISuggestSupport = {
triggerCharacters: [],
provideCompletionItems(model: IModel, position: Position): ISuggestResult {
const suggestions = Registry.as<ISnippetsRegistry>(Extensions.Snippets).getSnippetCompletions(model, position);
if (suggestions) {
return { suggestions };
}
return undefined;
}
};
export function setSnippetSuggestSupport(support: ISuggestSupport): ISuggestSupport {
const old = _snippetSuggestSupport;
_snippetSuggestSupport = support;
return old;
}
export function provideSuggestionItems(model: IModel, position: Position, snippetConfig: SnippetConfig = 'bottom', onlyFrom?: ISuggestSupport[]): TPromise<ISuggestionItem[]> {
......@@ -62,8 +53,8 @@ export function provideSuggestionItems(model: IModel, position: Position, snippe
const supports = SuggestRegistry.orderedGroups(model);
// add snippets provider unless turned off
if (snippetConfig !== 'none') {
supports.unshift([snippetSuggestSupport]);
if (snippetConfig !== 'none' && _snippetSuggestSupport) {
supports.unshift([_snippetSuggestSupport]);
}
// add suggestions from contributed providers - providers are ordered in groups of
......@@ -103,7 +94,7 @@ export function provideSuggestionItems(model: IModel, position: Position, snippe
}
}
if (len !== allSuggestions.length && support !== snippetSuggestSupport) {
if (len !== allSuggestions.length && support !== _snippetSuggestSupport) {
hasResult = true;
}
......@@ -217,7 +208,7 @@ CommonEditorRegistry.registerDefaultLanguageCommand('_executeCompletionItemProvi
return provideSuggestionItems(model, position).then(items => {
for (const {container, suggestion} of items) {
for (const { container, suggestion } of items) {
result.incomplete = result.incomplete || container.incomplete;
result.suggestions.push(suggestion);
}
......
......@@ -36,7 +36,6 @@ import { MainThreadFileSystemEventService } from './mainThreadFileSystemEventSer
import { MainThreadSCM } from './mainThreadSCM';
// --- other interested parties
import { MainProcessTextMateSnippet } from 'vs/editor/node/textMate/TMSnippets';
import { JSONValidationExtensionPoint } from 'vs/platform/jsonschemas/common/jsonValidationExtensionPoint';
import { LanguageConfigurationFileHandler } from 'vs/editor/node/languageConfigurationExtensionPoint';
import { SaveParticipant } from './mainThreadSaveParticipant';
......@@ -90,7 +89,6 @@ export class ExtHostContribution implements IWorkbenchContribution {
col.finish(true, this.threadService);
// Other interested parties
create(MainProcessTextMateSnippet);
create(JSONValidationExtensionPoint);
this.instantiationService.createInstance(LanguageConfigurationFileHandler);
create(MainThreadFileSystemEventService);
......
......@@ -5,18 +5,18 @@
'use strict';
import * as nls from 'vs/nls';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { parse } from 'vs/base/common/json';
import * as paths from 'vs/base/common/paths';
import { TPromise } from 'vs/base/common/winjs.base';
import { readFile } from 'vs/base/node/pfs';
import { ExtensionMessageCollector, ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry';
import { ISnippetsRegistry, Extensions, ISnippet } from 'vs/editor/common/modes/snippetsRegistry';
import { ISnippetsService, ISnippet } from 'vs/workbench/parts/snippets/electron-browser/snippetsService';
import { IModeService } from 'vs/editor/common/services/modeService';
import platform = require('vs/platform/platform');
import { languagesExtPoint } from 'vs/editor/common/services/modeServiceImpl';
import { LanguageIdentifier } from 'vs/editor/common/modes';
export interface ISnippetsExtensionPoint {
interface ISnippetsExtensionPoint {
language: string;
path: string;
}
......@@ -41,12 +41,12 @@ let snippetsExtensionPoint = ExtensionsRegistry.registerExtensionPoint<ISnippets
}
});
export class MainProcessTextMateSnippet {
private _modeService: IModeService;
constructor( @IModeService modeService: IModeService) {
this._modeService = modeService;
export class MainProcessTextMateSnippet implements IWorkbenchContribution {
constructor(
@IModeService private _modeService: IModeService,
@ISnippetsService private _snippetService: ISnippetsService
) {
snippetsExtensionPoint.setHandler((extensions) => {
for (let i = 0; i < extensions.length; i++) {
let tmSnippets = extensions[i].value;
......@@ -57,6 +57,10 @@ export class MainProcessTextMateSnippet {
});
}
getId() {
return 'tmSnippetExtension';
}
private _withSnippetContribution(extensionName: string, extensionFolderPath: string, snippet: ISnippetsExtensionPoint, collector: ExtensionMessageCollector): void {
if (!snippet.language || (typeof snippet.language !== 'string') || !this._modeService.isRegisteredMode(snippet.language)) {
collector.error(nls.localize('invalid.language', "Unknown language in `contributes.{0}.language`. Provided value: {1}", snippetsExtensionPoint.name, String(snippet.language)));
......@@ -79,19 +83,17 @@ export class MainProcessTextMateSnippet {
if (mode.getId() !== modeId) {
return;
}
readAndRegisterSnippets(languageIdentifier, normalizedAbsolutePath, extensionName);
readAndRegisterSnippets(this._snippetService, languageIdentifier, normalizedAbsolutePath, extensionName);
disposable.dispose();
});
}
}
}
let snippetsRegistry = <ISnippetsRegistry>platform.Registry.as(Extensions.Snippets);
export function readAndRegisterSnippets(languageIdentifier: LanguageIdentifier, filePath: string, ownerName: string): TPromise<void> {
export function readAndRegisterSnippets(snippetService: ISnippetsService, languageIdentifier: LanguageIdentifier, filePath: string, ownerName: string): TPromise<void> {
return readFile(filePath).then(fileContents => {
let snippets = parseSnippetFile(fileContents.toString(), ownerName);
snippetsRegistry.registerSnippets(languageIdentifier, snippets, filePath);
snippetService.registerSnippets(languageIdentifier, snippets, filePath);
});
}
......
......@@ -5,16 +5,15 @@
'use strict';
import * as nls from 'vs/nls';
import { Registry } from 'vs/platform/platform';
import { TPromise } from 'vs/base/common/winjs.base';
import { ICommonCodeEditor, EditorContextKeys } from 'vs/editor/common/editorCommon';
import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
import { SnippetController } from 'vs/editor/contrib/snippet/common/snippetController';
import { IQuickOpenService, IPickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen';
import { ISnippetsRegistry, Extensions, ISnippet } from 'vs/editor/common/modes/snippetsRegistry';
import { IModeService } from 'vs/editor/common/services/modeService';
import { LanguageId } from 'vs/editor/common/modes';
import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ISnippetsService, ISnippet } from 'vs/workbench/parts/snippets/electron-browser/snippetsService';
interface ISnippetPick extends IPickOpenEntry {
snippet: ISnippet;
......@@ -26,7 +25,7 @@ class Args {
if (!arg || typeof arg !== 'object') {
return Args._empty;
}
let {snippet, name, langId} = arg;
let { snippet, name, langId } = arg;
if (typeof snippet !== 'string') {
snippet = undefined;
}
......@@ -65,14 +64,15 @@ class InsertSnippetAction extends EditorAction {
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor, arg: any): TPromise<void> {
const modeService = accessor.get(IModeService);
const snippetService = accessor.get(ISnippetsService);
if (!editor.getModel()) {
return undefined;
}
const quickOpenService = accessor.get(IQuickOpenService);
const {lineNumber, column} = editor.getPosition();
let {snippet, name, langId} = Args.fromUser(arg);
const { lineNumber, column } = editor.getPosition();
let { snippet, name, langId } = Args.fromUser(arg);
return new TPromise<ISnippet>((resolve, reject) => {
......@@ -96,7 +96,7 @@ class InsertSnippetAction extends EditorAction {
// validate the `languageId` to ensure this is a user
// facing language with a name and the chance to have
// snippets, else fall back to the outer language
const {language} = modeService.getLanguageIdentifier(languageId);
const { language } = modeService.getLanguageIdentifier(languageId);
if (!modeService.getLanguageName(language)) {
languageId = editor.getModel().getLanguageIdentifier().id;
}
......@@ -104,7 +104,7 @@ class InsertSnippetAction extends EditorAction {
if (name) {
// take selected snippet
Registry.as<ISnippetsRegistry>(Extensions.Snippets).visitSnippets(languageId, snippet => {
snippetService.visitSnippets(languageId, snippet => {
if (snippet.name !== name) {
return true;
}
......@@ -114,7 +114,7 @@ class InsertSnippetAction extends EditorAction {
} else {
// let user pick a snippet
const picks: ISnippetPick[] = [];
Registry.as<ISnippetsRegistry>(Extensions.Snippets).visitSnippets(languageId, snippet => {
snippetService.visitSnippets(languageId, snippet => {
picks.push({
label: snippet.prefix,
detail: snippet.description,
......
......@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'vs/workbench/parts/snippets/electron-browser/snippetsService';
import 'vs/workbench/parts/snippets/electron-browser/insertSnippet';
import 'vs/workbench/parts/snippets/electron-browser/tabCompletion';
......@@ -16,6 +17,7 @@ import platform = require('vs/platform/platform');
import workbenchActionRegistry = require('vs/workbench/common/actionRegistry');
import workbenchContributions = require('vs/workbench/common/contributions');
import snippetsTracker = require('./snippetsTracker');
import tmSnippets = require('./TMSnippets');
import * as pfs from 'vs/base/node/pfs';
import errors = require('vs/base/common/errors');
import { IQuickOpenService, IPickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen';
......@@ -121,6 +123,9 @@ workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenSn
(<workbenchContributions.IWorkbenchContributionsRegistry>platform.Registry.as(workbenchContributions.Extensions.Workbench)).registerWorkbenchContribution(
snippetsTracker.SnippetsTracker
);
(<workbenchContributions.IWorkbenchContributionsRegistry>platform.Registry.as(workbenchContributions.Extensions.Workbench)).registerWorkbenchContribution(
tmSnippets.MainProcessTextMateSnippet
);
let schemaId = 'vscode://schemas/snippets';
let schema: IJSONSchema = {
......
......@@ -6,31 +6,21 @@
import { localize } from 'vs/nls';
import * as strings from 'vs/base/common/strings';
import { ITokenizedModel, IPosition } from 'vs/editor/common/editorCommon';
import { IModel, IPosition } from 'vs/editor/common/editorCommon';
import { ISuggestion, LanguageIdentifier, LanguageId } from 'vs/editor/common/modes';
import { Registry } from 'vs/platform/platform';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { setSnippetSuggestSupport } from 'vs/editor/contrib/suggest/common/suggest';
export const Extensions = {
Snippets: 'base.contributions.snippets'
};
export const ISnippetsService = createDecorator<ISnippetsService>('snippetService');
export interface ISnippetsRegistry {
export interface ISnippetsService {
_serviceBrand: any;
/**
* Register a snippet to the registry.
*/
registerSnippets(languageIdentifier: LanguageIdentifier, snippets: ISnippet[], owner?: string): void;
/**
* Visit all snippets
*/
visitSnippets(languageId: LanguageId, accept: (snippet: ISnippet) => void): void;
/**
* Get all snippet completions for the given position
*/
getSnippetCompletions(model: ITokenizedModel, position: IPosition): ISuggestion[];
}
export interface ISnippet {
......@@ -45,10 +35,22 @@ interface ISnippetSuggestion extends ISuggestion {
disambiguateLabel: string;
}
class SnippetsRegistry implements ISnippetsRegistry {
class SnippetsService implements ISnippetsService {
_serviceBrand: any;
private _snippets: { [owner: string]: ISnippet[] }[] = [];
constructor() {
setSnippetSuggestSupport({
triggerCharacters: undefined,
provideCompletionItems: (model, position) => {
const suggestions = this.getSnippetCompletions(<any>model, position);
return { suggestions };
}
});
}
public registerSnippets(languageIdentifier: LanguageIdentifier, snippets: ISnippet[], owner = ''): void {
let snippetsByMode = this._snippets[languageIdentifier.id];
if (!snippetsByMode) {
......@@ -69,7 +71,7 @@ class SnippetsRegistry implements ISnippetsRegistry {
}
}
public getSnippetCompletions(model: ITokenizedModel, position: IPosition): ISuggestion[] {
public getSnippetCompletions(model: IModel, position: IPosition): ISuggestion[] {
const languageId = model.getLanguageIdAtPosition(position.lineNumber, position.column);
if (!this._snippets[languageId]) {
return undefined;
......@@ -116,7 +118,7 @@ class SnippetsRegistry implements ISnippetsRegistry {
// dismbiguate suggestions with same labels
let lastSuggestion: ISnippetSuggestion;
for (const suggestion of result.sort(SnippetsRegistry._compareSuggestionsByLabel)) {
for (const suggestion of result.sort(SnippetsService._compareSuggestionsByLabel)) {
if (lastSuggestion && lastSuggestion.label === suggestion.label) {
// use the disambiguateLabel instead of the actual label
lastSuggestion.label = lastSuggestion.disambiguateLabel;
......@@ -133,6 +135,8 @@ class SnippetsRegistry implements ISnippetsRegistry {
}
}
registerSingleton(ISnippetsService, SnippetsService);
export interface ISimpleModel {
getLineContent(lineNumber): string;
}
......@@ -161,6 +165,3 @@ export function getNonWhitespacePrefix(model: ISimpleModel, position: IPosition)
return '';
}
const snippetsRegistry: ISnippetsRegistry = new SnippetsRegistry();
Registry.add(Extensions.Snippets, snippetsRegistry);
......@@ -13,7 +13,8 @@ import winjs = require('vs/base/common/winjs.base');
import { mkdirp, fileExists, readdir } from 'vs/base/node/pfs';
import { onUnexpectedError } from 'vs/base/common/errors';
import lifecycle = require('vs/base/common/lifecycle');
import { readAndRegisterSnippets } from 'vs/editor/node/textMate/TMSnippets';
import { readAndRegisterSnippets } from './TMSnippets';
import { ISnippetsService } from 'vs/workbench/parts/snippets/electron-browser/snippetsService';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
......@@ -31,6 +32,7 @@ export class SnippetsTracker implements workbenchExt.IWorkbenchContribution {
constructor(
@ILifecycleService private lifecycleService: ILifecycleService,
@IModeService private modeService: IModeService,
@ISnippetsService private snippetService: ISnippetsService,
@IEnvironmentService environmentService: IEnvironmentService,
@IExtensionService extensionService: IExtensionService
) {
......@@ -75,7 +77,7 @@ export class SnippetsTracker implements workbenchExt.IWorkbenchContribution {
var snippetPath = paths.join(this.snippetFolder, snippetFile);
let languageIdentifier = this.modeService.getLanguageIdentifier(modeId);
if (languageIdentifier) {
return readAndRegisterSnippets(languageIdentifier, snippetPath, localize('userSnippet', "User Snippet"));
return readAndRegisterSnippets(this.snippetService, languageIdentifier, snippetPath, localize('userSnippet', "User Snippet"));
}
return undefined;
}));
......
......@@ -9,7 +9,7 @@ import { localize } from 'vs/nls';
import { KeyCode } from 'vs/base/common/keyCodes';
import { RawContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ISnippetsRegistry, Extensions, getNonWhitespacePrefix, ISnippet } from 'vs/editor/common/modes/snippetsRegistry';
import { ISnippetsService, getNonWhitespacePrefix, ISnippet } from 'vs/workbench/parts/snippets/electron-browser/snippetsService';
import { Registry } from 'vs/platform/platform';
import { endsWith } from 'vs/base/common/strings';
import { IDisposable } from 'vs/base/common/lifecycle';
......@@ -20,8 +20,6 @@ import { IConfigurationRegistry, Extensions as ConfigExt } from "vs/platform/con
import EditorContextKeys = editorCommon.EditorContextKeys;
let snippetsRegistry = <ISnippetsRegistry>Registry.as(Extensions.Snippets);
@commonEditorContribution
export class TabCompletionController implements editorCommon.IEditorContribution {
......@@ -38,7 +36,8 @@ export class TabCompletionController implements editorCommon.IEditorContribution
constructor(
editor: editorCommon.ICommonCodeEditor,
@IContextKeyService contextKeyService: IContextKeyService
@IContextKeyService contextKeyService: IContextKeyService,
@ISnippetsService snippetService: ISnippetsService
) {
this._snippetController = SnippetController.get(editor);
const hasSnippets = TabCompletionController.ContextKey.bindTo(contextKeyService);
......@@ -59,7 +58,7 @@ export class TabCompletionController implements editorCommon.IEditorContribution
}
if (selectFn) {
snippetsRegistry.visitSnippets(editor.getModel().getLanguageIdentifier().id, s => {
snippetService.visitSnippets(editor.getModel().getLanguageIdentifier().id, s => {
if (selectFn(s)) {
this._currentSnippets.push(s);
}
......
......@@ -6,7 +6,8 @@
'use strict';
import * as assert from 'assert';
import { getNonWhitespacePrefix } from 'vs/editor/common/modes/snippetsRegistry';
import { getNonWhitespacePrefix } from 'vs/workbench/parts/snippets/electron-browser/snippetsService';
suite('getNonWhitespacePrefix', () => {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册