Example: Selection
The editor's state always holds at least one selection range. When
multiple
selections
are enabled, it may have several.
Ranges consist of an anchor (the side that doesn't move when you
shift-select) and a head (the moving side). When those are the same,
it is a cursor selection, otherwise it is a range.
When there are multiple selection ranges, one of them will be considered
the main range (this is also the one that the native selection will
reflect). If you have an editor state, you can find the main selection
range with state.selection.main
. It is a
SelectionRange
object with anchor
and
head
properties (and also from
/to
if you're interested in the
minimum or maximum side) holding document positions.
Like any editor state change, moving the selection is done by
dispatching a transaction. For example, this moves the cursor to the
start of the document:
view.dispatch({selection: {anchor: 0}})
The selection
property on a
transaction spec takes either a shorthand {anchor: number, head?: number}
object, or a full
EditorSelection
instance.
This code creates two selection ranges selecting the 4th and 6th
character in the editor, and a cursor selection at 8. It makes the
second range the primary one.
view.dispatch({
selection: EditorSelection.create([
EditorSelection.range(4, 5),
EditorSelection.range(6, 7),
EditorSelection.cursor(8)
], 1)
})
When a transaction makes a document change as well as setting the
selection, the new selection should point into the document as it is
after the change. For example, here's how you could insert an
asterisk at position 10 and then put the cursor after it.
view.dispatch({
changes: {from: 10, insert: "*"},
selection: {anchor: 11}
})
When writing commands that act on the selection, you have to take some
care to support multiple ranges. Helper methods like
replaceSelection
(which
replaces all ranges with the same text) and
changeByRange
(which allows you
to specify changes per range and merges them into a single transaction
spec) can be useful.