flowchart LR
P["PartialCursorState<br>model or view"] --> C["CursorsController"]
C --> M["model CursorState"]
C --> V["view CursorState"]
X["CursorContext conversions"] --> C///|
fn collapsed(position : @base_common.Position) -> @cursor.SingleCursorState {
SingleCursorState(position, position, Simple, position)
}
///|
test "moved either extends the anchor or starts a new caret" {
let start = collapsed(Position(2, 1))
let extended = start.moved(true, Position(4, 7))
let restarted = start.moved(false, Position(4, 7))
debug_inspect(
(
(extended.has_selection(), extended.selection()),
(restarted.has_selection(), restarted.selection()),
),
content=(
#|(
#| (
#| true,
#| {
#| selection_start: { line_number: 2, column: 1 },
#| position: { line_number: 4, column: 7 },
#| },
#| ),
#| (
#| false,
#| {
#| selection_start: { line_number: 4, column: 7 },
#| position: { line_number: 4, column: 7 },
#| },
#| ),
#|)
),
)
}///|
test "a word anchor retains its shape" {
let state = @cursor.SingleCursorState(
Position(2, 5),
Position(2, 10),
Word,
Position(2, 10),
)
debug_inspect(
(
state.moved(true, Position(4, 1)).selection(),
state.moved(true, Position(1, 1)).selection(),
),
content=(
#|(
#| {
#| selection_start: { line_number: 2, column: 5 },
#| position: { line_number: 4, column: 1 },
#| },
#| {
#| selection_start: { line_number: 2, column: 10 },
#| position: { line_number: 1, column: 1 },
#| },
#|)
),
)
}///|
fn identity_context() -> @cursor.CursorContext {
CursorContext(
view_to_model=position => position,
view_range_to_model=range => range,
model_to_view=position => position,
)
}
///|
fn controller_for(
text : String,
) -> (@cursor.CursorsController, @model.TextModel) raise {
let model = @model.TextModel(
@base_common.Uri::parse("file:///cursor-doc.mbt"),
"cursor-doc.mbt",
"moonbit",
1,
"rev-1",
text,
)
(CursorsController(model, identity_context()), model)
}
///|
fn set_selection(
controller : @cursor.CursorsController,
selection : @core.Selection,
) -> @cursor.CursorStateChange? {
controller.set_cursor_state(
Some(@cursor.CursorState::from_model_selection(selection)),
)
}
///|
test "an identical transition produces no second change" {
let (controller, model) = controller_for("fn main {\n println(1)\n}\n")
let selection = @core.Selection(Position(2, 3), Position(2, 3))
let first = set_selection(controller, selection)
let repeat = set_selection(controller, selection)
debug_inspect(
(first is Some(_), repeat is Some(_), controller.get_model_selection()),
content=(
#|(
#| true,
#| false,
#| {
#| selection_start: { line_number: 2, column: 3 },
#| position: { line_number: 2, column: 3 },
#| },
#|)
),
)
model.dispose()
}///|
test "out-of-range positions are clamped" {
let (controller, model) = controller_for("ab\ncd\n")
set_selection(controller, Selection(Position(99, 99), Position(99, 99)))
|> ignore
debug_inspect(
controller.get_model_selection(),
content=(
#|{
#| selection_start: { line_number: 3, column: 1 },
#| position: { line_number: 3, column: 1 },
#|}
),
)
model.dispose()
}moon test --target all viewer/common/cursortype CursorContextfn CursorContext::CursorContext(view_to_model~ : (Position) -> Position, view_range_to_model~ : (Range) -> Range, model_to_view~ : (Position) -> Position) -> CursorContextpub struct CursorState {
model_state : SingleCursorState
view_state : SingleCursorState
} derive(Eq, Debug)type CursorsControllerfn CursorsController::CursorsController(model : TextModel, context : CursorContext) -> CursorsControllerfn CursorsController::on_model_content_changed(self : CursorsController, event : InternalModelContentChangeEvent) -> CursorStateChange?fn CursorsController::set_cursor_state(self : CursorsController, state : PartialCursorState?, source? : String, reason? : CursorChangeReason) -> CursorStateChange?fn SingleCursorState::SingleCursorState(selection_start_start : Position, selection_start_end : Position, selection_start_kind : SelectionStartKind, position : Position, selection_start_leftover_visible_columns? : Int, leftover_visible_columns? : Int) -> SingleCursorStatefn SingleCursorState::moved(self : SingleCursorState, in_selection_mode : Bool, position : Position, leftover_visible_columns? : Int) -> SingleCursorStateInstall
Download zipReadonly MoonBit code viewer harness inspired by Monaco and CodeMirror.