@codemirror/view 0.19.21 → 0.19.25

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
@@ -1086,8 +1086,9 @@ class Decoration extends rangeset.RangeValue {
1086
1086
  position.
1087
1087
  */
1088
1088
  static widget(spec) {
1089
- let side = spec.side || 0;
1090
- return new PointDecoration(spec, side, side, !!spec.block, spec.widget || null, false);
1089
+ let side = spec.side || 0, block = !!spec.block;
1090
+ side += block ? (side > 0 ? 300000000 /* BlockAfter */ : -400000000 /* BlockBefore */) : (side > 0 ? 100000000 /* InlineAfter */ : -100000000 /* InlineBefore */);
1091
+ return new PointDecoration(spec, side, side, block, spec.widget || null, false);
1091
1092
  }
1092
1093
  /**
1093
1094
  Create a replace decoration which replaces the given range with
@@ -1096,8 +1097,8 @@ class Decoration extends rangeset.RangeValue {
1096
1097
  static replace(spec) {
1097
1098
  let block = !!spec.block;
1098
1099
  let { start, end } = getInclusive(spec, block);
1099
- let startSide = 100000000 /* Big */ * (start ? -1 : 1) * (block ? 2 : 1);
1100
- let endSide = 100000000 /* Big */ * (end ? 1 : -1) * (block ? 2 : 1);
1100
+ let startSide = block ? (start ? -300000000 /* BlockIncStart */ : -1 /* InlineIncStart */) : 400000000 /* NonIncStart */;
1101
+ let endSide = block ? (end ? 200000000 /* BlockIncEnd */ : 1 /* InlineIncEnd */) : -500000000 /* NonIncEnd */;
1101
1102
  return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
1102
1103
  }
1103
1104
  /**
@@ -1127,7 +1128,7 @@ Decoration.none = rangeset.RangeSet.empty;
1127
1128
  class MarkDecoration extends Decoration {
1128
1129
  constructor(spec) {
1129
1130
  let { start, end } = getInclusive(spec);
1130
- super(100000000 /* Big */ * (start ? -1 : 1), 100000000 /* Big */ * (end ? 1 : -1), null, spec);
1131
+ super(start ? -1 /* InlineIncStart */ : 400000000 /* NonIncStart */, end ? 1 /* InlineIncEnd */ : -500000000 /* NonIncEnd */, null, spec);
1131
1132
  this.tagName = spec.tagName || "span";
1132
1133
  this.class = spec.class || "";
1133
1134
  this.attrs = spec.attributes || null;
@@ -1148,7 +1149,7 @@ class MarkDecoration extends Decoration {
1148
1149
  MarkDecoration.prototype.point = false;
1149
1150
  class LineDecoration extends Decoration {
1150
1151
  constructor(spec) {
1151
- super(-100000000 /* Big */, -100000000 /* Big */, null, spec);
1152
+ super(-200000000 /* Line */, -200000000 /* Line */, null, spec);
1152
1153
  }
1153
1154
  eq(other) {
1154
1155
  return other instanceof LineDecoration && attrsEq(this.spec.attributes, other.spec.attributes);
@@ -1727,36 +1728,39 @@ class PluginInstance {
1727
1728
  this.value = null;
1728
1729
  }
1729
1730
  takeField(type, target) {
1730
- for (let { field, get } of this.spec.fields)
1731
- if (field == type)
1732
- target.push(get(this.value));
1731
+ if (this.spec)
1732
+ for (let { field, get } of this.spec.fields)
1733
+ if (field == type)
1734
+ target.push(get(this.value));
1733
1735
  }
1734
1736
  update(view) {
1735
1737
  if (!this.value) {
1736
- try {
1737
- this.value = this.spec.create(view);
1738
- }
1739
- catch (e) {
1740
- logException(view.state, e, "CodeMirror plugin crashed");
1741
- return PluginInstance.dummy;
1738
+ if (this.spec) {
1739
+ try {
1740
+ this.value = this.spec.create(view);
1741
+ }
1742
+ catch (e) {
1743
+ logException(view.state, e, "CodeMirror plugin crashed");
1744
+ this.deactivate();
1745
+ }
1742
1746
  }
1743
1747
  }
1744
1748
  else if (this.mustUpdate) {
1745
1749
  let update = this.mustUpdate;
1746
1750
  this.mustUpdate = null;
1747
- if (!this.value.update)
1748
- return this;
1749
- try {
1750
- this.value.update(update);
1751
- }
1752
- catch (e) {
1753
- logException(update.state, e, "CodeMirror plugin crashed");
1754
- if (this.value.destroy)
1755
- try {
1756
- this.value.destroy();
1757
- }
1758
- catch (_) { }
1759
- return PluginInstance.dummy;
1751
+ if (this.value.update) {
1752
+ try {
1753
+ this.value.update(update);
1754
+ }
1755
+ catch (e) {
1756
+ logException(update.state, e, "CodeMirror plugin crashed");
1757
+ if (this.value.destroy)
1758
+ try {
1759
+ this.value.destroy();
1760
+ }
1761
+ catch (_) { }
1762
+ this.deactivate();
1763
+ }
1760
1764
  }
1761
1765
  }
1762
1766
  return this;
@@ -1772,20 +1776,12 @@ class PluginInstance {
1772
1776
  }
1773
1777
  }
1774
1778
  }
1779
+ deactivate() {
1780
+ this.spec = this.value = null;
1781
+ }
1775
1782
  }
1776
- PluginInstance.dummy = new PluginInstance(ViewPlugin.define(() => ({})));
1777
- function combineFacetAttrs(values) {
1778
- let result = {};
1779
- for (let i = values.length - 1; i >= 0; i--)
1780
- combineAttrs(values[i], result);
1781
- return result;
1782
- }
1783
- const editorAttributes = state.Facet.define({
1784
- combine: combineFacetAttrs
1785
- });
1786
- const contentAttributes = state.Facet.define({
1787
- combine: combineFacetAttrs
1788
- });
1783
+ const editorAttributes = state.Facet.define();
1784
+ const contentAttributes = state.Facet.define();
1789
1785
  // Provide decorations
1790
1786
  const decorations = state.Facet.define();
1791
1787
  const styleModule = state.Facet.define();
@@ -1912,7 +1908,7 @@ class ViewUpdate {
1912
1908
  Whether the document changed in this update.
1913
1909
  */
1914
1910
  get docChanged() {
1915
- return this.transactions.some(tr => tr.docChanged);
1911
+ return !this.changes.empty;
1916
1912
  }
1917
1913
  /**
1918
1914
  Whether the selection was explicitly set in this update.
@@ -1933,12 +1929,12 @@ class DocView extends ContentView {
1933
1929
  this.compositionDeco = Decoration.none;
1934
1930
  this.decorations = [];
1935
1931
  // Track a minimum width for the editor. When measuring sizes in
1936
- // checkLayout, this is updated to point at the width of a given
1937
- // element and its extent in the document. When a change happens in
1938
- // that range, these are reset. That way, once we've seen a
1939
- // line/element of a given length, we keep the editor wide enough to
1940
- // fit at least that element, until it is changed, at which point we
1941
- // forget it again.
1932
+ // measureVisibleLineHeights, this is updated to point at the width
1933
+ // of a given element and its extent in the document. When a change
1934
+ // happens in that range, these are reset. That way, once we've seen
1935
+ // a line/element of a given length, we keep the editor wide enough
1936
+ // to fit at least that element, until it is changed, at which point
1937
+ // we forget it again.
1942
1938
  this.minWidth = 0;
1943
1939
  this.minWidthFrom = 0;
1944
1940
  this.minWidthTo = 0;
@@ -1988,10 +1984,7 @@ class DocView extends ContentView {
1988
1984
  let prevDeco = this.decorations, deco = this.updateDeco();
1989
1985
  let decoDiff = findChangedDeco(prevDeco, deco, update.changes);
1990
1986
  changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
1991
- if (this.dirty == 0 /* Not */ && changedRanges.length == 0 &&
1992
- !(update.flags & 4 /* Viewport */) &&
1993
- update.state.selection.main.from >= this.view.viewport.from &&
1994
- update.state.selection.main.to <= this.view.viewport.to) {
1987
+ if (this.dirty == 0 /* Not */ && changedRanges.length == 0) {
1995
1988
  return false;
1996
1989
  }
1997
1990
  else {
@@ -2011,9 +2004,10 @@ class DocView extends ContentView {
2011
2004
  this.updateSelection();
2012
2005
  }
2013
2006
  }
2014
- // Used both by update and checkLayout do perform the actual DOM
2007
+ // Used by update and the constructor do perform the actual DOM
2015
2008
  // update
2016
2009
  updateInner(changes, deco, oldLength) {
2010
+ this.view.viewState.mustMeasureContent = true;
2017
2011
  this.updateChildren(changes, deco, oldLength);
2018
2012
  let { observer } = this.view;
2019
2013
  observer.ignore(() => {
@@ -2021,7 +2015,7 @@ class DocView extends ContentView {
2021
2015
  // messes with the scroll position during DOM mutation (though
2022
2016
  // no relayout is triggered and I cannot imagine how it can
2023
2017
  // recompute the scroll position without a layout)
2024
- this.dom.style.height = this.view.viewState.domHeight + "px";
2018
+ this.dom.style.height = this.view.viewState.contentHeight + "px";
2025
2019
  this.dom.style.minWidth = this.minWidth ? this.minWidth + "px" : "";
2026
2020
  // Chrome will sometimes, when DOM mutations occur directly
2027
2021
  // around the selection, get confused and report a different
@@ -2306,7 +2300,7 @@ class DocView extends ContentView {
2306
2300
  let next = i == vs.viewports.length ? null : vs.viewports[i];
2307
2301
  let end = next ? next.from - 1 : this.length;
2308
2302
  if (end > pos) {
2309
- let height = vs.lineAt(end, 0).bottom - vs.lineAt(pos, 0).top;
2303
+ let height = vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top;
2310
2304
  deco.push(Decoration.replace({ widget: new BlockGapWidget(height), block: true, inclusive: true }).range(pos, end));
2311
2305
  }
2312
2306
  if (!next)
@@ -2913,13 +2907,14 @@ function domPosInText(node, x, y) {
2913
2907
  }
2914
2908
  function posAtCoords(view, { x, y }, precise, bias = -1) {
2915
2909
  var _a;
2916
- let content = view.contentDOM.getBoundingClientRect(), block;
2910
+ let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
2917
2911
  let halfLine = view.defaultLineHeight / 2;
2912
+ let block, yOffset = y - docTop;
2918
2913
  for (let bounced = false;;) {
2919
- block = view.blockAtHeight(y, content.top);
2920
- if (block.top > y || block.bottom < y) {
2921
- bias = block.top > y ? -1 : 1;
2922
- y = Math.min(block.bottom - halfLine, Math.max(block.top + halfLine, y));
2914
+ block = view.elementAtHeight(yOffset);
2915
+ if (block.top > yOffset || block.bottom < yOffset) {
2916
+ bias = block.top > yOffset ? -1 : 1;
2917
+ yOffset = Math.min(block.bottom - halfLine, Math.max(block.top + halfLine, yOffset));
2923
2918
  if (bounced)
2924
2919
  return precise ? null : 0;
2925
2920
  else
@@ -2927,11 +2922,12 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
2927
2922
  }
2928
2923
  if (block.type == exports.BlockType.Text)
2929
2924
  break;
2930
- y = bias > 0 ? block.bottom + halfLine : block.top - halfLine;
2925
+ yOffset = bias > 0 ? block.bottom + halfLine : block.top - halfLine;
2931
2926
  }
2927
+ y = docTop + yOffset;
2932
2928
  let lineStart = block.from;
2933
2929
  // Clip x to the viewport sides
2934
- x = Math.max(content.left + 1, Math.min(content.right - 1, x));
2930
+ x = Math.max(content.left + 1, Math.min(Math.max(content.right, content.left + view.docView.minWidth) - 1, x));
2935
2931
  // If this is outside of the rendered viewport, we can't determine a position
2936
2932
  if (lineStart < view.viewport.from)
2937
2933
  return view.viewport.from == 0 ? 0 : posAtCoordsImprecise(view, content, block, x, y);
@@ -3041,17 +3037,17 @@ function moveVertically(view, start, forward, distance) {
3041
3037
  return state.EditorSelection.cursor(startPos);
3042
3038
  let goal = start.goalColumn, startY;
3043
3039
  let rect = view.contentDOM.getBoundingClientRect();
3044
- let startCoords = view.coordsAtPos(startPos);
3040
+ let startCoords = view.coordsAtPos(startPos), docTop = view.documentTop;
3045
3041
  if (startCoords) {
3046
3042
  if (goal == null)
3047
3043
  goal = startCoords.left - rect.left;
3048
3044
  startY = dir < 0 ? startCoords.top : startCoords.bottom;
3049
3045
  }
3050
3046
  else {
3051
- let line = view.viewState.lineAt(startPos, view.dom.getBoundingClientRect().top);
3047
+ let line = view.viewState.lineBlockAt(startPos - docTop);
3052
3048
  if (goal == null)
3053
3049
  goal = Math.min(rect.right - rect.left, view.defaultCharacterWidth * (startPos - line.from));
3054
- startY = dir < 0 ? line.top : line.bottom;
3050
+ startY = (dir < 0 ? line.top : line.bottom) + docTop;
3055
3051
  }
3056
3052
  let resolvedGoal = rect.left + goal;
3057
3053
  let dist = distance !== null && distance !== void 0 ? distance : (view.defaultLineHeight >> 1);
@@ -3302,7 +3298,7 @@ class MouseSelection {
3302
3298
  this.extend = startEvent.shiftKey;
3303
3299
  this.multiple = view.state.facet(state.EditorState.allowMultipleSelections) && addsSelectionRange(view, startEvent);
3304
3300
  this.dragMove = dragMovesSelection(view, startEvent);
3305
- this.dragging = isInPrimarySelection(view, startEvent) ? null : false;
3301
+ this.dragging = isInPrimarySelection(view, startEvent) && getClickType(startEvent) == 1 ? null : false;
3306
3302
  // When clicking outside of the selection, immediately apply the
3307
3303
  // effect of starting the selection
3308
3304
  if (this.dragging === false) {
@@ -3523,7 +3519,7 @@ function basicMouseSelection(view, event) {
3523
3519
  let last = start, lastEvent = event;
3524
3520
  return {
3525
3521
  update(update) {
3526
- if (update.changes) {
3522
+ if (update.docChanged) {
3527
3523
  if (start)
3528
3524
  start.pos = update.changes.mapPos(start.pos);
3529
3525
  startSel = startSel.map(update.changes);
@@ -3787,7 +3783,10 @@ class HeightOracle {
3787
3783
  return lines * this.lineHeight;
3788
3784
  }
3789
3785
  setDoc(doc) { this.doc = doc; return this; }
3790
- mustRefresh(lineHeights, whiteSpace, direction) {
3786
+ mustRefreshForStyle(whiteSpace, direction) {
3787
+ return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping || this.direction != direction;
3788
+ }
3789
+ mustRefreshForHeights(lineHeights) {
3791
3790
  let newHeight = false;
3792
3791
  for (let i = 0; i < lineHeights.length; i++) {
3793
3792
  let h = lineHeights[i];
@@ -3799,7 +3798,7 @@ class HeightOracle {
3799
3798
  this.heightSamples[Math.floor(h * 10)] = true;
3800
3799
  }
3801
3800
  }
3802
- return newHeight || (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping || this.direction != direction;
3801
+ return newHeight;
3803
3802
  }
3804
3803
  refresh(whiteSpace, direction, lineHeight, charWidth, lineLength, knownHeights) {
3805
3804
  let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
@@ -3853,7 +3852,8 @@ class BlockInfo {
3853
3852
  */
3854
3853
  length,
3855
3854
  /**
3856
- The top position of the element.
3855
+ The top position of the element (relative to the top of the
3856
+ document).
3857
3857
  */
3858
3858
  top,
3859
3859
  /**
@@ -3887,6 +3887,12 @@ class BlockInfo {
3887
3887
  .concat(Array.isArray(other.type) ? other.type : [other]);
3888
3888
  return new BlockInfo(this.from, this.length + other.length, this.top, this.height + other.height, detail);
3889
3889
  }
3890
+ /**
3891
+ FIXME remove on next breaking release @internal
3892
+ */
3893
+ moveY(offset) {
3894
+ return !offset ? this : new BlockInfo(this.from, this.length, this.top + offset, this.height, Array.isArray(this.type) ? this.type.map(b => b.moveY(offset)) : this.type);
3895
+ }
3890
3896
  }
3891
3897
  var QueryType;
3892
3898
  (function (QueryType) {
@@ -3894,7 +3900,7 @@ var QueryType;
3894
3900
  QueryType[QueryType["ByHeight"] = 1] = "ByHeight";
3895
3901
  QueryType[QueryType["ByPosNoHeight"] = 2] = "ByPosNoHeight";
3896
3902
  })(QueryType || (QueryType = {}));
3897
- const Epsilon = 1e-4;
3903
+ const Epsilon = 1e-3;
3898
3904
  class HeightMap {
3899
3905
  constructor(length, // The number of characters covered
3900
3906
  height, // Height of this part of the document
@@ -4121,22 +4127,30 @@ class HeightMapGap extends HeightMap {
4121
4127
  // can't be widgets or collapsed ranges in those lines, because
4122
4128
  // they would already have been added to the heightmap (gaps
4123
4129
  // only contain plain text).
4124
- let nodes = [], pos = Math.max(offset, measured.from);
4130
+ let nodes = [], pos = Math.max(offset, measured.from), singleHeight = -1;
4131
+ let wasChanged = oracle.heightChanged;
4125
4132
  if (measured.from > offset)
4126
4133
  nodes.push(new HeightMapGap(measured.from - offset - 1).updateHeight(oracle, offset));
4127
4134
  while (pos <= end && measured.more) {
4128
4135
  let len = oracle.doc.lineAt(pos).length;
4129
4136
  if (nodes.length)
4130
4137
  nodes.push(null);
4131
- let line = new HeightMapText(len, measured.heights[measured.index++]);
4138
+ let height = measured.heights[measured.index++];
4139
+ if (singleHeight == -1)
4140
+ singleHeight = height;
4141
+ else if (Math.abs(height - singleHeight) >= Epsilon)
4142
+ singleHeight = -2;
4143
+ let line = new HeightMapText(len, height);
4132
4144
  line.outdated = false;
4133
4145
  nodes.push(line);
4134
4146
  pos += len + 1;
4135
4147
  }
4136
4148
  if (pos <= end)
4137
4149
  nodes.push(null, new HeightMapGap(end - pos).updateHeight(oracle, pos));
4138
- oracle.heightChanged = true;
4139
- return HeightMap.of(nodes);
4150
+ let result = HeightMap.of(nodes);
4151
+ oracle.heightChanged = wasChanged || singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon ||
4152
+ Math.abs(singleHeight - this.lines(oracle.doc, offset).lineHeight) >= Epsilon;
4153
+ return result;
4140
4154
  }
4141
4155
  else if (force || this.outdated) {
4142
4156
  this.setHeight(oracle, oracle.heightForGap(offset, offset + this.length));
@@ -4494,7 +4508,8 @@ class ViewState {
4494
4508
  this.inView = true;
4495
4509
  this.paddingTop = 0;
4496
4510
  this.paddingBottom = 0;
4497
- this.contentWidth = 0;
4511
+ this.contentDOMWidth = 0;
4512
+ this.contentDOMHeight = 0;
4498
4513
  this.editorHeight = 0;
4499
4514
  this.heightOracle = new HeightOracle;
4500
4515
  // See VP.MaxDOMHeight
@@ -4502,6 +4517,9 @@ class ViewState {
4502
4517
  this.scrollTarget = null;
4503
4518
  // Briefly set to true when printing, to disable viewport limiting
4504
4519
  this.printing = false;
4520
+ // Flag set when editor content was redrawn, so that the next
4521
+ // measure stage knows it must read DOM layout
4522
+ this.mustMeasureContent = true;
4505
4523
  this.visibleRanges = [];
4506
4524
  // Cursor 'assoc' is only significant when the cursor is on a line
4507
4525
  // wrap point, where it must stick to the character that it is
@@ -4514,6 +4532,7 @@ class ViewState {
4514
4532
  this.mustEnforceCursorAssoc = false;
4515
4533
  this.heightMap = HeightMap.empty().applyChanges(state.facet(decorations), text.Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
4516
4534
  this.viewport = this.getViewport(0, null);
4535
+ this.updateViewportLines();
4517
4536
  this.updateForViewport();
4518
4537
  this.lineGaps = this.ensureLineGaps([]);
4519
4538
  this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(false)));
@@ -4524,7 +4543,7 @@ class ViewState {
4524
4543
  for (let i = 0; i <= 1; i++) {
4525
4544
  let pos = i ? main.head : main.anchor;
4526
4545
  if (!viewports.some(({ from, to }) => pos >= from && pos <= to)) {
4527
- let { from, to } = this.lineAt(pos, 0);
4546
+ let { from, to } = this.lineBlockAt(pos);
4528
4547
  viewports.push(new Viewport(from, to));
4529
4548
  }
4530
4549
  }
@@ -4532,6 +4551,12 @@ class ViewState {
4532
4551
  this.scaler = this.heightMap.height <= 7000000 /* MaxDOMHeight */ ? IdScaler :
4533
4552
  new BigScaler(this.heightOracle.doc, this.heightMap, this.viewports);
4534
4553
  }
4554
+ updateViewportLines() {
4555
+ this.viewportLines = [];
4556
+ this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.state.doc, 0, 0, block => {
4557
+ this.viewportLines.push(this.scaler.scale == 1 ? block : scaleBlock(block, this.scaler));
4558
+ });
4559
+ }
4535
4560
  update(update, scrollTarget = null) {
4536
4561
  let prev = this.state;
4537
4562
  this.state = update.state;
@@ -4546,7 +4571,11 @@ class ViewState {
4546
4571
  if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) ||
4547
4572
  !this.viewportIsAppropriate(viewport))
4548
4573
  viewport = this.getViewport(0, scrollTarget);
4574
+ let updateLines = !update.changes.empty || (update.flags & 2 /* Height */) ||
4575
+ viewport.from != this.viewport.from || viewport.to != this.viewport.to;
4549
4576
  this.viewport = viewport;
4577
+ if (updateLines)
4578
+ this.updateViewportLines();
4550
4579
  this.updateForViewport();
4551
4580
  if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 /* DoubleMargin */)
4552
4581
  this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
@@ -4557,13 +4586,17 @@ class ViewState {
4557
4586
  update.state.selection.main.empty && update.state.selection.main.assoc)
4558
4587
  this.mustEnforceCursorAssoc = true;
4559
4588
  }
4560
- measure(docView, repeated) {
4561
- let dom = docView.dom, whiteSpace = "", direction = exports.Direction.LTR;
4562
- let result = 0;
4563
- if (!repeated) {
4589
+ measure(view) {
4590
+ let dom = view.contentDOM, style = window.getComputedStyle(dom);
4591
+ let oracle = this.heightOracle;
4592
+ let whiteSpace = style.whiteSpace, direction = style.direction == "rtl" ? exports.Direction.RTL : exports.Direction.LTR;
4593
+ let refresh = this.heightOracle.mustRefreshForStyle(whiteSpace, direction);
4594
+ let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
4595
+ let result = 0, bias = 0;
4596
+ if (measureContent) {
4597
+ this.mustMeasureContent = false;
4598
+ this.contentDOMHeight = dom.clientHeight;
4564
4599
  // Vertical padding
4565
- let style = window.getComputedStyle(dom);
4566
- whiteSpace = style.whiteSpace, direction = (style.direction == "rtl" ? exports.Direction.RTL : exports.Direction.LTR);
4567
4600
  let paddingTop = parseInt(style.paddingTop) || 0, paddingBottom = parseInt(style.paddingBottom) || 0;
4568
4601
  if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
4569
4602
  result |= 8 /* Geometry */;
@@ -4578,39 +4611,42 @@ class ViewState {
4578
4611
  this.inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
4579
4612
  if (!this.inView)
4580
4613
  return 0;
4581
- let lineHeights = docView.measureVisibleLineHeights();
4582
- let refresh = false, bias = 0, oracle = this.heightOracle;
4583
- if (!repeated) {
4584
- let contentWidth = docView.dom.clientWidth;
4585
- if (oracle.mustRefresh(lineHeights, whiteSpace, direction) ||
4586
- oracle.lineWrapping && Math.abs(contentWidth - this.contentWidth) > oracle.charWidth) {
4587
- let { lineHeight, charWidth } = docView.measureTextSize();
4614
+ if (measureContent) {
4615
+ let lineHeights = view.docView.measureVisibleLineHeights();
4616
+ if (oracle.mustRefreshForHeights(lineHeights))
4617
+ refresh = true;
4618
+ let contentWidth = dom.clientWidth;
4619
+ if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
4620
+ let { lineHeight, charWidth } = view.docView.measureTextSize();
4588
4621
  refresh = oracle.refresh(whiteSpace, direction, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
4589
4622
  if (refresh) {
4590
- docView.minWidth = 0;
4623
+ view.docView.minWidth = 0;
4591
4624
  result |= 8 /* Geometry */;
4592
4625
  }
4593
4626
  }
4594
- if (this.contentWidth != contentWidth) {
4595
- this.contentWidth = contentWidth;
4627
+ if (this.contentDOMWidth != contentWidth) {
4628
+ this.contentDOMWidth = contentWidth;
4596
4629
  result |= 8 /* Geometry */;
4597
4630
  }
4598
- if (this.editorHeight != docView.view.scrollDOM.clientHeight) {
4599
- this.editorHeight = docView.view.scrollDOM.clientHeight;
4631
+ if (this.editorHeight != view.scrollDOM.clientHeight) {
4632
+ this.editorHeight = view.scrollDOM.clientHeight;
4600
4633
  result |= 8 /* Geometry */;
4601
4634
  }
4602
4635
  if (dTop > 0 && dBottom > 0)
4603
4636
  bias = Math.max(dTop, dBottom);
4604
4637
  else if (dTop < 0 && dBottom < 0)
4605
4638
  bias = Math.min(dTop, dBottom);
4606
- }
4607
- oracle.heightChanged = false;
4608
- this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(this.viewport.from, lineHeights));
4609
- if (oracle.heightChanged)
4610
- result |= 2 /* Height */;
4611
- if (!this.viewportIsAppropriate(this.viewport, bias) ||
4612
- this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to))
4639
+ oracle.heightChanged = false;
4640
+ this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(this.viewport.from, lineHeights));
4641
+ if (oracle.heightChanged)
4642
+ result |= 2 /* Height */;
4643
+ }
4644
+ let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) ||
4645
+ this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to);
4646
+ if (viewportChange)
4613
4647
  this.viewport = this.getViewport(bias, this.scrollTarget);
4648
+ if ((result & 2 /* Height */) || viewportChange)
4649
+ this.updateViewportLines();
4614
4650
  this.updateForViewport();
4615
4651
  if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 /* DoubleMargin */)
4616
4652
  this.updateLineGaps(this.ensureLineGaps(refresh ? [] : this.lineGaps));
@@ -4621,12 +4657,12 @@ class ViewState {
4621
4657
  // to a line end is going to trigger a layout anyway, so it
4622
4658
  // can't be a pure write. It should be rare that it does any
4623
4659
  // writing.
4624
- docView.enforceCursorAssoc();
4660
+ view.docView.enforceCursorAssoc();
4625
4661
  }
4626
4662
  return result;
4627
4663
  }
4628
- get visibleTop() { return this.scaler.fromDOM(this.pixelViewport.top, 0); }
4629
- get visibleBottom() { return this.scaler.fromDOM(this.pixelViewport.bottom, 0); }
4664
+ get visibleTop() { return this.scaler.fromDOM(this.pixelViewport.top); }
4665
+ get visibleBottom() { return this.scaler.fromDOM(this.pixelViewport.bottom); }
4630
4666
  getViewport(bias, scrollTarget) {
4631
4667
  // This will divide VP.Margin between the top and the
4632
4668
  // bottom, depending on the bias (the change in viewport position
@@ -4686,12 +4722,12 @@ class ViewState {
4686
4722
  // This won't work at all in predominantly right-to-left text.
4687
4723
  if (this.heightOracle.direction != exports.Direction.LTR)
4688
4724
  return gaps;
4689
- this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.state.doc, 0, 0, line => {
4725
+ for (let line of this.viewportLines) {
4690
4726
  if (line.length < 4000 /* DoubleMargin */)
4691
- return;
4727
+ continue;
4692
4728
  let structure = lineStructure(line.from, line.to, this.state);
4693
4729
  if (structure.total < 4000 /* DoubleMargin */)
4694
- return;
4730
+ continue;
4695
4731
  let viewFrom, viewTo;
4696
4732
  if (this.heightOracle.lineWrapping) {
4697
4733
  let marginHeight = (2000 /* Margin */ / this.heightOracle.lineLength) * this.heightOracle.lineHeight;
@@ -4721,7 +4757,7 @@ class ViewState {
4721
4757
  Math.abs(gap.from - from) < 1000 /* HalfMargin */ && Math.abs(gap.to - to) < 1000 /* HalfMargin */) ||
4722
4758
  new LineGap(from, to, this.gapSize(line, from, to, structure)));
4723
4759
  }
4724
- });
4760
+ }
4725
4761
  return gaps;
4726
4762
  }
4727
4763
  gapSize(line, from, to, structure) {
@@ -4753,27 +4789,18 @@ class ViewState {
4753
4789
  this.visibleRanges = ranges;
4754
4790
  return changed ? 4 /* Viewport */ : 0;
4755
4791
  }
4756
- lineAt(pos, editorTop) {
4757
- editorTop += this.paddingTop;
4758
- return scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.state.doc, editorTop, 0), this.scaler, editorTop);
4759
- }
4760
- lineAtHeight(height, editorTop) {
4761
- editorTop += this.paddingTop;
4762
- return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height, editorTop), QueryType.ByHeight, this.state.doc, editorTop, 0), this.scaler, editorTop);
4792
+ lineBlockAt(pos) {
4793
+ return (pos >= this.viewport.from && pos <= this.viewport.to && this.viewportLines.find(b => b.from <= pos && b.to >= pos)) ||
4794
+ scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.state.doc, 0, 0), this.scaler);
4763
4795
  }
4764
- blockAtHeight(height, editorTop) {
4765
- editorTop += this.paddingTop;
4766
- return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height, editorTop), this.state.doc, editorTop, 0), this.scaler, editorTop);
4796
+ lineBlockAtHeight(height) {
4797
+ return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.state.doc, 0, 0), this.scaler);
4767
4798
  }
4768
- forEachLine(from, to, f, editorTop) {
4769
- editorTop += this.paddingTop;
4770
- return this.heightMap.forEachLine(from, to, this.state.doc, editorTop, 0, this.scaler.scale == 1 ? f : b => f(scaleBlock(b, this.scaler, editorTop)));
4799
+ elementAtHeight(height) {
4800
+ return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.state.doc, 0, 0), this.scaler);
4771
4801
  }
4772
4802
  get contentHeight() {
4773
- return this.domHeight + this.paddingTop + this.paddingBottom;
4774
- }
4775
- get domHeight() {
4776
- return this.scaler.toDOM(this.heightMap.height, this.paddingTop);
4803
+ return this.scaler.toDOM(this.heightMap.height) + this.paddingTop + this.paddingBottom;
4777
4804
  }
4778
4805
  }
4779
4806
  class Viewport {
@@ -4870,36 +4897,34 @@ class BigScaler {
4870
4897
  base = obj.bottom;
4871
4898
  }
4872
4899
  }
4873
- toDOM(n, top) {
4874
- n -= top;
4900
+ toDOM(n) {
4875
4901
  for (let i = 0, base = 0, domBase = 0;; i++) {
4876
4902
  let vp = i < this.viewports.length ? this.viewports[i] : null;
4877
4903
  if (!vp || n < vp.top)
4878
- return domBase + (n - base) * this.scale + top;
4904
+ return domBase + (n - base) * this.scale;
4879
4905
  if (n <= vp.bottom)
4880
- return vp.domTop + (n - vp.top) + top;
4906
+ return vp.domTop + (n - vp.top);
4881
4907
  base = vp.bottom;
4882
4908
  domBase = vp.domBottom;
4883
4909
  }
4884
4910
  }
4885
- fromDOM(n, top) {
4886
- n -= top;
4911
+ fromDOM(n) {
4887
4912
  for (let i = 0, base = 0, domBase = 0;; i++) {
4888
4913
  let vp = i < this.viewports.length ? this.viewports[i] : null;
4889
4914
  if (!vp || n < vp.domTop)
4890
- return base + (n - domBase) / this.scale + top;
4915
+ return base + (n - domBase) / this.scale;
4891
4916
  if (n <= vp.domBottom)
4892
- return vp.top + (n - vp.domTop) + top;
4917
+ return vp.top + (n - vp.domTop);
4893
4918
  base = vp.bottom;
4894
4919
  domBase = vp.domBottom;
4895
4920
  }
4896
4921
  }
4897
4922
  }
4898
- function scaleBlock(block, scaler, top) {
4923
+ function scaleBlock(block, scaler) {
4899
4924
  if (scaler.scale == 1)
4900
4925
  return block;
4901
- let bTop = scaler.toDOM(block.top, top), bBottom = scaler.toDOM(block.bottom, top);
4902
- return new BlockInfo(block.from, block.length, bTop, bBottom - bTop, Array.isArray(block.type) ? block.type.map(b => scaleBlock(b, scaler, top)) : block.type);
4926
+ let bTop = scaler.toDOM(block.top), bBottom = scaler.toDOM(block.bottom);
4927
+ return new BlockInfo(block.from, block.length, bTop, bBottom - bTop, Array.isArray(block.type) ? block.type.map(b => scaleBlock(b, scaler)) : block.type);
4903
4928
  }
4904
4929
 
4905
4930
  const theme = state.Facet.define({ combine: strs => strs.join(" ") });
@@ -5036,7 +5061,7 @@ const baseTheme = buildTheme("." + baseThemeID, {
5036
5061
  color: "inherit",
5037
5062
  fontSize: "70%",
5038
5063
  padding: ".2em 1em",
5039
- borderRadius: "3px"
5064
+ borderRadius: "1px"
5040
5065
  },
5041
5066
  "&light .cm-button": {
5042
5067
  backgroundImage: "linear-gradient(#eff1f5, #d9d9df)",
@@ -5358,6 +5383,7 @@ class DOMObserver {
5358
5383
  for (let dom of this.scrollTargets)
5359
5384
  dom.removeEventListener("scroll", this.onScroll);
5360
5385
  window.removeEventListener("scroll", this.onScroll);
5386
+ this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
5361
5387
  clearTimeout(this.parentCheck);
5362
5388
  clearTimeout(this.resizeTimeout);
5363
5389
  }
@@ -5654,6 +5680,7 @@ class EditorView {
5654
5680
  */
5655
5681
  config = {}) {
5656
5682
  this.plugins = [];
5683
+ this.pluginMap = new Map;
5657
5684
  this.editorAttrs = {};
5658
5685
  this.contentAttrs = {};
5659
5686
  this.bidiCache = [];
@@ -5823,6 +5850,7 @@ class EditorView {
5823
5850
  plugin.destroy(this);
5824
5851
  this.viewState = new ViewState(newState);
5825
5852
  this.plugins = newState.facet(viewPlugin).map(spec => new PluginInstance(spec).update(this));
5853
+ this.pluginMap.clear();
5826
5854
  this.docView = new DocView(this);
5827
5855
  this.inputState.ensureHandlers(this);
5828
5856
  this.mountStyles();
@@ -5853,6 +5881,7 @@ class EditorView {
5853
5881
  if (plugin.mustUpdate != update)
5854
5882
  plugin.destroy(this);
5855
5883
  this.plugins = newPlugins;
5884
+ this.pluginMap.clear();
5856
5885
  this.inputState.ensureHandlers(this);
5857
5886
  }
5858
5887
  else {
@@ -5860,7 +5889,7 @@ class EditorView {
5860
5889
  p.mustUpdate = update;
5861
5890
  }
5862
5891
  for (let i = 0; i < this.plugins.length; i++)
5863
- this.plugins[i] = this.plugins[i].update(this);
5892
+ this.plugins[i].update(this);
5864
5893
  }
5865
5894
  /**
5866
5895
  @internal
@@ -5878,11 +5907,11 @@ class EditorView {
5878
5907
  for (let i = 0;; i++) {
5879
5908
  this.updateState = 1 /* Measuring */;
5880
5909
  let oldViewport = this.viewport;
5881
- let changed = this.viewState.measure(this.docView, i > 0);
5910
+ let changed = this.viewState.measure(this);
5882
5911
  if (!changed && !this.measureRequests.length && this.viewState.scrollTarget == null)
5883
5912
  break;
5884
5913
  if (i > 5) {
5885
- console.warn("Viewport failed to stabilize");
5914
+ console.warn(this.measureRequests.length ? "Measure loop restarted more than 5 times" : "Viewport failed to stabilize");
5886
5915
  break;
5887
5916
  }
5888
5917
  let measuring = [];
@@ -5898,7 +5927,7 @@ class EditorView {
5898
5927
  return BadMeasure;
5899
5928
  }
5900
5929
  });
5901
- let update = new ViewUpdate(this, this.state);
5930
+ let update = new ViewUpdate(this, this.state), redrawn = false;
5902
5931
  update.flags |= changed;
5903
5932
  if (!updated)
5904
5933
  updated = update;
@@ -5908,13 +5937,15 @@ class EditorView {
5908
5937
  if (!update.empty) {
5909
5938
  this.updatePlugins(update);
5910
5939
  this.inputState.update(update);
5940
+ this.updateAttrs();
5941
+ redrawn = this.docView.update(update);
5911
5942
  }
5912
- this.updateAttrs();
5913
- let redrawn = changed > 0 && this.docView.update(update);
5914
5943
  for (let i = 0; i < measuring.length; i++)
5915
5944
  if (measured[i] != BadMeasure) {
5916
5945
  try {
5917
- measuring[i].write(measured[i], this);
5946
+ let m = measuring[i];
5947
+ if (m.write)
5948
+ m.write(measured[i], this);
5918
5949
  }
5919
5950
  catch (e) {
5920
5951
  logException(this.state, e);
@@ -5924,8 +5955,8 @@ class EditorView {
5924
5955
  this.docView.scrollIntoView(this.viewState.scrollTarget);
5925
5956
  this.viewState.scrollTarget = null;
5926
5957
  }
5927
- if (changed)
5928
- this.docView.updateSelection(redrawn);
5958
+ if (redrawn)
5959
+ this.docView.updateSelection(true);
5929
5960
  if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to && this.measureRequests.length == 0)
5930
5961
  break;
5931
5962
  }
@@ -5947,7 +5978,7 @@ class EditorView {
5947
5978
  this.state.facet(theme);
5948
5979
  }
5949
5980
  updateAttrs() {
5950
- let editorAttrs = combineAttrs(this.state.facet(editorAttributes), {
5981
+ let editorAttrs = attrsFromFacet(this, editorAttributes, {
5951
5982
  class: "cm-editor" + (this.hasFocus ? " cm-focused " : " ") + this.themeClasses
5952
5983
  });
5953
5984
  let contentAttrs = {
@@ -5963,7 +5994,7 @@ class EditorView {
5963
5994
  };
5964
5995
  if (this.state.readOnly)
5965
5996
  contentAttrs["aria-readonly"] = "true";
5966
- combineAttrs(this.state.facet(contentAttributes), contentAttrs);
5997
+ attrsFromFacet(this, contentAttributes, contentAttrs);
5967
5998
  this.observer.ignore(() => {
5968
5999
  updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs);
5969
6000
  updateAttrs(this.dom, this.editorAttrs, editorAttrs);
@@ -6032,10 +6063,24 @@ class EditorView {
6032
6063
  the return value of this method.
6033
6064
  */
6034
6065
  plugin(plugin) {
6035
- for (let inst of this.plugins)
6036
- if (inst.spec == plugin)
6037
- return inst.update(this).value;
6038
- return null;
6066
+ let known = this.pluginMap.get(plugin);
6067
+ if (known === undefined || known && known.spec != plugin)
6068
+ this.pluginMap.set(plugin, known = this.plugins.find(p => p.spec == plugin) || null);
6069
+ return known && known.update(this).value;
6070
+ }
6071
+ /**
6072
+ The top position of the document, in screen coordinates. This
6073
+ may be negative when the editor is scrolled down. Points
6074
+ directly to the top of the first line, not above the padding.
6075
+ */
6076
+ get documentTop() {
6077
+ return this.contentDOM.getBoundingClientRect().top + this.viewState.paddingTop;
6078
+ }
6079
+ /**
6080
+ Reports the padding above and below the document.
6081
+ */
6082
+ get documentPadding() {
6083
+ return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom };
6039
6084
  }
6040
6085
  /**
6041
6086
  Find the line or block widget at the given vertical position.
@@ -6047,10 +6092,21 @@ class EditorView {
6047
6092
  position, or a precomputed document top
6048
6093
  (`view.contentDOM.getBoundingClientRect().top`) to limit layout
6049
6094
  queries.
6095
+
6096
+ *Deprecated: use `blockAtHeight` instead.*
6050
6097
  */
6051
6098
  blockAtHeight(height, docTop) {
6099
+ let top = ensureTop(docTop, this);
6100
+ return this.elementAtHeight(height - top).moveY(top);
6101
+ }
6102
+ /**
6103
+ Find the text line or block widget at the given vertical
6104
+ position (which is interpreted as relative to the [top of the
6105
+ document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)
6106
+ */
6107
+ elementAtHeight(height) {
6052
6108
  this.readMeasured();
6053
- return this.viewState.blockAtHeight(height, ensureTop(docTop, this.contentDOM));
6109
+ return this.viewState.elementAtHeight(height);
6054
6110
  }
6055
6111
  /**
6056
6112
  Find information for the visual line (see
@@ -6062,20 +6118,43 @@ class EditorView {
6062
6118
  Defaults to treating `height` as a screen position. See
6063
6119
  [`blockAtHeight`](https://codemirror.net/6/docs/ref/#view.EditorView.blockAtHeight) for the
6064
6120
  interpretation of the `docTop` parameter.
6121
+
6122
+ *Deprecated: use `lineBlockAtHeight` instead.*
6065
6123
  */
6066
6124
  visualLineAtHeight(height, docTop) {
6125
+ let top = ensureTop(docTop, this);
6126
+ return this.lineBlockAtHeight(height - top).moveY(top);
6127
+ }
6128
+ /**
6129
+ Find the line block (see
6130
+ [`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) at the given
6131
+ height.
6132
+ */
6133
+ lineBlockAtHeight(height) {
6067
6134
  this.readMeasured();
6068
- return this.viewState.lineAtHeight(height, ensureTop(docTop, this.contentDOM));
6135
+ return this.viewState.lineBlockAtHeight(height);
6069
6136
  }
6070
6137
  /**
6071
6138
  Iterate over the height information of the visual lines in the
6072
6139
  viewport. The heights of lines are reported relative to the
6073
6140
  given document top, which defaults to the screen position of the
6074
6141
  document (forcing a layout).
6142
+
6143
+ *Deprecated: use `viewportLineBlocks` instead.*
6075
6144
  */
6076
6145
  viewportLines(f, docTop) {
6077
- let { from, to } = this.viewport;
6078
- this.viewState.forEachLine(from, to, f, ensureTop(docTop, this.contentDOM));
6146
+ let top = ensureTop(docTop, this);
6147
+ for (let line of this.viewportLineBlocks)
6148
+ f(line.moveY(top));
6149
+ }
6150
+ /**
6151
+ Get the extent and vertical position of all [line
6152
+ blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions
6153
+ are relative to the [top of the
6154
+ document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop);
6155
+ */
6156
+ get viewportLineBlocks() {
6157
+ return this.viewState.viewportLines;
6079
6158
  }
6080
6159
  /**
6081
6160
  Find the extent and height of the visual line (a range delimited
@@ -6086,9 +6165,22 @@ class EditorView {
6086
6165
  argument, which defaults to 0 for this method. You can pass
6087
6166
  `view.contentDOM.getBoundingClientRect().top` here to get screen
6088
6167
  coordinates.
6168
+
6169
+ *Deprecated: use `lineBlockAt` instead.*
6089
6170
  */
6090
6171
  visualLineAt(pos, docTop = 0) {
6091
- return this.viewState.lineAt(pos, docTop);
6172
+ return this.lineBlockAt(pos).moveY(docTop + this.viewState.paddingTop);
6173
+ }
6174
+ /**
6175
+ Find the line block around the given document position. A line
6176
+ block is a range delimited on both sides by either a
6177
+ non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range) line breaks, or the
6178
+ start/end of the document. It will usually just hold a line of
6179
+ text, but may be broken into multiple textblocks by block
6180
+ widgets.
6181
+ */
6182
+ lineBlockAt(pos) {
6183
+ return this.viewState.lineBlockAt(pos);
6092
6184
  }
6093
6185
  /**
6094
6186
  The editor's total content height.
@@ -6421,8 +6513,9 @@ search match).
6421
6513
  EditorView.announce = state.StateEffect.define();
6422
6514
  // Maximum line length for which we compute accurate bidi info
6423
6515
  const MaxBidiLine = 4096;
6424
- function ensureTop(given, dom) {
6425
- return given == null ? dom.getBoundingClientRect().top : given;
6516
+ // FIXME remove this and its callers on next breaking release
6517
+ function ensureTop(given, view) {
6518
+ return (given == null ? view.contentDOM.getBoundingClientRect().top : given) + view.viewState.paddingTop;
6426
6519
  }
6427
6520
  let resizeDebounce = -1;
6428
6521
  function ensureGlobalHandler() {
@@ -6460,6 +6553,14 @@ class CachedOrder {
6460
6553
  return result;
6461
6554
  }
6462
6555
  }
6556
+ function attrsFromFacet(view, facet, base) {
6557
+ for (let sources = view.state.facet(facet), i = sources.length - 1; i >= 0; i--) {
6558
+ let source = sources[i], value = typeof source == "function" ? source(view) : source;
6559
+ if (value)
6560
+ combineAttrs(value, base);
6561
+ }
6562
+ return base;
6563
+ }
6463
6564
 
6464
6565
  const currentPlatform = browser.mac ? "mac" : browser.windows ? "win" : browser.linux ? "linux" : "key";
6465
6566
  function normalizeKeyName(name, platform) {
@@ -6773,7 +6874,7 @@ function wrappedLine(view, pos, inside) {
6773
6874
  type: exports.BlockType.Text };
6774
6875
  }
6775
6876
  function blockAt(view, pos) {
6776
- let line = view.visualLineAt(pos);
6877
+ let line = view.lineBlockAt(pos);
6777
6878
  if (Array.isArray(line.type))
6778
6879
  for (let l of line.type) {
6779
6880
  if (l.to > pos || l.to == pos && (l.to == line.to || l.type == exports.BlockType.Text))
@@ -7112,35 +7213,29 @@ class TabWidget extends WidgetType {
7112
7213
  }
7113
7214
 
7114
7215
  const plugin = ViewPlugin.fromClass(class {
7115
- constructor(view) {
7116
- this.height = -1;
7117
- this.measure = {
7118
- read: view => Math.max(0, view.scrollDOM.clientHeight - view.defaultLineHeight),
7119
- write: (value, view) => {
7120
- if (Math.abs(value - this.height) > 1) {
7121
- this.height = value;
7122
- view.contentDOM.style.paddingBottom = value + "px";
7123
- }
7124
- }
7125
- };
7126
- view.requestMeasure(this.measure);
7216
+ constructor() {
7217
+ this.height = 1000;
7218
+ this.attrs = { style: "padding-bottom: 1000px" };
7127
7219
  }
7128
7220
  update(update) {
7129
- if (update.geometryChanged)
7130
- update.view.requestMeasure(this.measure);
7221
+ let height = update.view.viewState.editorHeight - update.view.defaultLineHeight;
7222
+ if (height != this.height) {
7223
+ this.height = height;
7224
+ this.attrs = { style: `padding-bottom: ${height}px` };
7225
+ }
7131
7226
  }
7132
7227
  });
7133
7228
  /**
7134
- Returns a plugin that makes sure the content has a bottom margin
7135
- equivalent to the height of the editor, minus one line height, so
7136
- that every line in the document can be scrolled to the top of the
7137
- editor.
7229
+ Returns an extension that makes sure the content has a bottom
7230
+ margin equivalent to the height of the editor, minus one line
7231
+ height, so that every line in the document can be scrolled to the
7232
+ top of the editor.
7138
7233
 
7139
7234
  This is only meaningful when the editor is scrollable, and should
7140
7235
  not be enabled in editors that take the size of their content.
7141
7236
  */
7142
7237
  function scrollPastEnd() {
7143
- return plugin;
7238
+ return [plugin, contentAttributes.of(view => { var _a; return ((_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.attrs) || null; })];
7144
7239
  }
7145
7240
 
7146
7241
  /**
@@ -7164,7 +7259,7 @@ const activeLineHighlighter = ViewPlugin.fromClass(class {
7164
7259
  for (let r of view.state.selection.ranges) {
7165
7260
  if (!r.empty)
7166
7261
  return Decoration.none;
7167
- let line = view.visualLineAt(r.head);
7262
+ let line = view.lineBlockAt(r.head);
7168
7263
  if (line.from > lastLineStart) {
7169
7264
  deco.push(lineDeco.range(line.from));
7170
7265
  lastLineStart = line.from;