Skip to content

Commit 7978b40

Browse files
thomasjmmarijnh
authored andcommitted
Add selectLeft/selectRight marker options
1 parent 7886f7f commit 7978b40

File tree

3 files changed

+91
-12
lines changed

3 files changed

+91
-12
lines changed

doc/manual.html

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,13 +1674,21 @@ <h3 id="api_marker">Text-marking methods</h3>
16741674
<dt id="mark_inclusiveRight"><code><strong>inclusiveRight</strong>: boolean</code></dt>
16751675
<dd>Like <code>inclusiveLeft</code>,
16761676
but for the right side.</dd>
1677+
<dt id="mark_selectLeft"><code><strong>selectLeft</strong>: boolean</code></dt>
1678+
<dd>For atomic ranges, determines whether the cursor is allowed
1679+
to be placed directly to the left of the range. Has no effect on
1680+
non-atomic ranges.</dd>
1681+
<dt id="mark_selectRight"><code><strong>selectRight</strong>: boolean</code></dt>
1682+
<dd>Like <code>selectLeft</code>,
1683+
but for the right side.</dd>
16771684
<dt id="mark_atomic"><code><strong>atomic</strong>: boolean</code></dt>
16781685
<dd>Atomic ranges act as a single unit when cursor movement is
16791686
concerned—i.e. it is impossible to place the cursor inside of
1680-
them. In atomic ranges, <code>inclusiveLeft</code>
1681-
and <code>inclusiveRight</code> have a different meaning—they
1682-
will prevent the cursor from being placed respectively
1683-
directly before and directly after the range.</dd>
1687+
them. You can control whether the cursor is allowed to be placed
1688+
directly before or after them using <code>selectLeft</code>
1689+
or <code>selectRight</code>. If <code>selectLeft</code>
1690+
(or right) is not provided, then <code>inclusiveLeft</code> (or
1691+
right) will control this behavior.</dd>
16841692
<dt id="mark_collapsed"><code><strong>collapsed</strong>: boolean</code></dt>
16851693
<dd>Collapsed ranges do not show up in the display. Setting a
16861694
range to be collapsed will automatically make it atomic.</dd>

src/model/selection_updates.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,15 @@ function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
150150
let line = getLine(doc, pos.line)
151151
if (line.markedSpans) for (let i = 0; i < line.markedSpans.length; ++i) {
152152
let sp = line.markedSpans[i], m = sp.marker
153-
if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
154-
(sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
153+
154+
// Determine if we should prevent the cursor being placed to the left/right of an atomic marker
155+
// Historically this was determined using the inclusiveLeft/Right option, but the new way to control it
156+
// is with selectLeft/Right
157+
let preventCursorLeft = ("selectLeft" in m) ? !m.selectLeft : m.inclusiveLeft
158+
let preventCursorRight = ("selectRight" in m) ? !m.selectRight : m.inclusiveRight
159+
160+
if ((sp.from == null || (preventCursorLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
161+
(sp.to == null || (preventCursorRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
155162
if (mayClear) {
156163
signal(m, "beforeCursorEnter")
157164
if (m.explicitlyCleared) {
@@ -163,14 +170,14 @@ function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
163170

164171
if (oldPos) {
165172
let near = m.find(dir < 0 ? 1 : -1), diff
166-
if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)
173+
if (dir < 0 ? preventCursorRight : preventCursorLeft)
167174
near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null)
168175
if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
169176
return skipAtomicInner(doc, near, pos, dir, mayClear)
170177
}
171178

172179
let far = m.find(dir < 0 ? -1 : 1)
173-
if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)
180+
if (dir < 0 ? preventCursorLeft : preventCursorRight)
174181
far = movePos(doc, far, dir, far.line == pos.line ? line : null)
175182
return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
176183
}

test/test.js

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,22 +1808,77 @@ testCM("addLineClass", function(cm) {
18081808

18091809
testCM("atomicMarker", function(cm) {
18101810
addDoc(cm, 10, 10);
1811-
function atom(ll, cl, lr, cr, li, ri) {
1812-
return cm.markText(Pos(ll, cl), Pos(lr, cr),
1813-
{atomic: true, inclusiveLeft: li, inclusiveRight: ri});
1811+
1812+
function atom(ll, cl, lr, cr, li, ri, ls, rs) {
1813+
var options = {
1814+
atomic: true,
1815+
inclusiveLeft: li,
1816+
inclusiveRight: ri
1817+
};
1818+
1819+
if (ls === true || ls === false) options["selectLeft"] = ls;
1820+
if (rs === true || rs === false) options["selectRight"] = rs;
1821+
1822+
return cm.markText(Pos(ll, cl), Pos(lr, cr), options);
18141823
}
1824+
1825+
// Can cursor to the left and right of a normal marker by jumping across it
18151826
var m = atom(0, 1, 0, 5);
18161827
cm.setCursor(Pos(0, 1));
18171828
cm.execCommand("goCharRight");
18181829
eqCursorPos(cm.getCursor(), Pos(0, 5));
18191830
cm.execCommand("goCharLeft");
18201831
eqCursorPos(cm.getCursor(), Pos(0, 1));
18211832
m.clear();
1833+
1834+
// Can't cursor to the left of a marker when inclusiveLeft=true
18221835
m = atom(0, 0, 0, 5, true);
18231836
eqCursorPos(cm.getCursor(), Pos(0, 5), "pushed out");
18241837
cm.execCommand("goCharLeft");
18251838
eqCursorPos(cm.getCursor(), Pos(0, 5));
18261839
m.clear();
1840+
1841+
// Can't cursor to the left of a marker when inclusiveLeft=false and selectLeft=false
1842+
m = atom(0, 0, 0, 5, false, false, false);
1843+
cm.setCursor(Pos(0, 5));
1844+
eqCursorPos(cm.getCursor(), Pos(0, 5), "pushed out");
1845+
cm.execCommand("goCharLeft");
1846+
eqCursorPos(cm.getCursor(), Pos(0, 5));
1847+
m.clear();
1848+
1849+
// Can cursor to the left of a marker when inclusiveLeft=false and selectLeft=True
1850+
m = atom(0, 0, 0, 5, false, false, true);
1851+
cm.setCursor(Pos(0, 5));
1852+
eqCursorPos(cm.getCursor(), Pos(0, 5), "pushed out");
1853+
cm.execCommand("goCharLeft");
1854+
eqCursorPos(cm.getCursor(), Pos(0, 0));
1855+
m.clear();
1856+
1857+
// Can't cursor to the right of a marker when inclusiveRight=true
1858+
m = atom(0, 0, 0, 5, false, true);
1859+
cm.setCursor(Pos(0, 0));
1860+
eqCursorPos(cm.getCursor(), Pos(0, 0));
1861+
cm.execCommand("goCharRight");
1862+
eqCursorPos(cm.getCursor(), Pos(0, 6));
1863+
m.clear();
1864+
1865+
// Can't cursor to the right of a marker when inclusiveRight=false and selectRight=false
1866+
m = atom(0, 0, 0, 5, false, false, true, false);
1867+
cm.setCursor(Pos(0, 0));
1868+
eqCursorPos(cm.getCursor(), Pos(0, 0));
1869+
cm.execCommand("goCharRight");
1870+
eqCursorPos(cm.getCursor(), Pos(0, 6));
1871+
m.clear();
1872+
1873+
// Can cursor to the right of a marker when inclusiveRight=false and selectRight=True
1874+
m = atom(0, 0, 0, 5, false, false, true, true);
1875+
cm.setCursor(Pos(0, 0));
1876+
eqCursorPos(cm.getCursor(), Pos(0, 0));
1877+
cm.execCommand("goCharRight");
1878+
eqCursorPos(cm.getCursor(), Pos(0, 5));
1879+
m.clear();
1880+
1881+
// Can't cursor to the right of a multiline marker when inclusiveRight=true
18271882
m = atom(8, 4, 9, 10, false, true);
18281883
cm.setCursor(Pos(9, 8));
18291884
eqCursorPos(cm.getCursor(), Pos(8, 4), "set");
@@ -1834,6 +1889,9 @@ testCM("atomicMarker", function(cm) {
18341889
cm.execCommand("goCharLeft");
18351890
eqCursorPos(cm.getCursor(), Pos(8, 3, "after"));
18361891
m.clear();
1892+
1893+
// Cursor jumps across a multiline atomic marker,
1894+
// and backspace deletes the entire marker
18371895
m = atom(1, 1, 3, 8);
18381896
cm.setCursor(Pos(0, 0));
18391897
cm.setCursor(Pos(2, 0));
@@ -1848,10 +1906,16 @@ testCM("atomicMarker", function(cm) {
18481906
eqCursorPos(cm.getCursor(), Pos(3, 8));
18491907
cm.execCommand("delCharBefore");
18501908
eq(cm.getValue().length, 80, "del chunk");
1909+
m.clear();
1910+
addDoc(cm, 10, 10);
1911+
1912+
// Delete before an atomic marker deletes the entire marker
18511913
m = atom(3, 0, 5, 5);
18521914
cm.setCursor(Pos(3, 0));
18531915
cm.execCommand("delWordAfter");
1854-
eq(cm.getValue().length, 53, "del chunk");
1916+
eq(cm.getValue().length, 82, "del chunk");
1917+
m.clear();
1918+
addDoc(cm, 10, 10);
18551919
});
18561920

18571921
testCM("selectionBias", function(cm) {

0 commit comments

Comments
 (0)