// Backing for the public read-API visible-range cluster, the `ViewModel` side
// of Monaco's `CodeEditorWidget.getVisibleRanges` / `getPosition` delegators
// (`vs/editor/common/viewModel/viewModelImpl.ts`). The completely-visible view
// line range is computed by the owner from its `ViewLayout` (Monaco's
// `getCompletelyVisibleViewRange`); this file ports the view→model conversion
// with the hidden-area split (`_toModelVisibleRanges`) plus the column/visibility
// helpers it needs.
///|
/// Merged one-based hidden model-line intervals, Monaco's
/// `ViewModel.getHiddenAreas` (`this._lines.getHiddenAreas()`).
pub fn ViewModel::get_hidden_areas(
self : ViewModel,
) -> Array[@base_common.Range] {
self.lines.get_hidden_areas()
}
///|
/// Whether a model position lands on a visible (non-hidden) line, Monaco's
/// `CoordinatesConverter.modelPositionIsVisible`. The read API gates
/// `getLineHeightForPosition` on this.
pub fn ViewModel::model_position_is_visible(
self : ViewModel,
position : @base_common.Position,
) -> Bool {
self.coordinates_converter.model_position_is_visible(position)
}
///|
/// Validates a model position before ViewZones derives its before/after
/// position — `TextModel.validatePosition` at `viewZones.ts:159-173`.
pub fn ViewModel::validate_model_position(
self : ViewModel,
position : @base_common.Position,
) -> @base_common.Position {
self.model.validate_position(position)
}
///|
/// Converts one validated-or-untrusted model position to view coordinates,
/// forwarding the ViewZones affinity and `allowZeroLineNumber` seam exactly.
/// The projected collection performs source-shaped model validation first.
pub fn ViewModel::model_position_to_view_position(
self : ViewModel,
position : @base_common.Position,
affinity? : @model.PositionAffinity,
allow_zero_line_number~ : Bool = false,
) -> @base_common.Position {
self.lines.convert_model_position_to_view_position(
position.line_number,
position.column,
affinity?,
allow_zero_line_number~,
)
}
///|
/// Minimum one-based column of a view line, Monaco's `getLineMinColumn`.
pub fn ViewModel::get_line_min_column(
self : ViewModel,
view_line_number : Int32,
) -> Int32 {
self.lines.get_view_line_min_column(view_line_number)
}
///|
/// Maximum one-based column of a view line, Monaco's `getLineMaxColumn`.
pub fn ViewModel::get_line_max_column(
self : ViewModel,
view_line_number : Int32,
) -> Int32 {
self.lines.get_view_line_max_column(view_line_number)
}
///|
/// Maximum one-based column of a model line, Monaco's `model.getLineMaxColumn`
/// (`content length + 1`). Used to close a split visible range at a hidden
/// region's boundary line.
pub fn ViewModel::model_line_max_column(
self : ViewModel,
model_line_number : Int32,
) -> Int32 {
self.model.snapshot.line_text(model_line_number - 1).length() + 1
}
///|
/// Splits a completely-visible *view* range into the model ranges it covers,
/// Monaco's `ViewModelImpl._toModelVisibleRanges`
/// (`viewModelImpl.ts:655`). With no hidden regions the converted model range is
/// returned whole; otherwise each hidden region carves the visible span into the
/// model ranges actually on screen above/below it.
pub fn ViewModel::to_model_visible_ranges(
self : ViewModel,
visible_view_range : @base_common.Range,
) -> Array[@base_common.Range] {
let visible = self.coordinates_converter.view_range_to_model_range(
visible_view_range,
)
let hidden_areas = self.get_hidden_areas()
if hidden_areas.length() == 0 {
return [visible]
}
let result : Array[@base_common.Range] = []
let mut start_line_number = visible.start_line_number
let mut start_column = visible.start_column
let end_line_number = visible.end_line_number
let end_column = visible.end_column
for hidden in hidden_areas {
let hidden_start_line_number = hidden.start_line_number
let hidden_end_line_number = hidden.end_line_number
if hidden_end_line_number < start_line_number {
continue
}
if hidden_start_line_number > end_line_number {
continue
}
if start_line_number < hidden_start_line_number {
result.push(
Range(
start_line_number,
start_column,
hidden_start_line_number - 1,
self.model_line_max_column(hidden_start_line_number - 1),
),
)
}
start_line_number = hidden_end_line_number + 1
start_column = 1
}
if start_line_number < end_line_number ||
(start_line_number == end_line_number && start_column < end_column) {
result.push(
Range(start_line_number, start_column, end_line_number, end_column),
)
}
result
}