flowchart LR
M["model column<br>(UTF-16 code units, 1-based)"]
V["visible column<br>(rendered cells, 0-based)"]
M -->|"visible_column_from_column(line, column, tab_size)"| V
V -->|"column_from_visible_column(line, visible, tab_size)"| M
M -->|"to_statusbar_column"| S["status bar column<br>(1-based, tab = 1 cell)"]///|
test "tabs make the visible column diverge from the model column" {
// "\tab" — one tab then three characters, tab size 4.
let line = "\tabc"
debug_inspect(
(
// model column 1 is before the tab, so nothing is rendered yet
@core.visible_column_from_column(line, 1, 4),
// model column 2 is after the tab: it has consumed a full tab stop
@core.visible_column_from_column(line, 2, 4),
@core.visible_column_from_column(line, 3, 4),
// and back again
@core.column_from_visible_column(line, 4, 4),
@core.column_from_visible_column(line, 5, 4),
),
content=(
#|(0, 4, 5, 2, 3)
),
)
}///|
test "with no tabs the two column spaces coincide" {
let line = "let x = 1"
debug_inspect(
(
@core.visible_column_from_column(line, 5, 4),
@core.column_from_visible_column(line, 4, 4),
),
content=(
#|(4, 5)
),
)
}///|
test "the status bar counts a tab as one character" {
let line = "\tabc"
debug_inspect(
(
@core.to_statusbar_column(line, 2, 4),
@core.visible_column_from_column(line, 2, 4),
),
content=(
#|(5, 4)
),
)
}flowchart LR
subgraph ltr["LTR — anchor before caret"]
A1["selection_start (2,1)"] --> P1["position (4,3)"]
end
subgraph rtl["RTL — caret before anchor"]
P2["position (2,1)"] --> A2["selection_start (4,3)"]
end///|
test "direction is preserved while start and end are normalized" {
let anchor = @base_common.Position(2, 1)
let caret = @base_common.Position(4, 3)
let forward = @core.Selection(anchor, caret)
let backward = @core.Selection(caret, anchor)
debug_inspect(
(
(forward.direction(), forward.start(), forward.end()),
(backward.direction(), backward.start(), backward.end()),
// the gesture endpoints are not normalized
(backward.get_selection_start(), backward.get_position()),
),
content=(
#|(
#| (LTR, { line_number: 2, column: 1 }, { line_number: 4, column: 3 }),
#| (RTL, { line_number: 2, column: 1 }, { line_number: 4, column: 3 }),
#| ({ line_number: 4, column: 3 }, { line_number: 2, column: 1 }),
#|)
),
)
}///|
test "an empty selection is a caret" {
let at = @base_common.Position(3, 7)
debug_inspect(
(
@core.Selection(at, at).is_empty(),
@core.Selection(at, Position(3, 8)).is_empty(),
),
content=(
#|(true, false)
),
)
}///|
test "endpoint updates are copies in document order" {
let original = @core.Selection(Position(2, 1), Position(4, 3))
let moved = original.set_end_position(9, 1)
debug_inspect(
(original, moved),
content=(
#|(
#| {
#| selection_start: { line_number: 2, column: 1 },
#| position: { line_number: 4, column: 3 },
#| },
#| {
#| selection_start: { line_number: 2, column: 1 },
#| position: { line_number: 9, column: 1 },
#| },
#|)
),
)
}///|
test "layout constants have one definition" {
debug_inspect(
(
@core.editor_vertical_scrollbar_size, @core.editor_horizontal_scrollbar_size,
),
content=(
#|(14, 12)
),
)
}moon test --target js viewer/common/corefn column_from_visible_column(line_content : String, visible_column : Int, tab_size : Int) -> Intlet editor_vertical_scrollbar_size : Doublefn to_statusbar_column(line_content : String, column : Int, tab_size : Int) -> Intfn visible_column_from_column(line_content : String, column : Int, tab_size : Int) -> IntInstall
Download zipReadonly MoonBit code viewer harness inspired by Monaco and CodeMirror.