mainThreadEditors.ts 9.8 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 { disposed } from 'vs/base/common/errors';
8 9 10
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { equals as objectEquals } from 'vs/base/common/objects';
import URI, { UriComponents } from 'vs/base/common/uri';
J
Johannes Rieken 已提交
11
import { TPromise } from 'vs/base/common/winjs.base';
12
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
13
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
14 15 16 17 18 19
import { IRange } from 'vs/editor/common/core/range';
import { ISelection } from 'vs/editor/common/core/selection';
import { IDecorationOptions, IDecorationRenderOptions, ILineChange } from 'vs/editor/common/editorCommon';
import { ISingleEditOperation } from 'vs/editor/common/model';
import { ITextEditorOptions, Position as EditorPosition } from 'vs/platform/editor/common/editor';
import { IApplyEditsOptions, ITextEditorConfigurationUpdate, IUndoStopOptions, TextEditorRevealType, WorkspaceEditDto, reviveWorkspaceEditDto } from 'vs/workbench/api/node/extHost.protocol';
J
Johannes Rieken 已提交
20 21
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
22
import { ExtHostContext, ExtHostEditorsShape, IExtHostContext, ITextDocumentShowOptions, ITextEditorPositionData, MainThreadTextEditorsShape } from '../node/extHost.protocol';
J
Johannes Rieken 已提交
23
import { MainThreadDocumentsAndEditors } from './mainThreadDocumentsAndEditors';
24
import { MainThreadTextEditor } from './mainThreadEditor';
25

26
export class MainThreadTextEditors implements MainThreadTextEditorsShape {
27

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

36
	constructor(
J
Johannes Rieken 已提交
37
		documentsAndEditors: MainThreadDocumentsAndEditors,
38
		extHostContext: IExtHostContext,
39
		@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
40
		@IBulkEditService private readonly _bulkEditService: IBulkEditService,
41 42
		@IWorkbenchEditorService workbenchEditorService: IWorkbenchEditorService,
		@IEditorGroupService editorGroupService: IEditorGroupService,
43
	) {
44
		this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditors);
J
Johannes Rieken 已提交
45
		this._documentsAndEditors = documentsAndEditors;
46 47 48 49
		this._workbenchEditorService = workbenchEditorService;
		this._toDispose = [];
		this._textEditorsListenersMap = Object.create(null);
		this._editorPositionData = null;
E
Erich Gamma 已提交
50

J
Johannes Rieken 已提交
51 52
		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 已提交
53

54
		this._toDispose.push(editorGroupService.onEditorsChanged(() => this._updateActiveAndVisibleTextEditors()));
55
		this._toDispose.push(editorGroupService.onEditorGroupMoved(() => this._updateActiveAndVisibleTextEditors()));
56 57

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

60 61 62 63 64 65
	public dispose(): void {
		Object.keys(this._textEditorsListenersMap).forEach((editorId) => {
			dispose(this._textEditorsListenersMap[editorId]);
		});
		this._textEditorsListenersMap = Object.create(null);
		this._toDispose = dispose(this._toDispose);
66 67 68 69
		for (let decorationType in this._registeredDecorationTypes) {
			this._codeEditorService.removeDecorationType(decorationType);
		}
		this._registeredDecorationTypes = Object.create(null);
E
Erich Gamma 已提交
70 71
	}

72 73 74
	private _onTextEditorAdd(textEditor: MainThreadTextEditor): void {
		let id = textEditor.getId();
		let toDispose: IDisposable[] = [];
75 76
		toDispose.push(textEditor.onPropertiesChanged((data) => {
			this._proxy.$acceptEditorPropertiesChanged(id, data);
77
		}));
E
Erich Gamma 已提交
78

79
		this._textEditorsListenersMap[id] = toDispose;
E
Erich Gamma 已提交
80 81
	}

J
Johannes Rieken 已提交
82
	private _onTextEditorRemove(id: string): void {
83 84
		dispose(this._textEditorsListenersMap[id]);
		delete this._textEditorsListenersMap[id];
E
Erich Gamma 已提交
85 86
	}

87
	private _updateActiveAndVisibleTextEditors(): void {
E
Erich Gamma 已提交
88

89 90 91 92
		// editor columns
		let editorPositionData = this._getTextEditorPositionData();
		if (!objectEquals(this._editorPositionData, editorPositionData)) {
			this._editorPositionData = editorPositionData;
93
			this._proxy.$acceptEditorPositionData(this._editorPositionData);
E
Erich Gamma 已提交
94 95 96
		}
	}

97 98 99
	private _getTextEditorPositionData(): ITextEditorPositionData {
		let result: ITextEditorPositionData = Object.create(null);
		for (let workbenchEditor of this._workbenchEditorService.getVisibleEditors()) {
J
Johannes Rieken 已提交
100 101 102
			const id = this._documentsAndEditors.findTextEditorIdFor(workbenchEditor);
			if (id) {
				result[id] = workbenchEditor.position;
103
			}
E
Erich Gamma 已提交
104
		}
105
		return result;
E
Erich Gamma 已提交
106 107
	}

108
	// --- from extension host process
E
Erich Gamma 已提交
109

A
Alex Dima 已提交
110 111 112
	$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): TPromise<string> {
		const uri = URI.revive(resource);

113
		const editorOptions: ITextEditorOptions = {
114
			preserveFocus: options.preserveFocus,
115 116
			pinned: options.pinned,
			selection: options.selection
117
		};
E
Erich Gamma 已提交
118

119
		const input = {
A
Alex Dima 已提交
120
			resource: uri,
121
			options: editorOptions
E
Erich Gamma 已提交
122 123
		};

124
		return this._workbenchEditorService.openEditor(input, options.position).then(editor => {
125
			if (!editor) {
M
Matt Bierner 已提交
126
				return undefined;
E
Erich Gamma 已提交
127
			}
J
Johannes Rieken 已提交
128
			return this._documentsAndEditors.findTextEditorIdFor(editor);
E
Erich Gamma 已提交
129 130 131
		});
	}

132
	$tryShowEditor(id: string, position: EditorPosition): TPromise<void> {
J
Johannes Rieken 已提交
133
		let mainThreadEditor = this._documentsAndEditors.getEditor(id);
134 135 136 137 138 139
		if (mainThreadEditor) {
			let model = mainThreadEditor.getModel();
			return this._workbenchEditorService.openEditor({
				resource: model.uri,
				options: { preserveFocus: false }
			}, position).then(() => { return; });
E
Erich Gamma 已提交
140
		}
M
Matt Bierner 已提交
141
		return undefined;
E
Erich Gamma 已提交
142 143
	}

144
	$tryHideEditor(id: string): TPromise<void> {
J
Johannes Rieken 已提交
145
		let mainThreadEditor = this._documentsAndEditors.getEditor(id);
146 147 148 149 150
		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 已提交
151 152 153
				}
			}
		}
M
Matt Bierner 已提交
154
		return undefined;
E
Erich Gamma 已提交
155 156
	}

157
	$trySetSelections(id: string, selections: ISelection[]): TPromise<void> {
J
Johannes Rieken 已提交
158
		if (!this._documentsAndEditors.getEditor(id)) {
159
			return TPromise.wrapError(disposed(`TextEditor(${id})`));
E
Erich Gamma 已提交
160
		}
J
Johannes Rieken 已提交
161
		this._documentsAndEditors.getEditor(id).setSelections(selections);
162
		return TPromise.as(null);
E
Erich Gamma 已提交
163 164
	}

165
	$trySetDecorations(id: string, key: string, ranges: IDecorationOptions[]): TPromise<void> {
J
Johannes Rieken 已提交
166
		if (!this._documentsAndEditors.getEditor(id)) {
167
			return TPromise.wrapError(disposed(`TextEditor(${id})`));
168
		}
J
Johannes Rieken 已提交
169
		this._documentsAndEditors.getEditor(id).setDecorations(key, ranges);
170
		return TPromise.as(null);
E
Erich Gamma 已提交
171 172
	}

173
	$trySetDecorationsFast(id: string, key: string, ranges: number[]): TPromise<void> {
174 175 176
		if (!this._documentsAndEditors.getEditor(id)) {
			return TPromise.wrapError(disposed(`TextEditor(${id})`));
		}
177
		this._documentsAndEditors.getEditor(id).setDecorationsFast(key, ranges);
178 179 180
		return TPromise.as(null);
	}

181
	$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise<void> {
J
Johannes Rieken 已提交
182
		if (!this._documentsAndEditors.getEditor(id)) {
183
			return TPromise.wrapError(disposed(`TextEditor(${id})`));
184
		}
J
Johannes Rieken 已提交
185
		this._documentsAndEditors.getEditor(id).revealRange(range, revealType);
M
Matt Bierner 已提交
186
		return undefined;
E
Erich Gamma 已提交
187 188
	}

189
	$trySetOptions(id: string, options: ITextEditorConfigurationUpdate): TPromise<void> {
J
Johannes Rieken 已提交
190
		if (!this._documentsAndEditors.getEditor(id)) {
191
			return TPromise.wrapError(disposed(`TextEditor(${id})`));
E
Erich Gamma 已提交
192
		}
J
Johannes Rieken 已提交
193
		this._documentsAndEditors.getEditor(id).setConfiguration(options);
194
		return TPromise.as(null);
E
Erich Gamma 已提交
195 196
	}

J
Johannes Rieken 已提交
197
	$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): TPromise<boolean> {
J
Johannes Rieken 已提交
198
		if (!this._documentsAndEditors.getEditor(id)) {
199
			return TPromise.wrapError<boolean>(disposed(`TextEditor(${id})`));
200
		}
J
Johannes Rieken 已提交
201
		return TPromise.as(this._documentsAndEditors.getEditor(id).applyEdits(modelVersionId, edits, opts));
E
Erich Gamma 已提交
202 203
	}

204 205
	$tryApplyWorkspaceEdit(dto: WorkspaceEditDto): TPromise<boolean> {
		const { edits } = reviveWorkspaceEditDto(dto);
206
		return this._bulkEditService.apply({ edits }, undefined).then(() => true, err => false);
207 208
	}

209
	$tryInsertSnippet(id: string, template: string, ranges: IRange[], opts: IUndoStopOptions): TPromise<boolean> {
J
Johannes Rieken 已提交
210
		if (!this._documentsAndEditors.getEditor(id)) {
211
			return TPromise.wrapError<boolean>(disposed(`TextEditor(${id})`));
212
		}
J
Johannes Rieken 已提交
213
		return TPromise.as(this._documentsAndEditors.getEditor(id).insertSnippet(template, ranges, opts));
214 215
	}

216
	$registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void {
217
		this._registeredDecorationTypes[key] = true;
J
Johannes Rieken 已提交
218
		this._codeEditorService.registerDecorationType(key, options);
E
Erich Gamma 已提交
219 220
	}

221
	$removeTextEditorDecorationType(key: string): void {
222
		delete this._registeredDecorationTypes[key];
J
Johannes Rieken 已提交
223
		this._codeEditorService.removeDecorationType(key);
224 225 226 227 228 229
	}

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

		if (!editor) {
230
			return TPromise.wrapError<ILineChange[]>(new Error('No such TextEditor'));
231 232 233 234 235 236 237 238 239 240
		}

		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 已提交
241

242
		return TPromise.as(diffEditor.getLineChanges());
E
Erich Gamma 已提交
243
	}
A
Alex Dima 已提交
244
}