LavaUI docs

class EditorController

Swift

final class EditorController

A code editor: line-number gutter, current-line highlight, rule-based syntax colouring, and find-match highlighting.

Everything about the buffer — cursor, selection, undo, wrapping, grapheme correctness — is TextEditingState, unchanged and already tested. This type is presentation plus a gutter, which is why it is a component rather than a rewrite of TextField.

Sources/LavaUI/EditorView.swift:148

Constructors

init()

Not documented.

Sources/LavaUI/EditorView.swift:157

Methods

func metrics() -> (bytes: Int, lines: Int)?

How many logical lines the mounted editor is showing, and how many bytes that answer was taken from.

For a status bar. The editor has counted the lines already — it needs the same number for the gutter — and a caller that recounts is scanning a multi-megabyte buffer to learn something a few pointers away. The byte count comes back with it because the caller has to check: during a document switch the editor still holds the outgoing buffer for a frame, and a status bar that believed it would flash the wrong number.

Nil when no editor is mounted.

Sources/LavaUI/EditorView.swift:234

func position() -> EditorPosition?

Where the editor is right now, or nil if it is not mounted.

Sources/LavaUI/EditorView.swift:190

@discardableResult func replace(_ ranges: [Range<Int>], with replacement: String) -> Int

Replaces ranges — character offsets, as TextSearch.matches gives them — with replacement, and returns how many were applied. Zero if the editor is not mounted.

This exists rather than leaving the app to rewrite the bound String itself, because doing it through the editor is what makes it one undo step, keeps the caret and the row table consistent with the new buffer, and redraws once instead of per match.

Ranges must come from the buffer as it is now. A TextSearch from before an edit holds offsets into a document that no longer exists — re-run find first, which is what TextSearch is built to expect.

Sources/LavaUI/EditorView.swift:205

@discardableResult func replaceAll(_ search: TextSearch, with replacement: String) -> Int

Replaces every match search found. Returns how many.

Sources/LavaUI/EditorView.swift:219

@discardableResult func replaceCurrent(_ search: TextSearch, with replacement: String) -> Bool

Replaces the one match search currently sits on. false when there is no current match, or the editor is not mounted.

Sources/LavaUI/EditorView.swift:212

func restore(_ position: EditorPosition)

Puts the editor back at position on its next reconcile.

Deliberately never immediate. The caller for this is a document switch, and at the moment of the switch the editor still holds the outgoing buffer — applying an offset from the incoming one would clamp it against the wrong length and scroll the document being left. Deferring to the pass that installs the new text is the only point at which the position means what it says.

Sources/LavaUI/EditorView.swift:244

func reveal(line: Int)

Select and reveal a one-based physical line. If the editor is not mounted yet (for example inside a collapsed disclosure), the request is retained and consumed when it mounts.

Sources/LavaUI/EditorView.swift:162

@discardableResult func reveal(range: Range<Int>) -> Bool

Selects a character range and scrolls it into view.

The reason this is not restore(_:) with the offsets filled in: an EditorPosition carries a scroll offset, so restoring one moves the selection to somewhere the editor is not looking. That is right for coming back to a document — the whole point is to land where you were — and wrong for a search hit, where the caller knows the offsets and has no idea what scroll they correspond to. Only the editor can answer that, because only the editor knows how the text is currently broken into rows.

Immediate rather than deferred, and false when the editor is not mounted — a caller stepping through matches wants to know.

Sources/LavaUI/EditorView.swift:185