Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/common/extHostDocumentsAndEditors.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as assert from '../../../base/common/assert.js';
7
import * as vscode from 'vscode';
8
import { Emitter, Event } from '../../../base/common/event.js';
9
import { dispose } from '../../../base/common/lifecycle.js';
10
import { URI } from '../../../base/common/uri.js';
11
import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
12
import { ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, MainContext } from './extHost.protocol.js';
13
import { ExtHostDocumentData } from './extHostDocumentData.js';
14
import { IExtHostRpcService } from './extHostRpcService.js';
15
import { ExtHostTextEditor } from './extHostTextEditor.js';
16
import * as typeConverters from './extHostTypeConverters.js';
17
import { ILogService } from '../../../platform/log/common/log.js';
18
import { ResourceMap } from '../../../base/common/map.js';
19
import { Schemas } from '../../../base/common/network.js';
20
import { Iterable } from '../../../base/common/iterator.js';
21
import { Lazy } from '../../../base/common/lazy.js';
22
23
class Reference<T> {
24
private _count = 0;
25
constructor(readonly value: T) { }
26
ref() {
27
this._count++;
28
}
29
unref() {
30
return --this._count === 0;
31
}
32
}
33
34
export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape {
35
36
readonly _serviceBrand: undefined;
37
38
private _activeEditorId: string | null = null;
39
40
private readonly _editors = new Map<string, ExtHostTextEditor>();
41
private readonly _documents = new ResourceMap<Reference<ExtHostDocumentData>>();
42
43
private readonly _onDidAddDocuments = new Emitter<readonly ExtHostDocumentData[]>();
44
private readonly _onDidRemoveDocuments = new Emitter<readonly ExtHostDocumentData[]>();
45
private readonly _onDidChangeVisibleTextEditors = new Emitter<readonly vscode.TextEditor[]>();
46
private readonly _onDidChangeActiveTextEditor = new Emitter<vscode.TextEditor | undefined>();
47
48
readonly onDidAddDocuments: Event<readonly ExtHostDocumentData[]> = this._onDidAddDocuments.event;
49
readonly onDidRemoveDocuments: Event<readonly ExtHostDocumentData[]> = this._onDidRemoveDocuments.event;
50
readonly onDidChangeVisibleTextEditors: Event<readonly vscode.TextEditor[]> = this._onDidChangeVisibleTextEditors.event;
51
readonly onDidChangeActiveTextEditor: Event<vscode.TextEditor | undefined> = this._onDidChangeActiveTextEditor.event;
52
53
constructor(
54
@IExtHostRpcService private readonly _extHostRpc: IExtHostRpcService,
55
@ILogService private readonly _logService: ILogService
56
) { }
57
58
$acceptDocumentsAndEditorsDelta(delta: IDocumentsAndEditorsDelta): void {
59
this.acceptDocumentsAndEditorsDelta(delta);
60
}
61
62
acceptDocumentsAndEditorsDelta(delta: IDocumentsAndEditorsDelta): void {
63
64
const removedDocuments: ExtHostDocumentData[] = [];
65
const addedDocuments: ExtHostDocumentData[] = [];
66
const removedEditors: ExtHostTextEditor[] = [];
67
68
if (delta.removedDocuments) {
69
for (const uriComponent of delta.removedDocuments) {
70
const uri = URI.revive(uriComponent);
71
const data = this._documents.get(uri);
72
if (data?.unref()) {
73
this._documents.delete(uri);
74
removedDocuments.push(data.value);
75
}
76
}
77
}
78
79
if (delta.addedDocuments) {
80
for (const data of delta.addedDocuments) {
81
const resource = URI.revive(data.uri);
82
let ref = this._documents.get(resource);
83
84
// double check -> only notebook cell documents should be
85
// referenced/opened more than once...
86
if (ref) {
87
if (resource.scheme !== Schemas.vscodeNotebookCell && resource.scheme !== Schemas.vscodeInteractiveInput) {
88
throw new Error(`document '${resource} already exists!'`);
89
}
90
}
91
if (!ref) {
92
ref = new Reference(new ExtHostDocumentData(
93
this._extHostRpc.getProxy(MainContext.MainThreadDocuments),
94
resource,
95
data.lines,
96
data.EOL,
97
data.versionId,
98
data.languageId,
99
data.isDirty,
100
data.encoding
101
));
102
this._documents.set(resource, ref);
103
addedDocuments.push(ref.value);
104
}
105
106
ref.ref();
107
}
108
}
109
110
if (delta.removedEditors) {
111
for (const id of delta.removedEditors) {
112
const editor = this._editors.get(id);
113
this._editors.delete(id);
114
if (editor) {
115
removedEditors.push(editor);
116
}
117
}
118
}
119
120
if (delta.addedEditors) {
121
for (const data of delta.addedEditors) {
122
const resource = URI.revive(data.documentUri);
123
assert.ok(this._documents.has(resource), `document '${resource}' does not exist`);
124
assert.ok(!this._editors.has(data.id), `editor '${data.id}' already exists!`);
125
126
const documentData = this._documents.get(resource)!.value;
127
const editor = new ExtHostTextEditor(
128
data.id,
129
this._extHostRpc.getProxy(MainContext.MainThreadTextEditors),
130
this._logService,
131
new Lazy(() => documentData.document),
132
data.selections.map(typeConverters.Selection.to),
133
data.options,
134
data.visibleRanges.map(range => typeConverters.Range.to(range)),
135
typeof data.editorPosition === 'number' ? typeConverters.ViewColumn.to(data.editorPosition) : undefined
136
);
137
this._editors.set(data.id, editor);
138
}
139
}
140
141
if (delta.newActiveEditor !== undefined) {
142
assert.ok(delta.newActiveEditor === null || this._editors.has(delta.newActiveEditor), `active editor '${delta.newActiveEditor}' does not exist`);
143
this._activeEditorId = delta.newActiveEditor;
144
}
145
146
dispose(removedDocuments);
147
dispose(removedEditors);
148
149
// now that the internal state is complete, fire events
150
if (delta.removedDocuments) {
151
this._onDidRemoveDocuments.fire(removedDocuments);
152
}
153
if (delta.addedDocuments) {
154
this._onDidAddDocuments.fire(addedDocuments);
155
}
156
157
if (delta.removedEditors || delta.addedEditors) {
158
this._onDidChangeVisibleTextEditors.fire(this.allEditors().map(editor => editor.value));
159
}
160
if (delta.newActiveEditor !== undefined) {
161
this._onDidChangeActiveTextEditor.fire(this.activeEditor());
162
}
163
}
164
165
getDocument(uri: URI): ExtHostDocumentData | undefined {
166
return this._documents.get(uri)?.value;
167
}
168
169
allDocuments(): Iterable<ExtHostDocumentData> {
170
return Iterable.map(this._documents.values(), ref => ref.value);
171
}
172
173
getEditor(id: string): ExtHostTextEditor | undefined {
174
return this._editors.get(id);
175
}
176
177
activeEditor(): vscode.TextEditor | undefined;
178
activeEditor(internal: true): ExtHostTextEditor | undefined;
179
activeEditor(internal?: true): vscode.TextEditor | ExtHostTextEditor | undefined {
180
if (!this._activeEditorId) {
181
return undefined;
182
}
183
const editor = this._editors.get(this._activeEditorId);
184
if (internal) {
185
return editor;
186
} else {
187
return editor?.value;
188
}
189
}
190
191
allEditors(): ExtHostTextEditor[] {
192
return [...this._editors.values()];
193
}
194
}
195
196
export interface IExtHostDocumentsAndEditors extends ExtHostDocumentsAndEditors { }
197
export const IExtHostDocumentsAndEditors = createDecorator<IExtHostDocumentsAndEditors>('IExtHostDocumentsAndEditors');
198
199