UNPKG

11.9 kBJavaScriptView Raw
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'use strict';
6Object.defineProperty(exports, "__esModule", { value: true });
7exports.NotebookDocuments = exports.NotebookSyncFeature = void 0;
8const vscode_languageserver_protocol_1 = require("vscode-languageserver-protocol");
9const textDocuments_1 = require("./textDocuments");
10const NotebookSyncFeature = (Base) => {
11 return class extends Base {
12 get synchronization() {
13 return {
14 onDidOpenNotebookDocument: (handler) => {
15 return this.connection.onNotification(vscode_languageserver_protocol_1.DidOpenNotebookDocumentNotification.type, (params) => {
16 handler(params);
17 });
18 },
19 onDidChangeNotebookDocument: (handler) => {
20 return this.connection.onNotification(vscode_languageserver_protocol_1.DidChangeNotebookDocumentNotification.type, (params) => {
21 handler(params);
22 });
23 },
24 onDidSaveNotebookDocument: (handler) => {
25 return this.connection.onNotification(vscode_languageserver_protocol_1.DidSaveNotebookDocumentNotification.type, (params) => {
26 handler(params);
27 });
28 },
29 onDidCloseNotebookDocument: (handler) => {
30 return this.connection.onNotification(vscode_languageserver_protocol_1.DidCloseNotebookDocumentNotification.type, (params) => {
31 handler(params);
32 });
33 }
34 };
35 }
36 };
37};
38exports.NotebookSyncFeature = NotebookSyncFeature;
39class CellTextDocumentConnection {
40 onDidOpenTextDocument(handler) {
41 this.openHandler = handler;
42 return vscode_languageserver_protocol_1.Disposable.create(() => { this.openHandler = undefined; });
43 }
44 openTextDocument(params) {
45 this.openHandler && this.openHandler(params);
46 }
47 onDidChangeTextDocument(handler) {
48 this.changeHandler = handler;
49 return vscode_languageserver_protocol_1.Disposable.create(() => { this.changeHandler = handler; });
50 }
51 changeTextDocument(params) {
52 this.changeHandler && this.changeHandler(params);
53 }
54 onDidCloseTextDocument(handler) {
55 this.closeHandler = handler;
56 return vscode_languageserver_protocol_1.Disposable.create(() => { this.closeHandler = undefined; });
57 }
58 closeTextDocument(params) {
59 this.closeHandler && this.closeHandler(params);
60 }
61 onWillSaveTextDocument() {
62 return CellTextDocumentConnection.NULL_DISPOSE;
63 }
64 onWillSaveTextDocumentWaitUntil() {
65 return CellTextDocumentConnection.NULL_DISPOSE;
66 }
67 onDidSaveTextDocument() {
68 return CellTextDocumentConnection.NULL_DISPOSE;
69 }
70}
71CellTextDocumentConnection.NULL_DISPOSE = Object.freeze({ dispose: () => { } });
72class NotebookDocuments {
73 constructor(configurationOrTextDocuments) {
74 if (configurationOrTextDocuments instanceof textDocuments_1.TextDocuments) {
75 this._cellTextDocuments = configurationOrTextDocuments;
76 }
77 else {
78 this._cellTextDocuments = new textDocuments_1.TextDocuments(configurationOrTextDocuments);
79 }
80 this.notebookDocuments = new Map();
81 this.notebookCellMap = new Map();
82 this._onDidOpen = new vscode_languageserver_protocol_1.Emitter();
83 this._onDidChange = new vscode_languageserver_protocol_1.Emitter();
84 this._onDidSave = new vscode_languageserver_protocol_1.Emitter();
85 this._onDidClose = new vscode_languageserver_protocol_1.Emitter();
86 }
87 get cellTextDocuments() {
88 return this._cellTextDocuments;
89 }
90 getCellTextDocument(cell) {
91 return this._cellTextDocuments.get(cell.document);
92 }
93 getNotebookDocument(uri) {
94 return this.notebookDocuments.get(uri);
95 }
96 getNotebookCell(uri) {
97 const value = this.notebookCellMap.get(uri);
98 return value && value[0];
99 }
100 findNotebookDocumentForCell(cell) {
101 const key = typeof cell === 'string' ? cell : cell.document;
102 const value = this.notebookCellMap.get(key);
103 return value && value[1];
104 }
105 get onDidOpen() {
106 return this._onDidOpen.event;
107 }
108 get onDidSave() {
109 return this._onDidSave.event;
110 }
111 get onDidChange() {
112 return this._onDidChange.event;
113 }
114 get onDidClose() {
115 return this._onDidClose.event;
116 }
117 /**
118 * Listens for `low level` notification on the given connection to
119 * update the notebook documents managed by this instance.
120 *
121 * Please note that the connection only provides handlers not an event model. Therefore
122 * listening on a connection will overwrite the following handlers on a connection:
123 * `onDidOpenNotebookDocument`, `onDidChangeNotebookDocument`, `onDidSaveNotebookDocument`,
124 * and `onDidCloseNotebookDocument`.
125 *
126 * @param connection The connection to listen on.
127 */
128 listen(connection) {
129 const cellTextDocumentConnection = new CellTextDocumentConnection();
130 const disposables = [];
131 disposables.push(this.cellTextDocuments.listen(cellTextDocumentConnection));
132 disposables.push(connection.notebooks.synchronization.onDidOpenNotebookDocument((params) => {
133 this.notebookDocuments.set(params.notebookDocument.uri, params.notebookDocument);
134 for (const cellTextDocument of params.cellTextDocuments) {
135 cellTextDocumentConnection.openTextDocument({ textDocument: cellTextDocument });
136 }
137 this.updateCellMap(params.notebookDocument);
138 this._onDidOpen.fire(params.notebookDocument);
139 }));
140 disposables.push(connection.notebooks.synchronization.onDidChangeNotebookDocument((params) => {
141 const notebookDocument = this.notebookDocuments.get(params.notebookDocument.uri);
142 if (notebookDocument === undefined) {
143 return;
144 }
145 notebookDocument.version = params.notebookDocument.version;
146 const oldMetadata = notebookDocument.metadata;
147 let metadataChanged = false;
148 const change = params.change;
149 if (change.metadata !== undefined) {
150 metadataChanged = true;
151 notebookDocument.metadata = change.metadata;
152 }
153 const opened = [];
154 const closed = [];
155 const data = [];
156 const text = [];
157 if (change.cells !== undefined) {
158 const changedCells = change.cells;
159 if (changedCells.structure !== undefined) {
160 const array = changedCells.structure.array;
161 notebookDocument.cells.splice(array.start, array.deleteCount, ...(array.cells !== undefined ? array.cells : []));
162 // Additional open cell text documents.
163 if (changedCells.structure.didOpen !== undefined) {
164 for (const open of changedCells.structure.didOpen) {
165 cellTextDocumentConnection.openTextDocument({ textDocument: open });
166 opened.push(open.uri);
167 }
168 }
169 // Additional closed cell test documents.
170 if (changedCells.structure.didClose) {
171 for (const close of changedCells.structure.didClose) {
172 cellTextDocumentConnection.closeTextDocument({ textDocument: close });
173 closed.push(close.uri);
174 }
175 }
176 }
177 if (changedCells.data !== undefined) {
178 const cellUpdates = new Map(changedCells.data.map(cell => [cell.document, cell]));
179 for (let i = 0; i <= notebookDocument.cells.length; i++) {
180 const change = cellUpdates.get(notebookDocument.cells[i].document);
181 if (change !== undefined) {
182 const old = notebookDocument.cells.splice(i, 1, change);
183 data.push({ old: old[0], new: change });
184 cellUpdates.delete(change.document);
185 if (cellUpdates.size === 0) {
186 break;
187 }
188 }
189 }
190 }
191 if (changedCells.textContent !== undefined) {
192 for (const cellTextDocument of changedCells.textContent) {
193 cellTextDocumentConnection.changeTextDocument({ textDocument: cellTextDocument.document, contentChanges: cellTextDocument.changes });
194 text.push(cellTextDocument.document.uri);
195 }
196 }
197 }
198 // Update internal data structure.
199 this.updateCellMap(notebookDocument);
200 const changeEvent = { notebookDocument };
201 if (metadataChanged) {
202 changeEvent.metadata = { old: oldMetadata, new: notebookDocument.metadata };
203 }
204 const added = [];
205 for (const open of opened) {
206 added.push(this.getNotebookCell(open));
207 }
208 const removed = [];
209 for (const close of closed) {
210 removed.push(this.getNotebookCell(close));
211 }
212 const textContent = [];
213 for (const change of text) {
214 textContent.push(this.getNotebookCell(change));
215 }
216 if (added.length > 0 || removed.length > 0 || data.length > 0 || textContent.length > 0) {
217 changeEvent.cells = { added, removed, changed: { data, textContent } };
218 }
219 if (changeEvent.metadata !== undefined || changeEvent.cells !== undefined) {
220 this._onDidChange.fire(changeEvent);
221 }
222 }));
223 disposables.push(connection.notebooks.synchronization.onDidSaveNotebookDocument((params) => {
224 const notebookDocument = this.notebookDocuments.get(params.notebookDocument.uri);
225 if (notebookDocument === undefined) {
226 return;
227 }
228 this._onDidSave.fire(notebookDocument);
229 }));
230 disposables.push(connection.notebooks.synchronization.onDidCloseNotebookDocument((params) => {
231 const notebookDocument = this.notebookDocuments.get(params.notebookDocument.uri);
232 if (notebookDocument === undefined) {
233 return;
234 }
235 this._onDidClose.fire(notebookDocument);
236 for (const cellTextDocument of params.cellTextDocuments) {
237 cellTextDocumentConnection.closeTextDocument({ textDocument: cellTextDocument });
238 }
239 this.notebookDocuments.delete(params.notebookDocument.uri);
240 for (const cell of notebookDocument.cells) {
241 this.notebookCellMap.delete(cell.document);
242 }
243 }));
244 return vscode_languageserver_protocol_1.Disposable.create(() => { disposables.forEach(disposable => disposable.dispose()); });
245 }
246 updateCellMap(notebookDocument) {
247 for (const cell of notebookDocument.cells) {
248 this.notebookCellMap.set(cell.document, [cell, notebookDocument]);
249 }
250 }
251}
252exports.NotebookDocuments = NotebookDocuments;