simpleServices.ts 16.5 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

J
Johannes Rieken 已提交
7
import { Schemas } from 'vs/base/common/network';
E
Erich Gamma 已提交
8
import Severity from 'vs/base/common/severity';
9
import URI from 'vs/base/common/uri';
J
Johannes Rieken 已提交
10
import { TPromise } from 'vs/base/common/winjs.base';
B
Benjamin Pasero 已提交
11
import { IConfigurationService, IConfigurationServiceEvent, IConfigurationValue, getConfigurationValue, IConfigurationKeys } from 'vs/platform/configuration/common/configuration';
J
Joao Moreno 已提交
12
import { IEditor, IEditorInput, IEditorOptions, IEditorService, IResourceInput, Position } from 'vs/platform/editor/common/editor';
13
import { ICommandService, ICommand, ICommandEvent, ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands';
14 15
import { AbstractKeybindingService } from 'vs/platform/keybinding/common/abstractKeybindingService';
import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding';
16
import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';
17
import { IKeybindingEvent, KeybindingSource, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';
18
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
J
Johannes Rieken 已提交
19
import { IConfirmation, IMessageService } from 'vs/platform/message/common/message';
20
import { IWorkspaceContextService, Workspace, IWorkspace } from 'vs/platform/workspace/common/workspace';
A
Alex Dima 已提交
21
import * as editorCommon from 'vs/editor/common/editorCommon';
J
Johannes Rieken 已提交
22 23 24 25 26 27
import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
import { Selection } from 'vs/editor/common/core/selection';
import Event, { Emitter } from 'vs/base/common/event';
import { getDefaultValues as getDefaultConfiguration } from 'vs/platform/configuration/common/model';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress';
28
import { ITextModelService, ITextModelContentProvider, ITextEditorModel } from 'vs/editor/common/services/resolverService';
29
import { IDisposable, IReference, ImmortalReference, combinedDisposable } from 'vs/base/common/lifecycle';
30 31
import * as dom from 'vs/base/browser/dom';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
A
Renames  
Alex Dima 已提交
32
import { KeybindingsRegistry, IKeybindingItem } from 'vs/platform/keybinding/common/keybindingsRegistry';
33
import { MenuId, IMenu, IMenuService } from 'vs/platform/actions/common/actions';
A
Alex Dima 已提交
34
import { Menu } from 'vs/platform/actions/common/menu';
35
import { ITelemetryService, ITelemetryExperiments, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
36
import { ResolvedKeybinding, Keybinding, createKeybinding, SimpleKeybinding } from 'vs/base/common/keyCodes';
37
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
A
Alex Dima 已提交
38
import { OS } from 'vs/base/common/platform';
39
import { IRange } from 'vs/editor/common/core/range';
E
Erich Gamma 已提交
40 41 42

export class SimpleEditor implements IEditor {

J
Johannes Rieken 已提交
43 44 45
	public input: IEditorInput;
	public options: IEditorOptions;
	public position: Position;
E
Erich Gamma 已提交
46

J
Johannes Rieken 已提交
47
	public _widget: editorCommon.IEditor;
E
Erich Gamma 已提交
48

J
Johannes Rieken 已提交
49
	constructor(editor: editorCommon.IEditor) {
E
Erich Gamma 已提交
50 51 52
		this._widget = editor;
	}

J
Johannes Rieken 已提交
53 54 55 56 57
	public getId(): string { return 'editor'; }
	public getControl(): editorCommon.IEditor { return this._widget; }
	public getSelection(): Selection { return this._widget.getSelection(); }
	public focus(): void { this._widget.focus(); }
	public isVisible(): boolean { return true; }
E
Erich Gamma 已提交
58

J
Johannes Rieken 已提交
59
	public withTypedEditor<T>(codeEditorCallback: (editor: ICodeEditor) => T, diffEditorCallback: (editor: IDiffEditor) => T): T {
A
Alex Dima 已提交
60
		if (editorCommon.isCommonCodeEditor(this._widget)) {
E
Erich Gamma 已提交
61
			// Single Editor
A
Alex Dima 已提交
62
			return codeEditorCallback(<ICodeEditor>this._widget);
E
Erich Gamma 已提交
63 64
		} else {
			// Diff Editor
A
Alex Dima 已提交
65
			return diffEditorCallback(<IDiffEditor>this._widget);
E
Erich Gamma 已提交
66 67 68 69
		}
	}
}

J
Johannes Rieken 已提交
70
export class SimpleModel implements ITextEditorModel {
E
Erich Gamma 已提交
71

J
Johannes Rieken 已提交
72
	private model: editorCommon.IModel;
73
	private _onDispose: Emitter<void>;
E
Erich Gamma 已提交
74

J
Johannes Rieken 已提交
75
	constructor(model: editorCommon.IModel) {
E
Erich Gamma 已提交
76
		this.model = model;
77 78 79 80 81
		this._onDispose = new Emitter<void>();
	}

	public get onDispose(): Event<void> {
		return this._onDispose.event;
E
Erich Gamma 已提交
82 83
	}

84 85 86 87
	public load(): TPromise<SimpleModel> {
		return TPromise.as(this);
	}

J
Johannes Rieken 已提交
88
	public get textEditorModel(): editorCommon.IModel {
E
Erich Gamma 已提交
89 90
		return this.model;
	}
91 92 93 94

	public dispose(): void {
		this._onDispose.fire();
	}
E
Erich Gamma 已提交
95 96 97
}

export interface IOpenEditorDelegate {
J
Johannes Rieken 已提交
98
	(url: string): boolean;
E
Erich Gamma 已提交
99 100 101
}

export class SimpleEditorService implements IEditorService {
102
	public _serviceBrand: any;
E
Erich Gamma 已提交
103

J
Johannes Rieken 已提交
104 105
	private editor: SimpleEditor;
	private openEditorDelegate: IOpenEditorDelegate;
E
Erich Gamma 已提交
106 107 108 109 110

	constructor() {
		this.openEditorDelegate = null;
	}

J
Johannes Rieken 已提交
111
	public setEditor(editor: editorCommon.IEditor): void {
E
Erich Gamma 已提交
112 113 114
		this.editor = new SimpleEditor(editor);
	}

J
Johannes Rieken 已提交
115
	public setOpenEditorDelegate(openEditorDelegate: IOpenEditorDelegate): void {
E
Erich Gamma 已提交
116 117 118
		this.openEditorDelegate = openEditorDelegate;
	}

J
Johannes Rieken 已提交
119
	public openEditor(typedData: IResourceInput, sideBySide?: boolean): TPromise<IEditor> {
E
Erich Gamma 已提交
120 121 122 123 124 125 126 127 128
		return TPromise.as(this.editor.withTypedEditor(
			(editor) => this.doOpenEditor(editor, typedData),
			(diffEditor) => (
				this.doOpenEditor(diffEditor.getOriginalEditor(), typedData) ||
				this.doOpenEditor(diffEditor.getModifiedEditor(), typedData)
			)
		));
	}

J
Johannes Rieken 已提交
129
	private doOpenEditor(editor: editorCommon.ICommonCodeEditor, data: IResourceInput): IEditor {
A
Alex Dima 已提交
130
		let model = this.findModel(editor, data);
E
Erich Gamma 已提交
131 132 133 134 135 136
		if (!model) {
			if (data.resource) {
				if (this.openEditorDelegate) {
					this.openEditorDelegate(data.resource.toString());
					return null;
				} else {
A
Alex Dima 已提交
137
					let schema = data.resource.scheme;
A
Alex Dima 已提交
138
					if (schema === Schemas.http || schema === Schemas.https) {
E
Erich Gamma 已提交
139 140 141 142 143 144 145 146 147
						// This is a fully qualified http or https URL
						window.open(data.resource.toString());
						return this.editor;
					}
				}
			}
			return null;
		}

A
Alex Dima 已提交
148
		let selection = <IRange>data.options.selection;
E
Erich Gamma 已提交
149 150 151
		if (selection) {
			if (typeof selection.endLineNumber === 'number' && typeof selection.endColumn === 'number') {
				editor.setSelection(selection);
A
Alex Dima 已提交
152
				editor.revealRangeInCenter(selection);
E
Erich Gamma 已提交
153
			} else {
A
Alex Dima 已提交
154
				let pos = {
E
Erich Gamma 已提交
155 156 157 158 159 160 161 162 163 164 165
					lineNumber: selection.startLineNumber,
					column: selection.startColumn
				};
				editor.setPosition(pos);
				editor.revealPositionInCenter(pos);
			}
		}

		return this.editor;
	}

J
Johannes Rieken 已提交
166
	private findModel(editor: editorCommon.ICommonCodeEditor, data: IResourceInput): editorCommon.IModel {
A
Alex Dima 已提交
167
		let model = editor.getModel();
J
Johannes Rieken 已提交
168
		if (model.uri.toString() !== data.resource.toString()) {
E
Erich Gamma 已提交
169 170 171 172 173 174 175
			return null;
		}

		return model;
	}
}

176
export class SimpleEditorModelResolverService implements ITextModelService {
177 178 179 180 181 182 183 184
	public _serviceBrand: any;

	private editor: SimpleEditor;

	public setEditor(editor: editorCommon.IEditor): void {
		this.editor = new SimpleEditor(editor);
	}

J
Joao Moreno 已提交
185
	public createModelReference(resource: URI): TPromise<IReference<ITextEditorModel>> {
186 187 188 189 190 191 192 193
		let model: editorCommon.IModel;

		model = this.editor.withTypedEditor(
			(editor) => this.findModel(editor, resource),
			(diffEditor) => this.findModel(diffEditor.getOriginalEditor(), resource) || this.findModel(diffEditor.getModifiedEditor(), resource)
		);

		if (!model) {
J
Joao Moreno 已提交
194
			return TPromise.as(new ImmortalReference(null));
195 196
		}

J
Joao Moreno 已提交
197
		return TPromise.as(new ImmortalReference(new SimpleModel(model)));
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
	}

	public registerTextModelContentProvider(scheme: string, provider: ITextModelContentProvider): IDisposable {
		return {
			dispose: function () { /* no op */ }
		};
	}

	private findModel(editor: editorCommon.ICommonCodeEditor, resource: URI): editorCommon.IModel {
		let model = editor.getModel();
		if (model.uri.toString() !== resource.toString()) {
			return null;
		}

		return model;
	}
}

216 217 218
export class SimpleProgressService implements IProgressService {
	_serviceBrand: any;

J
Johannes Rieken 已提交
219 220 221 222
	private static NULL_PROGRESS_RUNNER: IProgressRunner = {
		done: () => { },
		total: () => { },
		worked: () => { }
223 224 225 226 227 228 229 230 231 232 233 234 235
	};

	show(infinite: boolean, delay?: number): IProgressRunner;
	show(total: number, delay?: number): IProgressRunner;
	show(): IProgressRunner {
		return SimpleProgressService.NULL_PROGRESS_RUNNER;
	}

	showWhile(promise: TPromise<any>, delay?: number): TPromise<void> {
		return null;
	}
}

E
Erich Gamma 已提交
236
export class SimpleMessageService implements IMessageService {
237
	public _serviceBrand: any;
E
Erich Gamma 已提交
238

J
Johannes Rieken 已提交
239
	private static Empty = function () { /* nothing */ };
E
Erich Gamma 已提交
240

J
Johannes Rieken 已提交
241
	public show(sev: Severity, message: any): () => void {
E
Erich Gamma 已提交
242

J
Johannes Rieken 已提交
243
		switch (sev) {
E
Erich Gamma 已提交
244
			case Severity.Error:
245
				console.error(message);
E
Erich Gamma 已提交
246 247 248 249 250 251 252 253 254 255 256 257
				break;
			case Severity.Warning:
				console.warn(message);
				break;
			default:
				console.log(message);
				break;
		}

		return SimpleMessageService.Empty;
	}

J
Johannes Rieken 已提交
258
	public hideAll(): void {
E
Erich Gamma 已提交
259 260 261
		// No-op
	}

J
Johannes Rieken 已提交
262
	public confirm(confirmation: IConfirmation): boolean {
A
Alex Dima 已提交
263
		let messageText = confirmation.message;
E
Erich Gamma 已提交
264 265 266 267 268 269
		if (confirmation.detail) {
			messageText = messageText + '\n\n' + confirmation.detail;
		}

		return window.confirm(messageText);
	}
A
Alex Dima 已提交
270 271
}

A
Alex Dima 已提交
272 273
export class StandaloneCommandService implements ICommandService {
	_serviceBrand: any;
274

A
Alex Dima 已提交
275
	private readonly _instantiationService: IInstantiationService;
276 277
	private _dynamicCommands: { [id: string]: ICommand; };

278 279 280
	private _onWillExecuteCommand: Emitter<ICommandEvent> = new Emitter<ICommandEvent>();
	public readonly onWillExecuteCommand: Event<ICommandEvent> = this._onWillExecuteCommand.event;

A
Alex Dima 已提交
281 282
	constructor(instantiationService: IInstantiationService) {
		this._instantiationService = instantiationService;
283 284 285
		this._dynamicCommands = Object.create(null);
	}

286
	public addCommand(id: string, command: ICommand): IDisposable {
287
		this._dynamicCommands[id] = command;
288 289 290 291 292
		return {
			dispose: () => {
				delete this._dynamicCommands[id];
			}
		};
293 294
	}

A
Alex Dima 已提交
295 296 297
	public executeCommand<T>(id: string, ...args: any[]): TPromise<T> {
		const command = (CommandsRegistry.getCommand(id) || this._dynamicCommands[id]);
		if (!command) {
298
			return TPromise.wrapError<T>(new Error(`command '${id}' not found`));
A
Alex Dima 已提交
299 300 301
		}

		try {
302
			this._onWillExecuteCommand.fire({ commandId: id });
A
Alex Dima 已提交
303 304 305
			const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler].concat(args));
			return TPromise.as(result);
		} catch (err) {
306
			return TPromise.wrapError<T>(err);
A
Alex Dima 已提交
307
		}
308 309 310
	}
}

311 312
export class StandaloneKeybindingService extends AbstractKeybindingService {
	private _cachedResolver: KeybindingResolver;
E
Erich Gamma 已提交
313 314
	private _dynamicKeybindings: IKeybindingItem[];

A
Alex Dima 已提交
315
	constructor(
316
		contextKeyService: IContextKeyService,
A
Alex Dima 已提交
317 318 319 320
		commandService: ICommandService,
		messageService: IMessageService,
		domNode: HTMLElement
	) {
321
		super(contextKeyService, commandService, messageService);
322

323
		this._cachedResolver = null;
E
Erich Gamma 已提交
324
		this._dynamicKeybindings = [];
325

326 327
		this.toDispose.push(dom.addDisposableListener(domNode, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {
			let keyEvent = new StandardKeyboardEvent(e);
328
			let shouldPreventDefault = this._dispatch(keyEvent, keyEvent.target);
329 330 331 332
			if (shouldPreventDefault) {
				keyEvent.preventDefault();
			}
		}));
E
Erich Gamma 已提交
333 334
	}

335
	public addDynamicKeybinding(commandId: string, keybinding: number, handler: ICommandHandler, when: ContextKeyExpr): IDisposable {
336 337
		let toDispose: IDisposable[] = [];

E
Erich Gamma 已提交
338
		this._dynamicKeybindings.push({
A
Renames  
Alex Dima 已提交
339
			keybinding: createKeybinding(keybinding, OS),
E
Erich Gamma 已提交
340
			command: commandId,
341
			when: when,
E
Erich Gamma 已提交
342 343 344
			weight1: 1000,
			weight2: 0
		});
345

346 347 348 349 350 351 352 353 354 355 356 357 358
		toDispose.push({
			dispose: () => {
				for (let i = 0; i < this._dynamicKeybindings.length; i++) {
					let kb = this._dynamicKeybindings[i];
					if (kb.command === commandId) {
						this._dynamicKeybindings.splice(i, 1);
						this.updateResolver({ source: KeybindingSource.Default });
						return;
					}
				}
			}
		});

359 360
		let commandService = this._commandService;
		if (commandService instanceof StandaloneCommandService) {
361
			toDispose.push(commandService.addCommand(commandId, {
362
				handler: handler
363
			}));
364 365 366
		} else {
			throw new Error('Unknown command service!');
		}
C
Christof Marti 已提交
367
		this.updateResolver({ source: KeybindingSource.Default });
368

369
		return combinedDisposable(toDispose);
E
Erich Gamma 已提交
370 371
	}

372 373 374 375 376 377 378
	private updateResolver(event: IKeybindingEvent): void {
		this._cachedResolver = null;
		this._onDidUpdateKeybindings.fire(event);
	}

	protected _getResolver(): KeybindingResolver {
		if (!this._cachedResolver) {
379 380
			const defaults = this._toNormalizedKeybindingItems(KeybindingsRegistry.getDefaultKeybindings(), true);
			const overrides = this._toNormalizedKeybindingItems(this._dynamicKeybindings, false);
381
			this._cachedResolver = new KeybindingResolver(defaults, overrides);
382 383 384 385
		}
		return this._cachedResolver;
	}

386 387
	private _toNormalizedKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] {
		let result: ResolvedKeybindingItem[] = [], resultLen = 0;
388 389 390
		for (let i = 0, len = items.length; i < len; i++) {
			const item = items[i];
			const when = (item.when ? item.when.normalize() : null);
A
Alex Dima 已提交
391
			const keybinding = item.keybinding;
392

393 394 395 396 397 398 399 400 401
			if (!keybinding) {
				// This might be a removal keybinding item in user settings => accept it
				result[resultLen++] = new ResolvedKeybindingItem(null, item.command, item.commandArgs, when, isDefault);
			} else {
				const resolvedKeybindings = this.resolveKeybinding(keybinding);
				for (let j = 0; j < resolvedKeybindings.length; j++) {
					result[resultLen++] = new ResolvedKeybindingItem(resolvedKeybindings[j], item.command, item.commandArgs, when, isDefault);
				}
			}
402 403 404 405 406
		}

		return result;
	}

407 408
	public resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding[] {
		return [new USLayoutResolvedKeybinding(keybinding, OS)];
A
Alex Dima 已提交
409 410
	}

411 412 413 414 415 416 417 418
	public resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding {
		let keybinding = new SimpleKeybinding(
			keyboardEvent.ctrlKey,
			keyboardEvent.shiftKey,
			keyboardEvent.altKey,
			keyboardEvent.metaKey,
			keyboardEvent.keyCode
		);
419
		return new USLayoutResolvedKeybinding(keybinding, OS);
420
	}
421 422 423 424

	public resolveUserBinding(userBinding: string): ResolvedKeybinding[] {
		return [];
	}
E
Erich Gamma 已提交
425 426
}

427
export class SimpleConfigurationService implements IConfigurationService {
428

429 430
	_serviceBrand: any;

431 432
	private _onDidUpdateConfiguration = new Emitter<IConfigurationServiceEvent>();
	public onDidUpdateConfiguration: Event<IConfigurationServiceEvent> = this._onDidUpdateConfiguration.event;
433

434
	private _config: any;
435

436 437
	constructor() {
		this._config = getDefaultConfiguration();
438 439
	}

440
	public getConfiguration<T>(section?: any): T {
441
		return this._config;
442 443
	}

444
	public reloadConfiguration<T>(section?: string): TPromise<T> {
445
		return TPromise.as<T>(this.getConfiguration<T>(section));
446
	}
B
Benjamin Pasero 已提交
447 448 449 450 451 452 453 454

	public lookup<C>(key: string): IConfigurationValue<C> {
		return {
			value: getConfigurationValue<C>(this.getConfiguration(), key),
			default: getConfigurationValue<C>(this.getConfiguration(), key),
			user: getConfigurationValue<C>(this.getConfiguration(), key)
		};
	}
B
Benjamin Pasero 已提交
455 456 457 458

	public keys(): IConfigurationKeys {
		return { default: [], user: [] };
	}
459
}
A
Alex Dima 已提交
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474

export class SimpleMenuService implements IMenuService {

	_serviceBrand: any;

	private readonly _commandService: ICommandService;

	constructor(commandService: ICommandService) {
		this._commandService = commandService;
	}

	public createMenu(id: MenuId, contextKeyService: IContextKeyService): IMenu {
		return new Menu(id, TPromise.as(true), this._commandService, contextKeyService);
	}
}
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492

export class StandaloneTelemetryService implements ITelemetryService {
	_serviceBrand: void;

	public isOptedIn = false;

	public publicLog(eventName: string, data?: any): TPromise<void> {
		return TPromise.as<void>(null);
	}

	public getTelemetryInfo(): TPromise<ITelemetryInfo> {
		return null;
	}

	public getExperiments(): ITelemetryExperiments {
		return null;
	}
}
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529

export class SimpleWorkspaceContextService implements IWorkspaceContextService {

	public _serviceBrand: any;

	private readonly _onDidChangeFolders: Emitter<URI[]> = new Emitter<URI[]>();
	public readonly onDidChangeFolders: Event<URI[]> = this._onDidChangeFolders.event;

	private readonly folders: URI[];

	constructor(private workspace?: Workspace) {
		this.folders = workspace ? [workspace.resource] : [];
	}

	public getFolders(): URI[] {
		return this.folders;
	}

	public getWorkspace(): IWorkspace {
		return this.workspace;
	}

	public hasWorkspace(): boolean {
		return !!this.workspace;
	}

	public isInsideWorkspace(resource: URI): boolean {
		return this.workspace ? this.workspace.isInsideWorkspace(resource) : false;
	}

	public toWorkspaceRelativePath(resource: URI, toOSPath?: boolean): string {
		return this.workspace ? this.workspace.toWorkspaceRelativePath(resource, toOSPath) : null;
	}

	public toResource(workspaceRelativePath: string): URI {
		return this.workspace ? this.workspace.toResource(workspaceRelativePath) : null;
	}
530
}