mainThreadEditors.ts 12.2 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
import URI from 'vs/base/common/uri';
J
Johannes Rieken 已提交
8
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
9
import { disposed } from 'vs/base/common/errors';
J
Johannes Rieken 已提交
10
import { TPromise } from 'vs/base/common/winjs.base';
11
import { ISingleEditOperation, IDecorationRenderOptions, IDecorationOptions, ILineChange, ICommonCodeEditor, isCommonCodeEditor } from 'vs/editor/common/editorCommon';
J
Johannes Rieken 已提交
12 13 14
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
15
import { Position as EditorPosition, ITextEditorOptions } from 'vs/platform/editor/common/editor';
16 17
import { MainThreadTextEditor } from './mainThreadEditor';
import { ITextEditorConfigurationUpdate, TextEditorRevealType, IApplyEditsOptions, IUndoStopOptions } from 'vs/workbench/api/node/extHost.protocol';
J
Johannes Rieken 已提交
18
import { MainThreadDocumentsAndEditors } from './mainThreadDocumentsAndEditors';
J
Johannes Rieken 已提交
19 20
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { equals as objectEquals } from 'vs/base/common/objects';
21
import { ExtHostContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IExtHostContext, IWorkspaceResourceEdit } from '../node/extHost.protocol';
22 23
import { IRange } from 'vs/editor/common/core/range';
import { ISelection } from 'vs/editor/common/core/selection';
24 25 26 27
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IFileService } from 'vs/platform/files/common/files';
import { bulkEdit, IResourceEdit } from 'vs/editor/common/services/bulkEdit';
import { IModelService } from 'vs/editor/common/services/modelService';
28

29
export class MainThreadEditors implements MainThreadEditorsShape {
30

31
	private _proxy: ExtHostEditorsShape;
J
Johannes Rieken 已提交
32
	private _documentsAndEditors: MainThreadDocumentsAndEditors;
33 34 35 36 37
	private _workbenchEditorService: IWorkbenchEditorService;
	private _telemetryService: ITelemetryService;
	private _toDispose: IDisposable[];
	private _textEditorsListenersMap: { [editorId: string]: IDisposable[]; };
	private _editorPositionData: ITextEditorPositionData;
38
	private _registeredDecorationTypes: { [decorationType: string]: boolean; };
E
Erich Gamma 已提交
39

40
	constructor(
J
Johannes Rieken 已提交
41
		documentsAndEditors: MainThreadDocumentsAndEditors,
42
		extHostContext: IExtHostContext,
J
Johannes Rieken 已提交
43
		@ICodeEditorService private _codeEditorService: ICodeEditorService,
44 45
		@IWorkbenchEditorService workbenchEditorService: IWorkbenchEditorService,
		@IEditorGroupService editorGroupService: IEditorGroupService,
46 47 48 49
		@ITelemetryService telemetryService: ITelemetryService,
		@ITextModelService private readonly _textModelResolverService: ITextModelService,
		@IFileService private readonly _fileService: IFileService,
		@IModelService private readonly _modelService: IModelService,
50
	) {
51
		this._proxy = extHostContext.get(ExtHostContext.ExtHostEditors);
J
Johannes Rieken 已提交
52
		this._documentsAndEditors = documentsAndEditors;
53 54 55 56 57
		this._workbenchEditorService = workbenchEditorService;
		this._telemetryService = telemetryService;
		this._toDispose = [];
		this._textEditorsListenersMap = Object.create(null);
		this._editorPositionData = null;
E
Erich Gamma 已提交
58

J
Johannes Rieken 已提交
59 60
		this._toDispose.push(documentsAndEditors.onTextEditorAdd(editors => editors.forEach(this._onTextEditorAdd, this)));
		this._toDispose.push(documentsAndEditors.onTextEditorRemove(editors => editors.forEach(this._onTextEditorRemove, this)));
E
Erich Gamma 已提交
61

62 63
		this._toDispose.push(editorGroupService.onEditorsChanged(() => this._updateActiveAndVisibleTextEditors()));
		this._toDispose.push(editorGroupService.onEditorsMoved(() => this._updateActiveAndVisibleTextEditors()));
64 65

		this._registeredDecorationTypes = Object.create(null);
E
Erich Gamma 已提交
66 67
	}

68 69 70 71 72 73
	public dispose(): void {
		Object.keys(this._textEditorsListenersMap).forEach((editorId) => {
			dispose(this._textEditorsListenersMap[editorId]);
		});
		this._textEditorsListenersMap = Object.create(null);
		this._toDispose = dispose(this._toDispose);
74 75 76 77
		for (let decorationType in this._registeredDecorationTypes) {
			this._codeEditorService.removeDecorationType(decorationType);
		}
		this._registeredDecorationTypes = Object.create(null);
E
Erich Gamma 已提交
78 79
	}

80 81 82 83
	private _onTextEditorAdd(textEditor: MainThreadTextEditor): void {
		let id = textEditor.getId();
		let toDispose: IDisposable[] = [];
		toDispose.push(textEditor.onConfigurationChanged((opts) => {
84
			this._proxy.$acceptOptionsChanged(id, opts);
85
		}));
86 87
		toDispose.push(textEditor.onSelectionChanged((event) => {
			this._proxy.$acceptSelectionsChanged(id, event);
88
		}));
E
Erich Gamma 已提交
89

90
		this._textEditorsListenersMap[id] = toDispose;
E
Erich Gamma 已提交
91 92
	}

J
Johannes Rieken 已提交
93
	private _onTextEditorRemove(id: string): void {
94 95
		dispose(this._textEditorsListenersMap[id]);
		delete this._textEditorsListenersMap[id];
E
Erich Gamma 已提交
96 97
	}

98
	private _updateActiveAndVisibleTextEditors(): void {
E
Erich Gamma 已提交
99

100 101 102 103
		// editor columns
		let editorPositionData = this._getTextEditorPositionData();
		if (!objectEquals(this._editorPositionData, editorPositionData)) {
			this._editorPositionData = editorPositionData;
104
			this._proxy.$acceptEditorPositionData(this._editorPositionData);
E
Erich Gamma 已提交
105 106 107
		}
	}

108 109 110
	private _getTextEditorPositionData(): ITextEditorPositionData {
		let result: ITextEditorPositionData = Object.create(null);
		for (let workbenchEditor of this._workbenchEditorService.getVisibleEditors()) {
J
Johannes Rieken 已提交
111 112 113
			const id = this._documentsAndEditors.findTextEditorIdFor(workbenchEditor);
			if (id) {
				result[id] = workbenchEditor.position;
114
			}
E
Erich Gamma 已提交
115
		}
116
		return result;
E
Erich Gamma 已提交
117 118
	}

119
	// --- from extension host process
E
Erich Gamma 已提交
120

121
	$tryShowTextDocument(resource: URI, options: ITextDocumentShowOptions): TPromise<string> {
122
		const editorOptions: ITextEditorOptions = {
123
			preserveFocus: options.preserveFocus,
124 125
			pinned: options.pinned,
			selection: options.selection
126
		};
E
Erich Gamma 已提交
127

128 129
		const input = {
			resource,
130
			options: editorOptions
E
Erich Gamma 已提交
131 132
		};

133
		return this._workbenchEditorService.openEditor(input, options.position).then(editor => {
134
			if (!editor) {
M
Matt Bierner 已提交
135
				return undefined;
E
Erich Gamma 已提交
136
			}
J
Johannes Rieken 已提交
137
			return this._documentsAndEditors.findTextEditorIdFor(editor);
E
Erich Gamma 已提交
138 139 140
		});
	}

141
	$tryShowEditor(id: string, position: EditorPosition): TPromise<void> {
142
		// check how often this is used
K
kieferrm 已提交
143
		/* __GDPR__
K
kieferrm 已提交
144 145 146 147
			"api.deprecated" : {
				"function" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
			}
		*/
148
		this._telemetryService.publicLog('api.deprecated', { function: 'TextEditor.show' });
E
Erich Gamma 已提交
149

J
Johannes Rieken 已提交
150
		let mainThreadEditor = this._documentsAndEditors.getEditor(id);
151 152 153 154 155 156
		if (mainThreadEditor) {
			let model = mainThreadEditor.getModel();
			return this._workbenchEditorService.openEditor({
				resource: model.uri,
				options: { preserveFocus: false }
			}, position).then(() => { return; });
E
Erich Gamma 已提交
157
		}
M
Matt Bierner 已提交
158
		return undefined;
E
Erich Gamma 已提交
159 160
	}

161
	$tryHideEditor(id: string): TPromise<void> {
162
		// check how often this is used
K
kieferrm 已提交
163
		/* __GDPR__
K
kieferrm 已提交
164 165 166 167
			"api.deprecated" : {
				"function" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
			}
		*/
168 169
		this._telemetryService.publicLog('api.deprecated', { function: 'TextEditor.hide' });

J
Johannes Rieken 已提交
170
		let mainThreadEditor = this._documentsAndEditors.getEditor(id);
171 172 173 174 175
		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 已提交
176 177 178
				}
			}
		}
M
Matt Bierner 已提交
179
		return undefined;
E
Erich Gamma 已提交
180 181
	}

182
	$trySetSelections(id: string, selections: ISelection[]): TPromise<any> {
J
Johannes Rieken 已提交
183
		if (!this._documentsAndEditors.getEditor(id)) {
184
			return TPromise.wrapError(disposed(`TextEditor(${id})`));
E
Erich Gamma 已提交
185
		}
J
Johannes Rieken 已提交
186
		this._documentsAndEditors.getEditor(id).setSelections(selections);
187
		return TPromise.as(null);
E
Erich Gamma 已提交
188 189
	}

190
	$trySetDecorations(id: string, key: string, ranges: IDecorationOptions[]): TPromise<any> {
J
Johannes Rieken 已提交
191
		if (!this._documentsAndEditors.getEditor(id)) {
192
			return TPromise.wrapError(disposed(`TextEditor(${id})`));
193
		}
J
Johannes Rieken 已提交
194
		this._documentsAndEditors.getEditor(id).setDecorations(key, ranges);
195
		return TPromise.as(null);
E
Erich Gamma 已提交
196 197
	}

198 199 200 201 202 203 204 205
	$trySetDecorationsFast(id: string, key: string, ranges: string): TPromise<any> {
		if (!this._documentsAndEditors.getEditor(id)) {
			return TPromise.wrapError(disposed(`TextEditor(${id})`));
		}
		this._documentsAndEditors.getEditor(id).setDecorationsFast(key, /*TODO: marshaller is too slow*/JSON.parse(ranges));
		return TPromise.as(null);
	}

206
	$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise<any> {
J
Johannes Rieken 已提交
207
		if (!this._documentsAndEditors.getEditor(id)) {
208
			return TPromise.wrapError(disposed(`TextEditor(${id})`));
209
		}
J
Johannes Rieken 已提交
210
		this._documentsAndEditors.getEditor(id).revealRange(range, revealType);
M
Matt Bierner 已提交
211
		return undefined;
E
Erich Gamma 已提交
212 213
	}

214
	$trySetOptions(id: string, options: ITextEditorConfigurationUpdate): TPromise<any> {
J
Johannes Rieken 已提交
215
		if (!this._documentsAndEditors.getEditor(id)) {
216
			return TPromise.wrapError(disposed(`TextEditor(${id})`));
E
Erich Gamma 已提交
217
		}
J
Johannes Rieken 已提交
218
		this._documentsAndEditors.getEditor(id).setConfiguration(options);
219
		return TPromise.as(null);
E
Erich Gamma 已提交
220 221
	}

J
Johannes Rieken 已提交
222
	$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): TPromise<boolean> {
J
Johannes Rieken 已提交
223
		if (!this._documentsAndEditors.getEditor(id)) {
224
			return TPromise.wrapError<boolean>(disposed(`TextEditor(${id})`));
225
		}
J
Johannes Rieken 已提交
226
		return TPromise.as(this._documentsAndEditors.getEditor(id).applyEdits(modelVersionId, edits, opts));
E
Erich Gamma 已提交
227 228
	}

229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
	$tryApplyWorkspaceEdit(workspaceResourceEdits: IWorkspaceResourceEdit[]): TPromise<boolean> {

		// First check if loaded models were not changed in the meantime
		for (let i = 0, len = workspaceResourceEdits.length; i < len; i++) {
			const workspaceResourceEdit = workspaceResourceEdits[i];
			if (workspaceResourceEdit.modelVersionId) {
				let model = this._modelService.getModel(workspaceResourceEdit.resource);
				if (model && model.getVersionId() !== workspaceResourceEdit.modelVersionId) {
					// model changed in the meantime
					return TPromise.as(false);
				}
			}
		}

		// Convert to shape expected by bulkEdit below
		let resourceEdits: IResourceEdit[] = [];
		for (let i = 0, len = workspaceResourceEdits.length; i < len; i++) {
			const workspaceResourceEdit = workspaceResourceEdits[i];
			const uri = workspaceResourceEdit.resource;
			const edits = workspaceResourceEdit.edits;

			for (let j = 0, lenJ = edits.length; j < lenJ; j++) {
				const edit = edits[j];

				resourceEdits.push({
J
Johannes Rieken 已提交
254
					resource: uri,
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
					newText: edit.newText,
					newEol: edit.newEol,
					range: edit.range
				});
			}
		}

		let codeEditor: ICommonCodeEditor;
		let editor = this._workbenchEditorService.getActiveEditor();
		if (editor) {
			let candidate = editor.getControl();
			if (isCommonCodeEditor(candidate)) {
				codeEditor = candidate;
			}
		}

		return bulkEdit(this._textModelResolverService, codeEditor, resourceEdits, this._fileService)
			.then(() => true);
	}

275
	$tryInsertSnippet(id: string, template: string, ranges: IRange[], opts: IUndoStopOptions): TPromise<boolean> {
J
Johannes Rieken 已提交
276
		if (!this._documentsAndEditors.getEditor(id)) {
277
			return TPromise.wrapError<boolean>(disposed(`TextEditor(${id})`));
278
		}
J
Johannes Rieken 已提交
279
		return TPromise.as(this._documentsAndEditors.getEditor(id).insertSnippet(template, ranges, opts));
280 281
	}

282
	$registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void {
283
		this._registeredDecorationTypes[key] = true;
J
Johannes Rieken 已提交
284
		this._codeEditorService.registerDecorationType(key, options);
E
Erich Gamma 已提交
285 286
	}

287
	$removeTextEditorDecorationType(key: string): void {
288
		delete this._registeredDecorationTypes[key];
J
Johannes Rieken 已提交
289
		this._codeEditorService.removeDecorationType(key);
290 291 292 293 294 295
	}

	$getDiffInformation(id: string): TPromise<ILineChange[]> {
		const editor = this._documentsAndEditors.getEditor(id);

		if (!editor) {
296
			return TPromise.wrapError<ILineChange[]>(new Error('No such TextEditor'));
297 298 299 300 301 302 303 304 305 306
		}

		const codeEditor = editor.getCodeEditor();
		const codeEditorId = codeEditor.getId();
		const diffEditors = this._codeEditorService.listDiffEditors();
		const [diffEditor] = diffEditors.filter(d => d.getOriginalEditor().getId() === codeEditorId || d.getModifiedEditor().getId() === codeEditorId);

		if (!diffEditor) {
			return TPromise.as([]);
		}
J
Johannes Rieken 已提交
307

308
		return TPromise.as(diffEditor.getLineChanges());
E
Erich Gamma 已提交
309
	}
A
Alex Dima 已提交
310
}