#viewer/common/model

    Immutable text snapshots, readonly editor models, guides, and mutable model decorations. This is the viewer's reduced vs/editor/common/model boundary.

    flowchart TB H["host text"] -->|"normalize \r\n, \r → \n"| S["TextSnapshot<br>immutable, owns line starts"] S --> M["TextModel<br>URI, language, version, revision"] M --> D["decorations<br>interval trees"] M --> T["TokenizationTextModelPart<br>shared model state"] M --> G["GuidesTextModelPart"] M -->|"set_value replaces the whole snapshot"| S T -.->|"passive reads,<br>attachment-driven refresh"| TK["viewer/common/tokens"]

    #Text and identity

    TextSnapshot normalizes every input \r\n pair, lone \r, or \n to one \n before storage, then derives line starts from that normalized text. U+FEFF is ordinary content, U+2028/U+2029 are not line breaks, and every other UTF-16 unit (including lone surrogates) is retained exactly once. get_value, lengths, ranges, offsets, positions, provider boundaries, and content events therefore all use one coherent UTF-16 coordinate system.

    ///|
    fn doc(text : String) -> @model.TextModel raise {
    TextModel(
    @base_common.Uri::parse("file:///model-doc.mbt"),
    "model-doc.mbt",
    "moonbit",
    1,
    "rev-1",
    text,
    )
    }

    ///|
    test "every line terminator normalizes to a single \\n" {
    let model = doc("a\r\nb\rc\nd")
    debug_inspect(
    (model.get_line_count(), model.get_lines_content(), model.get_value()),
    content=(
    #|(4, ["a", "b", "c", "d"], "a\nb\nc\nd")
    ),
    )
    }

    Snapshots and models store one normalized LF representation. There is no TextDefined/CRLF read preference, BOM-preservation switch, or cached builder metadata that can disagree with the text.

    TextSnapshot owns offset/position conversion, which is the bridge between the 1-based Position space and the 0-based offset space that base/common deliberately leaves unimplemented.

    ///|
    test "offsets and positions convert through the snapshot" {
    let model = doc("let x = 1\nlet y = 2\n")
    debug_inspect(
    (
    model.get_offset_at(Position(2, 1)),
    model.get_position_at(10),
    model.get_position_at(0),
    // out-of-range input is clamped rather than raising
    model.get_position_at(9999),
    ),
    content=(
    #|(
    #| 10,
    #| { line_number: 2, column: 1 },
    #| { line_number: 1, column: 1 },
    #| { line_number: 3, column: 1 },
    #|)
    ),
    )
    }

    TextModel adds URI, display name, language id, caller-owned host version, revision, lifecycle, and a directly owned TokenizationTextModelPart. Ranges are generally clamped where Monaco throws, and the snapshot remains readable after TextModel::dispose.

    ///|
    test "reads are clamped, and the text survives disposal" {
    let model = doc("ab\ncd\n")
    let clamped = model.get_value_in_range(Range(1, 1, 99, 99))
    model.dispose()
    debug_inspect(
    (clamped, model.is_disposed(), model.get_value()),
    content=(
    #|("ab\ncd\n", true, "ab\ncd\n")
    ),
    )
    }

    Model-scoped async freshness uses physical TextModel identity plus the internal get_version_id() counter. URI, host version, revision, and decoration IDs are metadata and cannot substitute for that authority — two models can share a URI, and a host version is whatever the host says it is.

    ///|
    test "identity and version id are the freshness authority, not the URI" {
    let first = doc("one\n")
    let second = doc("two\n")
    let version_before = first.get_version_id()
    first.set_value("one changed\n")
    debug_inspect(
    (
    first.uri == second.uri,
    first.identity() == second.identity(),
    version_before,
    first.get_version_id(),
    ),
    content=(
    #|(true, false, 1, 2)
    ),
    )
    }

    set_value normalizes and replaces the complete snapshot in the same model, increments the internal version once, destroys old decorations, and fires the content-flush event using the old normalized range/length and new normalized text/EOL. There is no incremental edit/undo/redo, EOL mutation or preference or IME.

    #Words

    Word lookup delegates to the current snapshot. get_word_at_position returns None when the position is not inside a word.

    ///|
    test "word_at returns the word containing the position" {
    let model = doc("let value = 1\n")
    debug_inspect(
    (
    model.get_word_at_position(Position(1, 6)),
    model.get_word_at_position(Position(1, 4)),
    ),
    content=(
    #|(
    #| Some({ word: "value", start_column: 5, end_column: 10 }),
    #| Some({ word: "let", start_column: 1, end_column: 4 }),
    #|)
    ),
    )
    }

    #Mutable model-side state

    delta_decorations/change_decorations and the range-query APIs store regular, overview-ruler, and injected-text decorations in augmented interval trees. Decoration, token, and dispose events are part of the public model surface.

    delta_decorations is a replace operation: it takes the ids to retire and the new decorations to add, and returns the new ids. Passing [] for the old ids is a pure insert; passing [] for the new ones is a pure delete.

    ///|
    test "delta_decorations replaces one id set with another" {
    let model = doc("alpha\nbeta\ngamma\n")
    let options = @model.ModelDecorationOptions("doc-example")
    let ids = model.delta_decorations([], [
    { range: Range(1, 1, 1, 6), options, },
    { range: Range(3, 1, 3, 6), options, },
    ])
    let in_line_one = model.get_line_decorations(1).length()
    let after = model.delta_decorations(ids, [])
    debug_inspect(
    (
    ids.length(),
    in_line_one,
    after,
    model.get_decorations_in_range(model.get_full_model_range()).length(),
    ),
    content=(
    #|(2, 1, [], 0)
    ),
    )
    }

    A content flush destroys decorations, which is why a caller must not cache decoration ids across a set_value.

    ///|
    test "set_value destroys existing decorations" {
    let model = doc("alpha\nbeta\n")
    let ids = model.delta_decorations([], [
    {
    range: Range(1, 1, 1, 6),
    options: ModelDecorationOptions("doc-example"),
    },
    ])
    let before = model.get_decoration_range(ids[0]) is Some(_)
    model.set_value("replaced\n")
    debug_inspect(
    (before, model.get_decoration_range(ids[0])),
    content=(
    #|(true, None)
    ),
    )
    }

    Decorations are tracked: a query reports the decoration's current range, and stickiness decides how it behaves at its edges.

    ///|
    test "queries report the tracked range, filtered by the queried span" {
    let model = doc("alpha\nbeta\ngamma\n")
    let options = @model.ModelDecorationOptions("doc-example")
    model.delta_decorations([], [{ range: Range(2, 1, 2, 5), options, }])
    |> ignore
    debug_inspect(
    (
    model.get_decorations_in_range(Range(1, 1, 1, 6)).length(),
    model.get_decorations_in_range(Range(2, 1, 2, 5)).length(),
    model.get_decorations_in_range(Range(1, 1, 3, 6)).length(),
    ),
    content=(
    #|(0, 1, 1)
    ),
    )
    }

    GuidesTextModelPart computes indentation guides over a snapshot. Token stores, state queues, backends, attached-view aggregation, and scheduling are package-private implementations in this package. RangePriorityQueueImpl has one canonical definition here. The tokenizer backend tracks invalid end states, prioritizes attached visible ranges, yields between bounded slices, and makes stale scheduled generations inert after detach or disposal. Token lengths/offsets remain raw UTF-16 code-unit values, and theme encoding maps syntax tags directly to packed metadata.

    #Attachment and listeners

    Internal on_before_attached/on_before_detached calls maintain exact attached-view handles and select the first available scheduler for an aggregate attached epoch; final detach cancels that epoch before the scheduler is cleared. The model-owned on_did_change_attached event fires after tokenization observes only the aggregate 0 -> 1 and 1 -> 0 transitions and is released with the model.

    Attachment is an internal count, and only its edges are interesting: two views on one model do not schedule tokenization twice.

    Model listener ownership includes the token part's external token listeners alongside the model's will-dispose, decoration, attached, and content emitters. View models register the two ordered content callbacks and own the returned disposable handle; the model runs every structural callback before any outgoing callback without storing trait objects. Options, line-height, and token-derived font-decoration lanes remain N-A and have no placeholder emitters. Unexpected tokenizer failures are reported immediately through the package's host-neutral println seam, disable that support for the current reset, and leave the model live for a later reset.

    #Monaco map and boundary

    Use the pinned vscode/src/vs/editor/common/model/textModel.ts, common/model/textModelTokens.ts, common/model/tokens/{tokenizationTextModelPart,abstractSyntaxTokenBackend,tokenizerSyntaxTokenBackend,annotations}.ts, common/model.ts (IReadonlyTextBuffer), model/pieceTreeTextBuffer/pieceTreeBase.ts (StringBuffer/line starts), model/intervalTree.ts, and model/guidesTextModelPart.ts. The piece tree above its immutable leaf and all edit machinery are deliberately N-A. See docs/references/monaco.md for the current source-to-file map and the completed execution plan for the frozen parity ledger.

    The tokenization-specific public slice is deliberately small: default color and lexer-token encoding helpers, attached-view demand, model token events, scheduler construction, passive line-token reads, and passive token counts. Stores, queues, backends, lifecycle helpers, and model-state access stay private; pkg.generated.mbti is the exhaustive package API.

    Production dependencies are base/common, syntax, viewer/common/services, and viewer/common/tokens. The package must not import language providers, view/view-model, DOM, workspace, server, or host effects. Run:

    moon test --target js viewer/common/model moon test --target native viewer/common/model moon test --target js viewer/common/view_model moon test --target native viewer/common/view_model

    AttachedViewImpl

    type AttachedViewImpl

    One externally-owned attached-view handle.

    AttachedViewImpl::set_visible_lines

    fn AttachedViewImpl::set_visible_lines(self : AttachedViewImpl, visible_lines : Array[VisibleLineRange], stabilized : Bool) -> Unit

    Converts inclusive ranges to LineRange and notifies after committing the new state. Equality suppresses only the stored-state write; the source still invokes the owner callback for every setVisibleLines call.

    DecorationsTrees

    type DecorationsTrees

    DecorationsTrees: tree0 holds decorations that do not show up in the overview ruler, tree1 those that do, and the injected-text tree is the stubbed-empty third slot (see file header).

    DidChangeContentEmitter

    type DidChangeContentEmitter

    DidChangeContentEmitter (textModel.ts:2698): defers and merges content-change events inside a deferred-emit bracket. hasListeners (:2712) is N-A (no consumer in the ported slices); endDeferredEmit's resultingSelection write drops with the unported field (file header).

    DidChangeDecorationsEmitter

    type DidChangeDecorationsEmitter

    DidChangeDecorationsEmitter (textModel.ts:2586): batches decoration-change notifications into one event per deferred-emit bracket, accumulating the affects flags. The injected-text/line-height/font record sets and the handleBeforeFire fan-out are dropped with their out-of-scope features (see file header).

    InjectedTextOptions

    type InjectedTextOptions derive(Eq,
    Debug
    )

    InjectedTextOptions at the model tier (model.ts): the rendered content, its inline class, and the producer's attachment (attachedData, reduced to a source index for injected-text consumers). cursorStops is unported — the readonly viewer treats every injection as InjectedTextCursorStops.Both (the default), see normalize_projected_column_around_injections.

    InjectedTextOptions::InjectedTextOptions

    fn InjectedTextOptions::InjectedTextOptions(content : String, inline_class_name? : String, attached_index? : Int) -> InjectedTextOptions

    Constructs the read-only injected-text payload consumed by the production view-model projection.

    InjectedTextOptions::attached_index

    fn InjectedTextOptions::attached_index(self : InjectedTextOptions) -> Int

    Returns the producer-defined attachment index used by hit testing.

    InjectedTextOptions::content

    fn InjectedTextOptions::content(self : InjectedTextOptions) -> String

    Returns the text inserted into the rendered line.

    InjectedTextOptions::equal

    InjectedTextOptions::inline_class_name

    fn InjectedTextOptions::inline_class_name(self : InjectedTextOptions) -> String?

    Returns the optional inline CSS class for the inserted text.

    InjectedTextOptions::not_equal

    InternalModelContentChangeEvent

    pub struct InternalModelContentChangeEvent {
    raw_content_changed_event : ModelRawContentChangedEvent
    content_changed_event : ModelContentChangedEvent
    } derive(
    Debug
    )

    InternalModelContentChangeEvent (textModelEvents.ts:562-594).

    MinimapPosition

    pub(all) enum MinimapPosition {
    Inline
    Gutter
    } derive(Eq,
    Debug
    )

    Minimap decoration position, MinimapPosition (model.ts).

    MinimapPosition::equal

    MinimapPosition::not_equal

    fn MinimapPosition::not_equal(x : MinimapPosition, y : MinimapPosition) -> Bool

    ModelContentChange

    pub(all) struct ModelContentChange {
    range :
    Range

    range_offset : Int
    range_length : Int
    text : String
    } derive(
    Debug
    )

    IModelContentChange (model/mirrorTextModel.ts): one change entry of the public content-changed payload.

    ModelContentChangedEvent

    pub struct ModelContentChangedEvent {
    changes : Array[ModelContentChange]
    eol : String
    version_id : Int
    is_undoing : Bool
    is_redoing : Bool
    is_flush : Bool
    is_eol_change : Bool
    } derive(
    Debug
    )

    The public IModelContentChangedEvent (textModelEvents.ts:42-85) minus detailedReasons/detailedReasonsChangeLengths (file-header deviation). The I-prefix drops per the repo naming policy.

    ModelDecoration

    pub(all) struct ModelDecoration {
    id : String
    owner_id : Int
    range :
    Range

    options : ModelDecorationOptions
    } derive(
    Debug
    )

    A decoration query result — Monaco's IModelDecoration (id + ownerId + range + options). Monaco returns the tree's IntervalNodes cast to this interface; the port materializes value copies (same data, no aliasing).

    ModelDecorationMinimapOptions

    pub(all) struct ModelDecorationMinimapOptions {
    color : String
    position : MinimapPosition
    } derive(Eq,
    Debug
    )

    Minimap decoration options, IModelDecorationMinimapOptions. color is a theme-color id, carried inert (plan D4).

    ModelDecorationMinimapOptions::not_equal

    ModelDecorationOptions

    pub struct ModelDecorationOptions {
    class_name : String
    message : String?
    inline_class_name : String?
    inline_class_name_affects_letter_spacing : Bool
    z_index : Int
    is_whole_line : Bool
    show_if_collapsed : Bool
    should_fill_line_on_line_break : Bool
    stickiness : TrackedRangeStickiness
    overview_ruler : ModelDecorationOverviewRulerOptions?
    minimap : ModelDecorationMinimapOptions?
    glyph_margin_class_name : String?
    lines_decorations_class_name : String?
    first_line_decoration_class_name : String?
    margin_class_name : String?
    after_content_class_name : String?
    collapse_on_replace_edit : Bool
    description : String
    before : InjectedTextOptions?
    after : InjectedTextOptions?
    } derive(
    Debug
    )

    The ModelDecorationOptions subset (textModel.ts:2478-2580). Monaco field mapping: class_name = className ("" = undefined), message = hoverMessage, inline_class_name = inlineClassName, the rest keep their names.

    Omitted ModelDecorationOptions fields (out of scope, plan monaco-decoration-system-port.md): blockClassName/blockIsAfterEnd/ blockDoesNotCollapse/blockPadding (block decorations), lineNumberClassName/lineNumberHoverMessage/linesDecorationsTooltip/ glyphMarginHoverMessage (no consumer), hideInCommentTokens/ hideInStringTokens, lineHeight/fontSize/affectsFont (font/line- height decorations), textDirection, glyphMargin lane options (glyph margin view part deferred). overview_ruler/minimap colors are carried as strings — no theme-object resolution (recorded theming design).

    ModelDecorationOptions::ModelDecorationOptions

    fn ModelDecorationOptions::ModelDecorationOptions(class_name : String, message? : String, inline_class_name? : String, inline_class_name_affects_letter_spacing? : Bool, z_index? : Int, is_whole_line? : Bool, show_if_collapsed? : Bool, should_fill_line_on_line_break? : Bool, stickiness? : TrackedRangeStickiness, overview_ruler? : ModelDecorationOverviewRulerOptions, minimap? : ModelDecorationMinimapOptions, glyph_margin_class_name? : String, lines_decorations_class_name? : String, first_line_decoration_class_name? : String, margin_class_name? : String, after_content_class_name? : String, collapse_on_replace_edit? : Bool, description? : String, before? : InjectedTextOptions, after? : InjectedTextOptions) -> ModelDecorationOptions

    The single decoration-options constructor. Monaco's register/ createDynamic/_normalizeOptions collapse into this one function (plan Deviation 5 — register exists only to intern per-instance allocations). Class names are normalized with clean_class_name like the ModelDecorationOptions ctor; defaults mirror the source (stickiness AlwaysGrows, zIndex 0). Direct record literals bypass the cleaning, like nothing does in Monaco.

    ModelDecorationOverviewRulerOptions

    pub(all) struct ModelDecorationOverviewRulerOptions {
    color : String?
    position : OverviewRulerLane
    } derive(Eq,
    Debug
    )

    Overview-ruler decoration options, IModelDecorationOverviewRulerOptions. color is a theme-color id (themeColorFromId), carried inert (no overview ruler part paints it — plan D4).

    ModelDecorationOverviewRulerOptions::not_equal

    ModelDecorationsChangeAccessor

    pub struct ModelDecorationsChangeAccessor {
    add_decoration : (
    Range
    , ModelDecorationOptions) -> String
    change_decoration : (String,
    Range
    ) -> Unit
    change_decoration_options : (String, ModelDecorationOptions) -> Unit
    remove_decoration : (String) -> Unit
    delta_decorations : (Array[String], Array[ModelDeltaDecoration]) -> Array[String]
    }

    The IModelDecorationsChangeAccessor handed to change_decorations callbacks (textModel.ts:1681-1701). Fields are invalidated after the callback returns, like the source's invalidFunc swap.

    ModelDecorationsChangedEvent

    pub struct ModelDecorationsChangedEvent {
    affects_minimap : Bool
    affects_overview_ruler : Bool
    affects_glyph_margin : Bool
    affects_injected_text : Bool
    affects_line_number : Bool
    } derive(Eq,
    Debug
    )

    IModelDecorationsChangedEvent (textModelEvents.ts), fired by TextModel::on_did_change_decorations.

    ModelDecorationsChangedEvent::not_equal

    ModelDeltaDecoration

    pub(all) struct ModelDeltaDecoration {
    range :
    Range

    options : ModelDecorationOptions
    } derive(
    Debug
    )

    A (range, options) pair handed to TextModel::delta_decorations — Monaco's IModelDeltaDecoration.

    ModelRawChange

    pub enum ModelRawChange {
    ModelRawFlush
    ModelRawLineChanged(line_number~ : Int, line_number_post_edit~ : Int)
    ModelRawLinesDeleted(from_line_number~ : Int, to_line_number~ : Int, last_untouched_line_post_edit~ : Int)
    ModelRawLinesInserted(from_line_number~ : Int, from_line_number_post_edit~ : Int, count~ : Int)
    ModelRawEOLChanged
    } derive(
    Debug
    )

    The ModelRawChange union (textModelEvents.ts:451): ModelRawFlush (:233), ModelRawLineChanged (:308), ModelRawLinesDeleted (:380), ModelRawLinesInserted (:406), ModelRawEOLChanged (:444), with each class's fields as labeled payloads.

    ModelRawContentChangedEvent

    pub struct ModelRawContentChangedEvent {
    changes : Array[ModelRawChange]
    version_id : Int
    is_undoing : Bool
    is_redoing : Bool
    } derive(
    Debug
    )

    ModelRawContentChangedEvent (textModelEvents.ts:457-500) minus resultingSelection (file-header deviation).

    ModelRawContentChangedEvent::contains_event

    fn ModelRawContentChangedEvent::contains_event(self : ModelRawContentChangedEvent, change_type : RawContentChangedType) -> Bool

    containsEvent (textModelEvents.ts:483-491).

    ModelTokensChangedEvent

    pub(all) struct ModelTokensChangedEvent {
    semantic_tokens_applied : Bool
    ranges : Array[ModelTokensChangedRange]
    }

    Exact syntactic/semantic token-change event payload.

    ModelTokensChangedRange

    pub(all) struct ModelTokensChangedRange {
    from_line_number : Int
    to_line_number : Int
    }

    One inclusive changed line range.

    OverviewRulerLane

    pub(all) enum OverviewRulerLane {
    Left
    Center
    Right
    Full
    } derive(Eq,
    Debug
    )

    Overview-ruler lane, OverviewRulerLane (model.ts).

    OverviewRulerLane::equal

    OverviewRulerLane::not_equal

    fn OverviewRulerLane::not_equal(x : OverviewRulerLane, y : OverviewRulerLane) -> Bool

    PositionAffinity

    pub(all) enum PositionAffinity {
    Left
    Right
    None
    LeftOfInjectedText
    RightOfInjectedText
    } derive(Eq,
    Debug
    )

    Which side of an injected-text or soft-wrap boundary a position resolves to, PositionAffinity (model.ts:1455-1480).

    PositionAffinity::equal

    PositionAffinity::not_equal

    fn PositionAffinity::not_equal(x : PositionAffinity, y : PositionAffinity) -> Bool

    RawContentChangedType

    pub(all) enum RawContentChangedType {
    Flush
    LineChanged
    LinesDeleted
    LinesInserted
    EOLChanged
    } derive(Eq,
    Debug
    )

    RawContentChangedType (textModelEvents.ts:221-227). The source's numeric const-enum values (1-5) are not observable through this port; identity is by constructor.

    RawContentChangedType::equal

    RawContentChangedType::not_equal

    TextModel

    pub struct TextModel {
    uri :
    Uri

    display_name : String
    language_id : String
    version : Int
    revision : String
    snapshot : TextSnapshot
    tokenization : TokenizationTextModelPart
    on_will_dispose :
    Emitter
    [Unit]
    on_did_change_decorations : DidChangeDecorationsEmitter
    // private fields
    }

    TextModel::TextModel

    fn TextModel::TextModel(uri :
    Uri
    , display_name : String, language_id : String, version : Int, revision : String, text : String) -> TextModel

    Builds a readonly text model.

    version and revision are caller-owned metadata, not async freshness keys. Request owners use stable model identity plus get_version_id(). Empty display name and language id are normalized; non-positive versions become version 1.

    TextModel::change_decorations

    fn[T] TextModel::change_decorations(self : TextModel, callback : (ModelDecorationsChangeAccessor) -> T, owner_id? : Int) -> T

    changeDecorations (textModel.ts:1669-1678): runs callback against a change accessor inside one deferred-emit bracket.

    TextModel::delta_decorations

    fn TextModel::delta_decorations(self : TextModel, old_decorations : Array[String], new_decorations : Array[ModelDeltaDecoration], owner_id? : Int) -> Array[String]

    deltaDecorations (textModel.ts:1717-1740): the atomic remove+add primitive. Returns the new decoration ids.

    TextModel::dispose

    fn TextModel::dispose(self : TextModel) -> Unit

    Releases the model — dispose (textModel.ts:414). Fires onWillDispose first (the attached editor detaches itself there), then disposes the tokenization part — dropping its registry subscription — and the emitters. Monaco's disposed-buffer swap is N-A: the snapshot is immutable and garbage-collected.

    TextModel::get_decoration_range

    fn TextModel::get_decoration_range(self : TextModel, decoration_id : String) ->
    Range
    ?

    getDecorationRange (textModel.ts:1798-1804).

    TextModel::get_decorations_in_range

    fn TextModel::get_decorations_in_range(self : TextModel, range :
    Range
    , owner_id? : Int, filter_out_validation? : Bool, filter_font_decorations? : Bool, only_margin_decorations? : Bool) -> Array[ModelDecoration]

    getDecorationsInRange (textModel.ts:1826-1834). The onlyMinimapDecorations argument is dropped — the source forwards it only to the out-of-scope bracket provider. Provider merges N-A as above.

    TextModel::get_full_model_range

    The whole document as a Range. Mirrors getFullModelRange (textModel.ts:1168).

    TextModel::get_injected_text_decorations

    fn TextModel::get_injected_text_decorations(self : TextModel, owner_id? : Int) -> Array[ModelDecoration]

    getInjectedTextDecorations (textModel.ts): every decoration carrying before/after injected-text options. owner_id = 0 matches all owners (the tree's filter semantics).

    TextModel::get_language_id

    fn TextModel::get_language_id(self : TextModel) -> String

    Source document language id. Mirrors getLanguageId (textModel.ts:2085), delegating to the tokenization part as Monaco does.

    TextModel::get_line_content

    fn TextModel::get_line_content(self : TextModel, line_number : Int) -> String

    Text of the one-based line_number, clamped into the document. Mirrors getLineContent (textModel.ts:851).

    TextModel::get_line_count

    fn TextModel::get_line_count(self : TextModel) -> Int

    Number of logical lines. Mirrors getLineCount (textModel.ts:846).

    TextModel::get_line_decorations

    fn TextModel::get_line_decorations(self : TextModel, line_number : Int, owner_id? : Int, filter_out_validation? : Bool, filter_font_decorations? : Bool) -> Array[ModelDecoration]

    getLineDecorations (textModel.ts:1806-1812).

    TextModel::get_line_first_non_whitespace_column

    fn TextModel::get_line_first_non_whitespace_column(self : TextModel, line_number : Int) -> Int

    1-based column of the first non-whitespace character on line_number, or 0 for whitespace-only lines. Mirrors getLineFirstNonWhitespaceColumn (textModel.ts:905).

    TextModel::get_line_last_non_whitespace_column

    fn TextModel::get_line_last_non_whitespace_column(self : TextModel, line_number : Int) -> Int

    1-based column just past the last non-whitespace character on line_number, or 0 for whitespace-only lines. Mirrors getLineLastNonWhitespaceColumn (textModel.ts:913).

    TextModel::get_line_max_column

    fn TextModel::get_line_max_column(self : TextModel, line_number : Int) -> Int

    Max (1-based) column for line_number: content length + 1. Mirrors getLineMaxColumn (textModel.ts:897).

    TextModel::get_line_min_column

    fn TextModel::get_line_min_column(_self : TextModel, _line_number : Int) -> Int

    Minimum column of a line, always 1. Mirrors getLineMinColumn (textModel.ts:892).

    TextModel::get_lines_content

    fn TextModel::get_lines_content(self : TextModel) -> Array[String]

    Every line's content, EOLs excluded. Mirrors getLinesContent (textModel.ts:869).

    TextModel::get_offset_at

    fn TextModel::get_offset_at(self : TextModel, position :
    Position
    ) -> Int

    Clamped document offset of position. Mirrors getOffsetAt (textModel.ts:770): relaxed-validate, then the buffer's line/column arity.

    TextModel::get_position_at

    fn TextModel::get_position_at(self : TextModel, offset : Int) ->
    Position

    Position at the clamped document offset. Mirrors getPositionAt (textModel.ts:776).

    TextModel::get_value

    fn TextModel::get_value(self : TextModel) -> String

    Full normalized document text. Mirrors getValue (textModel.ts:799): derive the full model range, then read that range. U+FEFF is ordinary Viewer content and there is no EOL or preserve-BOM selector.

    TextModel::get_value_in_range

    fn TextModel::get_value_in_range(self : TextModel, range :
    Range
    ) -> String

    Text inside a validated range. Mirrors getValueInRange (textModel.ts:831): validate, then read the buffer.

    TextModel::get_version_id

    fn TextModel::get_version_id(self : TextModel) -> Int

    The current content version — getVersionId (textModel.ts:737-740); init 1 (:370), bumped by every content change. The decoration trees cache against it. _assertNotDisposed: N-A (readonly reads survive dispose, see the region header).

    TextModel::get_word_at_position

    TextModel.getWordAtPosition (textModel.ts:2108), default word definition: the word at position on its line, or None.

    TextModel::identity

    fn TextModel::identity(self : TextModel) -> Int

    Stable process-local key for identity-indexed package services.

    Most callers should prefer same; this numeric form exists for maps that cannot key directly by TextModel without falling back to reference equality.

    TextModel::is_disposed

    fn TextModel::is_disposed(self : TextModel) -> Bool

    Whether dispose has run — isDisposed (textModel.ts:445).

    TextModel::on_before_attached

    fn TextModel::on_before_attached(self : TextModel, scheduler? : TokenizationScheduler) -> AttachedViewImpl

    Begins one Viewer attachment (textModel.ts:607-614). The first non-None scheduler of an attached epoch wins. A late first scheduler wakes existing background work once without synthesizing another 0->1 notification.

    TextModel::on_before_detached

    fn TextModel::on_before_detached(self : TextModel, attached_view : AttachedViewImpl) -> Unit

    Finishes one Viewer attachment (textModel.ts:616-623). The final transition notifies/cancels backend work first, detaches the exact handle second, and clears the epoch scheduler last.

    TextModel::on_did_change_content

    Subscribes to content changes — onDidChangeContent (textModel.ts:245-247), unwrapping the internal event to its public payload.

    TextModel::on_did_change_decorations

    fn TextModel::on_did_change_decorations(self : TextModel, listener : (ModelDecorationsChangedEvent) -> Unit) ->
    Disposable

    onDidChangeDecorations (textModel.ts:225-226): one event per deferred-emit bracket. The backing _onDidChangeDecorations emitter is the same-named TextModel field.

    TextModel::on_did_change_tokens

    Subscribes to grammar-token changes — onDidChangeTokens, delegating to the tokenization part as the source's forwarded emitter does.

    TextModel::on_will_dispose

    fn TextModel::on_will_dispose(self : TextModel, listener : () -> Unit) ->
    Disposable

    Subscribes to the start of dispose — onWillDispose (textModel.ts:223).

    TextModel::register_view_model

    fn TextModel::register_view_model(self : TextModel, on_did_change_content_or_injected_text : (InternalModelContentChangeEvent) -> Unit, emit_content_change_event : (InternalModelContentChangeEvent) -> Unit) ->
    Disposable

    registerViewModel (textModel.ts:449-451) as a callback registration. The returned idempotent handle owns the matching unregisterViewModel lifetime (:453-455); callers never compare or retain trait-object boxes.

    TextModel::remove_all_decorations_with_owner_id

    fn TextModel::remove_all_decorations_with_owner_id(self : TextModel, owner_id : Int) -> Unit

    removeAllDecorationsWithOwnerId (textModel.ts:1777-1789). Like the source, this fires no change event.

    TextModel::same

    fn TextModel::same(self : TextModel, other : TextModel) -> Bool

    Whether two handles name the same stable text-model instance.

    TextModel::set_value

    fn TextModel::set_value(self : TextModel, value : String) -> Unit

    Replaces the whole content in place — setValue (textModel.ts:484-493): build the new buffer, then flush. The same model (and its registered view models) survives; all decorations are destroyed and the version bumps. The null | undefined argument guard is N-A (non-nullable String); EditSources.setValue() reasons are not ported (event deviation).

    TextModel::snapshot

    fn TextModel::snapshot(self : TextModel) -> TextSnapshot

    Returns the immutable snapshot consumed by tokenization, providers, and rendering.

    TextModel::to_repr

    TextModel::validate_position

    Clamps a position into the document, snapping out of the middle of a surrogate pair. Mirrors validatePosition (textModel.ts:1063).

    TextModel::validate_range

    Clamps a range into the document, expanding out of any surrogate pair its ends land inside. Mirrors validateRange (textModel.ts:1110).

    TextSnapshot

    type TextSnapshot derive(
    Debug
    )

    Immutable LF-normalized text plus cached line starts, the readonly analog of Monaco's text buffer: the field pair is the piece tree's leaf (StringBuffer { buffer, lineStarts }, pieceTreeBase.ts:147) and the 1-based methods are the IReadonlyTextBuffer read surface (model.ts:1524). Offsets and columns are UTF-16 code units so browser, Monaco, and LSP-facing code share one convention. Document identity (language id, version) lives on TextModel, not the buffer — same split as Monaco.

    TextSnapshot::TextSnapshot

    fn TextSnapshot::TextSnapshot(text : String) -> TextSnapshot

    Builds a snapshot by replacing every CRLF pair, lone CR, or LF with one LF before deriving line starts. U+FEFF, U+2028/U+2029, surrogate code units, and all other UTF-16 content are preserved verbatim.

    TextSnapshot::equals

    fn TextSnapshot::equals(self : TextSnapshot, other : TextSnapshot) -> Bool

    Whole-buffer equality — PieceTreeTextBuffer.equals behind TextModel.equalsTextBuffer (textModel.ts:457-459). The source compares its selected-EOL representation; the Viewer compares its coherent LF-normalized representation, including U+FEFF as ordinary content. Hosts use it for the refresh no-op early return (modelService.ts:370-373).

    TextSnapshot::get_line_content

    fn TextSnapshot::get_line_content(self : TextSnapshot, line_number : Int) -> String

    Text of the one-based line_number without its line break, clamped into the snapshot. Mirrors IReadonlyTextBuffer.getLineContent (the viewer clamps where Monaco throws Illegal value for lineNumber).

    TextSnapshot::get_line_first_non_whitespace_column

    fn TextSnapshot::get_line_first_non_whitespace_column(self : TextSnapshot, line : Int) -> Int

    1-based column of the first non-whitespace character on line, or 0 if the line is empty/whitespace-only. Mirrors getLineFirstNonWhitespaceColumn.

    TextSnapshot::get_line_max_column

    fn TextSnapshot::get_line_max_column(self : TextSnapshot, line : Int) -> Int

    Max (1-based) column for line: content length + 1. Mirrors getLineMaxColumn.

    TextSnapshot::get_offset_at

    fn TextSnapshot::get_offset_at(self : TextSnapshot, line_number : Int, column : Int) -> Int

    Converts a one-based line/column pair to a clamped document offset, undoing the +1 this boundary added in get_position_at. Mirrors IReadonlyTextBuffer.getOffsetAt (same arity; the Position-taking form is TextModel::get_offset_at).

    TextSnapshot::get_value

    fn TextSnapshot::get_value(self : TextSnapshot) -> String

    Full stored document text. Construction has already normalized every line ending to LF, so this is the direct fixed-LF getValue() result.

    TextSnapshot::line_count

    fn TextSnapshot::line_count(self : TextSnapshot) -> Int

    Number of logical lines, including the final empty line after a trailing newline.

    TextSnapshot::line_text

    fn TextSnapshot::line_text(self : TextSnapshot, line : Int) -> String

    Text of one logical line without its line break. Zero-based, part of the offset-centric internal layer (see the README parity ledger); the IReadonlyTextBuffer surface is get_line_content.

    TextSnapshot::offset_range_of

    Converts a line/column Range to an offset span (inverse of range_of).

    TextSnapshot::range_of

    Converts an offset span to a line/column Range (the boundary helper for code that carries Range but holds offsets, e.g. the hover widget).

    TextSnapshot::slice

    Returns a clamped half-open slice of the snapshot text.

    TokenizationIdleDeadline

    type TokenizationIdleDeadline

    Idle callback deadline. Callers must read time_remaining immediately.

    TokenizationIdleDeadline::TokenizationIdleDeadline

    fn TokenizationIdleDeadline::TokenizationIdleDeadline(read_time_remaining : () -> Double) -> TokenizationIdleDeadline

    Creates a deadline backed by a host-provided remaining-time reader.

    TokenizationScheduler

    type TokenizationScheduler

    FFI-free scheduling surface supplied by a browser host or deterministic test.

    TokenizationScheduler::TokenizationScheduler

    Creates a scheduler from cancellable idle, zero-timeout, delayed, and clock operations. All durations and clock values use milliseconds.

    TokenizationTextModelPart

    type TokenizationTextModelPart

    Public model tokenization part. Reads are passive; attached visible ranges and the background worker drive lexing.

    TokenizationTextModelPart::get_line_tokens

    Passive stored/default syntactic tokens; never invokes the lexer.

    TokenizationTextModelPart::token_count

    Passive telemetry count. One stored/default read per model line and zero lexer calls, including initial attach and token-change notification paths.

    TrackedRangeStickiness

    pub(all) enum TrackedRangeStickiness {
    AlwaysGrowsWhenTypingAtEdges
    NeverGrowsWhenTypingAtEdges
    GrowsOnlyWhenTypingBefore
    GrowsOnlyWhenTypingAfter
    } derive(Eq,
    Debug
    )

    How a decoration's range grows when text is typed at its edges, TrackedRangeStickiness (model.ts). Inert in the readonly viewer; carried for fidelity.

    TrackedRangeStickiness::equal

    TrackedRangeStickiness::not_equal

    VisibleLineRange

    pub(all) struct VisibleLineRange {
    start_line_number : Int
    end_line_number : Int
    } derive(Eq,
    Debug
    )

    Inclusive visible model-line range supplied by a view.

    VisibleLineRange::equal

    VisibleLineRange::not_equal

    fn VisibleLineRange::not_equal(x : VisibleLineRange, y : VisibleLineRange) -> Bool

    WordAtPosition

    pub struct WordAtPosition {
    word : String
    start_column : Int
    end_column : Int
    } derive(Eq,
    Debug
    )

    A word inside a model, IWordAtPosition (wordHelper.ts:16). Columns are 1-based.

    WordAtPosition::equal

    WordAtPosition::not_equal

    fn WordAtPosition::not_equal(x : WordAtPosition, y : WordAtPosition) -> Bool

    compute_indent_level

    fn compute_indent_level(line : String, tab_size : Int) -> Int

    Whitespace-run width of line (tabs expanded to tab_size), or -1 if the line consists only of whitespace. Mirrors model/utils.ts computeIndentLevel.

    default_token_color_map

    fn default_token_color_map() -> Array[String]

    The production color map: colorId -> CSS color, indexed by foreground ColorId. Reuses the workbench --vscode-token-* custom properties so the mtk<n> classes render in the same colors as the legacy tok-* classes. Mirrors Monaco's TokenizationRegistry.getColorMap() result.

    line_tokens_from_lexer_tokens

    Builds the faithful LineTokens for one model line from the lexer's line-local tokens. language_id is the model's numeric language id (from the codec); it is packed into every token's metadata word — including the plain gap/trailing fills — so each token reports the model's language.