insertSnippet.ts 4.2 KB
Newer Older
J
Johannes Rieken 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  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 nls from 'vs/nls';
J
Johannes Rieken 已提交
8 9 10 11 12
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';
J
Johannes Rieken 已提交
13
import { IQuickOpenService, IPickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen';
J
Johannes Rieken 已提交
14
import { ISnippetsRegistry, Extensions, ISnippet } from 'vs/editor/common/modes/snippetsRegistry';
15 16
import { IModeService } from 'vs/editor/common/services/modeService';
import { LanguageId } from 'vs/editor/common/modes';
17
import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands';
J
Johannes Rieken 已提交
18 19 20 21 22

interface ISnippetPick extends IPickOpenEntry {
	snippet: ISnippet;
}

23
class Args {
24

25
	static fromUser(arg: any): Args {
J
Johannes Rieken 已提交
26
		if (!arg || typeof arg !== 'object') {
27 28 29 30 31
			return Args._empty;
		}
		let {snippet, name, langId} = arg;
		if (typeof snippet !== 'string') {
			snippet = undefined;
32 33 34 35 36 37 38
		}
		if (typeof name !== 'string') {
			name = undefined;
		}
		if (typeof langId !== 'string') {
			langId = undefined;
		}
39
		return new Args(snippet, name, langId);
40 41
	}

42 43 44 45 46 47 48
	private static _empty = new Args(undefined, undefined, undefined);

	private constructor(
		public readonly snippet: string,
		public readonly name: string,
		public readonly langId: string
	) {
49 50 51 52 53

	}

}

A
Alex Dima 已提交
54
@editorAction
55
class InsertSnippetAction extends EditorAction {
J
Johannes Rieken 已提交
56

A
Alex Dima 已提交
57
	constructor() {
58
		super({
59
			id: 'editor.action.insertSnippet',
60 61 62 63
			label: nls.localize('snippet.suggestions.label', "Insert Snippet"),
			alias: 'Insert Snippet',
			precondition: EditorContextKeys.Writable
		});
J
Johannes Rieken 已提交
64 65
	}

66
	public run(accessor: ServicesAccessor, editor: ICommonCodeEditor, arg: any): TPromise<void> {
67
		const modeService = accessor.get(IModeService);
A
Alex Dima 已提交
68 69

		if (!editor.getModel()) {
70
			return undefined;
J
Johannes Rieken 已提交
71 72
		}

73
		const quickOpenService = accessor.get(IQuickOpenService);
74
		const {lineNumber, column} = editor.getPosition();
75
		let {snippet, name, langId} = Args.fromUser(arg);
J
Johannes Rieken 已提交
76 77


78
		return new TPromise<ISnippet>((resolve, reject) => {
79 80 81 82 83 84 85 86 87 88 89

			if (snippet) {
				return resolve({
					codeSnippet: snippet,
					description: undefined,
					name: undefined,
					owner: undefined,
					prefix: undefined
				});
			}

90 91
			let languageId: LanguageId;
			if (langId) {
92
				languageId = modeService.getLanguageIdentifier(langId).id;
93 94
			} else {
				languageId = editor.getModel().getLanguageIdAtPosition(lineNumber, column);
95 96 97 98 99 100 101 102

				// 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);
				if (!modeService.getLanguageName(language)) {
					languageId = editor.getModel().getLanguageIdentifier().id;
				}
103 104
			}

105 106
			if (name) {
				// take selected snippet
107
				Registry.as<ISnippetsRegistry>(Extensions.Snippets).visitSnippets(languageId, snippet => {
108 109 110 111
					if (snippet.name !== name) {
						return true;
					}
					resolve(snippet);
112
					return false;
113 114 115 116
				});
			} else {
				// let user pick a snippet
				const picks: ISnippetPick[] = [];
117
				Registry.as<ISnippetsRegistry>(Extensions.Snippets).visitSnippets(languageId, snippet => {
118 119 120 121 122 123 124 125 126 127 128 129
					picks.push({
						label: snippet.prefix,
						detail: snippet.description,
						snippet
					});
					return true;
				});
				return quickOpenService.pick(picks).then(pick => resolve(pick && pick.snippet), reject);
			}
		}).then(snippet => {
			if (snippet) {
				SnippetController.get(editor).insertSnippet(snippet.codeSnippet, 0, 0);
J
Johannes Rieken 已提交
130 131 132
			}
		});
	}
133
}
134 135 136 137 138

// compatibility command to make sure old keybinding are still working
CommandsRegistry.registerCommand('editor.action.showSnippets', accessor => {
	return accessor.get(ICommandService).executeCommand('editor.action.insertSnippet');
});