first pass of merging in warp (doesn't build)

This commit is contained in:
Ryan Ward
2026-07-01 16:08:58 -05:00
parent 2f64909469
commit 4770ac06b5
3662 changed files with 414574 additions and 89772 deletions
+43 -37
View File
@@ -1,22 +1,21 @@
use galaxyui::{AppContext, Entity, ModelAsRef, ModelContext, ModelHandle, units::Pixels};
use num_traits::SaturatingSub;
use std::ops::Range;
use vec1::Vec1;
use crate::{
content::{
buffer::{
AutoScrollBehavior, Buffer, BufferEvent, BufferSelectAction, SelectionOffsets,
ToBufferCharOffset, ToBufferPoint,
},
hidden_lines_model::HiddenLinesModel,
selection_model::BufferSelectionModel,
text::{BlockType, BufferBlockStyle, CodeBlockType},
},
render::model::{RenderState, SoftWrapPoint},
};
use galaxyui::text::{TextBuffer, point::Point, word_boundaries::WordBoundariesPolicy};
use num_traits::SaturatingSub;
use string_offset::CharOffset;
use vec1::Vec1;
use galaxyui_core::text::TextBuffer;
use galaxyui_core::text::point::Point;
use galaxyui_core::text::word_boundaries::WordBoundariesPolicy;
use galaxyui_core::{AppContext, Entity, ModelAsRef, ModelContext, ModelHandle};
use crate::content::buffer::{
AutoScrollBehavior, Buffer, BufferEvent, BufferSelectAction, SelectionOffsets,
ToBufferCharOffset, ToBufferPoint,
};
use crate::content::hidden_lines_model::HiddenLinesModel;
use crate::content::selection_model::BufferSelectionModel;
use crate::content::text::{BlockType, BufferBlockStyle, CodeBlockType};
use crate::render::model::{ColumnUnit, RenderState, SoftWrapPoint};
#[cfg(test)]
#[path = "selection_tests.rs"]
@@ -29,13 +28,13 @@ pub struct SelectionModel {
selection_model: ModelHandle<BufferSelectionModel>,
hidden_lines: Option<ModelHandle<HiddenLinesModel>>,
/// The goal x-coordinate in pixels. When moving between lines, the desired column
/// might not exist on the new line (because it's shorter than the previous line). Storing
/// the goal column lets us move back to that column when changing to a longer line.
/// The goal column when moving between lines. The desired column might not exist on the
/// new line (because it's shorter than the previous line). Storing the goal column lets
/// us move back to that column when changing to a longer line.
///
/// This is stored in pixels instead of characters so that, like other editors, we can
/// match the visual column, accounting for any differences in padding and character width.
pub goal_xs: Option<Vec1<Pixels>>,
/// Uses [`ColumnUnit`] to work in either pixel coordinates (GUI path) or char-cell
/// coordinates (TUI path). All values must use the same variant within one session.
pub goal_xs: Option<Vec1<ColumnUnit>>,
/// The in-progress selection.
pending_selection: Option<PendingSelection>,
@@ -95,7 +94,7 @@ pub struct NavigationResult {
/// The resulting character offset from text navigation.
pub offset: CharOffset,
/// The goal column based on the original offset, if it's different from the character offset.
pub goal_x: Option<Pixels>,
pub goal_x: Option<ColumnUnit>,
}
impl SelectionModel {
@@ -664,19 +663,19 @@ impl SelectionModel {
}
/// Modify all of the selections in a given way.
/// The currently active selections are looped though, along with any current x-pixel goal values,
/// and a new head and tail offsets and a new x-pixel goal value are calculated for each selection.
/// The currently active selections are looped though, along with any current goal column values,
/// and a new head, tail, and goal column are calculated for each selection.
///
/// selection_update: A function that takes the current selection, the current goal x, and the current
/// selection offsets, and returns the new goal x and the new selection offsets.
/// selection_update: A function that takes the current selection, the current goal column, and
/// the current selection offsets, and returns the new goal column and new selection offsets.
fn update_selections_internal<T>(&mut self, selection_update: T, ctx: &mut ModelContext<Self>)
where
T: Fn(
&SelectionModel,
&mut ModelContext<SelectionModel>,
&SelectionOffsets,
&Option<Pixels>,
) -> (Option<Pixels>, SelectionOffsets),
&Option<ColumnUnit>,
) -> (Option<ColumnUnit>, SelectionOffsets),
{
// Before we take action, merge any overlapping selections.
self.selection_model.update(ctx, |selection_model, _ctx| {
@@ -803,7 +802,7 @@ impl SelectionModel {
direction: TextDirection,
unit: TextUnit,
step_size: u32,
goal_x: Option<Pixels>,
goal_x: Option<ColumnUnit>,
ctx: &impl ModelAsRef,
) -> NavigationResult {
match unit {
@@ -870,7 +869,7 @@ impl SelectionModel {
start: CharOffset,
direction: TextDirection,
step_size: u32,
goal_x: Option<Pixels>,
goal_x: Option<ColumnUnit>,
ctx: &impl ModelAsRef,
) -> NavigationResult {
let render = self.render.as_ref(ctx);
@@ -910,7 +909,7 @@ impl SelectionModel {
// equivalent to self.goal_x.unwrap_or(next_point.column()), but captures the intent that we
// want to stick to the rightmost point along the path, especially with proportional fonts.
let goal_column = match goal_x {
Some(x) => x.max(next_point.column()),
Some(x) => x.col_max(next_point.column()),
None => next_point.column(),
};
let goal_point = SoftWrapPoint::new(next_point.row(), goal_column);
@@ -943,7 +942,7 @@ impl SelectionModel {
let start_point = render.offset_to_softwrap_point(start.saturating_sub(&1.into()));
let end_offset = match direction {
TextDirection::Backwards => {
let row_start = SoftWrapPoint::new(start_point.row(), Pixels::zero());
let row_start = SoftWrapPoint::new(start_point.row(), ColumnUnit::pixels_zero());
let soft_wrapped_start = render.softwrap_point_to_offset(row_start);
match content.indented_line_start(start) {
@@ -968,8 +967,10 @@ impl SelectionModel {
match content.indented_line_start(start) {
Some(indented_start) if indented_start > start => indented_start,
_ => {
let next_row_start =
SoftWrapPoint::new(start_point.row() + 1, Pixels::zero());
let next_row_start = SoftWrapPoint::new(
start_point.row() + 1,
ColumnUnit::pixels_zero(),
);
// TODO(CLD-558): This should have a -1.
render.softwrap_point_to_offset(next_row_start)
}
@@ -1004,7 +1005,12 @@ impl SelectionModel {
}
}
fn handle_buffer_event(&mut self, event: &BufferEvent, ctx: &mut ModelContext<Self>) {
fn handle_buffer_event(
&mut self,
_: ModelHandle<Buffer>,
event: &BufferEvent,
ctx: &mut ModelContext<Self>,
) {
match event {
BufferEvent::ContentChanged { origin, .. } if origin.from_user() => self.goal_xs = None,
BufferEvent::AnchorUpdated {
@@ -1028,7 +1034,7 @@ impl NavigationResult {
/// Creates a `NavigationResult` with both a new offset and an updated goal column.
/// If the goal column does not exist on the new line, it may not correspond to the
/// actual offset.
pub fn for_offset_and_goal(offset: CharOffset, goal_x: Option<Pixels>) -> Self {
pub fn for_offset_and_goal(offset: CharOffset, goal_x: Option<ColumnUnit>) -> Self {
Self { offset, goal_x }
}