mainThreadEditors.ts 11.3 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';

7 8 9 10 11 12
import URI from 'vs/base/common/uri';
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
import {TPromise} from 'vs/base/common/winjs.base';
import {IThreadService} from 'vs/workbench/services/thread/common/threadService';
import {EndOfLine} from './extHostTypes';
import {ISingleEditOperation, ISelection, IRange, IEditor, EditorType, ICommonCodeEditor, ICommonDiffEditor, IDecorationRenderOptions, IDecorationOptions} from 'vs/editor/common/editorCommon';
E
Erich Gamma 已提交
13
import {ICodeEditorService} from 'vs/editor/common/services/codeEditorService';
14 15 16
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService';
import {Position as EditorPosition} from 'vs/platform/editor/common/editor';
E
Erich Gamma 已提交
17
import {IModelService} from 'vs/editor/common/services/modelService';
18 19 20 21 22
import {MainThreadEditorsTracker, TextEditorRevealType, MainThreadTextEditor, ITextEditorConfigurationUpdate} from 'vs/workbench/api/node/mainThreadEditorsTracker';
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {IEventService} from 'vs/platform/event/common/event';
import {equals as arrayEquals} from 'vs/base/common/arrays';
import {equals as objectEquals} from 'vs/base/common/objects';
A
Alex Dima 已提交
23
import {ExtHostContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextEditorPositionData} from './extHost.protocol';
24

A
Alex Dima 已提交
25
export class MainThreadEditors extends MainThreadEditorsShape {
26

27
	private _proxy: ExtHostEditorsShape;
28 29 30 31 32 33 34 35 36
	private _workbenchEditorService: IWorkbenchEditorService;
	private _telemetryService: ITelemetryService;
	private _editorTracker: MainThreadEditorsTracker;
	private _toDispose: IDisposable[];
	private _textEditorsListenersMap: { [editorId: string]: IDisposable[]; };
	private _textEditorsMap: { [editorId: string]: MainThreadTextEditor; };
	private _activeTextEditor: string;
	private _visibleEditors: string[];
	private _editorPositionData: ITextEditorPositionData;
E
Erich Gamma 已提交
37

38
	constructor(
39 40 41 42 43 44 45
		@IThreadService threadService: IThreadService,
		@IWorkbenchEditorService workbenchEditorService: IWorkbenchEditorService,
		@IEditorGroupService editorGroupService: IEditorGroupService,
		@ITelemetryService telemetryService: ITelemetryService,
		@ICodeEditorService editorService: ICodeEditorService,
		@IEventService eventService: IEventService,
		@IModelService modelService: IModelService
46
	) {
A
Alex Dima 已提交
47
		super();
48 49 50 51 52 53 54 55 56
		this._proxy = threadService.get(ExtHostContext.ExtHostEditors);
		this._workbenchEditorService = workbenchEditorService;
		this._telemetryService = telemetryService;
		this._toDispose = [];
		this._textEditorsListenersMap = Object.create(null);
		this._textEditorsMap = Object.create(null);
		this._activeTextEditor = null;
		this._visibleEditors = [];
		this._editorPositionData = null;
E
Erich Gamma 已提交
57

58 59
		this._editorTracker = new MainThreadEditorsTracker(editorService, modelService);
		this._toDispose.push(this._editorTracker);
E
Erich Gamma 已提交
60

61 62
		this._toDispose.push(this._editorTracker.onTextEditorAdd((textEditor) => this._onTextEditorAdd(textEditor)));
		this._toDispose.push(this._editorTracker.onTextEditorRemove((textEditor) => this._onTextEditorRemove(textEditor)));
E
Erich Gamma 已提交
63

64 65 66 67
		this._toDispose.push(this._editorTracker.onDidUpdateTextEditors(() => this._updateActiveAndVisibleTextEditors()));
		this._toDispose.push(this._editorTracker.onChangedFocusedTextEditor((focusedTextEditorId) => this._updateActiveAndVisibleTextEditors()));
		this._toDispose.push(editorGroupService.onEditorsChanged(() => this._updateActiveAndVisibleTextEditors()));
		this._toDispose.push(editorGroupService.onEditorsMoved(() => this._updateActiveAndVisibleTextEditors()));
E
Erich Gamma 已提交
68 69
	}

70 71 72 73 74 75
	public dispose(): void {
		Object.keys(this._textEditorsListenersMap).forEach((editorId) => {
			dispose(this._textEditorsListenersMap[editorId]);
		});
		this._textEditorsListenersMap = Object.create(null);
		this._toDispose = dispose(this._toDispose);
E
Erich Gamma 已提交
76 77
	}

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
	private _onTextEditorAdd(textEditor: MainThreadTextEditor): void {
		let id = textEditor.getId();
		let toDispose: IDisposable[] = [];
		toDispose.push(textEditor.onConfigurationChanged((opts) => {
			this._proxy._acceptOptionsChanged(id, opts);
		}));
		toDispose.push(textEditor.onSelectionChanged((selection) => {
			this._proxy._acceptSelectionsChanged(id, selection);
		}));
		this._proxy._acceptTextEditorAdd({
			id: id,
			document: textEditor.getModel().uri,
			options: textEditor.getConfiguration(),
			selections: textEditor.getSelections(),
			editorPosition: this._findEditorPosition(textEditor)
		});
E
Erich Gamma 已提交
94

95 96
		this._textEditorsListenersMap[id] = toDispose;
		this._textEditorsMap[id] = textEditor;
E
Erich Gamma 已提交
97 98
	}

99 100 101 102 103 104
	private _onTextEditorRemove(textEditor: MainThreadTextEditor): void {
		let id = textEditor.getId();
		dispose(this._textEditorsListenersMap[id]);
		delete this._textEditorsListenersMap[id];
		delete this._textEditorsMap[id];
		this._proxy._acceptTextEditorRemove(id);
E
Erich Gamma 已提交
105 106
	}

107
	private _updateActiveAndVisibleTextEditors(): void {
E
Erich Gamma 已提交
108

109 110 111 112 113 114 115
		// active and visible editors
		let visibleEditors = this._editorTracker.getVisibleTextEditorIds();
		let activeEditor = this._findActiveTextEditorId();
		if (activeEditor !== this._activeTextEditor || !arrayEquals(this._visibleEditors, visibleEditors, (a, b) => a === b)) {
			this._activeTextEditor = activeEditor;
			this._visibleEditors = visibleEditors;
			this._proxy._acceptActiveEditorAndVisibleEditors(this._activeTextEditor, this._visibleEditors);
E
Erich Gamma 已提交
116 117
		}

118 119 120 121 122
		// editor columns
		let editorPositionData = this._getTextEditorPositionData();
		if (!objectEquals(this._editorPositionData, editorPositionData)) {
			this._editorPositionData = editorPositionData;
			this._proxy._acceptEditorPositionData(this._editorPositionData);
E
Erich Gamma 已提交
123 124 125
		}
	}

126 127 128 129
	private _findActiveTextEditorId(): string {
		let focusedTextEditorId = this._editorTracker.getFocusedTextEditorId();
		if (focusedTextEditorId) {
			return focusedTextEditorId;
A
Alex Dima 已提交
130 131
		}

132 133 134
		let activeEditor = this._workbenchEditorService.getActiveEditor();
		if (!activeEditor) {
			return null;
E
Erich Gamma 已提交
135 136
		}

137 138 139 140 141
		let editor = <IEditor>activeEditor.getControl();
		// Substitute for (editor instanceof ICodeEditor)
		if (!editor || typeof editor.getEditorType !== 'function') {
			// Not a text editor...
			return null;
E
Erich Gamma 已提交
142 143
		}

144 145
		if (editor.getEditorType() === EditorType.ICodeEditor) {
			return this._editorTracker.findTextEditorIdFor(<ICommonCodeEditor>editor);
A
Alex Dima 已提交
146 147
		}

148 149
		// Must be a diff editor => use the modified side
		return this._editorTracker.findTextEditorIdFor((<ICommonDiffEditor>editor).getModifiedEditor());
E
Erich Gamma 已提交
150 151
	}

152 153 154 155 156
	private _findEditorPosition(editor: MainThreadTextEditor): EditorPosition {
		for (let workbenchEditor of this._workbenchEditorService.getVisibleEditors()) {
			if (editor.matches(workbenchEditor)) {
				return workbenchEditor.position;
			}
157
		}
E
Erich Gamma 已提交
158 159
	}

160 161 162 163 164 165 166 167 168 169 170 171 172 173
	private _getTextEditorPositionData(): ITextEditorPositionData {
		let result: ITextEditorPositionData = Object.create(null);
		for (let workbenchEditor of this._workbenchEditorService.getVisibleEditors()) {
			let editor = <IEditor>workbenchEditor.getControl();
			// Substitute for (editor instanceof ICodeEditor)
			if (!editor || typeof editor.getEditorType !== 'function') {
				// Not a text editor...
				continue;
			}
			if (editor.getEditorType() === EditorType.ICodeEditor) {
				let id = this._editorTracker.findTextEditorIdFor(<ICommonCodeEditor>editor);
				if (id) {
					result[id] = workbenchEditor.position;
				}
174
			}
E
Erich Gamma 已提交
175
		}
176
		return result;
E
Erich Gamma 已提交
177 178
	}

179
	// --- from extension host process
E
Erich Gamma 已提交
180

181
	_tryShowTextDocument(resource: URI, position: EditorPosition, preserveFocus: boolean): TPromise<string> {
E
Erich Gamma 已提交
182

183 184 185
		const input = {
			resource,
			options: { preserveFocus }
E
Erich Gamma 已提交
186 187
		};

188
		return this._workbenchEditorService.openEditor(input, position).then(editor => {
E
Erich Gamma 已提交
189

190
			if (!editor) {
E
Erich Gamma 已提交
191 192 193
				return;
			}

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
			return new TPromise<void>(c => {
				// not very nice but the way it is: changes to the editor state aren't
				// send to the ext host as they happen but stuff is delayed a little. in
				// order to provide the real editor on #openTextEditor we need to sync on
				// that update
				let subscription: IDisposable;
				let handle: number;
				function contd() {
					subscription.dispose();
					clearTimeout(handle);
					c(undefined);
				}
				subscription = this._editorTracker.onDidUpdateTextEditors(() => {
					contd();
				});
				handle = setTimeout(() => {
					contd();
				}, 1000);

			}).then(() => {
				// find the editor we have just opened and return the
				// id we have assigned to it.
				for (let id in this._textEditorsMap) {
					if (this._textEditorsMap[id].matches(editor)) {
						return id;
					}
				}
			});
E
Erich Gamma 已提交
222 223 224
		});
	}

225 226 227
	_tryShowEditor(id: string, position: EditorPosition): TPromise<void> {
		// check how often this is used
		this._telemetryService.publicLog('api.deprecated', { function: 'TextEditor.show' });
E
Erich Gamma 已提交
228

229 230 231 232 233 234 235
		let mainThreadEditor = this._textEditorsMap[id];
		if (mainThreadEditor) {
			let model = mainThreadEditor.getModel();
			return this._workbenchEditorService.openEditor({
				resource: model.uri,
				options: { preserveFocus: false }
			}, position).then(() => { return; });
E
Erich Gamma 已提交
236 237 238
		}
	}

239 240 241 242 243 244 245 246 247 248
	_tryHideEditor(id: string): TPromise<void> {
		// check how often this is used
		this._telemetryService.publicLog('api.deprecated', { function: 'TextEditor.hide' });

		let mainThreadEditor = this._textEditorsMap[id];
		if (mainThreadEditor) {
			let editors = this._workbenchEditorService.getVisibleEditors();
			for (let editor of editors) {
				if (mainThreadEditor.matches(editor)) {
					return this._workbenchEditorService.closeEditor(editor.position, editor.input).then(() => { return; });
E
Erich Gamma 已提交
249 250 251 252 253
				}
			}
		}
	}

254 255 256
	_trySetSelections(id: string, selections: ISelection[]): TPromise<any> {
		if (!this._textEditorsMap[id]) {
			return TPromise.wrapError('TextEditor disposed');
E
Erich Gamma 已提交
257
		}
258 259
		this._textEditorsMap[id].setSelections(selections);
		return TPromise.as(null);
E
Erich Gamma 已提交
260 261
	}

262 263 264 265 266 267
	_trySetDecorations(id: string, key: string, ranges: IDecorationOptions[]): TPromise<any> {
		if (!this._textEditorsMap[id]) {
			return TPromise.wrapError('TextEditor disposed');
		}
		this._textEditorsMap[id].setDecorations(key, ranges);
		return TPromise.as(null);
E
Erich Gamma 已提交
268 269
	}

270 271 272 273 274
	_tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise<any> {
		if (!this._textEditorsMap[id]) {
			return TPromise.wrapError('TextEditor disposed');
		}
		this._textEditorsMap[id].revealRange(range, revealType);
E
Erich Gamma 已提交
275 276
	}

277 278 279
	_trySetOptions(id: string, options: ITextEditorConfigurationUpdate): TPromise<any> {
		if (!this._textEditorsMap[id]) {
			return TPromise.wrapError('TextEditor disposed');
E
Erich Gamma 已提交
280
		}
281 282
		this._textEditorsMap[id].setConfiguration(options);
		return TPromise.as(null);
E
Erich Gamma 已提交
283 284
	}

285 286 287 288 289
	_tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], setEndOfLine:EndOfLine): TPromise<boolean> {
		if (!this._textEditorsMap[id]) {
			return TPromise.wrapError('TextEditor disposed');
		}
		return TPromise.as(this._textEditorsMap[id].applyEdits(modelVersionId, edits, setEndOfLine));
E
Erich Gamma 已提交
290 291
	}

292 293
	_registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void {
		this._editorTracker.registerTextEditorDecorationType(key, options);
E
Erich Gamma 已提交
294 295
	}

296 297
	_removeTextEditorDecorationType(key: string): void {
		this._editorTracker.removeTextEditorDecorationType(key);
E
Erich Gamma 已提交
298
	}
A
Alex Dima 已提交
299
}