@jupyterlab/codemirror 4.0.0-alpha.9 → 4.0.0-beta.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 (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 -273
  8. package/lib/editor.js +220 -819
  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 +1687 -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 +1726 -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 +33 -187
  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 -82
  70. package/lib/mode.js +0 -150
  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 -8
  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,37 +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 (const key in options) {
310
- const k = key;
311
- editor.operation(() => {
312
- this.setOption(k, options[k]);
313
- });
314
- }
315
- 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);
316
182
  }
317
183
  /**
318
184
  * Returns the content for the given line number.
319
185
  */
320
186
  getLine(line) {
321
- 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;
322
190
  }
323
191
  /**
324
192
  * Find an offset for the given position.
325
193
  */
326
194
  getOffsetAt(position) {
327
- return this.doc.indexFromPos({
328
- ch: position.column,
329
- line: position.line
330
- });
195
+ // TODO: CM6 remove +1 when CM6 first line number has propagated
196
+ return this.doc.line(position.line + 1).from + position.column;
331
197
  }
332
198
  /**
333
199
  * Find a position for the given offset.
334
200
  */
335
201
  getPositionAt(offset) {
336
- const { ch, line } = this.doc.posFromIndex(offset);
337
- 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 };
338
205
  }
339
206
  /**
340
207
  * Undo one edit (if any undo events are stored).
@@ -352,8 +219,7 @@ export class CodeMirrorEditor {
352
219
  * Clear the undo history.
353
220
  */
354
221
  clearHistory() {
355
- var _a, _b;
356
- (_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();
357
223
  }
358
224
  /**
359
225
  * Brings browser focus to this editor text.
@@ -365,127 +231,60 @@ export class CodeMirrorEditor {
365
231
  * Test whether the editor has keyboard focus.
366
232
  */
367
233
  hasFocus() {
368
- return this._editor.getWrapperElement().contains(document.activeElement);
234
+ return this._editor.hasFocus;
369
235
  }
370
236
  /**
371
237
  * Explicitly blur the editor.
372
238
  */
373
239
  blur() {
374
- this._editor.getInputField().blur();
375
- }
376
- /**
377
- * Repaint editor.
378
- */
379
- refresh() {
380
- this._editor.refresh();
381
- this._needsRefresh = false;
382
- }
383
- /**
384
- * Refresh the editor if it is focused;
385
- * otherwise postpone refreshing till focusing.
386
- */
387
- resizeToFit() {
388
- if (this.hasFocus()) {
389
- this.refresh();
390
- }
391
- else {
392
- this._needsRefresh = true;
393
- }
394
- this._clearHover();
395
- }
396
- // todo: docs, maybe define overlay options as a type?
397
- addOverlay(mode, options) {
398
- this._editor.addOverlay(mode, options);
399
- }
400
- removeOverlay(mode) {
401
- this._editor.removeOverlay(mode);
402
- }
403
- getSearchCursor(query, start, caseFold) {
404
- return this._editor.getDoc().getSearchCursor(query, start, caseFold);
405
- }
406
- getCursor(start) {
407
- return this._editor.getDoc().getCursor(start);
240
+ this._editor.contentDOM.blur();
408
241
  }
409
242
  get state() {
410
243
  return this._editor.state;
411
244
  }
412
- operation(fn) {
413
- return this._editor.operation(fn);
414
- }
415
245
  firstLine() {
416
- return this._editor.getDoc().firstLine();
246
+ // TODO: return 1 when CM6 first line number has propagated
247
+ return 0;
417
248
  }
418
249
  lastLine() {
419
- return this._editor.getDoc().lastLine();
420
- }
421
- scrollIntoView(pos, margin) {
422
- this._editor.scrollIntoView(pos, margin);
423
- }
424
- scrollIntoViewCentered(pos) {
425
- var _a, _b;
426
- const top = this._editor.charCoords(pos, 'local').top;
427
- const height = this._editor.getWrapperElement().offsetHeight;
428
- (_b = (_a = this.host).scrollIntoView) === null || _b === void 0 ? void 0 : _b.call(_a, {
429
- behavior: 'auto',
430
- block: 'center',
431
- inline: 'center'
432
- });
433
- this._editor.scrollTo(null, top - height / 2);
250
+ return this.doc.lines - 1;
434
251
  }
435
252
  cursorCoords(where, mode) {
436
- 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;
437
257
  }
438
258
  getRange(from, to, separator) {
439
- return this._editor.getDoc().getRange(from, to, separator);
440
- }
441
- /**
442
- * Add a keydown handler to the editor.
443
- *
444
- * @param handler - A keydown handler.
445
- *
446
- * @returns A disposable that can be used to remove the handler.
447
- */
448
- addKeydownHandler(handler) {
449
- this._keydownHandlers.push(handler);
450
- return new DisposableDelegate(() => {
451
- ArrayExt.removeAllWhere(this._keydownHandlers, val => val === handler);
452
- });
453
- }
454
- /**
455
- * Set the size of the editor in pixels.
456
- */
457
- setSize(dimension) {
458
- if (dimension) {
459
- this._editor.setSize(dimension.width, dimension.height);
460
- }
461
- else {
462
- this._editor.setSize(null, null);
463
- }
464
- 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);
465
262
  }
466
263
  /**
467
264
  * Reveal the given position in the editor.
468
265
  */
469
266
  revealPosition(position) {
470
- const cmPosition = this._toCodeMirrorPosition(position);
471
- this._editor.scrollIntoView(cmPosition);
267
+ const offset = this.getOffsetAt(position);
268
+ this._editor.dispatch({
269
+ effects: EditorView.scrollIntoView(offset)
270
+ });
472
271
  }
473
272
  /**
474
273
  * Reveal the given selection in the editor.
475
274
  */
476
275
  revealSelection(selection) {
477
- const range = {
478
- from: this._toCodeMirrorPosition(selection.start),
479
- to: this._toCodeMirrorPosition(selection.end)
480
- };
481
- 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
+ });
482
281
  }
483
282
  /**
484
283
  * Get the window coordinates given a cursor position.
485
284
  */
486
285
  getCoordinateForPosition(position) {
487
- const pos = this._toCodeMirrorPosition(position);
488
- const rect = this.editor.charCoords(pos, 'page');
286
+ const offset = this.getOffsetAt(position);
287
+ const rect = this.editor.coordsAtPos(offset);
489
288
  return rect;
490
289
  }
491
290
  /**
@@ -497,14 +296,18 @@ export class CodeMirrorEditor {
497
296
  * contained in the editor.
498
297
  */
499
298
  getPositionForCoordinate(coordinate) {
500
- 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;
501
304
  }
502
305
  /**
503
306
  * Returns the primary position of the cursor, never `null`.
504
307
  */
505
308
  getCursorPosition() {
506
- const cursor = this.doc.getCursor();
507
- return this._toPosition(cursor);
309
+ const offset = this.state.selection.main.head;
310
+ return this.getPositionAt(offset);
508
311
  }
509
312
  /**
510
313
  * Set the primary position of the cursor.
@@ -513,12 +316,15 @@ export class CodeMirrorEditor {
513
316
  * This will remove any secondary cursors.
514
317
  */
515
318
  setCursorPosition(position, options) {
516
- const cursor = this._toCodeMirrorPosition(position);
517
- this.doc.setCursor(cursor, undefined, options);
319
+ const offset = this.getOffsetAt(position);
320
+ this.editor.dispatch({
321
+ selection: { anchor: offset },
322
+ scrollIntoView: true
323
+ });
518
324
  // If the editor does not have focus, this cursor change
519
325
  // will get screened out in _onCursorsChanged(). Make an
520
326
  // exception for this method.
521
- if (!this.editor.hasFocus()) {
327
+ if (!this.editor.hasFocus) {
522
328
  this.model.selections.set(this.uuid, this.getSelections());
523
329
  }
524
330
  }
@@ -538,11 +344,15 @@ export class CodeMirrorEditor {
538
344
  * Gets the selections for all the cursors, never `null` or empty.
539
345
  */
540
346
  getSelections() {
541
- const selections = this.doc.listSelections();
347
+ const selections = this.state.selection.ranges; //= [{anchor: number, head: number}]
542
348
  if (selections.length > 0) {
543
- 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));
544
354
  }
545
- const cursor = this.doc.getCursor();
355
+ const cursor = this._toCodeMirrorPosition(this.getPositionAt(this.state.selection.main.head));
546
356
  const selection = this._toSelection({ anchor: cursor, head: cursor });
547
357
  return [selection];
548
358
  }
@@ -552,50 +362,98 @@ export class CodeMirrorEditor {
552
362
  * Passing an empty array resets a cursor position to the start of a document.
553
363
  */
554
364
  setSelections(selections) {
555
- const cmSelections = this._toCodeMirrorSelections(selections);
556
- 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) });
557
369
  }
558
370
  /**
559
371
  * Replaces the current selection with the given text.
560
372
  *
373
+ * Behaviour for multiple selections is undefined.
374
+ *
561
375
  * @param text The text to be inserted.
562
376
  */
563
377
  replaceSelection(text) {
564
- 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 });
565
382
  }
566
383
  /**
567
384
  * Get a list of tokens for the current editor text content.
568
385
  */
569
386
  getTokens() {
570
- let tokens = [];
571
- for (let i = 0; i < this.lineCount; ++i) {
572
- const lineTokens = this.editor.getLineTokens(i).map(t => ({
573
- offset: this.getOffsetAt({ column: t.start, line: i }),
574
- value: t.string,
575
- type: t.type || ''
576
- }));
577
- 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
+ });
578
404
  }
579
405
  return tokens;
580
406
  }
581
407
  /**
582
408
  * Get the token at a given editor position.
583
409
  */
584
- getTokenForPosition(position) {
585
- var _a;
586
- const cursor = this._toCodeMirrorPosition(position);
587
- const token = this.editor.getTokenAt(cursor);
588
- return {
589
- offset: this.getOffsetAt({ column: token.start, line: cursor.line }),
590
- value: token.string,
591
- type: (_a = token.type) !== null && _a !== void 0 ? _a : undefined
592
- };
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);
593
448
  }
594
449
  /**
595
450
  * Insert a new indented line at the current cursor position.
596
451
  */
597
452
  newIndentedLine() {
598
- this.execCommand('newlineAndIndent');
453
+ insertNewlineAndIndent({
454
+ state: this.state,
455
+ dispatch: this.editor.dispatch
456
+ });
599
457
  }
600
458
  /**
601
459
  * Execute a codemirror command on the editor.
@@ -603,31 +461,31 @@ export class CodeMirrorEditor {
603
461
  * @param command - The name of the command to execute.
604
462
  */
605
463
  execCommand(command) {
606
- this._editor.execCommand(command);
464
+ command(this.editor);
465
+ }
466
+ onConfigChanged(configurator, changes) {
467
+ configurator.reconfigureExtensions(this._editor, changes);
607
468
  }
608
469
  /**
609
470
  * Handle keydown events from the editor.
610
471
  */
611
472
  onKeydown(event) {
612
- const position = this.getCursorPosition();
613
- const { line, column } = position;
614
- 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) {
615
475
  if (!event.shiftKey) {
616
476
  this.edgeRequested.emit('top');
617
477
  }
618
478
  return false;
619
479
  }
620
- if (line === 0 && event.keyCode === UP_ARROW) {
480
+ const line = this.doc.lineAt(position).number;
481
+ if (line === 1 && event.keyCode === UP_ARROW) {
621
482
  if (!event.shiftKey) {
622
483
  this.edgeRequested.emit('topLine');
623
484
  }
624
485
  return false;
625
486
  }
626
- const lastLine = this.lineCount - 1;
627
- const lastCh = this.getLine(lastLine).length;
628
- if (line === lastLine &&
629
- column === lastCh &&
630
- event.keyCode === DOWN_ARROW) {
487
+ const length = this.doc.length;
488
+ if (position === length && event.keyCode === DOWN_ARROW) {
631
489
  if (!event.shiftKey) {
632
490
  this.edgeRequested.emit('bottom');
633
491
  }
@@ -635,108 +493,25 @@ export class CodeMirrorEditor {
635
493
  }
636
494
  return false;
637
495
  }
638
- /**
639
- * Converts selections to code mirror selections.
640
- */
641
- _toCodeMirrorSelections(selections) {
642
- if (selections.length > 0) {
643
- return selections.map(selection => this._toCodeMirrorSelection(selection));
644
- }
645
- const position = { line: 0, ch: 0 };
646
- return [{ anchor: position, head: position }];
647
- }
648
496
  /**
649
497
  * Handles a mime type change.
650
498
  */
651
499
  _onMimeTypeChanged() {
652
- const mime = this._model.mimeType;
653
- const editor = this._editor;
654
- const extraKeys = (editor.getOption('extraKeys') ||
655
- {});
656
- const isCode = mime !== 'text/plain' && mime !== 'text/x-ipythongfm';
657
- if (isCode) {
658
- extraKeys['Backspace'] = 'delSpaceToPrevTabStop';
659
- }
660
- else {
661
- delete extraKeys['Backspace'];
662
- }
663
- this.setOption('extraKeys', extraKeys);
664
500
  // TODO: should we provide a hook for when the mode is done being set?
665
- void Mode.ensure(mime).then(spec => {
501
+ this._languages
502
+ .getLanguage(this._model.mimeType)
503
+ .then(language => {
666
504
  var _a;
667
- this.setOption('mode', (_a = spec === null || spec === void 0 ? void 0 : spec.mime) !== null && _a !== void 0 ? _a : 'null');
668
- });
669
- }
670
- /**
671
- * Handles a selections change.
672
- */
673
- _onSelectionsChanged(selections, args) {
674
- const uuid = args.key;
675
- if (uuid !== this.uuid) {
676
- this._cleanSelections(uuid);
677
- if (args.type !== 'remove' && args.newValue) {
678
- this._markSelections(uuid, args.newValue);
679
- }
680
- }
681
- }
682
- /**
683
- * Clean selections for the given uuid.
684
- */
685
- _cleanSelections(uuid) {
686
- const markers = this.selectionMarkers[uuid];
687
- if (markers) {
688
- markers.forEach(marker => {
689
- 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([])
690
513
  });
691
- }
692
- delete this.selectionMarkers[uuid];
693
- }
694
- /**
695
- * Marks selections.
696
- */
697
- _markSelections(uuid, selections) {
698
- const markers = [];
699
- // If we are marking selections corresponding to an active hover,
700
- // remove it.
701
- if (uuid === this._hoverId) {
702
- this._clearHover();
703
- }
704
- // If we can id the selection to a specific collaborator,
705
- // use that information.
706
- let collaborator;
707
- if (this._model.modelDB.collaborators) {
708
- collaborator = this._model.modelDB.collaborators.get(uuid);
709
- }
710
- // Style each selection for the uuid.
711
- selections.forEach(selection => {
712
- // Only render selections if the start is not equal to the end.
713
- // In that case, we don't need to render the cursor.
714
- if (!JSONExt.deepEqual(selection.start, selection.end)) {
715
- // Selections only appear to render correctly if the anchor
716
- // is before the head in the document. That is, reverse selections
717
- // do not appear as intended.
718
- const forward = selection.start.line < selection.end.line ||
719
- (selection.start.line === selection.end.line &&
720
- selection.start.column <= selection.end.column);
721
- const anchor = this._toCodeMirrorPosition(forward ? selection.start : selection.end);
722
- const head = this._toCodeMirrorPosition(forward ? selection.end : selection.start);
723
- let markerOptions;
724
- if (collaborator) {
725
- markerOptions = this._toTextMarkerOptions(Object.assign(Object.assign({}, selection.style), { color: collaborator.color }));
726
- }
727
- else {
728
- markerOptions = this._toTextMarkerOptions(selection.style);
729
- }
730
- markers.push(this.doc.markText(anchor, head, markerOptions));
731
- }
732
- else if (collaborator) {
733
- const caret = this._getCaret(collaborator);
734
- markers.push(this.doc.setBookmark(this._toCodeMirrorPosition(selection.end), {
735
- widget: caret
736
- }));
737
- }
738
514
  });
739
- this.selectionMarkers[uuid] = markers;
740
515
  }
741
516
  /**
742
517
  * Handles a cursor activity event.
@@ -744,7 +519,7 @@ export class CodeMirrorEditor {
744
519
  _onCursorActivity() {
745
520
  // Only add selections if the editor has focus. This avoids unwanted
746
521
  // triggering of cursor activity due to collaborator actions.
747
- if (this._editor.hasFocus()) {
522
+ if (this._editor.hasFocus) {
748
523
  const selections = this.getSelections();
749
524
  this.model.selections.set(this.uuid, selections);
750
525
  }
@@ -756,31 +531,7 @@ export class CodeMirrorEditor {
756
531
  return {
757
532
  uuid: this.uuid,
758
533
  start: this._toPosition(selection.anchor),
759
- end: this._toPosition(selection.head),
760
- style: this.selectionStyle
761
- };
762
- }
763
- /**
764
- * Converts the selection style to a text marker options.
765
- */
766
- _toTextMarkerOptions(style) {
767
- const r = parseInt(style.color.slice(1, 3), 16);
768
- const g = parseInt(style.color.slice(3, 5), 16);
769
- const b = parseInt(style.color.slice(5, 7), 16);
770
- const css = `background-color: rgba( ${r}, ${g}, ${b}, 0.15)`;
771
- return {
772
- className: style.className,
773
- title: style.displayName,
774
- css
775
- };
776
- }
777
- /**
778
- * Converts an editor selection to a code mirror selection.
779
- */
780
- _toCodeMirrorSelection(selection) {
781
- return {
782
- anchor: this._toCodeMirrorPosition(selection.start),
783
- head: this._toCodeMirrorPosition(selection.end)
534
+ end: this._toPosition(selection.head)
784
535
  };
785
536
  }
786
537
  /**
@@ -801,60 +552,13 @@ export class CodeMirrorEditor {
801
552
  ch: position.column
802
553
  };
803
554
  }
804
- /**
805
- * Handle model value changes.
806
- */
807
- _onValueChanged(value, args) {
808
- if (this._changeGuard) {
809
- return;
810
- }
811
- this._changeGuard = true;
812
- const doc = this.doc;
813
- switch (args.type) {
814
- case 'insert': {
815
- const pos = doc.posFromIndex(args.start);
816
- // Replace the range, including a '+input' origin,
817
- // which indicates that CodeMirror may merge changes
818
- // for undo/redo purposes.
819
- doc.replaceRange(args.value, pos, pos, '+input');
820
- break;
821
- }
822
- case 'remove': {
823
- const from = doc.posFromIndex(args.start);
824
- const to = doc.posFromIndex(args.end);
825
- // Replace the range, including a '+input' origin,
826
- // which indicates that CodeMirror may merge changes
827
- // for undo/redo purposes.
828
- doc.replaceRange('', from, to, '+input');
829
- break;
830
- }
831
- case 'set':
832
- doc.setValue(args.value);
833
- break;
834
- default:
835
- break;
836
- }
837
- this._changeGuard = false;
838
- }
839
555
  /**
840
556
  * Handles document changes.
841
557
  */
842
- _beforeDocChanged(doc, change) {
843
- if (this._changeGuard) {
844
- return;
845
- }
846
- this._changeGuard = true;
847
- const value = this._model.value;
848
- const start = doc.indexFromPos(change.from);
849
- const end = doc.indexFromPos(change.to);
850
- const inserted = change.text.join('\n');
851
- if (end !== start) {
852
- value.remove(start, end);
558
+ _onDocChanged(update) {
559
+ if (update.transactions.length && update.transactions[0].selection) {
560
+ this._onCursorActivity();
853
561
  }
854
- if (inserted) {
855
- value.insert(start, inserted);
856
- }
857
- this._changeGuard = false;
858
562
  }
859
563
  /**
860
564
  * Handle the DOM events for the editor.
@@ -874,9 +578,6 @@ export class CodeMirrorEditor {
874
578
  case 'blur':
875
579
  this._evtBlur(event);
876
580
  break;
877
- case 'scroll':
878
- this._evtScroll();
879
- break;
880
581
  default:
881
582
  break;
882
583
  }
@@ -885,9 +586,6 @@ export class CodeMirrorEditor {
885
586
  * Handle `focus` events for the editor.
886
587
  */
887
588
  _evtFocus(event) {
888
- if (this._needsRefresh) {
889
- this.refresh();
890
- }
891
589
  this.host.classList.add('jp-mod-focused');
892
590
  // Update the selections on editor gaining focus because
893
591
  // the onCursorActivity function filters usual cursor events
@@ -900,321 +598,24 @@ export class CodeMirrorEditor {
900
598
  _evtBlur(event) {
901
599
  this.host.classList.remove('jp-mod-focused');
902
600
  }
903
- /**
904
- * Handle `scroll` events for the editor.
905
- */
906
- _evtScroll() {
907
- // Remove any active hover.
908
- this._clearHover();
909
- }
910
- /**
911
- * Clear the hover for a caret, due to things like
912
- * scrolling, resizing, deactivation, etc, where
913
- * the position is no longer valid.
914
- */
915
- _clearHover() {
916
- if (this._caretHover) {
917
- window.clearTimeout(this._hoverTimeout);
918
- document.body.removeChild(this._caretHover);
919
- this._caretHover = null;
920
- }
921
- }
922
- /**
923
- * Construct a caret element representing the position
924
- * of a collaborator's cursor.
925
- */
926
- _getCaret(collaborator) {
927
- // FIXME-TRANS: Is this localizable?
928
- const name = collaborator ? collaborator.displayName : 'Anonymous';
929
- const color = collaborator
930
- ? collaborator.color
931
- : this._selectionStyle.color;
932
- const caret = document.createElement('span');
933
- caret.className = COLLABORATOR_CURSOR_CLASS;
934
- caret.style.borderBottomColor = color;
935
- caret.onmouseenter = () => {
936
- this._clearHover();
937
- this._hoverId = collaborator.sessionId;
938
- const rect = caret.getBoundingClientRect();
939
- // Construct and place the hover box.
940
- const hover = document.createElement('div');
941
- hover.className = COLLABORATOR_HOVER_CLASS;
942
- hover.style.left = String(rect.left) + 'px';
943
- hover.style.top = String(rect.bottom) + 'px';
944
- hover.textContent = name;
945
- hover.style.backgroundColor = color;
946
- // If the user mouses over the hover, take over the timer.
947
- hover.onmouseenter = () => {
948
- window.clearTimeout(this._hoverTimeout);
949
- };
950
- hover.onmouseleave = () => {
951
- this._hoverTimeout = window.setTimeout(() => {
952
- this._clearHover();
953
- }, HOVER_TIMEOUT);
954
- };
955
- this._caretHover = hover;
956
- document.body.appendChild(hover);
957
- };
958
- caret.onmouseleave = () => {
959
- this._hoverTimeout = window.setTimeout(() => {
960
- this._clearHover();
961
- }, HOVER_TIMEOUT);
962
- };
963
- return caret;
964
- }
965
- /**
966
- * Check for an out of sync editor.
967
- */
968
- _checkSync() {
969
- const change = this._lastChange;
970
- if (!change) {
971
- return;
972
- }
973
- this._lastChange = null;
974
- const editor = this._editor;
975
- const doc = editor.getDoc();
976
- if (doc.getValue() === this._model.value.text) {
977
- return;
978
- }
979
- void showDialog({
980
- title: this._trans.__('Code Editor out of Sync'),
981
- body: this._trans.__('Please open your browser JavaScript console for bug report instructions')
982
- });
983
- 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.');
984
- console.warn(JSON.stringify({
985
- model: this._model.value.text,
986
- view: doc.getValue(),
987
- selections: this.getSelections(),
988
- cursor: this.getCursorPosition(),
989
- lineSep: editor.getOption('lineSeparator'),
990
- mode: editor.getOption('mode'),
991
- change
992
- }));
993
- }
994
601
  }
995
- /**
996
- * The namespace for `CodeMirrorEditor` statics.
997
- */
998
- (function (CodeMirrorEditor) {
999
- /**
1000
- * The default configuration options for an editor.
1001
- */
1002
- 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 });
1003
- /**
1004
- * Add a command to CodeMirror.
1005
- *
1006
- * @param name - The name of the command to add.
1007
- *
1008
- * @param command - The command function.
1009
- */
1010
- function addCommand(name, command) {
1011
- CodeMirror.commands[name] = command;
1012
- }
1013
- CodeMirrorEditor.addCommand = addCommand;
1014
- })(CodeMirrorEditor || (CodeMirrorEditor = {}));
1015
602
  /**
1016
603
  * The namespace for module private data.
1017
604
  */
1018
605
  var Private;
1019
606
  (function (Private) {
1020
- function createEditor(host, config) {
1021
- const { autoClosingBrackets, fontFamily, fontSize, insertSpaces, lineHeight, lineWrap, wordWrapColumn, tabSize, readOnly } = config, otherOptions = __rest(config, ["autoClosingBrackets", "fontFamily", "fontSize", "insertSpaces", "lineHeight", "lineWrap", "wordWrapColumn", "tabSize", "readOnly"]);
1022
- const bareConfig = Object.assign({ autoCloseBrackets: autoClosingBrackets ? {} : false, indentUnit: tabSize, indentWithTabs: !insertSpaces, lineWrapping: lineWrap === 'off' ? false : true, readOnly }, otherOptions);
1023
- return CodeMirror(el => {
1024
- if (fontFamily) {
1025
- el.style.fontFamily = fontFamily;
1026
- }
1027
- if (fontSize) {
1028
- el.style.fontSize = fontSize + 'px';
1029
- }
1030
- if (lineHeight) {
1031
- el.style.lineHeight = lineHeight.toString();
1032
- }
1033
- if (readOnly) {
1034
- el.classList.add(READ_ONLY_CLASS);
1035
- }
1036
- if (lineWrap === 'wordWrapColumn') {
1037
- const lines = el.querySelector('.CodeMirror-lines');
1038
- lines.style.width = `${wordWrapColumn}ch`;
1039
- }
1040
- if (lineWrap === 'bounded') {
1041
- const lines = el.querySelector('.CodeMirror-lines');
1042
- lines.style.maxWidth = `${wordWrapColumn}ch`;
1043
- }
1044
- host.appendChild(el);
1045
- }, 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;
1046
618
  }
1047
619
  Private.createEditor = createEditor;
1048
- /**
1049
- * Indent or insert a tab as appropriate.
1050
- */
1051
- function indentMoreOrinsertTab(cm) {
1052
- const doc = cm.getDoc();
1053
- const from = doc.getCursor('from');
1054
- const to = doc.getCursor('to');
1055
- const sel = !posEq(from, to);
1056
- if (sel) {
1057
- CodeMirror.commands['indentMore'](cm);
1058
- return;
1059
- }
1060
- // Check for start of line.
1061
- const line = doc.getLine(from.line);
1062
- const before = line.slice(0, from.ch);
1063
- if (/^\s*$/.test(before)) {
1064
- CodeMirror.commands['indentMore'](cm);
1065
- }
1066
- else {
1067
- if (cm.getOption('indentWithTabs')) {
1068
- CodeMirror.commands['insertTab'](cm);
1069
- }
1070
- else {
1071
- CodeMirror.commands['insertSoftTab'](cm);
1072
- }
1073
- }
1074
- }
1075
- Private.indentMoreOrinsertTab = indentMoreOrinsertTab;
1076
- /**
1077
- * Delete spaces to the previous tab stop in a codemirror editor.
1078
- */
1079
- function delSpaceToPrevTabStop(cm) {
1080
- var _a;
1081
- const doc = cm.getDoc();
1082
- // default tabsize is 2, according to codemirror docs: https://codemirror.net/doc/manual.html#config
1083
- const tabSize = (_a = cm.getOption('indentUnit')) !== null && _a !== void 0 ? _a : 2;
1084
- const ranges = doc.listSelections(); // handle multicursor
1085
- for (let i = ranges.length - 1; i >= 0; i--) {
1086
- // iterate reverse so any deletions don't overlap
1087
- const head = ranges[i].head;
1088
- const anchor = ranges[i].anchor;
1089
- const isSelection = !posEq(head, anchor);
1090
- if (isSelection) {
1091
- doc.replaceRange('', anchor, head);
1092
- }
1093
- else {
1094
- const line = doc.getLine(head.line).substring(0, head.ch);
1095
- if (line.match(/^\ +$/) !== null) {
1096
- // delete tabs
1097
- const prevTabStop = (Math.ceil(head.ch / tabSize) - 1) * tabSize;
1098
- const from = CodeMirror.Pos(head.line, prevTabStop);
1099
- doc.replaceRange('', from, head);
1100
- }
1101
- else {
1102
- // delete non-tabs
1103
- const from = cm.findPosH(head, -1, 'char', false);
1104
- doc.replaceRange('', from, head);
1105
- }
1106
- }
1107
- }
1108
- }
1109
- Private.delSpaceToPrevTabStop = delSpaceToPrevTabStop;
1110
- /**
1111
- * Test whether two CodeMirror positions are equal.
1112
- */
1113
- function posEq(a, b) {
1114
- return a.line === b.line && a.ch === b.ch;
1115
- }
1116
- Private.posEq = posEq;
1117
- /**
1118
- * Get the list of active gutters
1119
- *
1120
- * @param config Editor configuration
1121
- */
1122
- function getActiveGutters(config) {
1123
- // The order of the classes will be the gutters order
1124
- const classToSwitch = {
1125
- 'CodeMirror-linenumbers': 'lineNumbers',
1126
- 'CodeMirror-foldgutter': 'codeFolding'
1127
- };
1128
- return Object.keys(classToSwitch).filter(gutter => config[classToSwitch[gutter]]);
1129
- }
1130
- /**
1131
- * Set a config option for the editor.
1132
- */
1133
- function setOption(editor, option, value, config) {
1134
- const el = editor.getWrapperElement();
1135
- switch (option) {
1136
- case 'cursorBlinkRate':
1137
- editor.setOption(option, value);
1138
- break;
1139
- case 'lineWrap': {
1140
- const lineWrapping = value === 'off' ? false : true;
1141
- const lines = el.querySelector('.CodeMirror-lines');
1142
- const maxWidth = value === 'bounded' ? `${config.wordWrapColumn}ch` : null;
1143
- const width = value === 'wordWrapColumn' ? `${config.wordWrapColumn}ch` : null;
1144
- lines.style.setProperty('max-width', maxWidth);
1145
- lines.style.setProperty('width', width);
1146
- editor.setOption('lineWrapping', lineWrapping);
1147
- break;
1148
- }
1149
- case 'wordWrapColumn': {
1150
- const { lineWrap } = config;
1151
- if (lineWrap === 'wordWrapColumn' || lineWrap === 'bounded') {
1152
- const lines = el.querySelector('.CodeMirror-lines');
1153
- const prop = lineWrap === 'wordWrapColumn' ? 'width' : 'maxWidth';
1154
- lines.style[prop] = `${value}ch`;
1155
- }
1156
- break;
1157
- }
1158
- case 'tabSize':
1159
- editor.setOption('indentUnit', value);
1160
- break;
1161
- case 'insertSpaces':
1162
- editor.setOption('indentWithTabs', !value);
1163
- break;
1164
- case 'autoClosingBrackets':
1165
- editor.setOption('autoCloseBrackets', value);
1166
- break;
1167
- case 'rulers': {
1168
- const rulers = value;
1169
- editor.setOption('rulers', rulers.map(column => {
1170
- return {
1171
- column,
1172
- className: 'jp-CodeMirror-ruler'
1173
- };
1174
- }));
1175
- break;
1176
- }
1177
- case 'readOnly':
1178
- el.classList.toggle(READ_ONLY_CLASS, value);
1179
- editor.setOption(option, value);
1180
- break;
1181
- case 'fontFamily':
1182
- el.style.fontFamily = value;
1183
- break;
1184
- case 'fontSize':
1185
- el.style.setProperty('font-size', value ? value + 'px' : null);
1186
- break;
1187
- case 'lineHeight':
1188
- el.style.lineHeight = (value ? value.toString() : null);
1189
- break;
1190
- case 'gutters':
1191
- editor.setOption(option, getActiveGutters(config));
1192
- break;
1193
- case 'lineNumbers':
1194
- editor.setOption(option, value);
1195
- editor.setOption('gutters', getActiveGutters(config));
1196
- break;
1197
- case 'codeFolding':
1198
- editor.setOption('foldGutter', value);
1199
- editor.setOption('gutters', getActiveGutters(config));
1200
- break;
1201
- case 'showTrailingSpace':
1202
- editor.setOption(option, value);
1203
- break;
1204
- default:
1205
- editor.setOption(option, value);
1206
- break;
1207
- }
1208
- }
1209
- Private.setOption = setOption;
1210
620
  })(Private || (Private = {}));
1211
- /**
1212
- * Add a CodeMirror command to delete until previous non blanking space
1213
- * character or first multiple of tabsize tabstop.
1214
- */
1215
- CodeMirrorEditor.addCommand('delSpaceToPrevTabStop', Private.delSpaceToPrevTabStop);
1216
- /**
1217
- * Add a CodeMirror command to indent or insert a tab as appropriate.
1218
- */
1219
- CodeMirrorEditor.addCommand('indentMoreOrinsertTab', Private.indentMoreOrinsertTab);
1220
621
  //# sourceMappingURL=editor.js.map