Text and events
Positions
The Editor speaks in the positions of a language server: EditorPosition is { line, character }, zero-based, with character in UTF-16 code units, and EditorRange is { start, end }. positionAt(offset), offsetAt(position) and textInRange(range) convert. A position past the end of its line or of the document lands on the end.
Mount options and revealLine count lines from one, like a person does. Everything else counts from zero.
Replacing the text
setText(text) is for a change from outside, such as a reload after the file changed on disk or an edit in another view of the same file. It applies only the lines that differ, as one undo step with the source external, so the caret, the scroll, the folds and the decorations stay wherever the text around them did.
applyEdits(changes) replaces ranges of the current text at once, as one undo step. Every range is in the text before the batch. It returns false and changes nothing when the editor is read-only, the list is empty, or the ranges overlap.
// 'red blue red' becomes 'green blue green'.
editor.applyEdits([
{ range: { start: { line: 0, character: 0 }, end: { line: 0, character: 3 } }, text: 'green' },
{ range: { start: { line: 0, character: 9 }, end: { line: 0, character: 12 } }, text: 'green' }
]);The editor has no expectedRevision. Guard an answer that took a while with a tracked range.
Change events
| Event | Fires when |
|---|---|
onTextChange(listener) | The text changed, setText, undo and redo included |
onChange(listener) | The text changed through the editor itself; setText does not fire it |
onCaret(listener) | The primary caret moved, with its new position |
onSave(listener) | Mod+S was pressed in the editor |
onBlur(listener) | The focus left the editor and its own widgets |
onViewChange(listener) | The editor scrolled or changed size, so screen positions moved |
onHover(listener) | The pointer moved onto another character, with its rect, or null off the text |
Each returns a function that removes the listener. Use onChange for a dirty marker, since a reload should not mark the file dirty, and onTextChange to keep a language server in sync.
EditorTextChange has a source (input, command or external) and changes, a list of EditorContentChanges in order: each range is in the text the change before it left. That is the shape of textDocument/didChange. It is not the shape applyEdits takes, so a list from the event cannot be passed back as one batch.
Selections
getCaret() returns the primary caret. getSelection() returns the primary selection with its start before its end, and getSelections() returns all of them, the primary one last. setCaret(position, reveal?), setSelection(range, reveal?) and setSelections(ranges, reveal?) replace them and scroll the primary one into view; an empty list changes nothing.
reveal decides the scroll. relative, the default, keeps the caret in view with a line of margin. center puts a target that is out of view a third from the top and leaves one in view alone. centerDown and centerUp do the same while stepping through results in one direction. revealLine(line, reveal?) puts the caret at the start of a one-based line.
getVisibleRange() is the range of lines on screen, which a feature such as inlay hints asks about. rectAt(position) is the box of a character in page pixels, or null where the editor has no layout, and is the anchor for a popup. Place the popup again on onViewChange.
Pointer and keys
onClick(handler) sees a press of the primary button on the text before the editor does. The first handler that returns true takes it, and the caret stays where it was. EditorClick carries the position and the mod, alt and shift keys. Mod and a click is how a host follows a name to its definition.
onContextMenu(listener) reports a request for the context menu: the position, whether it is inSelection, and x and y in page pixels. The editor draws no menu and moves no caret for it. onKeyDown is on Options and keymaps.
Commands
runCommand(command) runs a command on every caret, the way its key would, and returns false when nothing changed. It takes every command of the model and the view's own: collapseRegion, expandRegion, collapseAllRegions, expandAllRegions, collapseRegionRecursively, expandRegionRecursively, foldSelection, collapseDocComments, expandDocComments, expandAllToLevel1 through expandAllToLevel5, and toggleColumnMode.
focus() puts the keyboard focus in the editor.
Tracked ranges
trackRange(range) returns an EditorTrackedRange that follows its text through every change. get() returns where the range is now, or null once an edit replaced text inside it or landed between its ends. Text inserted exactly at an end leaves it alone. A disposed range is null.
const original = editor.textInRange(range);
const tracked = editor.trackRange(range);
const answer = await askForReplacement(original);
const current = tracked.get();
if (current !== null) {
editor.applyEdits([{ range: current, text: answer }]);
}
tracked.dispose();Each tracked range costs one mapping of two offsets per change, so dispose it when the answer is in or abandoned.