#base/common

    Host-neutral primitives at the bottom of the editor dependency graph. Every other package may depend on this one; this one depends on nothing in the product.

    The examples below are this package's own black-box tests, so they use the in-package alias @common. Callers import it as "moonbitlang/editor/base/common" @base_common and write @base_common. in their own code.

    #What lives here

    direction: right uri: resource identity { grid-columns: 1 a: Uri / UriError b: ExtUri (case policy) c: Posix / Win32 / extpath } coords: coordinates { grid-columns: 1 d: Position / Range e: LineRange / LineRangeSet f: OffsetRange } life: lifecycle + events { grid-columns: 1 g: Disposable h: Emitter i: MicrotaskEmitter } text: text + characters { grid-columns: 1 j: split_lines / whitespace scan k: compare_substring (case folding) l: CharacterClassifier / CharacterSet m: RTL + full-width probes } uri -> coords: "no dependency, one package" {style.stroke-dash: 3} coords -> life: "" {style.stroke-dash: 3} life -> text: "" {style.stroke-dash: 3}

    The four groups are independent; they are one package because every upper tier needs all four, and splitting them would only add import noise.

    #Coordinates

    Two coordinate spaces exist, and mixing them is the bug this package is shaped to prevent.

    flowchart LR subgraph one["1-based, UTF-16 code units"] P["Position<br>line_number, column"] R["Range<br>start/end line+column"] LR["LineRange<br>half-open line span"] end subgraph zero["0-based, UTF-16 code units"] O["OffsetRange<br>start, end_exclusive"] end P --- R R --- LR one <-->|"TextSnapshot<br>viewer/common/model"| zero

    Position, Range, and LineRange use 1-based UTF-16 line/column coordinates. OffsetRange is a 0-based half-open UTF-16 span. TextSnapshot in viewer/common/model owns conversion between those spaces — this package deliberately offers no conversion, because conversion needs text.

    Position compares lexicographically by line then column, and delta/with_ produce new values rather than mutating.

    ///|
    test "positions order by line then column" {
    let a = @common.Position(1, 5)
    let b = @common.Position(2, 1)
    debug_inspect(
    (a.is_before(b), a.compare(b), a.delta(delta_column=3), a.with_(column=1)),
    content=(
    #|(
    #| true,
    #| -1,
    #| { line_number: 1, column: 8 },
    #| { line_number: 1, column: 1 },
    #|)
    ),
    )
    }

    Range distinguishes containment from strict containment and from touching, which is what decoration and selection code needs at boundaries.

    ///|
    test "range containment, intersection, and touching are distinct" {
    let outer = @common.Range(1, 1, 3, 10)
    let inner = @common.Range(2, 1, 2, 5)
    let touching = @common.Range(3, 10, 4, 1)
    debug_inspect(
    (
    outer.contains_range(inner),
    outer.strict_contains_range(inner),
    outer.are_intersecting(touching),
    outer.are_intersecting_or_touching(touching),
    outer.plus_range(touching).to_string(),
    ),
    content=(
    #|(true, true, false, true, "[1,1 -> 4,1]")
    ),
    )
    }

    LineRange is half-open: end_line_number_exclusive is one past the last line, so an empty range is start == end. Unlike Monaco, OffsetRange normalizes inverted constructor input instead of throwing.

    ///|
    test "LineRange is half-open and OffsetRange normalizes inverted input" {
    let lines = @common.LineRange(4, 7)
    let inverted = @common.OffsetRange(9, 2)
    debug_inspect(
    (
    lines.length(),
    lines.contains(6),
    lines.contains(7),
    lines.is_empty(),
    inverted,
    ),
    content=(
    #|(3, true, false, false, { start: 2, end_exclusive: 9 })
    ),
    )
    }

    LineRange::join_many unions arrays of sorted ranges into a copied, normalized result without mutating caller arrays.

    ///|
    test "join_many unions sorted range arrays without mutating the inputs" {
    let left : Array[@common.LineRange] = [LineRange(1, 3), LineRange(8, 10)]
    let right = [@common.LineRange(2, 5)]
    let joined = @common.LineRange::join_many([left, right])
    debug_inspect(
    (joined, left.length(), right.length()),
    content=(
    #|(
    #| [
    #| { start_line_number: 1, end_line_number_exclusive: 5 },
    #| { start_line_number: 8, end_line_number_exclusive: 10 },
    #| ],
    #| 2,
    #| 1,
    #|)
    ),
    )
    }

    #Resource identity

    Uri stores decoded scheme, authority, path, query, and fragment; parse, from, and with_ raise UriError on invalid input. Use Uri, not a workspace-owned alias or an unparsed string, for resource identity.

    ///|
    test "Uri keeps decoded components and re-encodes on to_string" {
    let uri = @common.Uri::parse("https://example.com/a%20b/c.mbt?q=1#frag")
    debug_inspect(
    (uri.scheme, uri.authority, uri.path, uri.query, uri.fragment),
    content=(
    #|("https", "example.com", "/a b/c.mbt", "q=1", "frag")
    ),
    )
    debug_inspect(
    uri.to_string(),
    content=(
    #|"https://example.com/a%20b/c.mbt?q%3D1#frag"
    ),
    )
    }

    Invalid input raises rather than producing a half-built value.

    ///|
    test "a missing scheme is a UriError, not a silent default" {
    try @common.Uri::from(scheme="", strict=true) |> ignore catch {
    err =>
    debug_inspect(
    err,
    content=(
    #|UriError("[UriError]: Scheme is missing: {scheme: \"\", authority: \"\", path: \"\", query: \"\", fragment: \"\"}")
    ),
    )
    } noraise {
    _ => fail("expected a UriError")
    }
    }

    uri_to_fs_path is platform-sensitive. Package white-box conformance tests pin the internal platform detector for Windows and POSIX cases; callers see the current host platform and no test override enters the public interface.

    ExtUri, resources.mbt, and uri_to_fs_path provide resource comparison, joining, normalization, and filesystem conversion. The three prebuilt policies differ only in path-case sensitivity: ext_uri is case-sensitive, ext_uri_ignore_path_case folds case for every scheme, and ext_uri_biased_ignore_path_case folds case for file: only on platforms whose filesystems are conventionally case-insensitive — it answers like ext_uri on Linux and like ext_uri_ignore_path_case on macOS and Windows, so this example asserts the platform relationship rather than a value that would change under CI.

    ///|
    test "the ExtUri policies differ only in path-case handling" {
    let lower = @common.Uri::parse("file:///dir/file.mbt")
    let upper = @common.Uri::parse("file:///DIR/FILE.MBT")
    let biased = @common.ext_uri_biased_ignore_path_case.is_equal(
    Some(lower),
    Some(upper),
    )
    debug_inspect(
    (
    @common.ext_uri.is_equal(Some(lower), Some(upper)),
    @common.ext_uri_ignore_path_case.is_equal(Some(lower), Some(upper)),
    biased == !@common.is_linux,
    ),
    content=(
    #|(false, true, true)
    ),
    )
    }

    relative_path returns None when the two URIs are not on the same scheme/authority, so a caller cannot accidentally build a cross-resource path.

    ///|
    test "relative_path is None across schemes" {
    let root = @common.Uri::parse("file:///workspace")
    let inside = @common.Uri::parse("file:///workspace/src/main.mbt")
    let elsewhere = @common.Uri::parse("https://example.com/src/main.mbt")
    debug_inspect(
    (
    @common.ext_uri.relative_path(root, inside),
    @common.ext_uri.relative_path(root, elsewhere),
    ),
    content=(
    #|(Some("src/main.mbt"), None)
    ),
    )
    }

    #Paths

    Posix/Win32, path.mbt, and extpath.mbt provide path operations without depending on the host filesystem. Platform and process facts have target-specific JS/fallback implementations, so prefer the explicit Posix:: and Win32:: entry points when the answer must not vary by host.

    ///|
    test "Posix and Win32 normalize the same input differently" {
    let input = "/a/b/../c//d/"
    debug_inspect(
    (
    @common.Posix::normalize(input),
    @common.Win32::normalize(input),
    @common.Posix::join(["/a", "b", "../c"]),
    @common.Posix::relative("/a/b", "/a/c/d"),
    @common.Posix::extname("/a/b/file.mbt.md"),
    ),
    content=(
    #|("/a/c/d/", "\\a\\c\\d\\", "/a/c", "../c/d", ".md")
    ),
    )
    }

    #Lifecycle and events

    Disposable is idempotent. Emitter delivers listeners in registration order from a snapshot, so a listener that unsubscribes during delivery does not disturb the in-flight fan-out.

    ///|
    test "emitter delivers in registration order and disposal is idempotent" {
    let seen = []
    let emitter : @common.Emitter[Int32] = Emitter()
    let first = emitter.event(value => seen.push(("first", value)))
    emitter.event(value => seen.push(("second", value))) |> ignore
    emitter.fire(1)
    first.dispose()
    first.dispose()
    emitter.fire(2)
    debug_inspect(
    (seen, emitter.has_listeners()),
    content=(
    #|([("first", 1), ("second", 1), ("second", 2)], true)
    ),
    )
    }

    MicrotaskEmitter queues events and merges one flush's worth into a single delivered value. The scheduler is injected rather than hardcoded to queueMicrotask, because this package compiles for js and native. The default scheduler runs the flush inline, which degenerates to synchronous Emitter semantics — the queue never holds more than one event, so merge has nothing to combine.

    ///|
    test "the default inline scheduler never batches, so merge is a no-op" {
    let delivered = []
    let emitter : @common.MicrotaskEmitter[Int32] = MicrotaskEmitter(merge=batch => {
    batch.fold(init=0, (a, b) => a + b)
    })
    emitter.event(value => delivered.push(value)) |> ignore
    emitter.fire(1)
    emitter.fire(2)
    debug_inspect(
    delivered,
    content=(
    #|[1, 2]
    ),
    )
    }

    Merging appears only once a scheduler actually defers the flush. Browser hosts inject the real microtask scheduler for exactly this reason; a test can inject a manual one and drive it explicitly.

    ///|
    test "a deferring scheduler collapses the batch into one value" {
    let delivered = []
    let pending : Array[() -> Unit] = []
    let emitter : @common.MicrotaskEmitter[Int32] = MicrotaskEmitter(
    merge=batch => batch.fold(init=0, (a, b) => a + b),
    schedule=run => pending.push(run),
    )
    emitter.event(value => delivered.push(value)) |> ignore
    emitter.fire(1)
    emitter.fire(2)
    emitter.fire(39)
    // Only the queue's first event schedules a flush.
    let scheduled = pending.length()
    for run in pending {
    run()
    }
    debug_inspect(
    (scheduled, delivered),
    content=(
    #|(1, [42])
    ),
    )
    }

    run_async_tasks_sequentially is the host-neutral default for a closed task set. Browser owners may inject a concurrent runner at the call boundary without coupling shared packages to a particular coroutine runtime.

    #Text and characters

    String, character-classification, RTL/full-width, and line-splitting helpers are shared here so higher layers do not duplicate coordinate-sensitive logic. split_lines accepts all three line terminators; the model normalizes to \n before storage, but this helper is used on raw host input.

    There are two HTML escapers, and the difference is ". escape leaves it alone, matching Monaco's _tokenizeToString, which only ever emits element content. escape_html also escapes it, for text that can land in an attribute value.

    ///|
    test "the two escapers differ only on the quote character" {
    debug_inspect(
    (@common.escape("<a href=\"x\">"), @common.escape_html("<a href=\"x\">")),
    content=(
    #|("&lt;a href=\"x\"&gt;", "&lt;a href=&quot;x&quot;&gt;")
    ),
    )
    }

    ///|
    test "line splitting and whitespace scanning use UTF-16 indices" {
    debug_inspect(
    (
    @common.split_lines("a\r\nb\nc\rd"),
    @common.first_non_whitespace_index(" let x = 1"),
    @common.last_non_whitespace_index("let x = 1 "),
    @common.first_non_whitespace_index(" "),
    ),
    content=(
    #|(["a", "b", "c", "d"], 3, 8, -1)
    ),
    )
    }

    CharacterClassifier is a dense ASCII array plus a sparse map, which is how the word-boundary and bracket scanners stay allocation-free on the hot path. CharacterSet is the boolean specialization.

    ///|
    test "classifier separates ASCII fast path from the sparse map" {
    let classifier = @common.CharacterClassifier(0)
    classifier.set('(', 1)
    classifier.set(0x4E2D, 2)
    let set = @common.CharacterSet()
    set.add('_')
    debug_inspect(
    (
    classifier.get('('),
    classifier.get(0x4E2D),
    classifier.get('a'),
    set.has('_'),
    set.has('-'),
    ),
    content=(
    #|(1, 2, 0, true, false)
    ),
    )
    }

    Surrogate, full-width, and RTL probes take a UTF-16 code unit as Int, which is exactly what String indexing yields.

    ///|
    test "character probes operate on UTF-16 code units" {
    let emoji = "😀"
    debug_inspect(
    (
    @common.is_high_surrogate(emoji[0].to_int()),
    @common.is_low_surrogate(emoji[1].to_int()),
    @common.is_full_width_character(0x4E2D),
    @common.contains_rtl("hello"),
    @common.contains_rtl("שלום"),
    ),
    content=(
    #|(true, true, true, false, true)
    ),
    )
    }

    Case-insensitive comparison is explicit and substring-scoped, so callers never allocate a lowercased copy just to compare a slice.

    ///|
    test "substring comparison avoids allocating a folded copy" {
    debug_inspect(
    (
    @common.equals_ignore_case("MoonBit", "moonbit"),
    @common.starts_with_ignore_case("README.MBT.MD", "readme"),
    @common.compare_substring("abcXX", "abcYY", a_end=3, b_end=3),
    ),
    content=(
    #|(true, true, 0)
    ),
    )
    }

    #Monaco map

    The pinned vscode/ counterparts are the named files under src/vs/base/common/, plus src/vs/editor/common/core/position.ts, range.ts, characterClassifier.ts, and core/ranges/{lineRange,offsetRange}.ts.

    #Boundaries and checks

    This package must not import product, viewer, DOM, server, workspace, or host-effect packages. The exhaustive public surface is pkg.generated.mbti; focused coverage is

    moon test --target js base/common moon test --target native base/common

    UriError

    pub suberror UriError {
    UriError(String)
    } derive(
    Debug
    )

    Validation failure raised by the documented URI constructors.

    UriError::to_repr

    CharacterClassifier

    type CharacterClassifier

    Classifies char codes into small integer buckets.

    CharacterClassifier::CharacterClassifier

    fn CharacterClassifier::CharacterClassifier(default_value : Int) -> CharacterClassifier

    CharacterClassifier::get

    fn CharacterClassifier::get(self : CharacterClassifier, char_code : Int) -> Int

    CharacterClassifier::set

    fn CharacterClassifier::set(self : CharacterClassifier, char_code : Int, value : Int) -> Unit

    CharacterSet

    type CharacterSet

    A set of char codes, backed by a CharacterClassifier.

    CharacterSet::CharacterSet

    fn CharacterSet::CharacterSet() -> CharacterSet

    Creates the documented character-code set abstraction.

    CharacterSet::add

    fn CharacterSet::add(self : CharacterSet, char_code : Int) -> Unit

    Adds char_code to the set.

    CharacterSet::has

    fn CharacterSet::has(self : CharacterSet, char_code : Int) -> Bool

    Reports whether char_code belongs to the set.

    Disposable

    type Disposable

    Idempotent lifecycle handle for subscriptions, watches, and teardown callbacks. Calling dispose more than once runs the callback at most once.

    Disposable::dispose

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

    Runs the disposable's teardown callback if it has not already run.

    Disposable::from

    fn Disposable::from(dispose : () -> Unit) -> Disposable

    Builds a disposable handle from a teardown callback.

    Emitter

    type Emitter[T]

    Small typed event emitter for host-neutral subscription APIs. It stores listeners in registration order and returns a disposable per listener.

    Emitter::Emitter

    fn[T] Emitter::Emitter() -> Emitter[T]

    Creates an empty typed emitter.

    Emitter::dispose

    fn[T] Emitter::dispose(self : Emitter[T]) -> Unit

    Disposes every listener and prevents later registrations from firing.

    Emitter::event

    fn[T] Emitter::event(self : Emitter[T], listener : (T) -> Unit) -> Disposable

    Registers a listener and returns a disposable for just that listener.

    Emitter::fire

    fn[T] Emitter::fire(self : Emitter[T], event : T) -> Unit

    Notifies currently active listeners in registration order. Delivery iterates a snapshot: a listener disposing itself (or a sibling) mid-fire must not disturb the walk, and the active flag keeps listeners removed mid-fire from running.

    Emitter::has_listeners

    fn[T] Emitter::has_listeners(self : Emitter[T]) -> Bool

    Whether any active listener is registered, Emitter.hasListeners (event.ts).

    ExtUri

    type ExtUri

    ExtUri (resources.ts:139) — the single IExtUri implementation, parameterized by the _ignorePathCasing closure.

    ExtUri::basename

    fn ExtUri::basename(self : ExtUri, resource : Uri, suffix? : String) -> String

    Returns the basename of the URI path component.

    ExtUri::basename_or_authority

    fn ExtUri::basename_or_authority(self : ExtUri, resource : Uri) -> String

    Returns the path basename, falling back to the URI authority when needed.

    ExtUri::compare

    fn ExtUri::compare(self : ExtUri, uri1 : Uri, uri2 : Uri, ignore_fragment? : Bool) -> Int

    Compares two URIs using this identity policy and the ported lexical string ordering.

    ExtUri::dirname

    fn ExtUri::dirname(self : ExtUri, resource : Uri) -> Uri

    Returns a URI representing the resource's directory.

    ExtUri::extname

    fn ExtUri::extname(self : ExtUri, resource : Uri) -> String

    Returns the extension of the URI path component.

    ExtUri::get_comparison_key

    fn ExtUri::get_comparison_key(self : ExtUri, uri : Uri, ignore_fragment? : Bool) -> String

    Builds the stable comparison key used by resource maps.

    ExtUri::has_trailing_path_separator

    fn ExtUri::has_trailing_path_separator(self : ExtUri, resource : Uri, sep? : String) -> Bool

    Reports whether the URI path has a trailing path separator.

    ExtUri::ignore_path_casing

    fn ExtUri::ignore_path_casing(self : ExtUri, uri : Uri) -> Bool

    Reports whether this policy ignores the URI path component's casing.

    ExtUri::is_absolute_path

    fn ExtUri::is_absolute_path(self : ExtUri, resource : Uri) -> Bool

    Reports whether the URI path is absolute.

    ExtUri::is_equal

    fn ExtUri::is_equal(self : ExtUri, uri1 : Uri?, uri2 : Uri?, ignore_fragment? : Bool) -> Bool

    Tests two optional URIs for equality under this identity policy.

    ExtUri::is_equal_authority

    fn ExtUri::is_equal_authority(self : ExtUri, a1 : String, a2 : String) -> Bool

    Tests two URI authorities for equality under the resource policy.

    ExtUri::is_equal_or_parent

    fn ExtUri::is_equal_or_parent(self : ExtUri, base : Uri, parent_candidate : Uri, ignore_fragment? : Bool) -> Bool

    Tests whether parent_candidate is equal to or a parent of base.

    ExtUri::join_path

    fn ExtUri::join_path(self : ExtUri, resource : Uri, path_fragment : Array[String]) -> Uri

    Joins path fragments onto the resource URI.

    ExtUri::normalize_path

    fn ExtUri::normalize_path(self : ExtUri, resource : Uri) -> Uri

    Resolves . and .. elements in the resource path.

    ExtUri::relative_path

    fn ExtUri::relative_path(self : ExtUri, from : Uri, to : Uri) -> String?

    Returns the relative path from from to to, or None when their schemes or authorities are incompatible.

    ExtUri::remove_trailing_path_separator

    fn ExtUri::remove_trailing_path_separator(self : ExtUri, resource : Uri, sep? : String) -> Uri

    Removes a trailing path separator without removing the URI's first slash.

    ExtUri::resolve_path

    fn ExtUri::resolve_path(self : ExtUri, base : Uri, path : String) -> Uri

    Resolves an absolute or relative POSIX/Win32 path against a base URI.

    LineRange

    pub(all) struct LineRange {
    start_line_number : Int
    end_line_number_exclusive : Int
    } derive(Eq,
    Debug
    )

    A range of lines (1-based), [start_line_number, end_line_number_exclusive).

    LineRange::LineRange

    fn LineRange::LineRange(start_line_number : Int, end_line_number_exclusive : Int) -> LineRange

    LineRange::contains

    fn LineRange::contains(self : LineRange, line_number : Int) -> Bool

    Indicates whether this half-open line range contains the line number.

    LineRange::equal

    fn LineRange::equal(LineRange, LineRange) -> Bool

    LineRange::equals

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

    LineRange::is_empty

    fn LineRange::is_empty(self : LineRange) -> Bool

    Indicates if this line range is empty.

    LineRange::join

    fn LineRange::join(self : LineRange, other : LineRange) -> LineRange

    Combines this and the given line range into the smallest covering range.

    LineRange::join_many

    fn LineRange::join_many(line_ranges : Array[Array[LineRange]]) -> Array[LineRange]

    Joins arrays of already sorted line ranges into one normalized array without mutating caller arrays.

    LineRange::length

    fn LineRange::length(self : LineRange) -> Int

    The number of lines this line range spans.

    LineRange::not_equal

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

    LineRange::to_string

    fn LineRange::to_string(self : LineRange) -> String

    LineRangeSet

    type LineRangeSet

    A normalized set of line ranges (sorted by start, none touching/overlapping).

    LineRangeSet::LineRangeSet

    fn LineRangeSet::LineRangeSet(normalized_ranges? : Array[LineRange]) -> LineRangeSet

    LineRangeSet::add_range

    fn LineRangeSet::add_range(self : LineRangeSet, range : LineRange) -> Unit

    LineRangeSet::ranges

    fn LineRangeSet::ranges(self : LineRangeSet) -> Array[LineRange]

    MicrotaskEmitter

    type MicrotaskEmitter[T]

    Emitter that queues events fired in one tick and delivers them on a scheduled flush, MicrotaskEmitter (event.ts:1594-1620). With a merge function every event queued before the flush collapses into one merged event.

    Deviation: Monaco schedules the flush with a hardcoded queueMicrotask; this package compiles for js and native, so the scheduler is injected at construction. The default runs the flush inline, degenerating to the synchronous Emitter semantics — the browser host passes the real microtask scheduler (viewer/services.mbt).

    MicrotaskEmitter::MicrotaskEmitter

    fn[T] MicrotaskEmitter::MicrotaskEmitter(merge? : (Array[T]) -> T, schedule? : (() -> Unit) -> Unit) -> MicrotaskEmitter[T]

    Creates a queueing emitter; merge collapses one flush's events into one.

    MicrotaskEmitter::dispose

    fn[T] MicrotaskEmitter::dispose(self : MicrotaskEmitter[T]) -> Unit

    Releases every listener and pending queue state.

    MicrotaskEmitter::event

    fn[T] MicrotaskEmitter::event(self : MicrotaskEmitter[T], listener : (T) -> Unit) -> Disposable

    Registers a listener and returns a disposable for just that listener.

    MicrotaskEmitter::fire

    fn[T] MicrotaskEmitter::fire(self : MicrotaskEmitter[T], event : T) -> Unit

    Queues the event; the queue's first event schedules the flush (MicrotaskEmitter.fire). Events re-fired while the flush runs are dropped, matching the source's forEach + reassignment.

    OffsetRange

    pub struct OffsetRange {
    start : Int
    end_exclusive : Int
    } derive(Eq,
    Debug
    )

    A range of offsets (0-based), half-open [start, end_exclusive). A subset port of Monaco's OffsetRange (core/ranges/offsetRange.ts) containing the operations used by the viewer; field names use the repo's snake_case (end_exclusive). The name Range is reserved for Monaco's line/column range (see monaco_range.mbt).

    OffsetRange::OffsetRange

    fn OffsetRange::OffsetRange(start : Int, end_exclusive : Int) -> OffsetRange

    Builds a half-open offset range. Monaco's constructor throws a BugIndicatingError when start > end_exclusive; the readonly viewer avoids panics, so this normalizes by swapping instead. For valid inputs (start <= end_exclusive) the swap is a no-op, so every other method keeps Monaco's behavior.

    OffsetRange::add_range

    fn OffsetRange::add_range(range : OffsetRange, sorted_ranges : Array[OffsetRange]) -> Unit

    Inserts range into sorted_ranges, merging it with any ranges it touches or overlaps so the array stays sorted and non-overlapping. Mirrors Monaco's static OffsetRange.addRange.

    OffsetRange::contains

    fn OffsetRange::contains(self : OffsetRange, offset : Int) -> Bool

    Whether offset falls inside the half-open range. Mirrors Monaco's contains.

    OffsetRange::empty_at

    fn OffsetRange::empty_at(offset : Int) -> OffsetRange

    The empty range [offset, offset). Mirrors Monaco's OffsetRange.emptyAt.

    OffsetRange::equal

    fn OffsetRange::equal(OffsetRange, OffsetRange) -> Bool

    OffsetRange::equals

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

    Whether this range equals other. Mirrors Monaco's equals.

    OffsetRange::from_to

    fn OffsetRange::from_to(start : Int, end_exclusive : Int) -> OffsetRange

    [start, end_exclusive). Mirrors Monaco's static OffsetRange.fromTo.

    OffsetRange::is_empty

    fn OffsetRange::is_empty(self : OffsetRange) -> Bool

    Whether the range contains no offsets. Mirrors Monaco's isEmpty getter.

    OffsetRange::length

    fn OffsetRange::length(self : OffsetRange) -> Int

    The number of offsets in the range. Mirrors Monaco's length getter.

    OffsetRange::not_equal

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

    OffsetRange::of_length

    fn OffsetRange::of_length(length : Int) -> OffsetRange

    [0, length). Mirrors Monaco's static OffsetRange.ofLength.

    Position

    pub(all) struct Position {
    line_number : Int
    column : Int
    } derive(Eq,
    Debug
    )

    A position in the editor, the viewer-used subset of Monaco/VS Code's Position (vs/editor/common/core/position.ts). One-based on both axes: line_number starts at 1 and column starts at 1 (the first character on a line sits between column 1 and column 2). Field names use the repo's snake_case convention (line_number), matching Range::start_line_number.

    Position::Position

    fn Position::Position(line_number : Int, column : Int) -> Position

    Builds a position without normalization; callers decide the coordinate space before conversion through a snapshot.

    Position::compare

    fn Position::compare(a : Position, b : Position) -> Int

    Compares two positions by line and then column.

    Position::delta

    fn Position::delta(self : Position, delta_line_number? : Int, delta_column? : Int) -> Position

    Derives a shifted position, clamping both axes to at least one.

    Position::equal

    fn Position::equal(Position, Position) -> Bool

    Position::equals

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

    Whether this position equals other. Mirrors Monaco's Position.equals.

    Position::is_before

    fn Position::is_before(self : Position, other : Position) -> Bool

    Whether this position is strictly before other (equal positions return false). Mirrors Monaco's Position.isBefore.

    Position::is_before_or_equal

    fn Position::is_before_or_equal(self : Position, other : Position) -> Bool

    Whether this position is before or equal to other. Mirrors Monaco's Position.isBeforeOrEqual.

    Position::not_equal

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

    Position::to_repr

    Position::with_

    fn Position::with_(self : Position, line_number? : Int, column? : Int) -> Position

    A new position derived from this one. Retained as part of the documented coordinate-value contract.

    Posix

    type Posix

    The posix namespace of path.ts (D2) — uninhabited namespace type; only its static-style methods exist.

    Posix::basename

    fn Posix::basename(path : String, suffix? : String) -> String

    Returns the final POSIX path component, removing suffix when it matches.

    Posix::delimiter

    fn Posix::delimiter() -> String

    Returns the POSIX path-list delimiter (:).

    Posix::dirname

    fn Posix::dirname(path : String) -> String

    Returns the directory component of a POSIX path.

    Posix::extname

    fn Posix::extname(path : String) -> String

    Returns the extension of the final POSIX path component.

    Posix::is_absolute

    fn Posix::is_absolute(path : String) -> Bool

    Reports whether path is absolute under POSIX path rules.

    Posix::join

    fn Posix::join(paths : Array[String]) -> String

    Joins POSIX path fragments and normalizes the result.

    Posix::normalize

    fn Posix::normalize(path : String) -> String

    Normalizes a POSIX path.

    Posix::relative

    fn Posix::relative(from : String, to : String) -> String

    Computes the POSIX relative path from from to to.

    Posix::resolve

    fn Posix::resolve(path_segments : Array[String]) -> String

    Explicit POSIX path operations retained as the documented host-neutral path contract.

    Posix::sep

    fn Posix::sep() -> String

    Returns the POSIX path separator (/).

    Range

    pub(all) struct Range {
    start_line_number : Int
    start_column : Int
    end_line_number : Int
    end_column : Int
    } derive(Eq,
    Debug
    )

    A range in the editor. (start_line_number, start_column) is <= (end_line_number, end_column).

    Range::Range

    fn Range::Range(start_line_number : Int, start_column : Int, end_line_number : Int, end_column : Int) -> Range

    Range::are_intersecting

    fn Range::are_intersecting(a : Range, b : Range) -> Bool

    Tests whether two ranges overlap; touching ranges do not intersect.

    Range::are_intersecting_or_touching

    fn Range::are_intersecting_or_touching(a : Range, b : Range) -> Bool

    Test if the two ranges are touching in any way.

    Range::compare_ranges_using_starts

    fn Range::compare_ranges_using_starts(a : Range, b : Range) -> Int

    Compare ranges by start position, then end position.

    Range::contains_position

    fn Range::contains_position(self : Range, position : Position) -> Bool

    Test if position is in this range. If the position is at the edges, returns true.

    Range::contains_range

    fn Range::contains_range(self : Range, other : Range) -> Bool

    Tests whether other is contained in this range; equal ranges count as contained.

    Range::equal

    fn Range::equal(Range, Range) -> Bool

    Range::from_positions

    fn Range::from_positions(start : Position, end : Position) -> Range

    Build a range from two positions.

    Range::get_end_position

    fn Range::get_end_position(self : Range) -> Position

    The end boundary as a position, for callers that forward a range into selection and reveal APIs.

    Range::get_start_position

    fn Range::get_start_position(self : Range) -> Position

    The start position (before or equal to the end position).

    Range::intersect_ranges

    fn Range::intersect_ranges(self : Range, other : Range) -> Range?

    An intersection of the two ranges, or None if they do not intersect.

    Range::is_empty

    fn Range::is_empty(self : Range) -> Bool

    Test if this range is empty.

    Range::not_equal

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

    Range::plus_range

    fn Range::plus_range(self : Range, other : Range) -> Range

    A reunion of the two ranges (smallest start, largest end).

    Range::set_end_position

    fn Range::set_end_position(self : Range, end_line_number : Int, end_column : Int) -> Range

    New range with this range's start and the given end position.

    Range::strict_contains_range

    fn Range::strict_contains_range(self : Range, other : Range) -> Bool

    Tests whether other starts after and ends before this range.

    Range::to_repr

    Range::to_string

    fn Range::to_string(self : Range) -> String

    Transform to a user-presentable string representation.

    Uri

    pub struct Uri {
    scheme : String
    authority : String
    path : String
    query : String
    fragment : String
    // private fields
    }

    Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986. This class is a simple parser which creates the basic component parts (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation and encoding.

    foo://example.com:8042/over/there?name=ferret#nose \_/ \______________/\_________/ \_________/ \__/ | | | | | scheme authority path query fragment | _____________________|__ / \ / \ urn:example:animal:ferret:nose

    Components are stored decoded (uri.ts:125-146). The two mut fields are the _formatted/_fsPath lazy caches of the Uri subclass (uri.ts:455-477, D5).
    impl Eq for Uri
    impl Hash for Uri
    impl Debug for Uri

    Uri::equal

    fn Uri::equal(self : Uri, other : Uri) -> Bool

    Uri::file

    fn Uri::file(path : String) -> Uri

    URI.file (uri.ts:307): creates a new URI from a file system path, e.g. c:\my\files, /usr/home, or \\server\share\some\path.

    The difference between Uri::parse and Uri::file is that the latter treats the argument as path, not as stringified-uri: the path might contain characters that are interpreted (# and ?).

    Validation cannot fail on this shape (scheme file, slash-rooted path), so unlike parse/from this stays non-raising (D6).

    Uri::from

    fn Uri::from(scheme~ : String, authority? : String, path? : String, query? : String, fragment? : String, strict? : Bool) -> Uri raise UriError

    URI.from (uri.ts:341): creates a new URI from uri components with validation — use for untrusted components from storage, user input, command arguments etc. Unless strict the scheme defaults to file.

    Uri::fs_path

    fn Uri::fs_path(self : Uri) -> String

    Returns the URI's platform-specific filesystem path.

    Uri::hash

    fn Uri::hash(self : Uri) -> Int

    Uri::hash_combine

    fn Uri::hash_combine(self : Uri, hasher : Hasher) -> Unit

    Uri::join_path

    fn Uri::join_path(uri : Uri, path_fragment : Array[String]) -> Uri

    Joins path fragments onto a URI path.

    Uri::not_equal

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

    Uri::parse

    fn Uri::parse(value : String, strict? : Bool) -> Uri raise UriError

    URI.parse (uri.ts:271): creates a new URI from a string, e.g. http://www.example.com/some/path, file:///usr/home, or scheme:with/path. Components are percent-decoded before validation.

    Uri::to_repr

    Uri::to_string

    fn Uri::to_string(self : Uri, skip_encoding? : Bool) -> String

    toString(skipEncoding) (uri.ts:386, caching override uri.ts:467-477): guaranteed to round-trip through Uri::parse into an equal URI. The result is percent-encoded (mostly ignoring scheme-specific rules) and is meant for externalization or transport, not display.

    Uri::with_

    fn Uri::with_(self : Uri, scheme? : String, authority? : String, path? : String, query? : String, fragment? : String) -> Uri raise UriError

    Returns a URI with selected components replaced.

    Win32

    type Win32

    The win32 namespace of path.ts (D2) — uninhabited namespace type; only its static-style methods exist.

    Win32::basename

    fn Win32::basename(path : String, suffix? : String) -> String

    Returns the final Win32 path component, removing suffix when it matches.

    Win32::delimiter

    fn Win32::delimiter() -> String

    Returns the Win32 path-list delimiter (;).

    Win32::dirname

    fn Win32::dirname(path : String) -> String

    Returns the directory component of a Win32 path.

    Win32::extname

    fn Win32::extname(path : String) -> String

    Returns the extension of the final Win32 path component.

    Win32::is_absolute

    fn Win32::is_absolute(path : String) -> Bool

    Reports whether path is absolute under Win32 path rules.

    Win32::join

    fn Win32::join(paths : Array[String]) -> String

    Joins Win32 path fragments while preserving an initial UNC double slash.

    Win32::normalize

    fn Win32::normalize(path : String) -> String

    Normalizes a Win32 path, including the relative-colon guard from path.ts:346/CVE-2024-36139.

    Win32::relative

    fn Win32::relative(from : String, to : String) -> String

    Computes the case-insensitive Win32 relative path from from to to.

    Win32::resolve

    fn Win32::resolve(path_segments : Array[String]) -> String

    Explicit Win32 path operations retained as the documented host-neutral path contract.

    Win32::sep

    fn Win32::sep() -> String

    Returns the Win32 path separator (\\).

    basename_or_authority

    fn basename_or_authority(resource : Uri) -> String

    compare

    fn compare(a : String, b : String) -> Int

    Mirrors strings.compare (strings.ts:343): JS </> on strings is charwise UTF-16 code-unit lexicographic. Required because MoonBit's built-in String compare is length-first ("z" > "aa" here, not there).

    compare_substring

    fn compare_substring(a : String, b : String, a_start? : Int, a_end? : Int, b_start? : Int, b_end? : Int) -> Int

    Compares the selected UTF-16 substrings without allocating slices.

    compare_substring_ignore_case

    fn compare_substring_ignore_case(a : String, b : String, a_start? : Int, a_end? : Int, b_start? : Int, b_end? : Int) -> Int

    Compares the selected UTF-16 substrings with the documented case-folding policy and without allocating slices.

    contains_rtl

    fn contains_rtl(text : String) -> Bool

    Whether text contains any right-to-left character. Mirrors strings.containsRTL over the common BMP RTL blocks (Hebrew/Arabic U+0590..U+08FF, Arabic Presentation Forms-A U+FB1D..U+FDFF and Forms-B U+FE70..U+FEFF); supplementary-plane RTL is not detected, matching the viewer's existing simplified port.

    dirname

    fn dirname(path : String) -> String

    Platform-selected dirname (path.ts:1582).

    equals_ignore_case

    fn equals_ignore_case(a : String, b : String) -> Bool

    Case-insensitive whole-string equality retained as documented text API.

    escape

    fn escape(text : String) -> String

    HTML-escapes &, <, >. Mirrors strings.escape. It deliberately leaves " alone, matching Monaco's _tokenizeToString; use escape_html for text that can also land in an attribute value.

    escape_html

    fn escape_html(text : String) -> String

    HTML-escapes text for element content or attribute values: escape's three characters plus ". Callers that build markup by concatenation and may quote the result need this variant.

    ext_uri

    let ext_uri : ExtUri

    URI comparison/path policies retained as the documented resource identity contract.

    ext_uri_biased_ignore_path_case

    let ext_uri_biased_ignore_path_case : ExtUri

    Resource identity policy that ignores file-path case only on hosts where file paths are case-insensitive.

    ext_uri_ignore_path_case

    let ext_uri_ignore_path_case : ExtUri

    Resource identity policy that always ignores URI path casing.

    first_non_whitespace_index

    fn first_non_whitespace_index(text : String) -> Int

    Index of the first non-whitespace (non-space, non-tab) character, or -1. Mirrors strings.firstNonWhitespaceIndex.

    is_full_width_character

    fn is_full_width_character(char_code : Int) -> Bool

    Whether char_code is a full-width character (CJK and related blocks). Mirrors strings.isFullWidthCharacter.

    is_high_surrogate

    fn is_high_surrogate(char_code : Int) -> Bool

    0xD800 <= charCode <= 0xDBFF. Mirrors strings.isHighSurrogate; the std Int::is_leading_surrogate is the identical range check.

    is_linux

    let is_linux : Bool

    The host platform flag retained for the documented URI case-policy relationship.

    is_low_surrogate

    fn is_low_surrogate(char_code : Int) -> Bool

    0xDC00 <= charCode <= 0xDFFF. Mirrors strings.isLowSurrogate; the std Int::is_trailing_surrogate is the identical range check.

    is_macintosh

    let is_macintosh : Bool

    Monaco platform.isMacintosh.

    is_windows

    let is_windows : Bool

    Monaco platform.isWindows.

    last_non_whitespace_index

    fn last_non_whitespace_index(text : String) -> Int

    Index of the last non-whitespace (non-space, non-tab) character, or -1. Mirrors strings.lastNonWhitespaceIndex.

    platform_is_win32

    fn platform_is_win32() -> Bool

    path.ts:82 platformIsWin32 / the platform.isWindows reads inside uri.ts and resources.ts. Monaco binds the value at module load; we read it per call so the D8 test seam can flip it (observationally identical — the platform never changes mid-session, Deviation D1).

    run_async_tasks_sequentially

    async fn run_async_tasks_sequentially(tasks : Array[async () -> Unit]) -> Unit

    Runtime-neutral policy for starting a closed set of async tasks. Lower packages default to this ordered runner; hosts with their own async runtime may inject a concurrent runner without coupling shared packages to that runtime.

    schemas_in_memory

    let schemas_in_memory : String

    Schemas.inMemory (network.ts:18) — models that exist in memory only and have no correspondence on a server or such.

    single_letter_hash

    fn single_letter_hash(n : Int) -> String

    Maps n to a single letter (a..z then A..Z, wrapping). Mirrors strings.singleLetterHash; Monaco uses it to prefix per-instance id namespaces (model decoration ids, whitespace ids).

    split_lines

    fn split_lines(text : String) -> Array[String]

    Splits text on \r\n / \r / \n. Mirrors strings.splitLines (strings.ts:251), whose split regex treats \r\n as one separator.

    starts_with_ignore_case

    fn starts_with_ignore_case(str : String, candidate : String) -> Bool

    Case-insensitive prefix matching retained as documented text API.

    uri_to_fs_path

    fn uri_to_fs_path(uri : Uri, keep_drive_letter_casing : Bool) -> String

    Computes a platform-specific filesystem path with explicit drive-letter casing policy.