@codemirror/view 6.5.1 → 6.7.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.
package/dist/index.cjs CHANGED
@@ -1603,6 +1603,7 @@ class ContentBuilder {
1603
1603
  this.curLine = null;
1604
1604
  this.breakAtStart = 0;
1605
1605
  this.pendingBuffer = 0 /* Buf.No */;
1606
+ this.bufferMarks = [];
1606
1607
  // Set to false directly after a widget that covers the position after it
1607
1608
  this.atCursorPos = true;
1608
1609
  this.openStart = -1;
@@ -1625,20 +1626,20 @@ class ContentBuilder {
1625
1626
  }
1626
1627
  return this.curLine;
1627
1628
  }
1628
- flushBuffer(active) {
1629
+ flushBuffer(active = this.bufferMarks) {
1629
1630
  if (this.pendingBuffer) {
1630
1631
  this.curLine.append(wrapMarks(new WidgetBufferView(-1), active), active.length);
1631
1632
  this.pendingBuffer = 0 /* Buf.No */;
1632
1633
  }
1633
1634
  }
1634
1635
  addBlockWidget(view) {
1635
- this.flushBuffer([]);
1636
+ this.flushBuffer();
1636
1637
  this.curLine = null;
1637
1638
  this.content.push(view);
1638
1639
  }
1639
1640
  finish(openEnd) {
1640
- if (!openEnd)
1641
- this.flushBuffer([]);
1641
+ if (this.pendingBuffer && openEnd <= this.bufferMarks.length)
1642
+ this.flushBuffer();
1642
1643
  else
1643
1644
  this.pendingBuffer = 0 /* Buf.No */;
1644
1645
  if (!this.posCovered())
@@ -1658,8 +1659,9 @@ class ContentBuilder {
1658
1659
  this.content[this.content.length - 1].breakAfter = 1;
1659
1660
  else
1660
1661
  this.breakAtStart = 1;
1661
- this.flushBuffer([]);
1662
+ this.flushBuffer();
1662
1663
  this.curLine = null;
1664
+ this.atCursorPos = true;
1663
1665
  length--;
1664
1666
  continue;
1665
1667
  }
@@ -1701,7 +1703,7 @@ class ContentBuilder {
1701
1703
  else {
1702
1704
  let view = WidgetView.create(deco.widget || new NullWidget("span"), len, len ? 0 : deco.startSide);
1703
1705
  let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0);
1704
- let cursorAfter = !view.isEditable && (from < to || deco.startSide <= 0);
1706
+ let cursorAfter = !view.isEditable && (from < to || openStart > active.length || deco.startSide <= 0);
1705
1707
  let line = this.getLine();
1706
1708
  if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore)
1707
1709
  this.pendingBuffer = 0 /* Buf.No */;
@@ -1712,7 +1714,9 @@ class ContentBuilder {
1712
1714
  }
1713
1715
  line.append(wrapMarks(view, active), openStart);
1714
1716
  this.atCursorPos = cursorAfter;
1715
- this.pendingBuffer = !cursorAfter ? 0 /* Buf.No */ : from < to ? 1 /* Buf.Yes */ : 2 /* Buf.IfCursor */;
1717
+ this.pendingBuffer = !cursorAfter ? 0 /* Buf.No */ : from < to || openStart > active.length ? 1 /* Buf.Yes */ : 2 /* Buf.IfCursor */;
1718
+ if (this.pendingBuffer)
1719
+ this.bufferMarks = active.slice();
1716
1720
  }
1717
1721
  }
1718
1722
  else if (this.doc.lineAt(this.pos).from == this.pos) { // Line decoration
@@ -5291,7 +5295,6 @@ const baseTheme$1 = buildTheme("." + baseThemeID, {
5291
5295
  margin: 0,
5292
5296
  flexGrow: 2,
5293
5297
  flexShrink: 0,
5294
- minHeight: "100%",
5295
5298
  display: "block",
5296
5299
  whiteSpace: "pre",
5297
5300
  wordWrap: "normal",
@@ -5313,14 +5316,13 @@ const baseTheme$1 = buildTheme("." + baseThemeID, {
5313
5316
  "&dark .cm-content": { caretColor: "white" },
5314
5317
  ".cm-line": {
5315
5318
  display: "block",
5316
- padding: "0 2px 0 4px"
5317
- },
5318
- ".cm-selectionLayer": {
5319
- zIndex: -1,
5320
- contain: "size style"
5319
+ padding: "0 2px 0 6px"
5321
5320
  },
5322
- ".cm-selectionBackground": {
5323
- position: "absolute",
5321
+ ".cm-layer": {
5322
+ contain: "size style",
5323
+ "& > *": {
5324
+ position: "absolute"
5325
+ }
5324
5326
  },
5325
5327
  "&light .cm-selectionBackground": {
5326
5328
  background: "#d9d9d9"
@@ -5335,8 +5337,6 @@ const baseTheme$1 = buildTheme("." + baseThemeID, {
5335
5337
  background: "#233"
5336
5338
  },
5337
5339
  ".cm-cursorLayer": {
5338
- zIndex: 100,
5339
- contain: "size style",
5340
5340
  pointerEvents: "none"
5341
5341
  },
5342
5342
  "&.cm-focused .cm-cursorLayer": {
@@ -5348,7 +5348,6 @@ const baseTheme$1 = buildTheme("." + baseThemeID, {
5348
5348
  "@keyframes cm-blink": { "0%": {}, "50%": { opacity: 0 }, "100%": {} },
5349
5349
  "@keyframes cm-blink2": { "0%": {}, "50%": { opacity: 0 }, "100%": {} },
5350
5350
  ".cm-cursor, .cm-dropCursor": {
5351
- position: "absolute",
5352
5351
  borderLeft: "1.2px solid black",
5353
5352
  marginLeft: "-0.6px",
5354
5353
  pointerEvents: "none",
@@ -5442,6 +5441,21 @@ const baseTheme$1 = buildTheme("." + baseThemeID, {
5442
5441
  display: "inline-block",
5443
5442
  verticalAlign: "top",
5444
5443
  },
5444
+ ".cm-highlightSpace:before": {
5445
+ content: "attr(data-display)",
5446
+ position: "absolute",
5447
+ pointerEvents: "none",
5448
+ color: "#888"
5449
+ },
5450
+ ".cm-highlightTab": {
5451
+ backgroundImage: `url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="20"><path stroke="%23888" stroke-width="1" fill="none" d="M1 10H196L190 5M190 15L196 10M197 4L197 16"/></svg>')`,
5452
+ backgroundSize: "auto 100%",
5453
+ backgroundPosition: "right 90%",
5454
+ backgroundRepeat: "no-repeat"
5455
+ },
5456
+ ".cm-trailingSpace": {
5457
+ backgroundColor: "#ff332255"
5458
+ },
5445
5459
  ".cm-button": {
5446
5460
  verticalAlign: "middle",
5447
5461
  color: "inherit",
@@ -5744,7 +5758,8 @@ class DOMObserver {
5744
5758
  this.lastChange = 0;
5745
5759
  this.scrollTargets = [];
5746
5760
  this.intersection = null;
5747
- this.resize = null;
5761
+ this.resizeScroll = null;
5762
+ this.resizeContent = null;
5748
5763
  this.intersecting = false;
5749
5764
  this.gapIntersection = null;
5750
5765
  this.gaps = [];
@@ -5782,12 +5797,14 @@ class DOMObserver {
5782
5797
  this.onPrint = this.onPrint.bind(this);
5783
5798
  this.onScroll = this.onScroll.bind(this);
5784
5799
  if (typeof ResizeObserver == "function") {
5785
- this.resize = new ResizeObserver(() => {
5800
+ this.resizeScroll = new ResizeObserver(() => {
5786
5801
  var _a;
5787
5802
  if (((_a = this.view.docView) === null || _a === void 0 ? void 0 : _a.lastUpdate) < Date.now() - 75)
5788
5803
  this.onResize();
5789
5804
  });
5790
- this.resize.observe(view.scrollDOM);
5805
+ this.resizeScroll.observe(view.scrollDOM);
5806
+ this.resizeContent = new ResizeObserver(() => this.view.requestMeasure());
5807
+ this.resizeContent.observe(view.contentDOM);
5791
5808
  }
5792
5809
  this.addWindowListeners(this.win = view.win);
5793
5810
  this.start();
@@ -6106,11 +6123,12 @@ class DOMObserver {
6106
6123
  win.document.removeEventListener("selectionchange", this.onSelectionChange);
6107
6124
  }
6108
6125
  destroy() {
6109
- var _a, _b, _c;
6126
+ var _a, _b, _c, _d;
6110
6127
  this.stop();
6111
6128
  (_a = this.intersection) === null || _a === void 0 ? void 0 : _a.disconnect();
6112
6129
  (_b = this.gapIntersection) === null || _b === void 0 ? void 0 : _b.disconnect();
6113
- (_c = this.resize) === null || _c === void 0 ? void 0 : _c.disconnect();
6130
+ (_c = this.resizeScroll) === null || _c === void 0 ? void 0 : _c.disconnect();
6131
+ (_d = this.resizeContent) === null || _d === void 0 ? void 0 : _d.disconnect();
6114
6132
  for (let dom of this.scrollTargets)
6115
6133
  dom.removeEventListener("scroll", this.onScroll);
6116
6134
  this.removeWindowListeners(this.win);
@@ -6209,7 +6227,7 @@ class EditorView {
6209
6227
  this.scrollDOM.className = "cm-scroller";
6210
6228
  this.scrollDOM.appendChild(this.contentDOM);
6211
6229
  this.announceDOM = document.createElement("div");
6212
- this.announceDOM.style.cssText = "position: absolute; top: -10000px";
6230
+ this.announceDOM.style.cssText = "position: fixed; top: -10000px";
6213
6231
  this.announceDOM.setAttribute("aria-live", "polite");
6214
6232
  this.dom = document.createElement("div");
6215
6233
  this.dom.appendChild(this.announceDOM);
@@ -7294,51 +7312,21 @@ function runHandlers(map, event, view, scope) {
7294
7312
  return fallthrough;
7295
7313
  }
7296
7314
 
7297
- const CanHidePrimary = !browser.ios; // FIXME test IE
7298
- const selectionConfig = state.Facet.define({
7299
- combine(configs) {
7300
- return state.combineConfig(configs, {
7301
- cursorBlinkRate: 1200,
7302
- drawRangeCursor: true
7303
- }, {
7304
- cursorBlinkRate: (a, b) => Math.min(a, b),
7305
- drawRangeCursor: (a, b) => a || b
7306
- });
7307
- }
7308
- });
7309
7315
  /**
7310
- Returns an extension that hides the browser's native selection and
7311
- cursor, replacing the selection with a background behind the text
7312
- (with the `cm-selectionBackground` class), and the
7313
- cursors with elements overlaid over the code (using
7314
- `cm-cursor-primary` and `cm-cursor-secondary`).
7315
-
7316
- This allows the editor to display secondary selection ranges, and
7317
- tends to produce a type of selection more in line with that users
7318
- expect in a text editor (the native selection styling will often
7319
- leave gaps between lines and won't fill the horizontal space after
7320
- a line when the selection continues past it).
7321
-
7322
- It does have a performance cost, in that it requires an extra DOM
7323
- layout cycle for many updates (the selection is drawn based on DOM
7324
- layout information that's only available after laying out the
7325
- content).
7316
+ Implementation of [`LayerMarker`](https://codemirror.net/6/docs/ref/#view.LayerMarker) that creates
7317
+ a rectangle at a given set of coordinates.
7326
7318
  */
7327
- function drawSelection(config = {}) {
7328
- return [
7329
- selectionConfig.of(config),
7330
- drawSelectionPlugin,
7331
- hideNativeSelection,
7332
- nativeSelectionHidden.of(true)
7333
- ];
7334
- }
7335
- class Piece {
7336
- constructor(left, top, width, height, className) {
7319
+ class RectangleMarker {
7320
+ /**
7321
+ Create a marker with the given class and dimensions. If `width`
7322
+ is null, the DOM element will get no width style.
7323
+ */
7324
+ constructor(className, left, top, width, height) {
7325
+ this.className = className;
7337
7326
  this.left = left;
7338
7327
  this.top = top;
7339
7328
  this.width = width;
7340
7329
  this.height = height;
7341
- this.className = className;
7342
7330
  }
7343
7331
  draw() {
7344
7332
  let elt = document.createElement("div");
@@ -7346,10 +7334,16 @@ class Piece {
7346
7334
  this.adjust(elt);
7347
7335
  return elt;
7348
7336
  }
7337
+ update(elt, prev) {
7338
+ if (prev.className != this.className)
7339
+ return false;
7340
+ this.adjust(elt);
7341
+ return true;
7342
+ }
7349
7343
  adjust(elt) {
7350
7344
  elt.style.left = this.left + "px";
7351
7345
  elt.style.top = this.top + "px";
7352
- if (this.width >= 0)
7346
+ if (this.width != null)
7353
7347
  elt.style.width = this.width + "px";
7354
7348
  elt.style.height = this.height + "px";
7355
7349
  }
@@ -7357,82 +7351,26 @@ class Piece {
7357
7351
  return this.left == p.left && this.top == p.top && this.width == p.width && this.height == p.height &&
7358
7352
  this.className == p.className;
7359
7353
  }
7360
- }
7361
- const drawSelectionPlugin = ViewPlugin.fromClass(class {
7362
- constructor(view) {
7363
- this.view = view;
7364
- this.rangePieces = [];
7365
- this.cursors = [];
7366
- this.measureReq = { read: this.readPos.bind(this), write: this.drawSel.bind(this) };
7367
- this.selectionLayer = view.scrollDOM.appendChild(document.createElement("div"));
7368
- this.selectionLayer.className = "cm-selectionLayer";
7369
- this.selectionLayer.setAttribute("aria-hidden", "true");
7370
- this.cursorLayer = view.scrollDOM.appendChild(document.createElement("div"));
7371
- this.cursorLayer.className = "cm-cursorLayer";
7372
- this.cursorLayer.setAttribute("aria-hidden", "true");
7373
- view.requestMeasure(this.measureReq);
7374
- this.setBlinkRate();
7375
- }
7376
- setBlinkRate() {
7377
- this.cursorLayer.style.animationDuration = this.view.state.facet(selectionConfig).cursorBlinkRate + "ms";
7378
- }
7379
- update(update) {
7380
- let confChanged = update.startState.facet(selectionConfig) != update.state.facet(selectionConfig);
7381
- if (confChanged || update.selectionSet || update.geometryChanged || update.viewportChanged)
7382
- this.view.requestMeasure(this.measureReq);
7383
- if (update.transactions.some(tr => tr.scrollIntoView))
7384
- this.cursorLayer.style.animationName = this.cursorLayer.style.animationName == "cm-blink" ? "cm-blink2" : "cm-blink";
7385
- if (confChanged)
7386
- this.setBlinkRate();
7387
- }
7388
- readPos() {
7389
- let { state } = this.view, conf = state.facet(selectionConfig);
7390
- let rangePieces = state.selection.ranges.map(r => r.empty ? [] : measureRange(this.view, r)).reduce((a, b) => a.concat(b));
7391
- let cursors = [];
7392
- for (let r of state.selection.ranges) {
7393
- let prim = r == state.selection.main;
7394
- if (r.empty ? !prim || CanHidePrimary : conf.drawRangeCursor) {
7395
- let piece = measureCursor(this.view, r, prim);
7396
- if (piece)
7397
- cursors.push(piece);
7398
- }
7399
- }
7400
- return { rangePieces, cursors };
7401
- }
7402
- drawSel({ rangePieces, cursors }) {
7403
- if (rangePieces.length != this.rangePieces.length || rangePieces.some((p, i) => !p.eq(this.rangePieces[i]))) {
7404
- this.selectionLayer.textContent = "";
7405
- for (let p of rangePieces)
7406
- this.selectionLayer.appendChild(p.draw());
7407
- this.rangePieces = rangePieces;
7354
+ /**
7355
+ Create a set of rectangles for the given selection range,
7356
+ assigning them theclass`className`. Will create a single
7357
+ rectangle for empty ranges, and a set of selection-style
7358
+ rectangles covering the range's content (in a bidi-aware
7359
+ way) for non-empty ones.
7360
+ */
7361
+ static forRange(view, className, range) {
7362
+ if (range.empty) {
7363
+ let pos = view.coordsAtPos(range.head, range.assoc || 1);
7364
+ if (!pos)
7365
+ return [];
7366
+ let base = getBase(view);
7367
+ return [new RectangleMarker(className, pos.left - base.left, pos.top - base.top, null, pos.bottom - pos.top)];
7408
7368
  }
7409
- if (cursors.length != this.cursors.length || cursors.some((c, i) => !c.eq(this.cursors[i]))) {
7410
- let oldCursors = this.cursorLayer.children;
7411
- if (oldCursors.length !== cursors.length) {
7412
- this.cursorLayer.textContent = "";
7413
- for (const c of cursors)
7414
- this.cursorLayer.appendChild(c.draw());
7415
- }
7416
- else {
7417
- cursors.forEach((c, idx) => c.adjust(oldCursors[idx]));
7418
- }
7419
- this.cursors = cursors;
7369
+ else {
7370
+ return rectanglesForRange(view, className, range);
7420
7371
  }
7421
7372
  }
7422
- destroy() {
7423
- this.selectionLayer.remove();
7424
- this.cursorLayer.remove();
7425
- }
7426
- });
7427
- const themeSpec = {
7428
- ".cm-line": {
7429
- "& ::selection": { backgroundColor: "transparent !important" },
7430
- "&::selection": { backgroundColor: "transparent !important" }
7431
- }
7432
- };
7433
- if (CanHidePrimary)
7434
- themeSpec[".cm-line"].caretColor = "transparent !important";
7435
- const hideNativeSelection = state.Prec.highest(EditorView.theme(themeSpec));
7373
+ }
7436
7374
  function getBase(view) {
7437
7375
  let rect = view.scrollDOM.getBoundingClientRect();
7438
7376
  let left = view.textDirection == exports.Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth;
@@ -7453,7 +7391,7 @@ function blockAt(view, pos) {
7453
7391
  }
7454
7392
  return line;
7455
7393
  }
7456
- function measureRange(view, range) {
7394
+ function rectanglesForRange(view, className, range) {
7457
7395
  if (range.to <= view.viewport.from || range.from >= view.viewport.to)
7458
7396
  return [];
7459
7397
  let from = Math.max(range.from, view.viewport.from), to = Math.min(range.to, view.viewport.to);
@@ -7485,7 +7423,7 @@ function measureRange(view, range) {
7485
7423
  return pieces(top).concat(between).concat(pieces(bottom));
7486
7424
  }
7487
7425
  function piece(left, top, right, bottom) {
7488
- return new Piece(left - base.left, top - base.top - 0.01 /* C.Epsilon */, right - left, bottom - top + 0.01 /* C.Epsilon */, "cm-selectionBackground");
7426
+ return new RectangleMarker(className, left - base.left, top - base.top - 0.01 /* C.Epsilon */, right - left, bottom - top + 0.01 /* C.Epsilon */);
7489
7427
  }
7490
7428
  function pieces({ top, bottom, horizontal }) {
7491
7429
  let pieces = [];
@@ -7537,14 +7475,175 @@ function measureRange(view, range) {
7537
7475
  return { top: y, bottom: y, horizontal: [] };
7538
7476
  }
7539
7477
  }
7540
- function measureCursor(view, cursor, primary) {
7541
- let pos = view.coordsAtPos(cursor.head, cursor.assoc || 1);
7542
- if (!pos)
7543
- return null;
7544
- let base = getBase(view);
7545
- return new Piece(pos.left - base.left, pos.top - base.top, -1, pos.bottom - pos.top, primary ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary");
7478
+ function sameMarker(a, b) {
7479
+ return a.constructor == b.constructor && a.eq(b);
7480
+ }
7481
+ class LayerView {
7482
+ constructor(view, layer) {
7483
+ this.view = view;
7484
+ this.layer = layer;
7485
+ this.drawn = [];
7486
+ this.measureReq = { read: this.measure.bind(this), write: this.draw.bind(this) };
7487
+ this.dom = view.scrollDOM.appendChild(document.createElement("div"));
7488
+ this.dom.classList.add("cm-layer");
7489
+ if (layer.above)
7490
+ this.dom.classList.add("cm-layer-above");
7491
+ if (layer.class)
7492
+ this.dom.classList.add(layer.class);
7493
+ this.dom.setAttribute("aria-hidden", "true");
7494
+ this.setOrder(view.state);
7495
+ view.requestMeasure(this.measureReq);
7496
+ if (layer.mount)
7497
+ layer.mount(this.dom, view);
7498
+ }
7499
+ update(update) {
7500
+ if (update.startState.facet(layerOrder) != update.state.facet(layerOrder))
7501
+ this.setOrder(update.state);
7502
+ if (this.layer.update(update, this.dom) || update.geometryChanged)
7503
+ update.view.requestMeasure(this.measureReq);
7504
+ }
7505
+ setOrder(state) {
7506
+ let pos = 0, order = state.facet(layerOrder);
7507
+ while (pos < order.length && order[pos] != this.layer)
7508
+ pos++;
7509
+ this.dom.style.zIndex = String((this.layer.above ? 150 : -1) - pos);
7510
+ }
7511
+ measure() {
7512
+ return this.layer.markers(this.view);
7513
+ }
7514
+ draw(markers) {
7515
+ if (markers.length != this.drawn.length || markers.some((p, i) => !sameMarker(p, this.drawn[i]))) {
7516
+ let old = this.dom.firstChild, oldI = 0;
7517
+ for (let marker of markers) {
7518
+ if (marker.update && old && marker.constructor && this.drawn[oldI].constructor &&
7519
+ marker.update(old, this.drawn[oldI])) {
7520
+ old = old.nextSibling;
7521
+ oldI++;
7522
+ }
7523
+ else {
7524
+ this.dom.insertBefore(marker.draw(), old);
7525
+ }
7526
+ }
7527
+ while (old) {
7528
+ let next = old.nextSibling;
7529
+ old.remove();
7530
+ old = next;
7531
+ }
7532
+ this.drawn = markers;
7533
+ }
7534
+ }
7535
+ destroy() {
7536
+ if (this.layer.destroy)
7537
+ this.layer.destroy(this.dom, this.view);
7538
+ this.dom.remove();
7539
+ }
7540
+ }
7541
+ const layerOrder = state.Facet.define();
7542
+ /**
7543
+ Define a layer.
7544
+ */
7545
+ function layer(config) {
7546
+ return [
7547
+ ViewPlugin.define(v => new LayerView(v, config)),
7548
+ layerOrder.of(config)
7549
+ ];
7546
7550
  }
7547
7551
 
7552
+ const CanHidePrimary = !browser.ios; // FIXME test IE
7553
+ const selectionConfig = state.Facet.define({
7554
+ combine(configs) {
7555
+ return state.combineConfig(configs, {
7556
+ cursorBlinkRate: 1200,
7557
+ drawRangeCursor: true
7558
+ }, {
7559
+ cursorBlinkRate: (a, b) => Math.min(a, b),
7560
+ drawRangeCursor: (a, b) => a || b
7561
+ });
7562
+ }
7563
+ });
7564
+ /**
7565
+ Returns an extension that hides the browser's native selection and
7566
+ cursor, replacing the selection with a background behind the text
7567
+ (with the `cm-selectionBackground` class), and the
7568
+ cursors with elements overlaid over the code (using
7569
+ `cm-cursor-primary` and `cm-cursor-secondary`).
7570
+
7571
+ This allows the editor to display secondary selection ranges, and
7572
+ tends to produce a type of selection more in line with that users
7573
+ expect in a text editor (the native selection styling will often
7574
+ leave gaps between lines and won't fill the horizontal space after
7575
+ a line when the selection continues past it).
7576
+
7577
+ It does have a performance cost, in that it requires an extra DOM
7578
+ layout cycle for many updates (the selection is drawn based on DOM
7579
+ layout information that's only available after laying out the
7580
+ content).
7581
+ */
7582
+ function drawSelection(config = {}) {
7583
+ return [
7584
+ selectionConfig.of(config),
7585
+ cursorLayer,
7586
+ selectionLayer,
7587
+ hideNativeSelection,
7588
+ nativeSelectionHidden.of(true)
7589
+ ];
7590
+ }
7591
+ function configChanged(update) {
7592
+ return update.startState.facet(selectionConfig) != update.startState.facet(selectionConfig);
7593
+ }
7594
+ const cursorLayer = layer({
7595
+ above: true,
7596
+ markers(view) {
7597
+ let { state: state$1 } = view, conf = state$1.facet(selectionConfig);
7598
+ let cursors = [];
7599
+ for (let r of state$1.selection.ranges) {
7600
+ let prim = r == state$1.selection.main;
7601
+ if (r.empty ? !prim || CanHidePrimary : conf.drawRangeCursor) {
7602
+ let className = prim ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary";
7603
+ let cursor = r.empty ? r : state.EditorSelection.cursor(r.head, r.head > r.anchor ? -1 : 1);
7604
+ for (let piece of RectangleMarker.forRange(view, className, cursor))
7605
+ cursors.push(piece);
7606
+ }
7607
+ }
7608
+ return cursors;
7609
+ },
7610
+ update(update, dom) {
7611
+ if (update.transactions.some(tr => tr.scrollIntoView))
7612
+ dom.style.animationName = dom.style.animationName == "cm-blink" ? "cm-blink2" : "cm-blink";
7613
+ let confChange = configChanged(update);
7614
+ if (confChange)
7615
+ setBlinkRate(update.state, dom);
7616
+ return update.docChanged || update.selectionSet || confChange;
7617
+ },
7618
+ mount(dom, view) {
7619
+ setBlinkRate(view.state, dom);
7620
+ },
7621
+ class: "cm-cursorLayer"
7622
+ });
7623
+ function setBlinkRate(state, dom) {
7624
+ dom.style.animationDuration = state.facet(selectionConfig).cursorBlinkRate + "ms";
7625
+ }
7626
+ const selectionLayer = layer({
7627
+ above: false,
7628
+ markers(view) {
7629
+ return view.state.selection.ranges.map(r => r.empty ? [] : RectangleMarker.forRange(view, "cm-selectionBackground", r))
7630
+ .reduce((a, b) => a.concat(b));
7631
+ },
7632
+ update(update, dom) {
7633
+ return update.docChanged || update.selectionSet || update.viewportChanged || configChanged(update);
7634
+ },
7635
+ class: "cm-selectionLayer"
7636
+ });
7637
+ const themeSpec = {
7638
+ ".cm-line": {
7639
+ "& ::selection": { backgroundColor: "transparent !important" },
7640
+ "&::selection": { backgroundColor: "transparent !important" }
7641
+ }
7642
+ };
7643
+ if (CanHidePrimary)
7644
+ themeSpec[".cm-line"].caretColor = "transparent !important";
7645
+ const hideNativeSelection = state.Prec.highest(EditorView.theme(themeSpec));
7646
+
7548
7647
  const setDropCursorPos = state.StateEffect.define({
7549
7648
  map(pos, mapping) { return pos == null ? null : mapping.mapPos(pos); }
7550
7649
  });
@@ -8336,6 +8435,17 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
8336
8435
  : pos.bottom + (size.bottom - size.top) + offset.y > space.bottom) &&
8337
8436
  above == (space.bottom - pos.bottom > pos.top - space.top))
8338
8437
  above = !above;
8438
+ let spaceVert = (above ? pos.top - space.top : space.bottom - pos.bottom) - arrowHeight;
8439
+ if (spaceVert < height && tView.resize !== false) {
8440
+ if (spaceVert < this.view.defaultLineHeight) {
8441
+ dom.style.top = Outside;
8442
+ continue;
8443
+ }
8444
+ dom.style.height = (height = spaceVert) + "px";
8445
+ }
8446
+ else if (dom.style.height) {
8447
+ dom.style.height = "";
8448
+ }
8339
8449
  let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y;
8340
8450
  let right = left + width;
8341
8451
  if (tView.overlap !== true)
@@ -8379,7 +8489,8 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
8379
8489
  });
8380
8490
  const baseTheme = EditorView.baseTheme({
8381
8491
  ".cm-tooltip": {
8382
- zIndex: 100
8492
+ zIndex: 100,
8493
+ boxSizing: "border-box"
8383
8494
  },
8384
8495
  "&light .cm-tooltip": {
8385
8496
  border: "1px solid #bbb",
@@ -9298,6 +9409,57 @@ function highlightActiveLineGutter() {
9298
9409
  return activeLineGutterHighlighter;
9299
9410
  }
9300
9411
 
9412
+ const WhitespaceDeco = new Map();
9413
+ function getWhitespaceDeco(space) {
9414
+ let deco = WhitespaceDeco.get(space);
9415
+ if (!deco)
9416
+ WhitespaceDeco.set(space, deco = Decoration.mark({
9417
+ attributes: space === "\t" ? {
9418
+ class: "cm-highlightTab",
9419
+ } : {
9420
+ class: "cm-highlightSpace",
9421
+ "data-display": space.replace(/ /g, "·")
9422
+ }
9423
+ }));
9424
+ return deco;
9425
+ }
9426
+ function matcher(decorator) {
9427
+ return ViewPlugin.define(view => ({
9428
+ decorations: decorator.createDeco(view),
9429
+ update(u) {
9430
+ this.decorations = decorator.updateDeco(u, this.decorations);
9431
+ },
9432
+ }), {
9433
+ decorations: v => v.decorations
9434
+ });
9435
+ }
9436
+ const whitespaceHighlighter = matcher(new MatchDecorator({
9437
+ regexp: /\t| +/g,
9438
+ decoration: match => getWhitespaceDeco(match[0]),
9439
+ boundary: /\S/,
9440
+ }));
9441
+ /**
9442
+ Returns an extension that highlights whitespace, adding a
9443
+ `cm-highlightSpace` class to stretches of spaces, and a
9444
+ `cm-highlightTab` class to individual tab characters. By default,
9445
+ the former are shown as faint dots, and the latter as arrows.
9446
+ */
9447
+ function highlightWhitespace() {
9448
+ return whitespaceHighlighter;
9449
+ }
9450
+ const trailingHighlighter = matcher(new MatchDecorator({
9451
+ regexp: /\s+$/g,
9452
+ decoration: Decoration.mark({ class: "cm-trailingSpace" }),
9453
+ boundary: /\S/,
9454
+ }));
9455
+ /**
9456
+ Returns an extension that adds a `cm-trailingSpace` class to all
9457
+ trailing whitespace.
9458
+ */
9459
+ function highlightTrailingWhitespace() {
9460
+ return trailingHighlighter;
9461
+ }
9462
+
9301
9463
  /**
9302
9464
  @internal
9303
9465
  */
@@ -9309,6 +9471,7 @@ exports.Decoration = Decoration;
9309
9471
  exports.EditorView = EditorView;
9310
9472
  exports.GutterMarker = GutterMarker;
9311
9473
  exports.MatchDecorator = MatchDecorator;
9474
+ exports.RectangleMarker = RectangleMarker;
9312
9475
  exports.ViewPlugin = ViewPlugin;
9313
9476
  exports.ViewUpdate = ViewUpdate;
9314
9477
  exports.WidgetType = WidgetType;
@@ -9326,8 +9489,11 @@ exports.hasHoverTooltips = hasHoverTooltips;
9326
9489
  exports.highlightActiveLine = highlightActiveLine;
9327
9490
  exports.highlightActiveLineGutter = highlightActiveLineGutter;
9328
9491
  exports.highlightSpecialChars = highlightSpecialChars;
9492
+ exports.highlightTrailingWhitespace = highlightTrailingWhitespace;
9493
+ exports.highlightWhitespace = highlightWhitespace;
9329
9494
  exports.hoverTooltip = hoverTooltip;
9330
9495
  exports.keymap = keymap;
9496
+ exports.layer = layer;
9331
9497
  exports.lineNumberMarkers = lineNumberMarkers;
9332
9498
  exports.lineNumbers = lineNumbers;
9333
9499
  exports.logException = logException;