@kusto/monaco-kusto 5.6.6 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/package.json +26 -16
  2. package/release/dev/commandFormatter.d.ts +6 -0
  3. package/release/dev/commandHighlighter.d.ts +20 -0
  4. package/release/dev/extendedEditor.d.ts +7 -0
  5. package/release/dev/kustoMode.d.ts +8 -0
  6. package/release/dev/kustoMode.js +1730 -3278
  7. package/release/dev/kustoWorker.d.ts +92 -0
  8. package/release/dev/kustoWorker.js +5687 -8534
  9. package/release/dev/languageFeatures.d.ts +91 -0
  10. package/release/dev/languageService/kustoLanguageService.d.ts +143 -0
  11. package/release/dev/languageService/kustoMonarchLanguageDefinition.d.ts +1 -0
  12. package/release/dev/languageService/renderInfo.d.ts +31 -0
  13. package/release/dev/languageService/schema.d.ts +144 -0
  14. package/release/dev/languageService/settings.d.ts +30 -0
  15. package/release/dev/main-ac12725e.js +1958 -0
  16. package/release/dev/monaco.contribution.d.ts +15 -0
  17. package/release/dev/monaco.contribution.js +462 -309
  18. package/release/dev/workerManager.d.ts +23 -0
  19. package/release/esm/commandFormatter.d.ts +6 -0
  20. package/release/esm/commandHighlighter.d.ts +20 -0
  21. package/release/esm/extendedEditor.d.ts +7 -0
  22. package/release/esm/kusto.worker.js +2246 -5
  23. package/release/esm/kustoMode.d.ts +8 -0
  24. package/release/esm/kustoMode.js +1120 -88
  25. package/release/esm/kustoWorker.d.ts +92 -0
  26. package/release/esm/languageFeatures.d.ts +91 -0
  27. package/release/esm/languageService/kustoLanguageService.d.ts +143 -0
  28. package/release/esm/languageService/kustoMonarchLanguageDefinition.d.ts +1 -0
  29. package/release/esm/languageService/renderInfo.d.ts +31 -0
  30. package/release/esm/languageService/schema.d.ts +144 -0
  31. package/release/esm/languageService/settings.d.ts +30 -0
  32. package/release/esm/monaco.contribution.d.ts +1 -0
  33. package/release/esm/monaco.contribution.js +424 -181
  34. package/release/esm/workerManager.d.ts +23 -0
  35. package/release/min/commandFormatter.d.ts +6 -0
  36. package/release/min/commandHighlighter.d.ts +20 -0
  37. package/release/min/extendedEditor.d.ts +7 -0
  38. package/release/min/kustoMode.d.ts +8 -0
  39. package/release/min/kustoMode.js +2 -11
  40. package/release/min/kustoWorker.d.ts +92 -0
  41. package/release/min/kustoWorker.js +10 -53
  42. package/release/min/languageFeatures.d.ts +91 -0
  43. package/release/min/languageService/kustoLanguageService.d.ts +143 -0
  44. package/release/min/languageService/kustoMonarchLanguageDefinition.d.ts +1 -0
  45. package/release/min/languageService/renderInfo.d.ts +31 -0
  46. package/release/min/languageService/schema.d.ts +144 -0
  47. package/release/min/languageService/settings.d.ts +30 -0
  48. package/release/min/main-5b1cc297.js +7 -0
  49. package/release/min/monaco.contribution.d.ts +1 -0
  50. package/release/min/monaco.contribution.js +2 -2
  51. package/release/min/monaco.d.ts +1 -319
  52. package/release/min/workerManager.d.ts +23 -0
  53. package/release/{esm/monaco.d.ts → monaco.d.ts} +1 -1
  54. package/release/esm/_deps/lodash/lodash.js +0 -17209
  55. package/release/esm/_deps/vscode-languageserver-types/main.js +0 -1908
  56. package/release/esm/_deps/xregexp/xregexp-all.js +0 -4652
  57. package/release/esm/commandFormatter.js +0 -36
  58. package/release/esm/commandHighlighter.js +0 -51
  59. package/release/esm/extendedEditor.js +0 -38
  60. package/release/esm/kustoWorker.js +0 -245
  61. package/release/esm/languageFeatures.js +0 -1032
  62. package/release/esm/languageService/kustoLanguageService.js +0 -1912
  63. package/release/esm/languageService/kustoMonarchLanguageDefinition.js +0 -127
  64. package/release/esm/languageService/schema.js +0 -64
  65. package/release/esm/workerManager.js +0 -102
@@ -1,101 +1,1133 @@
1
- var __assign = (this && this.__assign) || function () {
2
- __assign = Object.assign || function(t) {
3
- for (var s, i = 1, n = arguments.length; i < n; i++) {
4
- s = arguments[i];
5
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
- t[p] = s[p];
1
+ /*!-----------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * monaco-kusto version: 6.1.0(b14a2ec944d355ac340af8280e7c1a4ea98f6c8c)
4
+ * Released under the MIT license
5
+ * https://https://github.com/Azure/monaco-kusto/blob/master/README.md
6
+ *-----------------------------------------------------------------------------*/
7
+
8
+ import * as ls from 'vscode-languageserver-types';
9
+ import debounce from 'lodash-es/debounce';
10
+
11
+ class WorkerManager {
12
+ constructor(_monacoInstance, defaults) {
13
+ this._monacoInstance = _monacoInstance;
14
+ this._defaults = defaults;
15
+ this._worker = null;
16
+ this._idleCheckInterval = self.setInterval(() => this._checkIfIdle(), 30 * 1000);
17
+ this._lastUsedTime = 0;
18
+ this._configChangeListener = this._defaults.onDidChange(() => this._saveStateAndStopWorker());
19
+ }
20
+ _stopWorker() {
21
+ if (this._worker) {
22
+ this._worker.dispose();
23
+ this._worker = null;
24
+ }
25
+ this._client = null;
26
+ }
27
+ _saveStateAndStopWorker() {
28
+ if (!this._worker) {
29
+ return;
30
+ }
31
+ this._worker.getProxy().then(proxy => {
32
+ proxy.getSchema().then(schema => {
33
+ this._storedState = {
34
+ schema: schema
35
+ };
36
+ this._stopWorker();
37
+ });
38
+ });
39
+ }
40
+ dispose() {
41
+ clearInterval(this._idleCheckInterval);
42
+ this._configChangeListener.dispose();
43
+ this._stopWorker();
44
+ }
45
+ _checkIfIdle() {
46
+ if (!this._worker) {
47
+ return;
48
+ }
49
+ const maxIdleTime = this._defaults.getWorkerMaxIdleTime();
50
+ let timePassedSinceLastUsed = Date.now() - this._lastUsedTime;
51
+ if (maxIdleTime > 0 && timePassedSinceLastUsed > maxIdleTime) {
52
+ this._saveStateAndStopWorker();
53
+ }
54
+ }
55
+ _getClient() {
56
+ this._lastUsedTime = Date.now();
57
+
58
+ // Since onDidProvideCompletionItems is not used in web worker, and since functions cannot be trivially serialized (throws exception unable to clone), We remove it here.
59
+ const {
60
+ onDidProvideCompletionItems,
61
+ ...languageSettings
62
+ } = this._defaults.languageSettings;
63
+ if (!this._client) {
64
+ this._worker = this._monacoInstance.editor.createWebWorker({
65
+ // module that exports the create() method and returns a `KustoWorker` instance
66
+ moduleId: 'vs/language/kusto/kustoWorker',
67
+ label: 'kusto',
68
+ // passed in to the create() method
69
+ createData: {
70
+ languageSettings: languageSettings,
71
+ languageId: 'kusto'
72
+ }
73
+ });
74
+ this._client = this._worker.getProxy().then(proxy => {
75
+ // push state we held onto before killing the client.
76
+ if (this._storedState) {
77
+ return proxy.setSchema(this._storedState.schema).then(() => proxy);
78
+ } else {
79
+ return proxy;
7
80
  }
8
- return t;
81
+ });
82
+ }
83
+ return this._client;
84
+ }
85
+ getLanguageServiceWorker(...resources) {
86
+ let _client;
87
+ return this._getClient().then(client => {
88
+ _client = client;
89
+ }).then(_ => {
90
+ return this._worker.withSyncedResources(resources);
91
+ }).then(_ => _client);
92
+ }
93
+ }
94
+
95
+ const KustoLanguageDefinition = {
96
+ name: 'kusto',
97
+ mimeTypes: ['text/kusto'],
98
+ displayName: 'Kusto',
99
+ defaultToken: 'invalid',
100
+ brackets: [['[', ']', 'delimiter.square'], ['(', ')', 'delimiter.parenthesis']],
101
+ wordDefinition: /(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,
102
+ // .slice() call is for creating a shallow copy of the array since bridge.net shoves a $type property on the array which monaco doesn't like.
103
+ promotedOperatorCommandTokens: Kusto.Data.IntelliSense.CslCommandParser.PromotedOperatorCommandTokens.slice(0),
104
+ operatorCommandTokens: Kusto.Data.IntelliSense.CslCommandParser.OperatorCommandTokens.slice(0),
105
+ keywords: ['by', 'on', 'contains', 'notcontains', 'containscs', 'notcontainscs', 'startswith', 'has', 'matches', 'regex', 'true', 'false', 'and', 'or', 'typeof', 'int', 'string', 'date', 'datetime', 'time', 'long', 'real', '​boolean', 'bool'],
106
+ operators: ['+', '-', '*', '/', '>', '<', '==', '<>', '<=', '>=', '~', '!~'],
107
+ builtinFunctions: ['countof', 'bin', 'extentid', 'extract', 'extractjson', 'floor', 'iif', 'isnull', 'isnotnull', 'notnull', 'isempty', 'isnotempty', 'notempty', 'now', 're2', 'strcat', 'strlen', 'toupper', 'tostring', 'count', 'cnt', 'sum', 'min', 'max', 'avg'],
108
+ tokenizer: {
109
+ root: [{
110
+ include: '@whitespace'
111
+ }, {
112
+ include: '@numbers'
113
+ }, {
114
+ include: '@strings'
115
+ }, {
116
+ include: '@dqstrings'
117
+ }, {
118
+ include: '@literals'
119
+ }, {
120
+ include: '@comments'
121
+ }, [/[;,.]/, 'delimiter'], [/[()\[\]]/, '@brackets'], [/[<>=!%&+\-*/|~^]/, 'operator'], [/[\w@#\-$]+/, {
122
+ cases: {
123
+ '@keywords': 'keyword',
124
+ '@promotedOperatorCommandTokens': 'operator.sql',
125
+ '@operatorCommandTokens': 'keyword',
126
+ '@operators': 'operator',
127
+ '@builtinFunctions': 'predefined',
128
+ '@default': 'identifier'
129
+ }
130
+ }]],
131
+ whitespace: [[/\s+/, 'white']],
132
+ comments: [['\\/\\/+.*', 'comment']],
133
+ numbers: [[/0[xX][0-9a-fA-F]*/, 'number'], [/[$][+-]*\d*(\.\d*)?/, 'number'], [/((\d+(\.\d*)?)|(\.\d+))([eE][\-+]?\d+)?/, 'number']],
134
+ strings: [[/H'/, {
135
+ token: 'string.quote',
136
+ bracket: '@open',
137
+ next: '@string'
138
+ }], [/h'/, {
139
+ token: 'string.quote',
140
+ bracket: '@open',
141
+ next: '@string'
142
+ }], [/'/, {
143
+ token: 'string.quote',
144
+ bracket: '@open',
145
+ next: '@string'
146
+ }]],
147
+ string: [[/[^']+/, 'string'], [/''/, 'string'], [/'/, {
148
+ token: 'string.quote',
149
+ bracket: '@close',
150
+ next: '@pop'
151
+ }]],
152
+ dqstrings: [[/H"/, {
153
+ token: 'string.quote',
154
+ bracket: '@open',
155
+ next: '@dqstring'
156
+ }], [/h"/, {
157
+ token: 'string.quote',
158
+ bracket: '@open',
159
+ next: '@dqstring'
160
+ }], [/"/, {
161
+ token: 'string.quote',
162
+ bracket: '@open',
163
+ next: '@dqstring'
164
+ }]],
165
+ dqstring: [[/[^"]+/, 'string'], [/""/, 'string'], [/"/, {
166
+ token: 'string.quote',
167
+ bracket: '@close',
168
+ next: '@pop'
169
+ }]],
170
+ literals: [[/datetime\(\d{4}-\d{2}-\d{2}(\s+\d{2}:\d{2}(:\d{2}(\.\d{0,3})?)?)?\)/, 'number'], [/time\((\d+(s(ec(onds?)?)?|m(in(utes?)?)?|h(ours?)?|d(ays?)?)|(\s*(('[^']+')|("[^"]+"))\s*))\)/, 'number'], [/guid\([\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}\)/, 'number'], [/typeof\((int|string|date|datetime|time|long|real|boolean|bool)\)/, 'number']]
171
+ }
172
+ };
173
+
174
+ var Uri = monaco.Uri;
175
+ monaco.Position;
176
+ var Range = monaco.Range;
177
+ monaco.Thenable;
178
+ monaco.CancellationToken;
179
+ monaco.IDisposable;
180
+ var ClassificationKind = Kusto.Language.Editor.ClassificationKind;
181
+ class DiagnosticsAdapter {
182
+ _disposables = [];
183
+ _contentListener = Object.create(null);
184
+ _configurationListener = Object.create(null);
185
+ _schemaListener = Object.create(null);
186
+ _cursorListener = Object.create(null);
187
+ _debouncedValidations = Object.create(null);
188
+ constructor(_monacoInstance, _languageId, _worker, defaults, onSchemaChange) {
189
+ this._monacoInstance = _monacoInstance;
190
+ this._languageId = _languageId;
191
+ this._worker = _worker;
192
+ this.defaults = defaults;
193
+ const onModelAdd = model => {
194
+ let languageId = model.getLanguageId();
195
+ const modelUri = model.uri.toString();
196
+ if (languageId !== this._languageId) {
197
+ return;
198
+ }
199
+ const debouncedValidation = this.getOrCreateDebouncedValidation(model, languageId);
200
+ this._contentListener[modelUri] = model.onDidChangeContent(e => {
201
+ const intervalsToValidate = changeEventToIntervals(e);
202
+ debouncedValidation(intervalsToValidate);
203
+ });
204
+ this._configurationListener[modelUri] = this.defaults.onDidChange(() => {
205
+ self.setTimeout(() => this._doValidate(model, languageId, []), 0);
206
+ });
207
+ this._schemaListener[modelUri] = onSchemaChange(() => {
208
+ self.setTimeout(() => this._doValidate(model, languageId, []), 0);
209
+ });
210
+ };
211
+ const onEditorAdd = editor => {
212
+ const editorId = editor.getId();
213
+ if (!this._cursorListener[editorId]) {
214
+ editor.onDidDispose(() => {
215
+ this._cursorListener[editorId]?.dispose();
216
+ delete this._cursorListener[editorId];
217
+ });
218
+ this._cursorListener[editorId] = editor.onDidChangeCursorSelection(e => {
219
+ const model = editor.getModel();
220
+ const languageId = model.getLanguageId();
221
+ if (languageId !== this._languageId) {
222
+ return;
223
+ }
224
+ const cursorOffset = model.getOffsetAt(e.selection.getPosition());
225
+ const debouncedValidation = this.getOrCreateDebouncedValidation(model, languageId);
226
+ debouncedValidation([{
227
+ start: cursorOffset,
228
+ end: cursorOffset
229
+ }]);
230
+ });
231
+ }
9
232
  };
10
- return __assign.apply(this, arguments);
233
+ const onModelRemoved = model => {
234
+ this._monacoInstance.editor.setModelMarkers(model, this._languageId, []);
235
+ let uriStr = model.uri.toString();
236
+ let contentListener = this._contentListener[uriStr];
237
+ if (contentListener) {
238
+ contentListener.dispose();
239
+ delete this._contentListener[uriStr];
240
+ }
241
+ let configurationListener = this._configurationListener[uriStr];
242
+ if (configurationListener) {
243
+ configurationListener.dispose();
244
+ delete this._configurationListener[uriStr];
245
+ }
246
+ let schemaListener = this._schemaListener[uriStr];
247
+ if (schemaListener) {
248
+ schemaListener.dispose();
249
+ delete this._schemaListener[uriStr];
250
+ }
251
+ let debouncedValidation = this._debouncedValidations[uriStr];
252
+ if (debouncedValidation) {
253
+ debouncedValidation.cancel();
254
+ delete this._debouncedValidations[uriStr];
255
+ }
256
+ };
257
+ if (this.defaults.languageSettings.enableQuickFixes) {
258
+ this._disposables.push(monaco.languages.registerCodeActionProvider(this._languageId, {
259
+ provideCodeActions: async (model, range, context, _token) => {
260
+ const startOffset = model.getOffsetAt(range.getStartPosition());
261
+ const endOffset = model.getOffsetAt(range.getEndPosition());
262
+ // We want to show the quick fix option only if we have markers in our selected range
263
+ const showQuickFix = context.markers.length > 0;
264
+ const actions = await this.getMonacoCodeActions(model, startOffset, endOffset, showQuickFix);
265
+ return {
266
+ actions,
267
+ dispose: () => {}
268
+ };
269
+ }
270
+ }));
271
+ }
272
+ this._disposables.push(this._monacoInstance.editor.onDidCreateEditor(onEditorAdd));
273
+ this._disposables.push(this._monacoInstance.editor.onDidCreateModel(onModelAdd));
274
+ this._disposables.push(this._monacoInstance.editor.onWillDisposeModel(onModelRemoved));
275
+ this._disposables.push(this._monacoInstance.editor.onDidChangeModelLanguage(event => {
276
+ onModelRemoved(event.model);
277
+ onModelAdd(event.model);
278
+ }));
279
+ this._disposables.push({
280
+ dispose: () => {
281
+ for (let key in this._contentListener) {
282
+ this._contentListener[key].dispose();
283
+ }
284
+ for (let key in this._cursorListener) {
285
+ this._cursorListener[key].dispose();
286
+ }
287
+ for (let key in this._debouncedValidations) {
288
+ this._debouncedValidations[key].cancel();
289
+ }
290
+ }
291
+ });
292
+ this._monacoInstance.editor.getModels().forEach(onModelAdd);
293
+ this._monacoInstance.editor.getEditors().forEach(onEditorAdd);
294
+ }
295
+ async getMonacoCodeActions(model, startOffset, endOffset, enableQuickFix) {
296
+ const actions = [];
297
+ const worker = await this._worker(model.uri);
298
+ const resource = model.uri;
299
+ const codeActions = await worker.getResultActions(resource.toString(), startOffset, endOffset);
300
+ for (let i = 0; i < codeActions.length; i++) {
301
+ const codeAction = codeActions[i];
302
+ if (codeAction.kind.includes('Extract Function')) {
303
+ // Ignore extract function actions for now since they are buggy currently
304
+ continue;
305
+ }
306
+ const codeActionKind = this.defaults.languageSettings.quickFixCodeActions?.find(actionKind => codeAction.kind.includes(actionKind)) ? 'quickfix' : 'custom';
307
+ if (codeActionKind === 'quickfix' && !enableQuickFix) {
308
+ return;
309
+ }
310
+ const changes = codeAction.changes;
311
+ const edits = changes.map(change => {
312
+ const startPosition = model.getPositionAt(change.start);
313
+ const endPosition = model.getPositionAt(change.start + change.deleteLength);
314
+ return {
315
+ resource: model.uri,
316
+ textEdit: {
317
+ range: {
318
+ startLineNumber: startPosition.lineNumber,
319
+ startColumn: startPosition.column,
320
+ endLineNumber: endPosition.lineNumber,
321
+ endColumn: endPosition.column
322
+ },
323
+ text: change.insertText ?? ''
324
+ }
325
+ };
326
+ });
327
+ actions.push({
328
+ title: codeAction.title,
329
+ diagnostics: [],
330
+ kind: codeActionKind,
331
+ edit: {
332
+ edits: [...edits]
333
+ }
334
+ });
335
+ }
336
+ return actions;
337
+ }
338
+ getOrCreateDebouncedValidation(model, languageId) {
339
+ const modelUri = model.uri.toString();
340
+ if (!this._debouncedValidations[modelUri]) {
341
+ this._debouncedValidations[modelUri] = debounce(intervals => this._doValidate(model, languageId, intervals), 500);
342
+ }
343
+ return this._debouncedValidations[modelUri];
344
+ }
345
+ dispose() {
346
+ this._disposables.forEach(d => d && d.dispose());
347
+ this._disposables = [];
348
+ }
349
+ _doValidate(model, languageId, intervals) {
350
+ if (model.isDisposed()) {
351
+ return;
352
+ }
353
+ const resource = model.uri;
354
+ const versionNumberBefore = model.getVersionId();
355
+ this._worker(resource).then(worker => {
356
+ return worker.doValidation(resource.toString(), intervals);
357
+ }).then(diagnostics => {
358
+ const newModel = this._monacoInstance.editor.getModel(resource);
359
+ const versionId = newModel.getVersionId();
360
+ if (versionId !== versionNumberBefore) {
361
+ return;
362
+ }
363
+ const markers = diagnostics.map(d => toDiagnostics(resource, d));
364
+ let model = this._monacoInstance.editor.getModel(resource);
365
+ let oldDecorations = model.getAllDecorations().filter(decoration => decoration.options.className == 'squiggly-error').map(decoration => decoration.id);
366
+ if (model && model.getLanguageId() === languageId) {
367
+ const syntaxErrorAsMarkDown = this.defaults.languageSettings.syntaxErrorAsMarkDown;
368
+ if (!syntaxErrorAsMarkDown || !syntaxErrorAsMarkDown.enableSyntaxErrorAsMarkDown) {
369
+ // Remove previous syntax error decorations and set the new markers (for example, when disabling syntaxErrorAsMarkDown after it was enabled)
370
+ model.deltaDecorations(oldDecorations, []);
371
+ this._monacoInstance.editor.setModelMarkers(model, languageId, markers);
372
+ } else {
373
+ // Add custom popup for syntax error: icon, header and message as markdown
374
+ const header = syntaxErrorAsMarkDown.header ? `**${syntaxErrorAsMarkDown.header}** \n\n` : '';
375
+ const icon = syntaxErrorAsMarkDown.icon ? `![](${syntaxErrorAsMarkDown.icon})` : '';
376
+ const popupErrorHoverHeaderMessage = `${icon} ${header}`;
377
+ const newDecorations = markers.map(marker => {
378
+ return {
379
+ range: {
380
+ startLineNumber: marker.startLineNumber,
381
+ startColumn: marker.startColumn,
382
+ endLineNumber: marker.endLineNumber,
383
+ endColumn: marker.endColumn
384
+ },
385
+ options: {
386
+ hoverMessage: {
387
+ value: popupErrorHoverHeaderMessage + marker.message
388
+ },
389
+ className: 'squiggly-error',
390
+ // monaco syntax error style (red underline)
391
+ zIndex: 100,
392
+ // This message will be the upper most mesage in the popup
393
+ overviewRuler: {
394
+ // The color indication on the right ruler
395
+ color: 'rgb(255, 18, 18, 0.7)',
396
+ position: monaco.editor.OverviewRulerLane.Right
397
+ },
398
+ minimap: {
399
+ color: 'rgb(255, 18, 18, 0.7)',
400
+ position: monaco.editor.MinimapPosition.Inline
401
+ }
402
+ }
403
+ };
404
+ });
405
+ const oldMarkers = monaco.editor.getModelMarkers({
406
+ owner: languageId,
407
+ resource: resource
408
+ });
409
+ if (oldMarkers && oldMarkers.length > 0) {
410
+ // In case there were previous markers, remove their decorations (for example, when enabling syntaxErrorAsMarkDown after it was disabled)
411
+ oldDecorations = [];
412
+ // Remove previous markers
413
+ this._monacoInstance.editor.setModelMarkers(model, languageId, []);
414
+ }
415
+
416
+ // Remove previous syntax error decorations and set the new decorations
417
+ model.deltaDecorations(oldDecorations, newDecorations);
418
+ }
419
+ }
420
+ }).then(undefined, err => {
421
+ console.error(err);
422
+ });
423
+ }
424
+ }
425
+ function changeEventToIntervals(e) {
426
+ return e.changes.map(change => ({
427
+ start: change.rangeOffset,
428
+ end: change.rangeOffset + change.text.length
429
+ }));
430
+ }
431
+ function toSeverity(lsSeverity) {
432
+ switch (lsSeverity) {
433
+ case ls.DiagnosticSeverity.Error:
434
+ return monaco.MarkerSeverity.Error;
435
+ case ls.DiagnosticSeverity.Warning:
436
+ return monaco.MarkerSeverity.Warning;
437
+ case ls.DiagnosticSeverity.Information:
438
+ return monaco.MarkerSeverity.Info;
439
+ case ls.DiagnosticSeverity.Hint:
440
+ return monaco.MarkerSeverity.Hint;
441
+ default:
442
+ return monaco.MarkerSeverity.Info;
443
+ }
444
+ }
445
+ function toDiagnostics(resource, diag) {
446
+ let code = typeof diag.code === 'number' ? String(diag.code) : diag.code;
447
+ return {
448
+ severity: toSeverity(diag.severity),
449
+ startLineNumber: diag.range.start.line + 1,
450
+ startColumn: diag.range.start.character + 1,
451
+ endLineNumber: diag.range.end.line + 1,
452
+ endColumn: diag.range.end.character + 1,
453
+ message: diag.message,
454
+ code: code,
455
+ source: diag.source
456
+ };
457
+ }
458
+ // commented here is the color definitions are were defined by v1 intellisense terminology:
459
+ // { token: 'comment', foreground: '008000' }, // CommentToken Green
460
+ // { token: 'variable.predefined', foreground: '800080' }, // CalculatedColumnToken Purple
461
+ // { token: 'function', foreground: '0000FF' }, // FunctionNameToken Blue
462
+ // { token: 'operator.sql', foreground: 'FF4500' }, // OperatorToken OrangeRed (now changed to darker color CC3700 because wasn't accessible)
463
+ // { token: 'string', foreground: 'B22222' }, // StringLiteralToken Firebrick
464
+ // { token: 'operator.scss', foreground: '0000FF' }, // SubOperatorToken Blue
465
+ // { token: 'variable', foreground: 'C71585' }, // TableColumnToken MediumVioletRed
466
+ // { token: 'variable.parameter', foreground: '9932CC' }, // TableToken DarkOrchid
467
+ // { token: '', foreground: '000000' }, // UnknownToken, PlainTextToken Black
468
+ // { token: 'type', foreground: '0000FF' }, // DataTypeToken Blue
469
+ // { token: 'tag', foreground: '0000FF' }, // ControlCommandToken Blue
470
+ // { token: 'annotation', foreground: '2B91AF' }, // QueryParametersToken FF2B91AF
471
+ // { token: 'keyword', foreground: '0000FF' }, // CslCommandToken, PluginToken Blue
472
+ // { token: 'number', foreground: '191970' }, // LetVariablesToken MidnightBlue
473
+ // { token: 'annotation', foreground: '9400D3' }, // ClientDirectiveToken DarkViolet
474
+ // { token: 'invalid', background: 'cd3131' },
475
+ const classificationToColorLight = {
476
+ Column: 'C71585',
477
+ Comment: '008000',
478
+ Database: 'C71585',
479
+ Function: '0000FF',
480
+ Identifier: '000000',
481
+ Keyword: '0000FF',
482
+ Literal: 'B22222',
483
+ ScalarOperator: '0000FF',
484
+ MaterializedView: 'C71585',
485
+ MathOperator: '000000',
486
+ Command: '0000FF',
487
+ Parameter: '2B91AF',
488
+ PlainText: '000000',
489
+ Punctuation: '000000',
490
+ QueryOperator: 'CC3700',
491
+ QueryParameter: 'CC3700',
492
+ StringLiteral: 'B22222',
493
+ Table: 'C71585',
494
+ Type: '0000FF',
495
+ Variable: '191970',
496
+ Directive: '9400D3',
497
+ ClientParameter: 'b5cea8',
498
+ SchemaMember: 'C71585',
499
+ SignatureParameter: '2B91AF',
500
+ Option: '000000'
11
501
  };
12
- import { WorkerManager } from './workerManager';
13
- import { KustoLanguageDefinition } from './languageService/kustoMonarchLanguageDefinition';
14
- import * as languageFeatures from './languageFeatures';
15
- var kustoWorker;
16
- var resolveWorker;
17
- var rejectWorker;
18
- var workerPromise = new Promise(function (resolve, reject) {
19
- resolveWorker = resolve;
20
- rejectWorker = reject;
21
- });
502
+ const classificationToColorDark = {
503
+ Column: '4ec9b0',
504
+ Comment: '6A9B34',
505
+ Database: 'c586c0',
506
+ Function: 'dcdcaa',
507
+ Identifier: 'd4d4d4',
508
+ Keyword: '569cd6',
509
+ Literal: 'ce9178',
510
+ ScalarOperator: '569cd6',
511
+ MaterializedView: 'c586c0',
512
+ MathOperator: 'd4d4d4',
513
+ Command: 'd4d4d4',
514
+ Parameter: '2B91AF',
515
+ PlainText: 'd4d4d4',
516
+ Punctuation: 'd4d4d4',
517
+ QueryOperator: '9cdcfe',
518
+ QueryParameter: '9cdcfe',
519
+ StringLiteral: 'ce9178',
520
+ Table: 'c586c0',
521
+ Type: '569cd6',
522
+ Variable: 'd7ba7d',
523
+ Directive: 'b5cea8',
524
+ ClientParameter: 'b5cea8',
525
+ SchemaMember: '4ec9b0',
526
+ SignatureParameter: '2B91AF',
527
+ Option: 'd4d4d4'
528
+ };
529
+ class ColorizationAdapter {
530
+ _disposables = [];
531
+ _contentListener = Object.create(null);
532
+ _configurationListener = Object.create(null);
533
+ _schemaListener = Object.create(null);
534
+ decorations = [];
535
+ constructor(_monacoInstance, _languageId, _worker, defaults, onSchemaChange) {
536
+ this._monacoInstance = _monacoInstance;
537
+ this._languageId = _languageId;
538
+ this._worker = _worker;
539
+ injectCss();
540
+ const onModelAdd = model => {
541
+ let languageId = model.getLanguageId();
542
+ if (languageId !== this._languageId) {
543
+ return;
544
+ }
545
+ const debouncedColorization = debounce(intervals => this._doColorization(model, languageId, intervals), 500);
546
+ this._contentListener[model.uri.toString()] = model.onDidChangeContent(e => {
547
+ // Changes are represented as a range in doc before change, plus the text that it was replaced with.
548
+ // We are interested in the range _after_ the change (since that's what we need to colorize).
549
+ // following logic calculates that.
550
+ const intervalsToColorize = changeEventToIntervals(e);
551
+ debouncedColorization(intervalsToColorize);
552
+ });
553
+ this._configurationListener[model.uri.toString()] = defaults.onDidChange(() => {
554
+ self.setTimeout(() => this._doColorization(model, languageId, []), 0);
555
+ });
556
+ this._schemaListener[model.uri.toString()] = onSchemaChange(() => {
557
+ self.setTimeout(() => this._doColorization(model, languageId, []), 0);
558
+ });
559
+ };
560
+ const onModelRemoved = model => {
561
+ model.deltaDecorations(this.decorations, []);
562
+ let uriStr = model.uri.toString();
563
+ let contentListener = this._contentListener[uriStr];
564
+ if (contentListener) {
565
+ contentListener.dispose();
566
+ delete this._contentListener[uriStr];
567
+ }
568
+ let configurationListener = this._configurationListener[uriStr];
569
+ if (configurationListener) {
570
+ configurationListener.dispose();
571
+ delete this._configurationListener[uriStr];
572
+ }
573
+ let schemaListener = this._configurationListener[uriStr];
574
+ if (schemaListener) {
575
+ schemaListener.dispose();
576
+ delete this._schemaListener[uriStr];
577
+ }
578
+ };
579
+ this._disposables.push(this._monacoInstance.editor.onDidCreateModel(onModelAdd));
580
+ this._disposables.push(this._monacoInstance.editor.onWillDisposeModel(onModelRemoved));
581
+ this._disposables.push(this._monacoInstance.editor.onDidChangeModelLanguage(event => {
582
+ onModelRemoved(event.model);
583
+ onModelAdd(event.model);
584
+ }));
585
+ this._disposables.push({
586
+ dispose: () => {
587
+ for (let key in this._contentListener) {
588
+ this._contentListener[key].dispose();
589
+ }
590
+ }
591
+ });
592
+ this._monacoInstance.editor.getModels().forEach(onModelAdd);
593
+ }
594
+ dispose() {
595
+ this._disposables.forEach(d => d && d.dispose());
596
+ this._disposables = [];
597
+ }
598
+
599
+ /**
600
+ * Return true if the range doesn't intersect any of the line ranges.
601
+ * @param range Range
602
+ * @param impactedLineRanges an array of line ranges
603
+ */
604
+ _rangeDoesNotIntersectAny(range, impactedLineRanges) {
605
+ return impactedLineRanges.every(lineRange => range.startLineNumber > lineRange.lastImpactedLine || range.endLineNumber < lineRange.firstImpactedLine);
606
+ }
607
+ _doColorization(model, languageId, intervals) {
608
+ if (model.isDisposed()) {
609
+ return;
610
+ }
611
+ const resource = model.uri;
612
+ const versionNumberBeforeColorization = model.getVersionId();
613
+ this._worker(resource).then(worker => {
614
+ return worker.doColorization(resource.toString(), intervals);
615
+ }).then(colorizationRanges => {
616
+ const newModel = this._monacoInstance.editor.getModel(model.uri);
617
+ const versionId = newModel.getVersionId();
618
+
619
+ // don't colorize an older version of the document.
620
+ if (versionId !== versionNumberBeforeColorization) {
621
+ return;
622
+ }
623
+ const decorationRanges = colorizationRanges.map(colorizationRange => {
624
+ const decorations = colorizationRange.classifications.map(classification => toDecoration(model, classification))
625
+ // The following line will prevent things that aren't going to be colorized anyway to get a CSS class.
626
+ // This will prevent the case where the non-semantic colorizer already figured out that a keyword needs
627
+ // to be colorized, but the outdated semantic colorizer still thinks it's a plain text and wants it colored
628
+ // in black.
629
+ .filter(d => d.options.inlineClassName !== 'PlainText' && d.options.inlineClassName != 'Identifier');
630
+ const firstImpactedLine = model.getPositionAt(colorizationRange.absoluteStart).lineNumber;
631
+ const endPosition = model.getPositionAt(colorizationRange.absoluteEnd);
632
+
633
+ // A token that ends in the first column of the next line is not considered to be part of that line.
634
+ const lastImpactedLine = endPosition.column == 1 && endPosition.lineNumber > 1 ? endPosition.lineNumber - 1 : endPosition.lineNumber;
635
+ return {
636
+ decorations,
637
+ firstImpactedLine,
638
+ lastImpactedLine
639
+ };
640
+ });
641
+
642
+ // Compute the previous decorations we want to replace with the new ones.
643
+ const oldDecorations = decorationRanges.map(range => model.getLinesDecorations(range.firstImpactedLine, range.lastImpactedLine).filter(d => classificationToColorLight[d.options.inlineClassName]) // Don't delete any other decorations
644
+ .map(d => d.id)).reduce((prev, curr) => prev.concat(curr), []);
645
+
646
+ // Flatten decoration groups to an array of decorations
647
+ const newDecorations = decorationRanges.reduce((prev, next) => prev.concat(next.decorations), []);
648
+ if (model && model.getLanguageId() === languageId) {
649
+ this.decorations = model.deltaDecorations(oldDecorations, newDecorations);
650
+ }
651
+ }).then(undefined, err => {
652
+ console.error(err);
653
+ });
654
+ }
655
+ }
656
+
22
657
  /**
23
- * Called when Kusto language is first needed (a model has the language set)
24
- * @param defaults
658
+ * Gets all keys of an enum (the string keys not the numeric values).
659
+ * @param e Enum type
25
660
  */
26
- export function setupMode(defaults, monacoInstance) {
27
- var onSchemaChange = new monaco.Emitter();
28
- // TODO: when should we dispose of these? seems like monaco-css and monaco-typescript don't dispose of these.
29
- var disposables = [];
30
- var monarchTokensProvider;
31
- var client = new WorkerManager(monacoInstance, defaults);
32
- disposables.push(client);
33
- var workerAccessor = function (first) {
34
- var more = [];
35
- for (var _i = 1; _i < arguments.length; _i++) {
36
- more[_i - 1] = arguments[_i];
37
- }
38
- var augmentedSetSchema = function (schema, worker, globalScalarParameters, globalTabularParameters) {
39
- var workerPromise = worker.setSchema(schema);
40
- workerPromise.then(function () {
41
- onSchemaChange.fire(schema);
42
- });
661
+ function getEnumKeys(e) {
662
+ return Object.keys(e).filter(k => typeof e[k] === 'number');
663
+ }
664
+
665
+ /**
666
+ * Generates a mapping between ClassificationKind and color.
667
+ */
668
+ function getClassificationColorTriplets() {
669
+ const keys = getEnumKeys(ClassificationKind);
670
+ const result = keys.map(key => ({
671
+ classification: key,
672
+ colorLight: classificationToColorLight[key],
673
+ colorDark: classificationToColorDark[key]
674
+ }));
675
+ return result;
676
+ }
677
+
678
+ /**
679
+ * Returns a string which is a css describing all tokens and their colors.
680
+ * looks a little bit something like this:
681
+ *
682
+ * .vs .Literal {color: '#000000';} .vs-dark .Literal {color: '#FFFFFF';}
683
+ * .vs .Comment {color: '#111111';} .vs-dark .Comment {color: '#EEEEEE';}
684
+ */
685
+ function getCssForClassification() {
686
+ const classificationColorTriplets = getClassificationColorTriplets();
687
+ const cssInnerHtml = classificationColorTriplets.map(pair => `.vs .${pair.classification} {color: #${pair.colorLight};} .vs-dark .${pair.classification} {color: #${pair.colorDark};}`).join('\n');
688
+ return cssInnerHtml;
689
+ }
690
+
691
+ /**
692
+ * Inject a CSS sheet to the head of document, coloring kusto elements by classification.
693
+ * TODO: make idempotent
694
+ */
695
+ function injectCss() {
696
+ const container = document.getElementsByTagName('head')[0];
697
+ var style = document.createElement('style');
698
+ style.type = 'text/css';
699
+ style.media = 'screen';
700
+ container.appendChild(style);
701
+ style.innerHTML = getCssForClassification();
702
+ }
703
+ function toDecoration(model, classification) {
704
+ const start = model.getPositionAt(classification.start);
705
+ const end = model.getPositionAt(classification.start + classification.length);
706
+ const range = new Range(start.lineNumber, start.column, end.lineNumber, end.column);
707
+ const inlineClassName = ClassificationKind.$names[classification.kind];
708
+ return {
709
+ range,
710
+ options: {
711
+ inlineClassName,
712
+ stickiness: monaco.editor.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
713
+ }
714
+ };
715
+ }
716
+ // --- completion ------
717
+
718
+ function fromPosition(position) {
719
+ if (!position) {
720
+ return void 0;
721
+ }
722
+ return {
723
+ character: position.column - 1,
724
+ line: position.lineNumber - 1
725
+ };
726
+ }
727
+ function fromRange(range) {
728
+ if (!range) {
729
+ return void 0;
730
+ }
731
+ return {
732
+ start: fromPosition(range.getStartPosition()),
733
+ end: fromPosition(range.getEndPosition())
734
+ };
735
+ }
736
+ function toRange(range) {
737
+ if (!range) {
738
+ return void 0;
739
+ }
740
+ return new Range(range.start.line + 1, range.start.character + 1, range.end.line + 1, range.end.character + 1);
741
+ }
742
+ function toCompletionItemKind(kind) {
743
+ let mItemKind = monaco.languages.CompletionItemKind;
744
+ switch (kind) {
745
+ case ls.CompletionItemKind.Text:
746
+ return mItemKind.Text;
747
+ case ls.CompletionItemKind.Method:
748
+ return mItemKind.Method;
749
+ case ls.CompletionItemKind.Function:
750
+ return mItemKind.Function;
751
+ case ls.CompletionItemKind.Constructor:
752
+ return mItemKind.Constructor;
753
+ case ls.CompletionItemKind.Field:
754
+ return mItemKind.Field;
755
+ case ls.CompletionItemKind.Variable:
756
+ return mItemKind.Variable;
757
+ case ls.CompletionItemKind.Class:
758
+ return mItemKind.Class;
759
+ case ls.CompletionItemKind.Interface:
760
+ return mItemKind.Interface;
761
+ case ls.CompletionItemKind.Module:
762
+ return mItemKind.Module;
763
+ case ls.CompletionItemKind.Property:
764
+ return mItemKind.Property;
765
+ case ls.CompletionItemKind.Unit:
766
+ return mItemKind.Unit;
767
+ case ls.CompletionItemKind.Value:
768
+ return mItemKind.Value;
769
+ case ls.CompletionItemKind.Enum:
770
+ return mItemKind.Enum;
771
+ case ls.CompletionItemKind.Keyword:
772
+ return mItemKind.Keyword;
773
+ case ls.CompletionItemKind.Snippet:
774
+ return mItemKind.Snippet;
775
+ case ls.CompletionItemKind.Color:
776
+ return mItemKind.Color;
777
+ case ls.CompletionItemKind.File:
778
+ return mItemKind.File;
779
+ case ls.CompletionItemKind.Reference:
780
+ return mItemKind.Reference;
781
+ }
782
+ return mItemKind.Property;
783
+ }
784
+ function toTextEdit(textEdit) {
785
+ if (!textEdit) {
786
+ return void 0;
787
+ }
788
+ return {
789
+ range: toRange(textEdit.range),
790
+ text: textEdit.newText
791
+ };
792
+ }
793
+ const DOCS_BASE_URL = 'https://learn.microsoft.com/azure/data-explorer/kusto/query';
794
+ function formatDocLink(docString) {
795
+ // If the docString is empty, we want to return undefined to prevent an empty documentation popup.
796
+ if (!docString) {
797
+ return undefined;
798
+ }
799
+ const target = {};
800
+ const urisProxy = new Proxy(target, {
801
+ get(_target, prop, _receiver) {
802
+ // The link comes with a postfix of ".md" that we want to remove
803
+ const linkWithoutPostfix = prop.toString().replace('.md', '');
804
+ // Sometimes we get the link as a full URL. For example in the main doc link of the item
805
+ const fullURL = linkWithoutPostfix.startsWith('https') ? linkWithoutPostfix : `${DOCS_BASE_URL}/${linkWithoutPostfix}`;
806
+ return monaco.Uri.parse(fullURL);
807
+ }
808
+ });
809
+ return {
810
+ value: docString,
811
+ isTrusted: true,
812
+ uris: urisProxy
813
+ };
814
+ }
815
+ class CompletionAdapter {
816
+ constructor(_worker, languageSettings) {
817
+ this._worker = _worker;
818
+ this.languageSettings = languageSettings;
819
+ }
820
+ get triggerCharacters() {
821
+ return [' '];
822
+ }
823
+ provideCompletionItems(model, position, context, token) {
824
+ const wordInfo = model.getWordUntilPosition(position);
825
+ const wordRange = new Range(position.lineNumber, wordInfo.startColumn, position.lineNumber, wordInfo.endColumn);
826
+ const resource = model.uri;
827
+ const onDidProvideCompletionItems = this.languageSettings.onDidProvideCompletionItems;
828
+ return this._worker(resource).then(worker => {
829
+ return worker.doComplete(resource.toString(), fromPosition(position));
830
+ }).then(info => onDidProvideCompletionItems ? onDidProvideCompletionItems(info) : info).then(info => {
831
+ if (!info) {
832
+ return;
833
+ }
834
+ let items = info.items.map(entry => {
835
+ let item = {
836
+ label: entry.label,
837
+ insertText: entry.insertText,
838
+ sortText: entry.sortText,
839
+ filterText: entry.filterText,
840
+ documentation: formatDocLink(entry.documentation?.value),
841
+ detail: entry.detail,
842
+ range: wordRange,
843
+ kind: toCompletionItemKind(entry.kind)
43
844
  };
44
- var worker = client.getLanguageServiceWorker.apply(client, [first].concat(more));
45
- return worker.then(function (worker) {
46
- return (__assign(__assign({}, worker), { setSchema: function (schema) { return augmentedSetSchema(schema, worker); }, setSchemaFromShowSchema: function (schema, connection, database, globalScalarParameters, globalTabularParameters) {
47
- worker
48
- .normalizeSchema(schema, connection, database)
49
- .then(function (schema) {
50
- return globalScalarParameters
51
- ? __assign(__assign({}, schema), { globalScalarParameters: globalScalarParameters, globalTabularParameters: globalTabularParameters }) : schema;
52
- })
53
- .then(function (normalized) { return augmentedSetSchema(normalized, worker); });
54
- } }));
55
- });
56
- };
57
- var language = 'kusto';
58
- disposables.push(monacoInstance.languages.registerCompletionItemProvider(language, new languageFeatures.CompletionAdapter(workerAccessor, defaults.languageSettings)));
59
- // Monaco tokenization runs in main thread so we're using a quick schema-unaware tokenization.
60
- // a web worker will run semantic colorization in the background (ColorizationAdapter).
61
- if (defaults.languageSettings.useTokenColorization) {
62
- monarchTokensProvider = monacoInstance.languages.setMonarchTokensProvider(language, KustoLanguageDefinition);
63
- }
64
- // listen to configuration changes and if we're switching from semantic to monarch colorization, do the switch.
65
- defaults.onDidChange(function (e) {
66
- if (!e.languageSettings.useTokenColorization && monarchTokensProvider !== undefined) {
67
- monarchTokensProvider.dispose();
68
- monarchTokensProvider = undefined;
845
+ if (entry.textEdit) {
846
+ item.range = toRange(entry.textEdit.range);
847
+ item.insertText = entry.textEdit.newText;
69
848
  }
70
- if (e.languageSettings.useTokenColorization && monarchTokensProvider == undefined) {
71
- monarchTokensProvider = monacoInstance.languages.setMonarchTokensProvider(language, KustoLanguageDefinition);
849
+ if (entry.insertTextFormat === ls.InsertTextFormat.Snippet) {
850
+ item.insertTextRules = monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet;
72
851
  }
852
+ return item;
853
+ });
854
+ return {
855
+ isIncomplete: info.isIncomplete,
856
+ suggestions: items
857
+ };
73
858
  });
74
- disposables.push(new languageFeatures.DiagnosticsAdapter(monacoInstance, language, workerAccessor, defaults, onSchemaChange.event));
75
- disposables.push(new languageFeatures.ColorizationAdapter(monacoInstance, language, workerAccessor, defaults, onSchemaChange.event));
76
- disposables.push(monacoInstance.languages.registerDocumentRangeFormattingEditProvider(language, new languageFeatures.FormatAdapter(workerAccessor)));
77
- disposables.push(monacoInstance.languages.registerFoldingRangeProvider(language, new languageFeatures.FoldingAdapter(workerAccessor)));
78
- disposables.push(monacoInstance.languages.registerDefinitionProvider(language, new languageFeatures.DefinitionAdapter(workerAccessor)));
79
- disposables.push(monacoInstance.languages.registerRenameProvider(language, new languageFeatures.RenameAdapter(workerAccessor)));
80
- disposables.push(monacoInstance.languages.registerReferenceProvider(language, new languageFeatures.ReferenceAdapter(workerAccessor)));
81
- if (defaults.languageSettings.enableHover) {
82
- disposables.push(monacoInstance.languages.registerHoverProvider(language, new languageFeatures.HoverAdapter(workerAccessor)));
83
- }
84
- monacoInstance.languages.registerDocumentFormattingEditProvider(language, new languageFeatures.DocumentFormatAdapter(workerAccessor));
85
- kustoWorker = workerAccessor;
86
- resolveWorker(workerAccessor);
87
- monacoInstance.languages.setLanguageConfiguration(language, {
88
- folding: {
89
- offSide: false,
90
- markers: { start: /^\s*[\r\n]/gm, end: /^\s*[\r\n]/gm },
91
- },
92
- comments: {
93
- lineComment: '//',
94
- blockComment: null,
859
+ }
860
+ }
861
+ function isMarkupContent(thing) {
862
+ return thing && typeof thing === 'object' && typeof thing.kind === 'string';
863
+ }
864
+ function toMarkdownString(entry) {
865
+ if (typeof entry === 'string') {
866
+ return {
867
+ value: entry
868
+ };
869
+ }
870
+ if (isMarkupContent(entry)) {
871
+ if (entry.kind === 'plaintext') {
872
+ return {
873
+ value: entry.value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
874
+ };
875
+ }
876
+ return {
877
+ value: entry.value
878
+ };
879
+ }
880
+ return {
881
+ value: '```' + entry.value + '\n' + entry.value + '\n```\n'
882
+ };
883
+ }
884
+ function toMarkedStringArray(contents) {
885
+ if (!contents) {
886
+ return void 0;
887
+ }
888
+ if (Array.isArray(contents)) {
889
+ return contents.map(toMarkdownString);
890
+ }
891
+ return [toMarkdownString(contents)];
892
+ }
893
+
894
+ // --- definition ------
895
+
896
+ function toLocation(location) {
897
+ return {
898
+ uri: Uri.parse(location.uri),
899
+ range: toRange(location.range)
900
+ };
901
+ }
902
+ class DefinitionAdapter {
903
+ constructor(_worker) {
904
+ this._worker = _worker;
905
+ }
906
+ provideDefinition(model, position, token) {
907
+ const resource = model.uri;
908
+ return this._worker(resource).then(worker => {
909
+ return worker.findDefinition(resource.toString(), fromPosition(position));
910
+ }).then(definition => {
911
+ if (!definition || definition.length == 0) {
912
+ return;
913
+ }
914
+ return [toLocation(definition[0])];
915
+ });
916
+ }
917
+ }
918
+
919
+ // --- references ------
920
+
921
+ class ReferenceAdapter {
922
+ constructor(_worker) {
923
+ this._worker = _worker;
924
+ }
925
+ provideReferences(model, position, context, token) {
926
+ const resource = model.uri;
927
+ return this._worker(resource).then(worker => {
928
+ return worker.findReferences(resource.toString(), fromPosition(position));
929
+ }).then(entries => {
930
+ if (!entries) {
931
+ return;
932
+ }
933
+ return entries.map(toLocation);
934
+ });
935
+ }
936
+ }
937
+
938
+ // --- rename ------
939
+
940
+ function toWorkspaceEdit(edit) {
941
+ if (!edit || !edit.changes) {
942
+ return void 0;
943
+ }
944
+ let resourceEdits = [];
945
+ for (let uri in edit.changes) {
946
+ const _uri = Uri.parse(uri);
947
+ for (let e of edit.changes[uri]) {
948
+ resourceEdits.push({
949
+ resource: _uri,
950
+ textEdit: {
951
+ range: toRange(e.range),
952
+ text: e.newText
95
953
  },
954
+ versionId: undefined
955
+ });
956
+ }
957
+ }
958
+ return {
959
+ edits: resourceEdits
960
+ };
961
+ }
962
+ class RenameAdapter {
963
+ constructor(_worker) {
964
+ this._worker = _worker;
965
+ }
966
+ provideRenameEdits(model, position, newName, token) {
967
+ const resource = model.uri;
968
+ return this._worker(resource).then(worker => {
969
+ return worker.doRename(resource.toString(), fromPosition(position), newName);
970
+ }).then(edit => {
971
+ return toWorkspaceEdit(edit);
972
+ });
973
+ }
974
+ }
975
+
976
+ // --- formatting -----
977
+
978
+ class DocumentFormatAdapter {
979
+ constructor(_worker) {
980
+ this._worker = _worker;
981
+ }
982
+ provideDocumentFormattingEdits(model, options, token) {
983
+ const resource = model.uri;
984
+ return this._worker(resource).then(worker => {
985
+ return worker.doDocumentFormat(resource.toString()).then(edits => edits.map(edit => toTextEdit(edit)));
986
+ });
987
+ }
988
+ }
989
+ class FormatAdapter {
990
+ constructor(_worker) {
991
+ this._worker = _worker;
992
+ }
993
+ provideDocumentRangeFormattingEdits(model, range, options, token) {
994
+ const resource = model.uri;
995
+ return this._worker(resource).then(worker => {
996
+ return worker.doRangeFormat(resource.toString(), fromRange(range)).then(edits => edits.map(edit => toTextEdit(edit)));
997
+ });
998
+ }
999
+ }
1000
+
1001
+ // --- Folding ---
1002
+ class FoldingAdapter {
1003
+ constructor(_worker) {
1004
+ this._worker = _worker;
1005
+ }
1006
+ provideFoldingRanges(model, context, token) {
1007
+ const resource = model.uri;
1008
+ return this._worker(resource).then(worker => {
1009
+ return worker.doFolding(resource.toString()).then(foldingRanges => foldingRanges.map(range => toFoldingRange(range)));
1010
+ });
1011
+ }
1012
+ }
1013
+ function toFoldingRange(range) {
1014
+ return {
1015
+ start: range.startLine + 1,
1016
+ end: range.endLine + 1,
1017
+ kind: monaco.languages.FoldingRangeKind.Region
1018
+ };
1019
+ }
1020
+
1021
+ // --- hover ------
1022
+
1023
+ class HoverAdapter {
1024
+ constructor(_worker) {
1025
+ this._worker = _worker;
1026
+ }
1027
+ provideHover(model, position, token) {
1028
+ let resource = model.uri;
1029
+ return this._worker(resource).then(worker => {
1030
+ return worker.doHover(resource.toString(), fromPosition(position));
1031
+ }).then(info => {
1032
+ if (!info) {
1033
+ return;
1034
+ }
1035
+ return {
1036
+ range: toRange(info.range),
1037
+ contents: toMarkedStringArray(info.contents)
1038
+ };
96
1039
  });
97
- return kustoWorker;
1040
+ }
1041
+ }
1042
+
1043
+ monaco.Uri;
1044
+ monaco.IDisposable;
1045
+ let kustoWorker;
1046
+ let resolveWorker;
1047
+ let workerPromise = new Promise((resolve, reject) => {
1048
+ resolveWorker = resolve;
1049
+ });
1050
+
1051
+ /**
1052
+ * Called when Kusto language is first needed (a model has the language set)
1053
+ * @param defaults
1054
+ */
1055
+ function setupMode(defaults, monacoInstance) {
1056
+ let onSchemaChange = new monaco.Emitter();
1057
+ // TODO: when should we dispose of these? seems like monaco-css and monaco-typescript don't dispose of these.
1058
+ let disposables = [];
1059
+ let monarchTokensProvider;
1060
+ const client = new WorkerManager(monacoInstance, defaults);
1061
+ disposables.push(client);
1062
+ const workerAccessor = (first, ...more) => {
1063
+ const augmentedSetSchema = (schema, worker, globalScalarParameters, globalTabularParameters) => {
1064
+ const workerPromise = worker.setSchema(schema);
1065
+ workerPromise.then(() => {
1066
+ onSchemaChange.fire(schema);
1067
+ });
1068
+ };
1069
+ const worker = client.getLanguageServiceWorker(...[first].concat(more));
1070
+ return worker.then(worker => ({
1071
+ ...worker,
1072
+ setSchema: schema => augmentedSetSchema(schema, worker),
1073
+ setSchemaFromShowSchema: (schema, connection, database, globalScalarParameters, globalTabularParameters) => {
1074
+ worker.normalizeSchema(schema, connection, database).then(schema => globalScalarParameters ? {
1075
+ ...schema,
1076
+ globalScalarParameters,
1077
+ globalTabularParameters
1078
+ } : schema).then(normalized => augmentedSetSchema(normalized, worker));
1079
+ }
1080
+ }));
1081
+ };
1082
+ const language = 'kusto';
1083
+ disposables.push(monacoInstance.languages.registerCompletionItemProvider(language, new CompletionAdapter(workerAccessor, defaults.languageSettings)));
1084
+
1085
+ // Monaco tokenization runs in main thread so we're using a quick schema-unaware tokenization.
1086
+ // a web worker will run semantic colorization in the background (ColorizationAdapter).
1087
+ if (defaults.languageSettings.useTokenColorization) {
1088
+ monarchTokensProvider = monacoInstance.languages.setMonarchTokensProvider(language, KustoLanguageDefinition);
1089
+ }
1090
+
1091
+ // listen to configuration changes and if we're switching from semantic to monarch colorization, do the switch.
1092
+ defaults.onDidChange(e => {
1093
+ if (!e.languageSettings.useTokenColorization && monarchTokensProvider !== undefined) {
1094
+ monarchTokensProvider.dispose();
1095
+ monarchTokensProvider = undefined;
1096
+ }
1097
+ if (e.languageSettings.useTokenColorization && monarchTokensProvider == undefined) {
1098
+ monarchTokensProvider = monacoInstance.languages.setMonarchTokensProvider(language, KustoLanguageDefinition);
1099
+ }
1100
+ });
1101
+ disposables.push(new DiagnosticsAdapter(monacoInstance, language, workerAccessor, defaults, onSchemaChange.event));
1102
+ disposables.push(new ColorizationAdapter(monacoInstance, language, workerAccessor, defaults, onSchemaChange.event));
1103
+ disposables.push(monacoInstance.languages.registerDocumentRangeFormattingEditProvider(language, new FormatAdapter(workerAccessor)));
1104
+ disposables.push(monacoInstance.languages.registerFoldingRangeProvider(language, new FoldingAdapter(workerAccessor)));
1105
+ disposables.push(monacoInstance.languages.registerDefinitionProvider(language, new DefinitionAdapter(workerAccessor)));
1106
+ disposables.push(monacoInstance.languages.registerRenameProvider(language, new RenameAdapter(workerAccessor)));
1107
+ disposables.push(monacoInstance.languages.registerReferenceProvider(language, new ReferenceAdapter(workerAccessor)));
1108
+ if (defaults.languageSettings.enableHover) {
1109
+ disposables.push(monacoInstance.languages.registerHoverProvider(language, new HoverAdapter(workerAccessor)));
1110
+ }
1111
+ monacoInstance.languages.registerDocumentFormattingEditProvider(language, new DocumentFormatAdapter(workerAccessor));
1112
+ kustoWorker = workerAccessor;
1113
+ resolveWorker(workerAccessor);
1114
+ monacoInstance.languages.setLanguageConfiguration(language, {
1115
+ folding: {
1116
+ offSide: false,
1117
+ markers: {
1118
+ start: /^\s*[\r\n]/gm,
1119
+ end: /^\s*[\r\n]/gm
1120
+ }
1121
+ },
1122
+ comments: {
1123
+ lineComment: '//',
1124
+ blockComment: null
1125
+ }
1126
+ });
1127
+ return kustoWorker;
98
1128
  }
99
- export function getKustoWorker() {
100
- return workerPromise.then(function () { return kustoWorker; });
1129
+ function getKustoWorker() {
1130
+ return workerPromise.then(() => kustoWorker);
101
1131
  }
1132
+
1133
+ export { getKustoWorker, setupMode };