use super::base_tokens::build_base_tokens;
use super::folding::{apply_folding, fold_adjusted_visible_count, fold_skip_set};
use super::style::fold_placeholder_style;
use super::transforms::{
apply_conceal_ranges, apply_soft_breaks, apply_wrapping_transform, inject_virtual_lines,
};
use super::MAX_SAFE_LINE_WIDTH;
use crate::state::{EditorState, ViewMode};
use crate::view::folding::FoldManager;
use crate::view::theme::Theme;
use crate::view::ui::view_pipeline::{ViewLine, ViewLineIterator};
use crate::view::viewport::Viewport;
use fresh_core::api::ViewTransformPayload;
pub(super) struct ViewData {
pub lines: Vec<ViewLine>,
}
#[allow(clippy::too_many_arguments)]
pub(super) fn build_view_data(
state: &mut EditorState,
viewport: &Viewport,
view_transform: Option<ViewTransformPayload>,
estimated_line_length: usize,
visible_count: usize,
line_wrap_enabled: bool,
content_width: usize,
gutter_width: usize,
view_mode: &ViewMode,
folds: &FoldManager,
theme: &Theme,
) -> ViewData {
let adjusted_visible_count = fold_adjusted_visible_count(
&state.buffer,
&state.marker_list,
folds,
viewport.top_byte,
visible_count,
);
let is_binary = state.buffer.is_binary();
let line_ending = state.buffer.line_ending();
let fold_skip = fold_skip_set(&state.buffer, &state.marker_list, folds);
let base_tokens = build_base_tokens(
&mut state.buffer,
viewport.top_byte,
estimated_line_length,
adjusted_visible_count,
is_binary,
line_ending,
&fold_skip,
);
let has_view_transform = view_transform.is_some();
let mut tokens = view_transform.map(|vt| vt.tokens).unwrap_or(base_tokens);
let is_compose = matches!(view_mode, ViewMode::PageView);
if is_compose && !state.soft_breaks.is_empty() {
let viewport_end = tokens
.iter()
.filter_map(|t| t.source_offset)
.next_back()
.unwrap_or(viewport.top_byte)
+ 1;
let soft_breaks =
state
.soft_breaks
.query_viewport(viewport.top_byte, viewport_end, &state.marker_list);
if !soft_breaks.is_empty() {
tokens = apply_soft_breaks(tokens, &soft_breaks);
}
}
if is_compose && !state.conceals.is_empty() {
let viewport_end = tokens
.iter()
.filter_map(|t| t.source_offset)
.next_back()
.unwrap_or(viewport.top_byte)
+ 1;
let conceal_ranges =
state
.conceals
.query_viewport(viewport.top_byte, viewport_end, &state.marker_list);
if !conceal_ranges.is_empty() {
tokens = apply_conceal_ranges(tokens, &conceal_ranges);
}
}
let effective_width = if line_wrap_enabled {
let base = if let Some(col) = viewport.wrap_column {
col.min(content_width)
} else {
content_width
};
base.saturating_sub(1).max(1)
} else {
MAX_SAFE_LINE_WIDTH
};
let hanging_indent = line_wrap_enabled && viewport.wrap_indent;
tokens = apply_wrapping_transform(tokens, effective_width, gutter_width, hanging_indent);
let is_binary = state.buffer.is_binary();
let ansi_aware = !is_binary;
let at_buffer_end = if has_view_transform {
false
} else {
let max_source_offset = tokens
.iter()
.filter_map(|t| t.source_offset)
.max()
.unwrap_or(0);
max_source_offset + 2 >= state.buffer.len()
};
let source_lines: Vec<ViewLine> = ViewLineIterator::new(
&tokens,
is_binary,
ansi_aware,
state.buffer_settings.tab_size,
at_buffer_end,
)
.with_fold_skip(&fold_skip)
.collect();
let lines = inject_virtual_lines(source_lines, state, theme);
let placeholder_style = fold_placeholder_style(theme);
let lines = apply_folding(
lines,
&state.buffer,
&state.marker_list,
folds,
&placeholder_style,
);
ViewData { lines }
}