@jupyterlab/codemirror 4.0.0-alpha.2 → 4.0.0-alpha.21

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 (78) hide show
  1. package/lib/codemirror-ipythongfm.d.ts +9 -3
  2. package/lib/codemirror-ipythongfm.js +52 -30
  3. package/lib/codemirror-ipythongfm.js.map +1 -1
  4. package/lib/commands.d.ts +13 -0
  5. package/lib/commands.js +32 -0
  6. package/lib/commands.js.map +1 -0
  7. package/lib/editor.d.ts +48 -279
  8. package/lib/editor.js +220 -818
  9. package/lib/editor.js.map +1 -1
  10. package/lib/extension.d.ts +236 -0
  11. package/lib/extension.js +696 -0
  12. package/lib/extension.js.map +1 -0
  13. package/lib/extensions/customStyle.d.ts +25 -0
  14. package/lib/extensions/customStyle.js +51 -0
  15. package/lib/extensions/customStyle.js.map +1 -0
  16. package/lib/extensions/index.d.ts +3 -0
  17. package/lib/extensions/index.js +8 -0
  18. package/lib/extensions/index.js.map +1 -0
  19. package/lib/extensions/rulers.d.ts +8 -0
  20. package/lib/extensions/rulers.js +85 -0
  21. package/lib/extensions/rulers.js.map +1 -0
  22. package/lib/extensions/ybinding.d.ts +129 -0
  23. package/lib/extensions/ybinding.js +229 -0
  24. package/lib/extensions/ybinding.js.map +1 -0
  25. package/lib/factory.d.ts +15 -5
  26. package/lib/factory.js +53 -24
  27. package/lib/factory.js.map +1 -1
  28. package/lib/index.d.ts +7 -19
  29. package/lib/index.js +7 -23
  30. package/lib/index.js.map +1 -1
  31. package/lib/language.d.ts +96 -0
  32. package/lib/language.js +1690 -0
  33. package/lib/language.js.map +1 -0
  34. package/lib/mimetype.d.ts +3 -0
  35. package/lib/mimetype.js +16 -5
  36. package/lib/mimetype.js.map +1 -1
  37. package/lib/searchprovider.d.ts +219 -0
  38. package/lib/searchprovider.js +640 -0
  39. package/lib/searchprovider.js.map +1 -0
  40. package/lib/theme.d.ts +57 -0
  41. package/lib/theme.js +194 -0
  42. package/lib/theme.js.map +1 -0
  43. package/lib/token.d.ts +375 -0
  44. package/lib/token.js +18 -0
  45. package/lib/token.js.map +1 -0
  46. package/package.json +45 -41
  47. package/src/codemirror-ipythongfm.ts +109 -0
  48. package/src/commands.ts +34 -0
  49. package/src/editor.ts +783 -0
  50. package/src/extension.ts +890 -0
  51. package/src/extensions/customStyle.ts +79 -0
  52. package/src/extensions/index.ts +8 -0
  53. package/src/extensions/rulers.ts +112 -0
  54. package/src/extensions/ybinding.ts +295 -0
  55. package/src/factory.ts +100 -0
  56. package/src/index.ts +17 -0
  57. package/src/language.ts +1729 -0
  58. package/src/mimetype.ts +54 -0
  59. package/src/searchprovider.ts +813 -0
  60. package/src/theme.ts +219 -0
  61. package/src/token.ts +436 -0
  62. package/src/typings.d.ts +13 -0
  63. package/style/base.css +34 -162
  64. package/style/index.css +1 -7
  65. package/style/index.js +1 -7
  66. package/lib/codemirror-ipython.d.ts +0 -2
  67. package/lib/codemirror-ipython.js +0 -30
  68. package/lib/codemirror-ipython.js.map +0 -1
  69. package/lib/mode.d.ts +0 -81
  70. package/lib/mode.js +0 -149
  71. package/lib/mode.js.map +0 -1
  72. package/lib/syntaxstatus.d.ts +0 -67
  73. package/lib/syntaxstatus.js +0 -140
  74. package/lib/syntaxstatus.js.map +0 -1
  75. package/lib/tokens.d.ts +0 -18
  76. package/lib/tokens.js +0 -9
  77. package/lib/tokens.js.map +0 -1
  78. package/typings/codemirror/codemirror.d.ts +0 -227
package/lib/editor.js CHANGED
@@ -1,69 +1,19 @@
1
1
  /* eslint-disable @typescript-eslint/ban-types */
2
2
  // Copyright (c) Jupyter Development Team.
3
3
  // Distributed under the terms of the Modified BSD License.
4
- // / <reference types="codemirror"/>
5
- // / <reference types="codemirror/searchcursor"/>
6
- var __rest = (this && this.__rest) || function (s, e) {
7
- var t = {};
8
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
9
- t[p] = s[p];
10
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
11
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
12
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
13
- t[p[i]] = s[p[i]];
14
- }
15
- return t;
16
- };
17
- import { showDialog } from '@jupyterlab/apputils';
18
- import { CodeEditor } from '@jupyterlab/codeeditor';
19
- import { nullTranslator } from '@jupyterlab/translation';
20
- import { ArrayExt } from '@lumino/algorithm';
21
- import { JSONExt, UUID } from '@lumino/coreutils';
22
- import { DisposableDelegate } from '@lumino/disposable';
23
- import { Poll } from '@lumino/polling';
4
+ import { insertNewlineAndIndent } from '@codemirror/commands';
5
+ import { ensureSyntaxTree } from '@codemirror/language';
6
+ import { Compartment, EditorSelection, EditorState, Prec } from '@codemirror/state';
7
+ import { EditorView } from '@codemirror/view';
8
+ import { UUID } from '@lumino/coreutils';
24
9
  import { Signal } from '@lumino/signaling';
25
- import CodeMirror from 'codemirror';
26
- import 'codemirror/addon/comment/comment.js';
27
- import 'codemirror/addon/display/rulers.js';
28
- import 'codemirror/addon/edit/closebrackets.js';
29
- import 'codemirror/addon/edit/matchbrackets.js';
30
- import 'codemirror/addon/fold/brace-fold.js';
31
- import 'codemirror/addon/fold/comment-fold.js';
32
- import 'codemirror/addon/fold/foldcode.js';
33
- import 'codemirror/addon/fold/foldgutter.js';
34
- import 'codemirror/addon/fold/indent-fold.js';
35
- import 'codemirror/addon/fold/markdown-fold.js';
36
- import 'codemirror/addon/fold/xml-fold.js';
37
- import 'codemirror/addon/mode/simple';
38
- import 'codemirror/addon/scroll/scrollpastend.js';
39
- import 'codemirror/addon/search/jump-to-line';
40
- import 'codemirror/addon/search/search';
41
- import 'codemirror/addon/search/searchcursor';
42
- import 'codemirror/addon/selection/active-line';
43
- import 'codemirror/addon/selection/mark-selection';
44
- import 'codemirror/addon/selection/selection-pointer';
45
- import 'codemirror/addon/edit/trailingspace.js';
46
- import 'codemirror/keymap/emacs.js';
47
- import 'codemirror/keymap/sublime.js';
48
- import { CodemirrorBinding } from 'y-codemirror';
49
- import { Mode } from './mode';
50
- // import 'codemirror/keymap/vim.js'; lazy loading of vim mode is available in ../codemirror-extension/index.ts
10
+ import './codemirror-ipythongfm';
11
+ import { ExtensionsHandler } from './extension';
12
+ import { EditorLanguageRegistry } from './language';
51
13
  /**
52
14
  * The class name added to CodeMirrorWidget instances.
53
15
  */
54
16
  const EDITOR_CLASS = 'jp-CodeMirrorEditor';
55
- /**
56
- * The class name added to read only cell editor widgets.
57
- */
58
- const READ_ONLY_CLASS = 'jp-mod-readOnly';
59
- /**
60
- * The class name for the hover box for collaborator cursors.
61
- */
62
- const COLLABORATOR_CURSOR_CLASS = 'jp-CollaboratorCursor';
63
- /**
64
- * The class name for the hover box for collaborator cursors.
65
- */
66
- const COLLABORATOR_HOVER_CLASS = 'jp-CollaboratorCursor-hover';
67
17
  /**
68
18
  * The key code for the up arrow key.
69
19
  */
@@ -72,13 +22,6 @@ const UP_ARROW = 38;
72
22
  * The key code for the down arrow key.
73
23
  */
74
24
  const DOWN_ARROW = 40;
75
- /**
76
- * The time that a collaborator name hover persists.
77
- */
78
- const HOVER_TIMEOUT = 1000;
79
- // @todo Remove the duality of having a modeldb and a y-codemirror
80
- // binding as it just introduces a lot of additional complexity without gaining anything.
81
- const USE_YCODEMIRROR_BINDING = true;
82
25
  /**
83
26
  * CodeMirror editor.
84
27
  */
@@ -87,119 +30,50 @@ export class CodeMirrorEditor {
87
30
  * Construct a CodeMirror editor.
88
31
  */
89
32
  constructor(options) {
90
- var _a;
33
+ var _a, _b, _c, _d, _e, _f;
91
34
  /**
92
35
  * A signal emitted when either the top or bottom edge is requested.
93
36
  */
94
37
  this.edgeRequested = new Signal(this);
95
- this.selectionMarkers = {};
96
- this._keydownHandlers = new Array();
97
- this._changeGuard = false;
98
- this._uuid = '';
99
- this._needsRefresh = false;
100
38
  this._isDisposed = false;
101
- this._lastChange = null;
39
+ this._language = new Compartment();
40
+ this._uuid = '';
41
+ this._languages = (_a = options.languages) !== null && _a !== void 0 ? _a : new EditorLanguageRegistry();
42
+ this._configurator =
43
+ (_d = (_b = options.extensionsRegistry) === null || _b === void 0 ? void 0 : _b.createNew({
44
+ ...options,
45
+ inline: (_c = options.inline) !== null && _c !== void 0 ? _c : false
46
+ })) !== null && _d !== void 0 ? _d : new ExtensionsHandler();
102
47
  const host = (this.host = options.host);
103
- this.translator = options.translator || nullTranslator;
104
- this._trans = this.translator.load('jupyterlab');
105
48
  host.classList.add(EDITOR_CLASS);
106
49
  host.classList.add('jp-Editor');
107
50
  host.addEventListener('focus', this, true);
108
51
  host.addEventListener('blur', this, true);
109
52
  host.addEventListener('scroll', this, true);
110
- this._uuid = options.uuid || UUID.uuid4();
111
- // Handle selection style.
112
- const style = options.selectionStyle || {};
113
- this._selectionStyle = Object.assign(Object.assign({}, CodeEditor.defaultSelectionStyle), style);
53
+ this._uuid = (_e = options.uuid) !== null && _e !== void 0 ? _e : UUID.uuid4();
114
54
  const model = (this._model = options.model);
115
- const config = options.config || {};
116
- const fullConfig = (this._config = Object.assign(Object.assign({}, CodeMirrorEditor.defaultConfig), config));
117
- const editor = (this._editor = Private.createEditor(host, fullConfig));
118
- this._initializeEditorBinding();
119
- // every time the model is switched, we need to re-initialize the editor binding
120
- this.model.sharedModelSwitched.connect(this._initializeEditorBinding, this);
121
- const doc = editor.getDoc();
122
- // Handle initial values for text, mimetype, and selections.
123
- if (!USE_YCODEMIRROR_BINDING) {
124
- doc.setValue(model.value.text);
125
- }
126
- this._onMimeTypeChanged();
127
- this._onCursorActivity();
128
- this._poll = new Poll({
129
- factory: async () => {
130
- this._checkSync();
131
- },
132
- frequency: { interval: 3000, backoff: false },
133
- standby: () => {
134
- // If changed, only stand by when hidden, otherwise always stand by.
135
- return this._lastChange ? 'when-hidden' : true;
55
+ // Default keydown handler - it will have low priority
56
+ const onKeyDown = EditorView.domEventHandlers({
57
+ keydown: (event, view) => {
58
+ return this.onKeydown(event);
136
59
  }
137
60
  });
138
- // Connect to changes.
139
- if (!USE_YCODEMIRROR_BINDING) {
140
- model.value.changed.connect(this._onValueChanged, this);
141
- }
142
- model.mimeTypeChanged.connect(this._onMimeTypeChanged, this);
143
- model.selections.changed.connect(this._onSelectionsChanged, this);
144
- CodeMirror.on(editor, 'keydown', (editor, event) => {
145
- const index = ArrayExt.findFirstIndex(this._keydownHandlers, handler => {
146
- if (handler(this, event) === true) {
147
- event.preventDefault();
148
- return true;
149
- }
150
- return false;
151
- });
152
- if (index === -1) {
153
- this.onKeydown(event);
154
- }
155
- });
156
- if (USE_YCODEMIRROR_BINDING) {
157
- (_a = this._yeditorBinding) === null || _a === void 0 ? void 0 : _a.on('cursorActivity', () => this._onCursorActivity());
158
- }
159
- else {
160
- CodeMirror.on(editor, 'cursorActivity', () => this._onCursorActivity());
161
- CodeMirror.on(editor.getDoc(), 'beforeChange', (instance, change) => {
162
- this._beforeDocChanged(instance, change);
163
- });
164
- }
165
- CodeMirror.on(editor.getDoc(), 'change', (instance, change) => {
166
- // Manually refresh after setValue to make sure editor is properly sized.
167
- if (change.origin === 'setValue' && this.hasFocus()) {
168
- this.refresh();
169
- }
170
- this._lastChange = change;
171
- });
172
- // Turn off paste handling in codemirror since sometimes we want to
173
- // replace it with our own.
174
- editor.on('paste', (instance, event) => {
175
- var _a;
176
- const handlePaste = (_a = this._config['handlePaste']) !== null && _a !== void 0 ? _a : true;
177
- if (!handlePaste) {
178
- event.codemirrorIgnore = true;
179
- }
61
+ const updateListener = EditorView.updateListener.of((update) => {
62
+ this._onDocChanged(update);
180
63
  });
181
- // Manually refresh on paste to make sure editor is properly sized.
182
- editor.getWrapperElement().addEventListener('paste', () => {
183
- if (this.hasFocus()) {
184
- this.refresh();
185
- }
186
- });
187
- }
188
- /**
189
- * Initialize the editor binding.
190
- */
191
- _initializeEditorBinding() {
192
- var _a;
193
- if (!USE_YCODEMIRROR_BINDING) {
194
- return;
195
- }
196
- (_a = this._yeditorBinding) === null || _a === void 0 ? void 0 : _a.destroy();
197
- const sharedModel = this.model.sharedModel;
198
- const opts = sharedModel.undoManager
199
- ? { yUndoManager: sharedModel.undoManager }
200
- : {};
201
- const awareness = sharedModel.awareness;
202
- this._yeditorBinding = new CodemirrorBinding(sharedModel.ysource, this.editor, awareness, opts);
64
+ this._editor = Private.createEditor(host, this._configurator, [
65
+ // We need to set the order to high, otherwise the keybinding for ArrowUp/ArrowDown
66
+ // will process the event shunting our edge detection code.
67
+ Prec.high(onKeyDown),
68
+ updateListener,
69
+ // Initialize with empty extension
70
+ this._language.of([]),
71
+ ...((_f = options.extensions) !== null && _f !== void 0 ? _f : [])
72
+ ], model.sharedModel.source);
73
+ this._onMimeTypeChanged();
74
+ this._onCursorActivity();
75
+ this._configurator.configChanged.connect(this.onConfigChanged, this);
76
+ model.mimeTypeChanged.connect(this._onMimeTypeChanged, this);
203
77
  }
204
78
  /**
205
79
  * The uuid of this editor;
@@ -210,15 +84,6 @@ export class CodeMirrorEditor {
210
84
  set uuid(value) {
211
85
  this._uuid = value;
212
86
  }
213
- /**
214
- * The selection style of this editor.
215
- */
216
- get selectionStyle() {
217
- return this._selectionStyle;
218
- }
219
- set selectionStyle(value) {
220
- this._selectionStyle = value;
221
- }
222
87
  /**
223
88
  * Get the codemirror editor wrapped by the editor.
224
89
  */
@@ -229,13 +94,13 @@ export class CodeMirrorEditor {
229
94
  * Get the codemirror doc wrapped by the widget.
230
95
  */
231
96
  get doc() {
232
- return this._editor.getDoc();
97
+ return this._editor.state.doc;
233
98
  }
234
99
  /**
235
100
  * Get the number of lines in the editor.
236
101
  */
237
102
  get lineCount() {
238
- return this.doc.lineCount();
103
+ return this.doc.lines;
239
104
  }
240
105
  /**
241
106
  * Returns a model for this editor.
@@ -247,13 +112,13 @@ export class CodeMirrorEditor {
247
112
  * The height of a line in the editor in pixels.
248
113
  */
249
114
  get lineHeight() {
250
- return this._editor.defaultTextHeight();
115
+ return this._editor.defaultLineHeight;
251
116
  }
252
117
  /**
253
118
  * The widget of a character in the editor in pixels.
254
119
  */
255
120
  get charWidth() {
256
- return this._editor.defaultCharWidth();
121
+ return this._editor.defaultCharacterWidth;
257
122
  }
258
123
  /**
259
124
  * Tests whether the editor is disposed.
@@ -272,28 +137,27 @@ export class CodeMirrorEditor {
272
137
  this.host.removeEventListener('focus', this, true);
273
138
  this.host.removeEventListener('blur', this, true);
274
139
  this.host.removeEventListener('scroll', this, true);
275
- if (this._yeditorBinding) {
276
- this._yeditorBinding.destroy();
277
- }
278
- this._keydownHandlers.length = 0;
279
- this._poll.dispose();
140
+ this._configurator.dispose();
280
141
  Signal.clearData(this);
142
+ this.editor.destroy();
281
143
  }
282
144
  /**
283
145
  * Get a config option for the editor.
284
146
  */
285
147
  getOption(option) {
286
- return this._config[option];
148
+ return this._configurator.getOption(option);
149
+ }
150
+ /**
151
+ * Whether the option exists or not.
152
+ */
153
+ hasOption(option) {
154
+ return this._configurator.hasOption(option);
287
155
  }
288
156
  /**
289
157
  * Set a config option for the editor.
290
158
  */
291
159
  setOption(option, value) {
292
- // Don't bother setting the option if it is already the same.
293
- if (this._config[option] !== value) {
294
- this._config[option] = value;
295
- Private.setOption(this.editor, option, value, this._config);
296
- }
160
+ this._configurator.setOption(option, value);
297
161
  }
298
162
  /**
299
163
  * Set config options for the editor.
@@ -304,36 +168,40 @@ export class CodeMirrorEditor {
304
168
  * is set.
305
169
  */
306
170
  setOptions(options) {
307
- const editor = this._editor;
308
- editor.startOperation();
309
- for (let key in options) {
310
- editor.operation(() => {
311
- this.setOption(key, options[key]);
312
- });
313
- }
314
- editor.endOperation();
171
+ this._configurator.setOptions(options);
172
+ }
173
+ /**
174
+ * Inject an extension into the editor
175
+ *
176
+ * @alpha
177
+ * @experimental
178
+ * @param ext CodeMirror 6 extension
179
+ */
180
+ injectExtension(ext) {
181
+ this._configurator.injectExtension(this._editor, ext);
315
182
  }
316
183
  /**
317
184
  * Returns the content for the given line number.
318
185
  */
319
186
  getLine(line) {
320
- return this.doc.getLine(line);
187
+ // TODO: CM6 remove +1 when CM6 first line number has propagated
188
+ line = line + 1;
189
+ return line <= this.doc.lines ? this.doc.line(line).text : undefined;
321
190
  }
322
191
  /**
323
192
  * Find an offset for the given position.
324
193
  */
325
194
  getOffsetAt(position) {
326
- return this.doc.indexFromPos({
327
- ch: position.column,
328
- line: position.line
329
- });
195
+ // TODO: CM6 remove +1 when CM6 first line number has propagated
196
+ return this.doc.line(position.line + 1).from + position.column;
330
197
  }
331
198
  /**
332
199
  * Find a position for the given offset.
333
200
  */
334
201
  getPositionAt(offset) {
335
- const { ch, line } = this.doc.posFromIndex(offset);
336
- return { line, column: ch };
202
+ // TODO: CM6 remove -1 when CM6 first line number has propagated
203
+ const line = this.doc.lineAt(offset);
204
+ return { line: line.number - 1, column: offset - line.from };
337
205
  }
338
206
  /**
339
207
  * Undo one edit (if any undo events are stored).
@@ -351,8 +219,7 @@ export class CodeMirrorEditor {
351
219
  * Clear the undo history.
352
220
  */
353
221
  clearHistory() {
354
- var _a, _b;
355
- (_b = (_a = this._yeditorBinding) === null || _a === void 0 ? void 0 : _a.yUndoManager) === null || _b === void 0 ? void 0 : _b.clear();
222
+ this.model.sharedModel.clearUndoHistory();
356
223
  }
357
224
  /**
358
225
  * Brings browser focus to this editor text.
@@ -364,127 +231,60 @@ export class CodeMirrorEditor {
364
231
  * Test whether the editor has keyboard focus.
365
232
  */
366
233
  hasFocus() {
367
- return this._editor.getWrapperElement().contains(document.activeElement);
234
+ return this._editor.hasFocus;
368
235
  }
369
236
  /**
370
237
  * Explicitly blur the editor.
371
238
  */
372
239
  blur() {
373
- this._editor.getInputField().blur();
374
- }
375
- /**
376
- * Repaint editor.
377
- */
378
- refresh() {
379
- this._editor.refresh();
380
- this._needsRefresh = false;
381
- }
382
- /**
383
- * Refresh the editor if it is focused;
384
- * otherwise postpone refreshing till focusing.
385
- */
386
- resizeToFit() {
387
- if (this.hasFocus()) {
388
- this.refresh();
389
- }
390
- else {
391
- this._needsRefresh = true;
392
- }
393
- this._clearHover();
394
- }
395
- // todo: docs, maybe define overlay options as a type?
396
- addOverlay(mode, options) {
397
- this._editor.addOverlay(mode, options);
398
- }
399
- removeOverlay(mode) {
400
- this._editor.removeOverlay(mode);
401
- }
402
- getSearchCursor(query, start, caseFold) {
403
- return this._editor.getDoc().getSearchCursor(query, start, caseFold);
404
- }
405
- getCursor(start) {
406
- return this._editor.getDoc().getCursor(start);
240
+ this._editor.contentDOM.blur();
407
241
  }
408
242
  get state() {
409
243
  return this._editor.state;
410
244
  }
411
- operation(fn) {
412
- return this._editor.operation(fn);
413
- }
414
245
  firstLine() {
415
- return this._editor.getDoc().firstLine();
246
+ // TODO: return 1 when CM6 first line number has propagated
247
+ return 0;
416
248
  }
417
249
  lastLine() {
418
- return this._editor.getDoc().lastLine();
419
- }
420
- scrollIntoView(pos, margin) {
421
- this._editor.scrollIntoView(pos, margin);
422
- }
423
- scrollIntoViewCentered(pos) {
424
- var _a, _b;
425
- const top = this._editor.charCoords(pos, 'local').top;
426
- const height = this._editor.getWrapperElement().offsetHeight;
427
- (_b = (_a = this.host).scrollIntoView) === null || _b === void 0 ? void 0 : _b.call(_a, {
428
- behavior: 'auto',
429
- block: 'center',
430
- inline: 'center'
431
- });
432
- this._editor.scrollTo(null, top - height / 2);
250
+ return this.doc.lines - 1;
433
251
  }
434
252
  cursorCoords(where, mode) {
435
- return this._editor.cursorCoords(where, mode);
253
+ const selection = this.state.selection.main;
254
+ const pos = where ? selection.from : selection.to;
255
+ const rect = this.editor.coordsAtPos(pos);
256
+ return rect;
436
257
  }
437
258
  getRange(from, to, separator) {
438
- return this._editor.getDoc().getRange(from, to, separator);
439
- }
440
- /**
441
- * Add a keydown handler to the editor.
442
- *
443
- * @param handler - A keydown handler.
444
- *
445
- * @returns A disposable that can be used to remove the handler.
446
- */
447
- addKeydownHandler(handler) {
448
- this._keydownHandlers.push(handler);
449
- return new DisposableDelegate(() => {
450
- ArrayExt.removeAllWhere(this._keydownHandlers, val => val === handler);
451
- });
452
- }
453
- /**
454
- * Set the size of the editor in pixels.
455
- */
456
- setSize(dimension) {
457
- if (dimension) {
458
- this._editor.setSize(dimension.width, dimension.height);
459
- }
460
- else {
461
- this._editor.setSize(null, null);
462
- }
463
- this._needsRefresh = false;
259
+ const fromOffset = this.getOffsetAt(this._toPosition(from));
260
+ const toOffset = this.getOffsetAt(this._toPosition(to));
261
+ return this.state.sliceDoc(fromOffset, toOffset);
464
262
  }
465
263
  /**
466
264
  * Reveal the given position in the editor.
467
265
  */
468
266
  revealPosition(position) {
469
- const cmPosition = this._toCodeMirrorPosition(position);
470
- this._editor.scrollIntoView(cmPosition);
267
+ const offset = this.getOffsetAt(position);
268
+ this._editor.dispatch({
269
+ effects: EditorView.scrollIntoView(offset)
270
+ });
471
271
  }
472
272
  /**
473
273
  * Reveal the given selection in the editor.
474
274
  */
475
275
  revealSelection(selection) {
476
- const range = {
477
- from: this._toCodeMirrorPosition(selection.start),
478
- to: this._toCodeMirrorPosition(selection.end)
479
- };
480
- this._editor.scrollIntoView(range);
276
+ const start = this.getOffsetAt(selection.start);
277
+ const end = this.getOffsetAt(selection.end);
278
+ this._editor.dispatch({
279
+ effects: EditorView.scrollIntoView(EditorSelection.range(start, end))
280
+ });
481
281
  }
482
282
  /**
483
283
  * Get the window coordinates given a cursor position.
484
284
  */
485
285
  getCoordinateForPosition(position) {
486
- const pos = this._toCodeMirrorPosition(position);
487
- const rect = this.editor.charCoords(pos, 'page');
286
+ const offset = this.getOffsetAt(position);
287
+ const rect = this.editor.coordsAtPos(offset);
488
288
  return rect;
489
289
  }
490
290
  /**
@@ -496,14 +296,18 @@ export class CodeMirrorEditor {
496
296
  * contained in the editor.
497
297
  */
498
298
  getPositionForCoordinate(coordinate) {
499
- return this._toPosition(this.editor.coordsChar(coordinate)) || null;
299
+ const offset = this.editor.posAtCoords({
300
+ x: coordinate.left,
301
+ y: coordinate.top
302
+ });
303
+ return this.getPositionAt(offset) || null;
500
304
  }
501
305
  /**
502
306
  * Returns the primary position of the cursor, never `null`.
503
307
  */
504
308
  getCursorPosition() {
505
- const cursor = this.doc.getCursor();
506
- return this._toPosition(cursor);
309
+ const offset = this.state.selection.main.head;
310
+ return this.getPositionAt(offset);
507
311
  }
508
312
  /**
509
313
  * Set the primary position of the cursor.
@@ -512,12 +316,15 @@ export class CodeMirrorEditor {
512
316
  * This will remove any secondary cursors.
513
317
  */
514
318
  setCursorPosition(position, options) {
515
- const cursor = this._toCodeMirrorPosition(position);
516
- this.doc.setCursor(cursor, undefined, options);
319
+ const offset = this.getOffsetAt(position);
320
+ this.editor.dispatch({
321
+ selection: { anchor: offset },
322
+ scrollIntoView: true
323
+ });
517
324
  // If the editor does not have focus, this cursor change
518
325
  // will get screened out in _onCursorsChanged(). Make an
519
326
  // exception for this method.
520
- if (!this.editor.hasFocus()) {
327
+ if (!this.editor.hasFocus) {
521
328
  this.model.selections.set(this.uuid, this.getSelections());
522
329
  }
523
330
  }
@@ -537,11 +344,15 @@ export class CodeMirrorEditor {
537
344
  * Gets the selections for all the cursors, never `null` or empty.
538
345
  */
539
346
  getSelections() {
540
- const selections = this.doc.listSelections();
347
+ const selections = this.state.selection.ranges; //= [{anchor: number, head: number}]
541
348
  if (selections.length > 0) {
542
- return selections.map(selection => this._toSelection(selection));
349
+ const sel = selections.map(r => ({
350
+ anchor: this._toCodeMirrorPosition(this.getPositionAt(r.from)),
351
+ head: this._toCodeMirrorPosition(this.getPositionAt(r.to))
352
+ }));
353
+ return sel.map(selection => this._toSelection(selection));
543
354
  }
544
- const cursor = this.doc.getCursor();
355
+ const cursor = this._toCodeMirrorPosition(this.getPositionAt(this.state.selection.main.head));
545
356
  const selection = this._toSelection({ anchor: cursor, head: cursor });
546
357
  return [selection];
547
358
  }
@@ -551,50 +362,98 @@ export class CodeMirrorEditor {
551
362
  * Passing an empty array resets a cursor position to the start of a document.
552
363
  */
553
364
  setSelections(selections) {
554
- const cmSelections = this._toCodeMirrorSelections(selections);
555
- this.doc.setSelections(cmSelections, 0);
365
+ const sel = selections.length
366
+ ? selections.map(r => EditorSelection.range(this.getOffsetAt(r.start), this.getOffsetAt(r.end)))
367
+ : [EditorSelection.range(0, 0)];
368
+ this.editor.dispatch({ selection: EditorSelection.create(sel) });
556
369
  }
557
370
  /**
558
371
  * Replaces the current selection with the given text.
559
372
  *
373
+ * Behaviour for multiple selections is undefined.
374
+ *
560
375
  * @param text The text to be inserted.
561
376
  */
562
377
  replaceSelection(text) {
563
- this.doc.replaceSelection(text);
378
+ const firstSelection = this.getSelections()[0];
379
+ this.model.sharedModel.updateSource(this.getOffsetAt(firstSelection.start), this.getOffsetAt(firstSelection.end), text);
380
+ const newPosition = this.getPositionAt(this.getOffsetAt(firstSelection.start) + text.length);
381
+ this.setSelection({ start: newPosition, end: newPosition });
564
382
  }
565
383
  /**
566
384
  * Get a list of tokens for the current editor text content.
567
385
  */
568
386
  getTokens() {
569
- let tokens = [];
570
- for (let i = 0; i < this.lineCount; ++i) {
571
- const lineTokens = this.editor.getLineTokens(i).map(t => ({
572
- offset: this.getOffsetAt({ column: t.start, line: i }),
573
- value: t.string,
574
- type: t.type || ''
575
- }));
576
- tokens = tokens.concat(lineTokens);
387
+ const tokens = [];
388
+ const tree = ensureSyntaxTree(this.state, this.doc.length);
389
+ if (tree) {
390
+ tree.iterate({
391
+ enter: (node) => {
392
+ // If it has a child, it is not a leaf, but we still want to enter
393
+ if (node.node.firstChild !== null) {
394
+ return true;
395
+ }
396
+ tokens.push({
397
+ value: this.state.sliceDoc(node.from, node.to),
398
+ offset: node.from,
399
+ type: node.name
400
+ });
401
+ return true;
402
+ }
403
+ });
577
404
  }
578
405
  return tokens;
579
406
  }
580
407
  /**
581
408
  * Get the token at a given editor position.
582
409
  */
583
- getTokenForPosition(position) {
584
- var _a;
585
- const cursor = this._toCodeMirrorPosition(position);
586
- const token = this.editor.getTokenAt(cursor);
587
- return {
588
- offset: this.getOffsetAt({ column: token.start, line: cursor.line }),
589
- value: token.string,
590
- type: (_a = token.type) !== null && _a !== void 0 ? _a : undefined
591
- };
410
+ getTokenAt(offset) {
411
+ const tree = ensureSyntaxTree(this.state, offset);
412
+ let token = null;
413
+ if (tree) {
414
+ tree.iterate({
415
+ enter: (node) => {
416
+ // If it has a child, it is not a leaf, but we still want to enter
417
+ if (node.node.firstChild !== null) {
418
+ return true;
419
+ }
420
+ if (offset >= node.from && offset <= node.to) {
421
+ token = {
422
+ value: this.state.sliceDoc(node.from, node.to),
423
+ offset: node.from,
424
+ type: node.name
425
+ };
426
+ // We have just found the relevant leaf token, no need to iterate further
427
+ return false;
428
+ }
429
+ return true;
430
+ }
431
+ });
432
+ }
433
+ if (token !== null) {
434
+ return token;
435
+ }
436
+ else {
437
+ return {
438
+ value: '',
439
+ offset: offset
440
+ };
441
+ }
442
+ }
443
+ /**
444
+ * Get the token a the cursor position.
445
+ */
446
+ getTokenAtCursor() {
447
+ return this.getTokenAt(this.state.selection.main.head);
592
448
  }
593
449
  /**
594
450
  * Insert a new indented line at the current cursor position.
595
451
  */
596
452
  newIndentedLine() {
597
- this.execCommand('newlineAndIndent');
453
+ insertNewlineAndIndent({
454
+ state: this.state,
455
+ dispatch: this.editor.dispatch
456
+ });
598
457
  }
599
458
  /**
600
459
  * Execute a codemirror command on the editor.
@@ -602,31 +461,31 @@ export class CodeMirrorEditor {
602
461
  * @param command - The name of the command to execute.
603
462
  */
604
463
  execCommand(command) {
605
- this._editor.execCommand(command);
464
+ command(this.editor);
465
+ }
466
+ onConfigChanged(configurator, changes) {
467
+ configurator.reconfigureExtensions(this._editor, changes);
606
468
  }
607
469
  /**
608
470
  * Handle keydown events from the editor.
609
471
  */
610
472
  onKeydown(event) {
611
- const position = this.getCursorPosition();
612
- const { line, column } = position;
613
- if (line === 0 && column === 0 && event.keyCode === UP_ARROW) {
473
+ const position = this.state.selection.main.head;
474
+ if (position === 0 && event.keyCode === UP_ARROW) {
614
475
  if (!event.shiftKey) {
615
476
  this.edgeRequested.emit('top');
616
477
  }
617
478
  return false;
618
479
  }
619
- if (line === 0 && event.keyCode === UP_ARROW) {
480
+ const line = this.doc.lineAt(position).number;
481
+ if (line === 1 && event.keyCode === UP_ARROW) {
620
482
  if (!event.shiftKey) {
621
483
  this.edgeRequested.emit('topLine');
622
484
  }
623
485
  return false;
624
486
  }
625
- const lastLine = this.lineCount - 1;
626
- const lastCh = this.getLine(lastLine).length;
627
- if (line === lastLine &&
628
- column === lastCh &&
629
- event.keyCode === DOWN_ARROW) {
487
+ const length = this.doc.length;
488
+ if (position === length && event.keyCode === DOWN_ARROW) {
630
489
  if (!event.shiftKey) {
631
490
  this.edgeRequested.emit('bottom');
632
491
  }
@@ -634,108 +493,25 @@ export class CodeMirrorEditor {
634
493
  }
635
494
  return false;
636
495
  }
637
- /**
638
- * Converts selections to code mirror selections.
639
- */
640
- _toCodeMirrorSelections(selections) {
641
- if (selections.length > 0) {
642
- return selections.map(selection => this._toCodeMirrorSelection(selection));
643
- }
644
- const position = { line: 0, ch: 0 };
645
- return [{ anchor: position, head: position }];
646
- }
647
496
  /**
648
497
  * Handles a mime type change.
649
498
  */
650
499
  _onMimeTypeChanged() {
651
- const mime = this._model.mimeType;
652
- const editor = this._editor;
653
- const extraKeys = (editor.getOption('extraKeys') ||
654
- {});
655
- const isCode = mime !== 'text/plain' && mime !== 'text/x-ipythongfm';
656
- if (isCode) {
657
- extraKeys['Backspace'] = 'delSpaceToPrevTabStop';
658
- }
659
- else {
660
- delete extraKeys['Backspace'];
661
- }
662
- this.setOption('extraKeys', extraKeys);
663
500
  // TODO: should we provide a hook for when the mode is done being set?
664
- void Mode.ensure(mime).then(spec => {
501
+ this._languages
502
+ .getLanguage(this._model.mimeType)
503
+ .then(language => {
665
504
  var _a;
666
- this.setOption('mode', (_a = spec === null || spec === void 0 ? void 0 : spec.mime) !== null && _a !== void 0 ? _a : 'null');
667
- });
668
- }
669
- /**
670
- * Handles a selections change.
671
- */
672
- _onSelectionsChanged(selections, args) {
673
- const uuid = args.key;
674
- if (uuid !== this.uuid) {
675
- this._cleanSelections(uuid);
676
- if (args.type !== 'remove' && args.newValue) {
677
- this._markSelections(uuid, args.newValue);
678
- }
679
- }
680
- }
681
- /**
682
- * Clean selections for the given uuid.
683
- */
684
- _cleanSelections(uuid) {
685
- const markers = this.selectionMarkers[uuid];
686
- if (markers) {
687
- markers.forEach(marker => {
688
- marker.clear();
505
+ this._editor.dispatch({
506
+ effects: this._language.reconfigure((_a = language === null || language === void 0 ? void 0 : language.support) !== null && _a !== void 0 ? _a : [])
507
+ });
508
+ })
509
+ .catch(reason => {
510
+ console.log(`Failed to load language for '${this._model.mimeType}'.`, reason);
511
+ this._editor.dispatch({
512
+ effects: this._language.reconfigure([])
689
513
  });
690
- }
691
- delete this.selectionMarkers[uuid];
692
- }
693
- /**
694
- * Marks selections.
695
- */
696
- _markSelections(uuid, selections) {
697
- const markers = [];
698
- // If we are marking selections corresponding to an active hover,
699
- // remove it.
700
- if (uuid === this._hoverId) {
701
- this._clearHover();
702
- }
703
- // If we can id the selection to a specific collaborator,
704
- // use that information.
705
- let collaborator;
706
- if (this._model.modelDB.collaborators) {
707
- collaborator = this._model.modelDB.collaborators.get(uuid);
708
- }
709
- // Style each selection for the uuid.
710
- selections.forEach(selection => {
711
- // Only render selections if the start is not equal to the end.
712
- // In that case, we don't need to render the cursor.
713
- if (!JSONExt.deepEqual(selection.start, selection.end)) {
714
- // Selections only appear to render correctly if the anchor
715
- // is before the head in the document. That is, reverse selections
716
- // do not appear as intended.
717
- const forward = selection.start.line < selection.end.line ||
718
- (selection.start.line === selection.end.line &&
719
- selection.start.column <= selection.end.column);
720
- const anchor = this._toCodeMirrorPosition(forward ? selection.start : selection.end);
721
- const head = this._toCodeMirrorPosition(forward ? selection.end : selection.start);
722
- let markerOptions;
723
- if (collaborator) {
724
- markerOptions = this._toTextMarkerOptions(Object.assign(Object.assign({}, selection.style), { color: collaborator.color }));
725
- }
726
- else {
727
- markerOptions = this._toTextMarkerOptions(selection.style);
728
- }
729
- markers.push(this.doc.markText(anchor, head, markerOptions));
730
- }
731
- else if (collaborator) {
732
- const caret = this._getCaret(collaborator);
733
- markers.push(this.doc.setBookmark(this._toCodeMirrorPosition(selection.end), {
734
- widget: caret
735
- }));
736
- }
737
514
  });
738
- this.selectionMarkers[uuid] = markers;
739
515
  }
740
516
  /**
741
517
  * Handles a cursor activity event.
@@ -743,7 +519,7 @@ export class CodeMirrorEditor {
743
519
  _onCursorActivity() {
744
520
  // Only add selections if the editor has focus. This avoids unwanted
745
521
  // triggering of cursor activity due to collaborator actions.
746
- if (this._editor.hasFocus()) {
522
+ if (this._editor.hasFocus) {
747
523
  const selections = this.getSelections();
748
524
  this.model.selections.set(this.uuid, selections);
749
525
  }
@@ -755,31 +531,7 @@ export class CodeMirrorEditor {
755
531
  return {
756
532
  uuid: this.uuid,
757
533
  start: this._toPosition(selection.anchor),
758
- end: this._toPosition(selection.head),
759
- style: this.selectionStyle
760
- };
761
- }
762
- /**
763
- * Converts the selection style to a text marker options.
764
- */
765
- _toTextMarkerOptions(style) {
766
- const r = parseInt(style.color.slice(1, 3), 16);
767
- const g = parseInt(style.color.slice(3, 5), 16);
768
- const b = parseInt(style.color.slice(5, 7), 16);
769
- const css = `background-color: rgba( ${r}, ${g}, ${b}, 0.15)`;
770
- return {
771
- className: style.className,
772
- title: style.displayName,
773
- css
774
- };
775
- }
776
- /**
777
- * Converts an editor selection to a code mirror selection.
778
- */
779
- _toCodeMirrorSelection(selection) {
780
- return {
781
- anchor: this._toCodeMirrorPosition(selection.start),
782
- head: this._toCodeMirrorPosition(selection.end)
534
+ end: this._toPosition(selection.head)
783
535
  };
784
536
  }
785
537
  /**
@@ -800,60 +552,13 @@ export class CodeMirrorEditor {
800
552
  ch: position.column
801
553
  };
802
554
  }
803
- /**
804
- * Handle model value changes.
805
- */
806
- _onValueChanged(value, args) {
807
- if (this._changeGuard) {
808
- return;
809
- }
810
- this._changeGuard = true;
811
- const doc = this.doc;
812
- switch (args.type) {
813
- case 'insert': {
814
- const pos = doc.posFromIndex(args.start);
815
- // Replace the range, including a '+input' origin,
816
- // which indicates that CodeMirror may merge changes
817
- // for undo/redo purposes.
818
- doc.replaceRange(args.value, pos, pos, '+input');
819
- break;
820
- }
821
- case 'remove': {
822
- const from = doc.posFromIndex(args.start);
823
- const to = doc.posFromIndex(args.end);
824
- // Replace the range, including a '+input' origin,
825
- // which indicates that CodeMirror may merge changes
826
- // for undo/redo purposes.
827
- doc.replaceRange('', from, to, '+input');
828
- break;
829
- }
830
- case 'set':
831
- doc.setValue(args.value);
832
- break;
833
- default:
834
- break;
835
- }
836
- this._changeGuard = false;
837
- }
838
555
  /**
839
556
  * Handles document changes.
840
557
  */
841
- _beforeDocChanged(doc, change) {
842
- if (this._changeGuard) {
843
- return;
844
- }
845
- this._changeGuard = true;
846
- const value = this._model.value;
847
- const start = doc.indexFromPos(change.from);
848
- const end = doc.indexFromPos(change.to);
849
- const inserted = change.text.join('\n');
850
- if (end !== start) {
851
- value.remove(start, end);
558
+ _onDocChanged(update) {
559
+ if (update.transactions.length && update.transactions[0].selection) {
560
+ this._onCursorActivity();
852
561
  }
853
- if (inserted) {
854
- value.insert(start, inserted);
855
- }
856
- this._changeGuard = false;
857
562
  }
858
563
  /**
859
564
  * Handle the DOM events for the editor.
@@ -873,9 +578,6 @@ export class CodeMirrorEditor {
873
578
  case 'blur':
874
579
  this._evtBlur(event);
875
580
  break;
876
- case 'scroll':
877
- this._evtScroll();
878
- break;
879
581
  default:
880
582
  break;
881
583
  }
@@ -884,9 +586,6 @@ export class CodeMirrorEditor {
884
586
  * Handle `focus` events for the editor.
885
587
  */
886
588
  _evtFocus(event) {
887
- if (this._needsRefresh) {
888
- this.refresh();
889
- }
890
589
  this.host.classList.add('jp-mod-focused');
891
590
  // Update the selections on editor gaining focus because
892
591
  // the onCursorActivity function filters usual cursor events
@@ -899,321 +598,24 @@ export class CodeMirrorEditor {
899
598
  _evtBlur(event) {
900
599
  this.host.classList.remove('jp-mod-focused');
901
600
  }
902
- /**
903
- * Handle `scroll` events for the editor.
904
- */
905
- _evtScroll() {
906
- // Remove any active hover.
907
- this._clearHover();
908
- }
909
- /**
910
- * Clear the hover for a caret, due to things like
911
- * scrolling, resizing, deactivation, etc, where
912
- * the position is no longer valid.
913
- */
914
- _clearHover() {
915
- if (this._caretHover) {
916
- window.clearTimeout(this._hoverTimeout);
917
- document.body.removeChild(this._caretHover);
918
- this._caretHover = null;
919
- }
920
- }
921
- /**
922
- * Construct a caret element representing the position
923
- * of a collaborator's cursor.
924
- */
925
- _getCaret(collaborator) {
926
- // FIXME-TRANS: Is this localizable?
927
- const name = collaborator ? collaborator.displayName : 'Anonymous';
928
- const color = collaborator
929
- ? collaborator.color
930
- : this._selectionStyle.color;
931
- const caret = document.createElement('span');
932
- caret.className = COLLABORATOR_CURSOR_CLASS;
933
- caret.style.borderBottomColor = color;
934
- caret.onmouseenter = () => {
935
- this._clearHover();
936
- this._hoverId = collaborator.sessionId;
937
- const rect = caret.getBoundingClientRect();
938
- // Construct and place the hover box.
939
- const hover = document.createElement('div');
940
- hover.className = COLLABORATOR_HOVER_CLASS;
941
- hover.style.left = String(rect.left) + 'px';
942
- hover.style.top = String(rect.bottom) + 'px';
943
- hover.textContent = name;
944
- hover.style.backgroundColor = color;
945
- // If the user mouses over the hover, take over the timer.
946
- hover.onmouseenter = () => {
947
- window.clearTimeout(this._hoverTimeout);
948
- };
949
- hover.onmouseleave = () => {
950
- this._hoverTimeout = window.setTimeout(() => {
951
- this._clearHover();
952
- }, HOVER_TIMEOUT);
953
- };
954
- this._caretHover = hover;
955
- document.body.appendChild(hover);
956
- };
957
- caret.onmouseleave = () => {
958
- this._hoverTimeout = window.setTimeout(() => {
959
- this._clearHover();
960
- }, HOVER_TIMEOUT);
961
- };
962
- return caret;
963
- }
964
- /**
965
- * Check for an out of sync editor.
966
- */
967
- _checkSync() {
968
- const change = this._lastChange;
969
- if (!change) {
970
- return;
971
- }
972
- this._lastChange = null;
973
- const editor = this._editor;
974
- const doc = editor.getDoc();
975
- if (doc.getValue() === this._model.value.text) {
976
- return;
977
- }
978
- void showDialog({
979
- title: this._trans.__('Code Editor out of Sync'),
980
- body: this._trans.__('Please open your browser JavaScript console for bug report instructions')
981
- });
982
- console.warn('If you are able and willing to publicly share the text or code in your editor, you can help us debug the "Code Editor out of Sync" message by pasting the following to the public issue at https://github.com/jupyterlab/jupyterlab/issues/2951. Please note that the data below includes the text/code in your editor.');
983
- console.warn(JSON.stringify({
984
- model: this._model.value.text,
985
- view: doc.getValue(),
986
- selections: this.getSelections(),
987
- cursor: this.getCursorPosition(),
988
- lineSep: editor.getOption('lineSeparator'),
989
- mode: editor.getOption('mode'),
990
- change
991
- }));
992
- }
993
601
  }
994
- /**
995
- * The namespace for `CodeMirrorEditor` statics.
996
- */
997
- (function (CodeMirrorEditor) {
998
- /**
999
- * The default configuration options for an editor.
1000
- */
1001
- CodeMirrorEditor.defaultConfig = Object.assign(Object.assign({}, CodeEditor.defaultConfig), { mode: 'null', theme: 'jupyter', smartIndent: true, electricChars: true, keyMap: 'default', extraKeys: null, gutters: [], fixedGutter: true, showCursorWhenSelecting: false, coverGutterNextToScrollbar: false, dragDrop: true, lineSeparator: null, scrollbarStyle: 'native', lineWiseCopyCut: true, scrollPastEnd: false, styleActiveLine: false, styleSelectedText: true, selectionPointer: false, rulers: [], foldGutter: false, handlePaste: true });
1002
- /**
1003
- * Add a command to CodeMirror.
1004
- *
1005
- * @param name - The name of the command to add.
1006
- *
1007
- * @param command - The command function.
1008
- */
1009
- function addCommand(name, command) {
1010
- CodeMirror.commands[name] = command;
1011
- }
1012
- CodeMirrorEditor.addCommand = addCommand;
1013
- })(CodeMirrorEditor || (CodeMirrorEditor = {}));
1014
602
  /**
1015
603
  * The namespace for module private data.
1016
604
  */
1017
605
  var Private;
1018
606
  (function (Private) {
1019
- function createEditor(host, config) {
1020
- const { autoClosingBrackets, fontFamily, fontSize, insertSpaces, lineHeight, lineWrap, wordWrapColumn, tabSize, readOnly } = config, otherOptions = __rest(config, ["autoClosingBrackets", "fontFamily", "fontSize", "insertSpaces", "lineHeight", "lineWrap", "wordWrapColumn", "tabSize", "readOnly"]);
1021
- const bareConfig = Object.assign({ autoCloseBrackets: autoClosingBrackets ? {} : false, indentUnit: tabSize, indentWithTabs: !insertSpaces, lineWrapping: lineWrap === 'off' ? false : true, readOnly }, otherOptions);
1022
- return CodeMirror(el => {
1023
- if (fontFamily) {
1024
- el.style.fontFamily = fontFamily;
1025
- }
1026
- if (fontSize) {
1027
- el.style.fontSize = fontSize + 'px';
1028
- }
1029
- if (lineHeight) {
1030
- el.style.lineHeight = lineHeight.toString();
1031
- }
1032
- if (readOnly) {
1033
- el.classList.add(READ_ONLY_CLASS);
1034
- }
1035
- if (lineWrap === 'wordWrapColumn') {
1036
- const lines = el.querySelector('.CodeMirror-lines');
1037
- lines.style.width = `${wordWrapColumn}ch`;
1038
- }
1039
- if (lineWrap === 'bounded') {
1040
- const lines = el.querySelector('.CodeMirror-lines');
1041
- lines.style.maxWidth = `${wordWrapColumn}ch`;
1042
- }
1043
- host.appendChild(el);
1044
- }, bareConfig);
607
+ function createEditor(host, editorConfig, additionalExtensions, doc) {
608
+ const extensions = editorConfig.getInitialExtensions();
609
+ extensions.push(...additionalExtensions);
610
+ const view = new EditorView({
611
+ state: EditorState.create({
612
+ doc,
613
+ extensions
614
+ }),
615
+ parent: host
616
+ });
617
+ return view;
1045
618
  }
1046
619
  Private.createEditor = createEditor;
1047
- /**
1048
- * Indent or insert a tab as appropriate.
1049
- */
1050
- function indentMoreOrinsertTab(cm) {
1051
- const doc = cm.getDoc();
1052
- const from = doc.getCursor('from');
1053
- const to = doc.getCursor('to');
1054
- const sel = !posEq(from, to);
1055
- if (sel) {
1056
- CodeMirror.commands['indentMore'](cm);
1057
- return;
1058
- }
1059
- // Check for start of line.
1060
- const line = doc.getLine(from.line);
1061
- const before = line.slice(0, from.ch);
1062
- if (/^\s*$/.test(before)) {
1063
- CodeMirror.commands['indentMore'](cm);
1064
- }
1065
- else {
1066
- if (cm.getOption('indentWithTabs')) {
1067
- CodeMirror.commands['insertTab'](cm);
1068
- }
1069
- else {
1070
- CodeMirror.commands['insertSoftTab'](cm);
1071
- }
1072
- }
1073
- }
1074
- Private.indentMoreOrinsertTab = indentMoreOrinsertTab;
1075
- /**
1076
- * Delete spaces to the previous tab stop in a codemirror editor.
1077
- */
1078
- function delSpaceToPrevTabStop(cm) {
1079
- var _a;
1080
- const doc = cm.getDoc();
1081
- // default tabsize is 2, according to codemirror docs: https://codemirror.net/doc/manual.html#config
1082
- const tabSize = (_a = cm.getOption('indentUnit')) !== null && _a !== void 0 ? _a : 2;
1083
- const ranges = doc.listSelections(); // handle multicursor
1084
- for (let i = ranges.length - 1; i >= 0; i--) {
1085
- // iterate reverse so any deletions don't overlap
1086
- const head = ranges[i].head;
1087
- const anchor = ranges[i].anchor;
1088
- const isSelection = !posEq(head, anchor);
1089
- if (isSelection) {
1090
- doc.replaceRange('', anchor, head);
1091
- }
1092
- else {
1093
- const line = doc.getLine(head.line).substring(0, head.ch);
1094
- if (line.match(/^\ +$/) !== null) {
1095
- // delete tabs
1096
- const prevTabStop = (Math.ceil(head.ch / tabSize) - 1) * tabSize;
1097
- const from = CodeMirror.Pos(head.line, prevTabStop);
1098
- doc.replaceRange('', from, head);
1099
- }
1100
- else {
1101
- // delete non-tabs
1102
- const from = cm.findPosH(head, -1, 'char', false);
1103
- doc.replaceRange('', from, head);
1104
- }
1105
- }
1106
- }
1107
- }
1108
- Private.delSpaceToPrevTabStop = delSpaceToPrevTabStop;
1109
- /**
1110
- * Test whether two CodeMirror positions are equal.
1111
- */
1112
- function posEq(a, b) {
1113
- return a.line === b.line && a.ch === b.ch;
1114
- }
1115
- Private.posEq = posEq;
1116
- /**
1117
- * Get the list of active gutters
1118
- *
1119
- * @param config Editor configuration
1120
- */
1121
- function getActiveGutters(config) {
1122
- // The order of the classes will be the gutters order
1123
- const classToSwitch = {
1124
- 'CodeMirror-linenumbers': 'lineNumbers',
1125
- 'CodeMirror-foldgutter': 'codeFolding'
1126
- };
1127
- return Object.keys(classToSwitch).filter(gutter => config[classToSwitch[gutter]]);
1128
- }
1129
- /**
1130
- * Set a config option for the editor.
1131
- */
1132
- function setOption(editor, option, value, config) {
1133
- const el = editor.getWrapperElement();
1134
- switch (option) {
1135
- case 'cursorBlinkRate':
1136
- editor.setOption(option, value);
1137
- break;
1138
- case 'lineWrap': {
1139
- const lineWrapping = value === 'off' ? false : true;
1140
- const lines = el.querySelector('.CodeMirror-lines');
1141
- const maxWidth = value === 'bounded' ? `${config.wordWrapColumn}ch` : null;
1142
- const width = value === 'wordWrapColumn' ? `${config.wordWrapColumn}ch` : null;
1143
- lines.style.setProperty('max-width', maxWidth);
1144
- lines.style.setProperty('width', width);
1145
- editor.setOption('lineWrapping', lineWrapping);
1146
- break;
1147
- }
1148
- case 'wordWrapColumn': {
1149
- const { lineWrap } = config;
1150
- if (lineWrap === 'wordWrapColumn' || lineWrap === 'bounded') {
1151
- const lines = el.querySelector('.CodeMirror-lines');
1152
- const prop = lineWrap === 'wordWrapColumn' ? 'width' : 'maxWidth';
1153
- lines.style[prop] = `${value}ch`;
1154
- }
1155
- break;
1156
- }
1157
- case 'tabSize':
1158
- editor.setOption('indentUnit', value);
1159
- break;
1160
- case 'insertSpaces':
1161
- editor.setOption('indentWithTabs', !value);
1162
- break;
1163
- case 'autoClosingBrackets':
1164
- editor.setOption('autoCloseBrackets', value);
1165
- break;
1166
- case 'rulers': {
1167
- const rulers = value;
1168
- editor.setOption('rulers', rulers.map(column => {
1169
- return {
1170
- column,
1171
- className: 'jp-CodeMirror-ruler'
1172
- };
1173
- }));
1174
- break;
1175
- }
1176
- case 'readOnly':
1177
- el.classList.toggle(READ_ONLY_CLASS, value);
1178
- editor.setOption(option, value);
1179
- break;
1180
- case 'fontFamily':
1181
- el.style.fontFamily = value;
1182
- break;
1183
- case 'fontSize':
1184
- el.style.setProperty('font-size', value ? value + 'px' : null);
1185
- break;
1186
- case 'lineHeight':
1187
- el.style.lineHeight = (value ? value.toString() : null);
1188
- break;
1189
- case 'gutters':
1190
- editor.setOption(option, getActiveGutters(config));
1191
- break;
1192
- case 'lineNumbers':
1193
- editor.setOption(option, value);
1194
- editor.setOption('gutters', getActiveGutters(config));
1195
- break;
1196
- case 'codeFolding':
1197
- editor.setOption('foldGutter', value);
1198
- editor.setOption('gutters', getActiveGutters(config));
1199
- break;
1200
- case 'showTrailingSpace':
1201
- editor.setOption(option, value);
1202
- break;
1203
- default:
1204
- editor.setOption(option, value);
1205
- break;
1206
- }
1207
- }
1208
- Private.setOption = setOption;
1209
620
  })(Private || (Private = {}));
1210
- /**
1211
- * Add a CodeMirror command to delete until previous non blanking space
1212
- * character or first multiple of tabsize tabstop.
1213
- */
1214
- CodeMirrorEditor.addCommand('delSpaceToPrevTabStop', Private.delSpaceToPrevTabStop);
1215
- /**
1216
- * Add a CodeMirror command to indent or insert a tab as appropriate.
1217
- */
1218
- CodeMirrorEditor.addCommand('indentMoreOrinsertTab', Private.indentMoreOrinsertTab);
1219
621
  //# sourceMappingURL=editor.js.map