@codemirror/view 6.43.12 → 6.43.13

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/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 6.43.13 (2026-09-22)
2
+
3
+ ### Bug fixes
4
+
5
+ Make `coordsAtPos` (and thus also the drawn cursor) return the outside of the line when the queried side points out of the line and there is non-dominant-direction text at that side.
6
+
7
+ `visualLineSide`, which is now deprecated because it doesn't do anything non-trivial, now just returns the logical line side, since that is actually the more correct thing to do when moving to the start or end of line.
8
+
9
+ `moveVisually` now uses positions at the logical start/end of the line to represent the first/last position in the line when the text at that side isn't int he line's dominant text direction.
10
+
1
11
  ## 6.43.12 (2026-09-15)
2
12
 
3
13
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -1273,10 +1273,12 @@ let movedOver = "";
1273
1273
  // This implementation moves strictly visually, without concern for a
1274
1274
  // traversal visiting every logical position in the string. It will
1275
1275
  // still do so for simple input, but situations like multiple isolates
1276
- // with the same level next to each other, or text going against the
1277
- // main dir at the end of the line, will make some positions
1276
+ // with the same level next to each other will make some positions
1278
1277
  // unreachable with this motion. Each visible cursor position will
1279
- // correspond to the lower-level bidi span that touches it.
1278
+ // correspond to the lower-level bidi span that touches it, except
1279
+ // positions at start/end of line, when the text there isn't in the
1280
+ // dominant direction, which will use a cursor at the start/end with
1281
+ // an an assoc pointing out of the line instead.
1280
1282
  //
1281
1283
  // The alternative would be to solve an order globally for a given
1282
1284
  // line, making sure that it includes every position, but that would
@@ -1285,8 +1287,22 @@ let movedOver = "";
1285
1287
  // people. (And would generally be a lot more complicated.)
1286
1288
  function moveVisually(line, order, dir, start, forward) {
1287
1289
  var _a;
1288
- let startIndex = start.head - line.from;
1289
- let spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc);
1290
+ if (!line.length)
1291
+ return null;
1292
+ let startIndex = start.head - line.from, spanI;
1293
+ if (start.head == line.from && start.assoc < 0) { // Start of line.
1294
+ if (!forward)
1295
+ return null;
1296
+ startIndex = order[spanI = 0].side(false, dir);
1297
+ }
1298
+ else if (start.head == line.to && start.assoc > 0) { // End of line
1299
+ if (forward)
1300
+ return null;
1301
+ startIndex = order[spanI = order.length - 1].side(true, dir);
1302
+ }
1303
+ else {
1304
+ spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc);
1305
+ }
1290
1306
  let span = order[spanI], spanEnd = span.side(forward, dir);
1291
1307
  // End of span
1292
1308
  if (startIndex == spanEnd) {
@@ -1302,8 +1318,13 @@ function moveVisually(line, order, dir, start, forward) {
1302
1318
  nextIndex = spanEnd;
1303
1319
  movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex));
1304
1320
  let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)];
1305
- if (nextSpan && nextIndex == spanEnd && nextSpan.level + (forward ? 0 : 1) < span.level)
1306
- return state.EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, nextSpan.forward(forward, dir) ? 1 : -1, nextSpan.level);
1321
+ if (nextIndex == spanEnd) {
1322
+ // End of line
1323
+ if (!nextSpan)
1324
+ return forward ? state.EditorSelection.cursor(line.to, 1) : state.EditorSelection.cursor(line.from, -1);
1325
+ if (nextSpan.level + (forward ? 0 : 1) < span.level)
1326
+ return state.EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, nextSpan.forward(forward, dir) ? 1 : -1, nextSpan.level);
1327
+ }
1307
1328
  return state.EditorSelection.cursor(nextIndex + line.from, span.forward(forward, dir) ? -1 : 1, span.level);
1308
1329
  }
1309
1330
  function autoDirection(text, from, to) {
@@ -3678,9 +3699,6 @@ function moveToLineBoundary(view, start, forward, includeWrap) {
3678
3699
  if (pos != null)
3679
3700
  return state.EditorSelection.cursor(pos, forward ? -1 : 1);
3680
3701
  }
3681
- let line = view.state.doc.lineAt(start.head);
3682
- if (forward ? line.to == block.to : line.from == block.from)
3683
- return view.visualLineSide(line, forward);
3684
3702
  return state.EditorSelection.cursor(forward ? block.to : block.from, forward ? -1 : 1);
3685
3703
  }
3686
3704
  function moveByChar(view, start, forward, by) {
@@ -3694,7 +3712,7 @@ function moveByChar(view, start, forward, by) {
3694
3712
  char = "\n";
3695
3713
  line = view.state.doc.line(line.number + (forward ? 1 : -1));
3696
3714
  spans = view.bidiSpans(line);
3697
- next = view.visualLineSide(line, !forward);
3715
+ next = forward ? state.EditorSelection.cursor(line.from, -1) : state.EditorSelection.cursor(line.to, 1);
3698
3716
  }
3699
3717
  if (!check) {
3700
3718
  if (!by)
@@ -4482,7 +4500,9 @@ function selectionFromPoints(points, base) {
4482
4500
  if (points.length == 0)
4483
4501
  return null;
4484
4502
  let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
4485
- return anchor > -1 && head > -1 ? state.EditorSelection.single(anchor + base, head + base) : null;
4503
+ return anchor < 0 || head < 0 ? null
4504
+ : anchor == head ? state.EditorSelection.create([state.EditorSelection.cursor(head + base, -1)])
4505
+ : state.EditorSelection.single(anchor + base, head + base);
4486
4506
  }
4487
4507
  function sameSelPos(selection, range) {
4488
4508
  return range.head == selection.main.head && range.anchor == selection.main.anchor;
@@ -4634,8 +4654,9 @@ class InputState {
4634
4654
  if (mods.shiftKey && browser.ios && !/^(off|none)$/.test(this.view.contentDOM.autocapitalize) &&
4635
4655
  iosVirtualKeyboardOpen(this.view.win))
4636
4656
  mods.shiftKey = false;
4637
- this.pendingIOSKey = { key: event.key, keyCode: event.keyCode, mods };
4638
- setTimeout(() => this.flushIOSKey(), 50);
4657
+ let pending = this.pendingIOSKey = { key: event.key, keyCode: event.keyCode, mods };
4658
+ setTimeout(() => { if (this.pendingIOSKey == pending)
4659
+ this.flushIOSKey(); }, 50);
4639
4660
  return true;
4640
4661
  }
4641
4662
  if (event.keyCode != 229)
@@ -4924,14 +4945,14 @@ function doPaste(view, input) {
4924
4945
  lastLine = line.from;
4925
4946
  let insert = state$1.toText((byLine ? text.line(i++).text : input) + state$1.lineBreak);
4926
4947
  return { changes: { from: line.from, insert },
4927
- range: state.EditorSelection.cursor(range.from + insert.length) };
4948
+ range: state.EditorSelection.cursor(range.from + insert.length, -1) };
4928
4949
  });
4929
4950
  }
4930
4951
  else if (byLine) {
4931
4952
  changes = state$1.changeByRange(range => {
4932
4953
  let line = text.line(i++);
4933
4954
  return { changes: { from: range.from, to: range.to, insert: line.text },
4934
- range: state.EditorSelection.cursor(range.from + line.length) };
4955
+ range: state.EditorSelection.cursor(range.from + line.length, -1) };
4935
4956
  });
4936
4957
  }
4937
4958
  else {
@@ -5628,13 +5649,13 @@ class HeightMap {
5628
5649
  after += next.size;
5629
5650
  }
5630
5651
  }
5631
- let brk = 0;
5652
+ let brk = false;
5632
5653
  if (nodes[i - 1] == null) {
5633
- brk = 1;
5654
+ brk = true;
5634
5655
  i--;
5635
5656
  }
5636
5657
  else if (nodes[i] == null) {
5637
- brk = 1;
5658
+ brk = true;
5638
5659
  j++;
5639
5660
  }
5640
5661
  return new HeightMapBranch(HeightMap.of(nodes.slice(0, i)), brk, HeightMap.of(nodes.slice(j)));
@@ -5863,12 +5884,14 @@ class HeightMapGap extends HeightMap {
5863
5884
  }
5864
5885
  class HeightMapBranch extends HeightMap {
5865
5886
  constructor(left, brk, right) {
5866
- super(left.length + brk + right.length, left.height + right.height, brk | (left.outdated || right.outdated ? 2 /* Flag.Outdated */ : 0));
5887
+ super(left.length + (brk ? 1 : 0) + right.length, left.height + right.height, (brk ? 1 /* Flag.Break */ : 0) | (left.outdated || right.outdated ? 2 /* Flag.Outdated */ : 0));
5867
5888
  this.left = left;
5868
5889
  this.right = right;
5869
5890
  this.size = left.size + right.size;
5870
5891
  }
5871
- get break() { return this.flags & 1 /* Flag.Break */; }
5892
+ // Returns 1 if there is a line break between this.left and
5893
+ // this.right, 0 otherwise.
5894
+ get break() { return (this.flags & 1 /* Flag.Break */); }
5872
5895
  blockAt(height, oracle, top, offset) {
5873
5896
  let mid = top + this.left.height;
5874
5897
  return height < mid ? this.left.blockAt(height, oracle, top, offset)
@@ -5898,11 +5921,11 @@ class HeightMapBranch extends HeightMap {
5898
5921
  else {
5899
5922
  let mid = this.lineAt(rightOffset, QueryType.ByPos, oracle, top, offset);
5900
5923
  if (from < mid.from)
5901
- this.left.forEachLine(from, mid.from - 1, oracle, top, offset, f);
5924
+ this.left.forEachLine(from, Math.min(to, mid.from - 1), oracle, top, offset, f);
5902
5925
  if (mid.to >= from && mid.from <= to)
5903
5926
  f(mid);
5904
5927
  if (to > mid.to)
5905
- this.right.forEachLine(mid.to + 1, to, oracle, rightTop, rightOffset, f);
5928
+ this.right.forEachLine(Math.max(from, mid.to + 1), to, oracle, rightTop, rightOffset, f);
5906
5929
  }
5907
5930
  }
5908
5931
  replace(from, to, nodes) {
@@ -8471,15 +8494,11 @@ class EditorView {
8471
8494
  return skipAtoms(this, start, moveByChar(this, start, forward, initial => byGroup(this, start.head, initial)));
8472
8495
  }
8473
8496
  /**
8474
- Get the cursor position visually at the start or end of a line.
8475
- Note that this may differ from the _logical_ position at its
8476
- start or end (which is simply at `line.from`/`line.to`) if text
8477
- at the start or end goes against the line's base text direction.
8497
+ **\[DEPRECATED]** Get the cursor position visually at the start
8498
+ or end of a line.
8478
8499
  */
8479
8500
  visualLineSide(line, end) {
8480
- let order = this.bidiSpans(line), dir = this.textDirectionAt(line.from);
8481
- let span = order[end ? order.length - 1 : 0];
8482
- return state.EditorSelection.cursor(span.side(end, dir) + line.from, span.forward(!end, dir) ? 1 : -1);
8501
+ return end ? state.EditorSelection.cursor(line.to, 1) : state.EditorSelection.cursor(line.from, -1);
8483
8502
  }
8484
8503
  /**
8485
8504
  Move to the next line boundary in the given direction. If
@@ -8548,6 +8567,20 @@ class EditorView {
8548
8567
  this.readMeasured();
8549
8568
  let line = this.state.doc.lineAt(pos), order = this.bidiSpans(line);
8550
8569
  let span = order[BidiSpan.find(order, pos - line.from, -1, side)];
8570
+ // For positions at start/end of line, if the side points out of
8571
+ // the line and the text there isn't in the dominant dir, return
8572
+ // the position of the outermost character on the line.
8573
+ if (line.length && (pos == line.from && side < 0 || pos == line.to && side > 0) &&
8574
+ span.dir != this.textDirectionAt(line.from)) {
8575
+ if (pos == line.to) {
8576
+ pos = line.from + span.from;
8577
+ side = 1;
8578
+ }
8579
+ else {
8580
+ pos = line.from + span.to;
8581
+ side = -1;
8582
+ }
8583
+ }
8551
8584
  return this.docView.coordsAt(pos, side, span.dir == exports.Direction.RTL);
8552
8585
  }
8553
8586
  /**
package/dist/index.d.cts CHANGED
@@ -959,10 +959,8 @@ declare class EditorView {
959
959
  */
960
960
  moveByGroup(start: SelectionRange, forward: boolean): SelectionRange;
961
961
  /**
962
- Get the cursor position visually at the start or end of a line.
963
- Note that this may differ from the _logical_ position at its
964
- start or end (which is simply at `line.from`/`line.to`) if text
965
- at the start or end goes against the line's base text direction.
962
+ **\[DEPRECATED]** Get the cursor position visually at the start
963
+ or end of a line.
966
964
  */
967
965
  visualLineSide(line: Line, end: boolean): SelectionRange;
968
966
  /**
package/dist/index.d.ts CHANGED
@@ -959,10 +959,8 @@ declare class EditorView {
959
959
  */
960
960
  moveByGroup(start: SelectionRange, forward: boolean): SelectionRange;
961
961
  /**
962
- Get the cursor position visually at the start or end of a line.
963
- Note that this may differ from the _logical_ position at its
964
- start or end (which is simply at `line.from`/`line.to`) if text
965
- at the start or end goes against the line's base text direction.
962
+ **\[DEPRECATED]** Get the cursor position visually at the start
963
+ or end of a line.
966
964
  */
967
965
  visualLineSide(line: Line, end: boolean): SelectionRange;
968
966
  /**
package/dist/index.js CHANGED
@@ -1269,10 +1269,12 @@ let movedOver = "";
1269
1269
  // This implementation moves strictly visually, without concern for a
1270
1270
  // traversal visiting every logical position in the string. It will
1271
1271
  // still do so for simple input, but situations like multiple isolates
1272
- // with the same level next to each other, or text going against the
1273
- // main dir at the end of the line, will make some positions
1272
+ // with the same level next to each other will make some positions
1274
1273
  // unreachable with this motion. Each visible cursor position will
1275
- // correspond to the lower-level bidi span that touches it.
1274
+ // correspond to the lower-level bidi span that touches it, except
1275
+ // positions at start/end of line, when the text there isn't in the
1276
+ // dominant direction, which will use a cursor at the start/end with
1277
+ // an an assoc pointing out of the line instead.
1276
1278
  //
1277
1279
  // The alternative would be to solve an order globally for a given
1278
1280
  // line, making sure that it includes every position, but that would
@@ -1281,8 +1283,22 @@ let movedOver = "";
1281
1283
  // people. (And would generally be a lot more complicated.)
1282
1284
  function moveVisually(line, order, dir, start, forward) {
1283
1285
  var _a;
1284
- let startIndex = start.head - line.from;
1285
- let spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc);
1286
+ if (!line.length)
1287
+ return null;
1288
+ let startIndex = start.head - line.from, spanI;
1289
+ if (start.head == line.from && start.assoc < 0) { // Start of line.
1290
+ if (!forward)
1291
+ return null;
1292
+ startIndex = order[spanI = 0].side(false, dir);
1293
+ }
1294
+ else if (start.head == line.to && start.assoc > 0) { // End of line
1295
+ if (forward)
1296
+ return null;
1297
+ startIndex = order[spanI = order.length - 1].side(true, dir);
1298
+ }
1299
+ else {
1300
+ spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc);
1301
+ }
1286
1302
  let span = order[spanI], spanEnd = span.side(forward, dir);
1287
1303
  // End of span
1288
1304
  if (startIndex == spanEnd) {
@@ -1298,8 +1314,13 @@ function moveVisually(line, order, dir, start, forward) {
1298
1314
  nextIndex = spanEnd;
1299
1315
  movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex));
1300
1316
  let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)];
1301
- if (nextSpan && nextIndex == spanEnd && nextSpan.level + (forward ? 0 : 1) < span.level)
1302
- return EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, nextSpan.forward(forward, dir) ? 1 : -1, nextSpan.level);
1317
+ if (nextIndex == spanEnd) {
1318
+ // End of line
1319
+ if (!nextSpan)
1320
+ return forward ? EditorSelection.cursor(line.to, 1) : EditorSelection.cursor(line.from, -1);
1321
+ if (nextSpan.level + (forward ? 0 : 1) < span.level)
1322
+ return EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, nextSpan.forward(forward, dir) ? 1 : -1, nextSpan.level);
1323
+ }
1303
1324
  return EditorSelection.cursor(nextIndex + line.from, span.forward(forward, dir) ? -1 : 1, span.level);
1304
1325
  }
1305
1326
  function autoDirection(text, from, to) {
@@ -3674,9 +3695,6 @@ function moveToLineBoundary(view, start, forward, includeWrap) {
3674
3695
  if (pos != null)
3675
3696
  return EditorSelection.cursor(pos, forward ? -1 : 1);
3676
3697
  }
3677
- let line = view.state.doc.lineAt(start.head);
3678
- if (forward ? line.to == block.to : line.from == block.from)
3679
- return view.visualLineSide(line, forward);
3680
3698
  return EditorSelection.cursor(forward ? block.to : block.from, forward ? -1 : 1);
3681
3699
  }
3682
3700
  function moveByChar(view, start, forward, by) {
@@ -3690,7 +3708,7 @@ function moveByChar(view, start, forward, by) {
3690
3708
  char = "\n";
3691
3709
  line = view.state.doc.line(line.number + (forward ? 1 : -1));
3692
3710
  spans = view.bidiSpans(line);
3693
- next = view.visualLineSide(line, !forward);
3711
+ next = forward ? EditorSelection.cursor(line.from, -1) : EditorSelection.cursor(line.to, 1);
3694
3712
  }
3695
3713
  if (!check) {
3696
3714
  if (!by)
@@ -4478,7 +4496,9 @@ function selectionFromPoints(points, base) {
4478
4496
  if (points.length == 0)
4479
4497
  return null;
4480
4498
  let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
4481
- return anchor > -1 && head > -1 ? EditorSelection.single(anchor + base, head + base) : null;
4499
+ return anchor < 0 || head < 0 ? null
4500
+ : anchor == head ? EditorSelection.create([EditorSelection.cursor(head + base, -1)])
4501
+ : EditorSelection.single(anchor + base, head + base);
4482
4502
  }
4483
4503
  function sameSelPos(selection, range) {
4484
4504
  return range.head == selection.main.head && range.anchor == selection.main.anchor;
@@ -4630,8 +4650,9 @@ class InputState {
4630
4650
  if (mods.shiftKey && browser.ios && !/^(off|none)$/.test(this.view.contentDOM.autocapitalize) &&
4631
4651
  iosVirtualKeyboardOpen(this.view.win))
4632
4652
  mods.shiftKey = false;
4633
- this.pendingIOSKey = { key: event.key, keyCode: event.keyCode, mods };
4634
- setTimeout(() => this.flushIOSKey(), 50);
4653
+ let pending = this.pendingIOSKey = { key: event.key, keyCode: event.keyCode, mods };
4654
+ setTimeout(() => { if (this.pendingIOSKey == pending)
4655
+ this.flushIOSKey(); }, 50);
4635
4656
  return true;
4636
4657
  }
4637
4658
  if (event.keyCode != 229)
@@ -4920,14 +4941,14 @@ function doPaste(view, input) {
4920
4941
  lastLine = line.from;
4921
4942
  let insert = state.toText((byLine ? text.line(i++).text : input) + state.lineBreak);
4922
4943
  return { changes: { from: line.from, insert },
4923
- range: EditorSelection.cursor(range.from + insert.length) };
4944
+ range: EditorSelection.cursor(range.from + insert.length, -1) };
4924
4945
  });
4925
4946
  }
4926
4947
  else if (byLine) {
4927
4948
  changes = state.changeByRange(range => {
4928
4949
  let line = text.line(i++);
4929
4950
  return { changes: { from: range.from, to: range.to, insert: line.text },
4930
- range: EditorSelection.cursor(range.from + line.length) };
4951
+ range: EditorSelection.cursor(range.from + line.length, -1) };
4931
4952
  });
4932
4953
  }
4933
4954
  else {
@@ -5623,13 +5644,13 @@ class HeightMap {
5623
5644
  after += next.size;
5624
5645
  }
5625
5646
  }
5626
- let brk = 0;
5647
+ let brk = false;
5627
5648
  if (nodes[i - 1] == null) {
5628
- brk = 1;
5649
+ brk = true;
5629
5650
  i--;
5630
5651
  }
5631
5652
  else if (nodes[i] == null) {
5632
- brk = 1;
5653
+ brk = true;
5633
5654
  j++;
5634
5655
  }
5635
5656
  return new HeightMapBranch(HeightMap.of(nodes.slice(0, i)), brk, HeightMap.of(nodes.slice(j)));
@@ -5858,12 +5879,14 @@ class HeightMapGap extends HeightMap {
5858
5879
  }
5859
5880
  class HeightMapBranch extends HeightMap {
5860
5881
  constructor(left, brk, right) {
5861
- super(left.length + brk + right.length, left.height + right.height, brk | (left.outdated || right.outdated ? 2 /* Flag.Outdated */ : 0));
5882
+ super(left.length + (brk ? 1 : 0) + right.length, left.height + right.height, (brk ? 1 /* Flag.Break */ : 0) | (left.outdated || right.outdated ? 2 /* Flag.Outdated */ : 0));
5862
5883
  this.left = left;
5863
5884
  this.right = right;
5864
5885
  this.size = left.size + right.size;
5865
5886
  }
5866
- get break() { return this.flags & 1 /* Flag.Break */; }
5887
+ // Returns 1 if there is a line break between this.left and
5888
+ // this.right, 0 otherwise.
5889
+ get break() { return (this.flags & 1 /* Flag.Break */); }
5867
5890
  blockAt(height, oracle, top, offset) {
5868
5891
  let mid = top + this.left.height;
5869
5892
  return height < mid ? this.left.blockAt(height, oracle, top, offset)
@@ -5893,11 +5916,11 @@ class HeightMapBranch extends HeightMap {
5893
5916
  else {
5894
5917
  let mid = this.lineAt(rightOffset, QueryType.ByPos, oracle, top, offset);
5895
5918
  if (from < mid.from)
5896
- this.left.forEachLine(from, mid.from - 1, oracle, top, offset, f);
5919
+ this.left.forEachLine(from, Math.min(to, mid.from - 1), oracle, top, offset, f);
5897
5920
  if (mid.to >= from && mid.from <= to)
5898
5921
  f(mid);
5899
5922
  if (to > mid.to)
5900
- this.right.forEachLine(mid.to + 1, to, oracle, rightTop, rightOffset, f);
5923
+ this.right.forEachLine(Math.max(from, mid.to + 1), to, oracle, rightTop, rightOffset, f);
5901
5924
  }
5902
5925
  }
5903
5926
  replace(from, to, nodes) {
@@ -8466,15 +8489,11 @@ class EditorView {
8466
8489
  return skipAtoms(this, start, moveByChar(this, start, forward, initial => byGroup(this, start.head, initial)));
8467
8490
  }
8468
8491
  /**
8469
- Get the cursor position visually at the start or end of a line.
8470
- Note that this may differ from the _logical_ position at its
8471
- start or end (which is simply at `line.from`/`line.to`) if text
8472
- at the start or end goes against the line's base text direction.
8492
+ **\[DEPRECATED]** Get the cursor position visually at the start
8493
+ or end of a line.
8473
8494
  */
8474
8495
  visualLineSide(line, end) {
8475
- let order = this.bidiSpans(line), dir = this.textDirectionAt(line.from);
8476
- let span = order[end ? order.length - 1 : 0];
8477
- return EditorSelection.cursor(span.side(end, dir) + line.from, span.forward(!end, dir) ? 1 : -1);
8496
+ return end ? EditorSelection.cursor(line.to, 1) : EditorSelection.cursor(line.from, -1);
8478
8497
  }
8479
8498
  /**
8480
8499
  Move to the next line boundary in the given direction. If
@@ -8543,6 +8562,20 @@ class EditorView {
8543
8562
  this.readMeasured();
8544
8563
  let line = this.state.doc.lineAt(pos), order = this.bidiSpans(line);
8545
8564
  let span = order[BidiSpan.find(order, pos - line.from, -1, side)];
8565
+ // For positions at start/end of line, if the side points out of
8566
+ // the line and the text there isn't in the dominant dir, return
8567
+ // the position of the outermost character on the line.
8568
+ if (line.length && (pos == line.from && side < 0 || pos == line.to && side > 0) &&
8569
+ span.dir != this.textDirectionAt(line.from)) {
8570
+ if (pos == line.to) {
8571
+ pos = line.from + span.from;
8572
+ side = 1;
8573
+ }
8574
+ else {
8575
+ pos = line.from + span.to;
8576
+ side = -1;
8577
+ }
8578
+ }
8546
8579
  return this.docView.coordsAt(pos, side, span.dir == Direction.RTL);
8547
8580
  }
8548
8581
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.43.12",
3
+ "version": "6.43.13",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",