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
+55 -4
View File
@@ -2,11 +2,9 @@ use anyhow::{anyhow, Result};
use itertools::Itertools;
use string_offset::{ByteOffset, CharCounter, CharOffset};
use crate::event::ModifiersState;
use self::point::Point;
use self::word_boundaries::WordBoundaries;
use self::word_boundaries::{WordBoundaries, WordBoundariesPolicy};
use crate::event::ModifiersState;
pub mod header;
pub mod point;
@@ -189,6 +187,59 @@ pub trait TextBuffer {
self,
))
}
/// Returns the target [`Point`] for expanding a semantic (double-click) selection from
/// `position` in the given `direction`, respecting the word-boundary `policy`.
fn semantic_expansion_target<T: BufferIndex>(
&self,
position: T,
direction: SelectionDirection,
policy: &WordBoundariesPolicy,
) -> Result<Point> {
let offset = position.to_char_offset(self)?;
let target = match direction {
SelectionDirection::Forward => {
let mut chars = self.chars_at(offset)?;
let mut end = offset;
// Include the character under the cursor (if any).
if chars.next().is_some() {
end += 1;
// Extend through the following word only if the very next character is part
// of a word; a boundary char here stops us (no trailing whitespace, no
// crossing into the next word past a separator run).
if chars.next().is_some_and(|c| !policy.is_word_boundary(c)) {
end += 1;
for c in chars {
if policy.is_word_boundary(c) {
break;
}
end += 1;
}
}
}
end
}
SelectionDirection::Backward => {
let mut chars = self.chars_rev_at(offset)?;
let mut start = offset;
// Extend left through a preceding word only if the character immediately before
// the cursor is part of a word.
if chars.next().is_some_and(|c| !policy.is_word_boundary(c)) {
start -= 1;
for c in chars {
if policy.is_word_boundary(c) {
break;
}
start -= 1;
}
}
start
}
};
self.to_point(target)
}
}
/// A type which can index into a text buffer.
+2 -7
View File
@@ -1,10 +1,5 @@
use super::{
count_chars_up_to_byte,
point::Point,
{char_slice, BufferIndex, TextBuffer},
};
use super::str_to_byte_vec;
use super::point::Point;
use super::{char_slice, count_chars_up_to_byte, str_to_byte_vec, BufferIndex, TextBuffer};
#[test]
fn test_str_to_byte_vec() {
+2 -4
View File
@@ -1,7 +1,5 @@
use std::{
cmp::Ordering,
ops::{Add, AddAssign, Sub},
};
use std::cmp::Ordering;
use std::ops::{Add, AddAssign, Sub};
/// A point within a document. The exact coordinate system (whether or not rows
/// are soft-wrapped, what the unit for characters is) is unspecified.
@@ -1,11 +1,11 @@
use std::borrow::Cow;
use std::collections::HashSet;
use std::iter::Peekable;
use std::{borrow::Cow, collections::HashSet};
use itertools::Either;
use string_offset::CharOffset;
use super::point::Point;
use super::words::is_default_word_boundary;
use super::TextBuffer;
@@ -20,6 +20,19 @@ pub enum WordBoundariesPolicy {
OnlyWhitespace,
}
impl WordBoundariesPolicy {
/// Returns whether `c` is a word-boundary (separator) character under this policy.
pub fn is_word_boundary(&self, c: char) -> bool {
match self {
WordBoundariesPolicy::Default => is_default_word_boundary(c),
WordBoundariesPolicy::Custom(boundary_chars) => {
c.is_whitespace() || boundary_chars.contains(&c)
}
WordBoundariesPolicy::OnlyWhitespace => c.is_whitespace(),
}
}
}
#[derive(Clone, Copy)]
pub enum WordBoundariesApproach {
ForwardWordStarts,
@@ -150,13 +163,7 @@ impl<'a, T: TextBuffer + ?Sized> WordBoundaries<'a, T> {
}
fn is_word_boundary(&self, c: char) -> bool {
match self.policy.as_ref() {
WordBoundariesPolicy::Default => is_default_word_boundary(c),
WordBoundariesPolicy::Custom(boundary_chars) => {
c.is_whitespace() || boundary_chars.contains(&c)
}
WordBoundariesPolicy::OnlyWhitespace => c.is_whitespace(),
}
self.policy.is_word_boundary(c)
}
}
@@ -1,4 +1,71 @@
use super::*;
use crate::text::SelectionDirection;
/// Convenience wrapper for the forward exclusive-end target under the default policy.
fn fwd(buffer: &str, offset: usize) -> Point {
buffer
.semantic_expansion_target(
CharOffset::from(offset),
SelectionDirection::Forward,
&WordBoundariesPolicy::Default,
)
.unwrap()
}
/// Convenience wrapper for the backward inclusive-start target under the default policy.
fn bwd(buffer: &str, offset: usize) -> Point {
buffer
.semantic_expansion_target(
CharOffset::from(offset),
SelectionDirection::Backward,
&WordBoundariesPolicy::Default,
)
.unwrap()
}
#[test]
fn test_semantic_expansion_matches_block_list() {
// semantic_expansion_target must behave exactly like the terminal grid's
// semantic_search_left/right, which crucially never includes trailing whitespace when the
// tail sits on a non-word character.
// Char offsets: f0 o1 o2 .3 .4 .5 <space>6 b7 a8 r9 <space>10 b11 a12 z13
let dots = "foo... bar baz";
// Forward, tail on the LAST char of a punctuation run: the run is included up to that char,
// but the trailing space is NOT (exclusive end 6 = "foo...", not 7 which would add the space).
assert_eq!(
fwd(dots, 5),
Point::new(0, 6),
"trailing space must be excluded"
);
// Forward, tail on an earlier punctuation char: stops right after that char (next is a
// boundary), per the grid's per-cell behavior.
assert_eq!(fwd(dots, 3), Point::new(0, 4));
assert_eq!(fwd(dots, 4), Point::new(0, 5));
// Forward, tail on a word char: ordinary word selection (unchanged).
assert_eq!(fwd(dots, 1), Point::new(0, 3));
assert_eq!(fwd(dots, 0), Point::new(0, 3));
// Forward, tail directly on whitespace whose next char is a word: extends through that word
// (matches the grid, where a space's right neighbor pulls in the word).
assert_eq!(fwd(dots, 6), Point::new(0, 10));
// Backward, tail on a punctuation char whose left neighbor is also a boundary: stays put.
assert_eq!(bwd(dots, 5), Point::new(0, 5));
assert_eq!(bwd(dots, 4), Point::new(0, 4));
// Backward, tail on a word char: ordinary word selection (start of "bar").
assert_eq!(bwd(dots, 8), Point::new(0, 7));
// A comma followed by a space: forward from the comma includes the comma but excludes the
// following space (the reporter's exact case).
// Char offsets: f0 o1 o2 ,3 <space>4 b5 a6 r7
let comma = "foo, bar";
assert_eq!(
fwd(comma, 3),
Point::new(0, 4),
"comma included, trailing space excluded",
);
}
#[test]
fn test_word_boundaries() {