Clamp UTF-16 to point conversions
This commit is contained in:
parent
bb32599ded
commit
074e3cfbd6
6 changed files with 65 additions and 45 deletions
|
@ -55,7 +55,7 @@ use link_go_to_definition::{
|
||||||
};
|
};
|
||||||
pub use multi_buffer::{
|
pub use multi_buffer::{
|
||||||
Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
|
Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
|
||||||
ToPoint,
|
ToOffsetClamped, ToPoint,
|
||||||
};
|
};
|
||||||
use multi_buffer::{MultiBufferChunks, ToOffsetUtf16};
|
use multi_buffer::{MultiBufferChunks, ToOffsetUtf16};
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
|
|
|
@ -72,6 +72,10 @@ pub trait ToOffset: 'static + fmt::Debug {
|
||||||
fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
|
fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ToOffsetClamped: 'static + fmt::Debug {
|
||||||
|
fn to_offset_clamped(&self, snapshot: &MultiBufferSnapshot) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ToOffsetUtf16: 'static + fmt::Debug {
|
pub trait ToOffsetUtf16: 'static + fmt::Debug {
|
||||||
fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16;
|
fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16;
|
||||||
}
|
}
|
||||||
|
@ -1945,9 +1949,9 @@ impl MultiBufferSnapshot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
|
pub fn point_utf16_to_offset_clamped(&self, point: PointUtf16) -> usize {
|
||||||
if let Some((_, _, buffer)) = self.as_singleton() {
|
if let Some((_, _, buffer)) = self.as_singleton() {
|
||||||
return buffer.point_utf16_to_offset(point);
|
return buffer.point_utf16_to_offset_clamped(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>();
|
let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>();
|
||||||
|
@ -1961,7 +1965,7 @@ impl MultiBufferSnapshot {
|
||||||
.offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
|
.offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
|
||||||
let buffer_offset = excerpt
|
let buffer_offset = excerpt
|
||||||
.buffer
|
.buffer
|
||||||
.point_utf16_to_offset(excerpt_start_point + overshoot);
|
.point_utf16_to_offset_clamped(excerpt_start_point + overshoot);
|
||||||
*start_offset + (buffer_offset - excerpt_start_offset)
|
*start_offset + (buffer_offset - excerpt_start_offset)
|
||||||
} else {
|
} else {
|
||||||
self.excerpts.summary().text.len
|
self.excerpts.summary().text.len
|
||||||
|
@ -3274,12 +3278,6 @@ impl ToOffset for Point {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToOffset for PointUtf16 {
|
|
||||||
fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
|
|
||||||
snapshot.point_utf16_to_offset(*self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToOffset for usize {
|
impl ToOffset for usize {
|
||||||
fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
|
fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
|
||||||
assert!(*self <= snapshot.len(), "offset is out of range");
|
assert!(*self <= snapshot.len(), "offset is out of range");
|
||||||
|
@ -3293,6 +3291,12 @@ impl ToOffset for OffsetUtf16 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToOffsetClamped for PointUtf16 {
|
||||||
|
fn to_offset_clamped<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
|
||||||
|
snapshot.point_utf16_to_offset_clamped(*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToOffsetUtf16 for OffsetUtf16 {
|
impl ToOffsetUtf16 for OffsetUtf16 {
|
||||||
fn to_offset_utf16(&self, _snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
|
fn to_offset_utf16(&self, _snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
|
||||||
*self
|
*self
|
||||||
|
|
|
@ -14,6 +14,7 @@ use util::post_inc;
|
||||||
use crate::{
|
use crate::{
|
||||||
display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
|
display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
|
||||||
Anchor, DisplayPoint, ExcerptId, MultiBuffer, MultiBufferSnapshot, SelectMode, ToOffset,
|
Anchor, DisplayPoint, ExcerptId, MultiBuffer, MultiBufferSnapshot, SelectMode, ToOffset,
|
||||||
|
ToOffsetClamped,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -544,11 +545,33 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||||
T: ToOffset,
|
T: ToOffset,
|
||||||
{
|
{
|
||||||
let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
||||||
|
let ranges = ranges
|
||||||
|
.into_iter()
|
||||||
|
.map(|range| range.start.to_offset(&buffer)..range.end.to_offset(&buffer));
|
||||||
|
self.select_offset_ranges(ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_clamped_ranges<I, T>(&mut self, ranges: I)
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = Range<T>>,
|
||||||
|
T: ToOffsetClamped,
|
||||||
|
{
|
||||||
|
let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
||||||
|
let ranges = ranges.into_iter().map(|range| {
|
||||||
|
range.start.to_offset_clamped(&buffer)..range.end.to_offset_clamped(&buffer)
|
||||||
|
});
|
||||||
|
self.select_offset_ranges(ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_offset_ranges<I>(&mut self, ranges: I)
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = Range<usize>>,
|
||||||
|
{
|
||||||
let selections = ranges
|
let selections = ranges
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|range| {
|
.map(|range| {
|
||||||
let mut start = range.start.to_offset(&buffer);
|
let mut start = range.start;
|
||||||
let mut end = range.end.to_offset(&buffer);
|
let mut end = range.end;
|
||||||
let reversed = if start > end {
|
let reversed = if start > end {
|
||||||
mem::swap(&mut start, &mut end);
|
mem::swap(&mut start, &mut end);
|
||||||
true
|
true
|
||||||
|
|
|
@ -151,7 +151,7 @@ impl ProjectSymbolsView {
|
||||||
let editor = workspace.open_project_item::<Editor>(buffer, cx);
|
let editor = workspace.open_project_item::<Editor>(buffer, cx);
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
editor.change_selections(Some(Autoscroll::center()), cx, |s| {
|
editor.change_selections(Some(Autoscroll::center()), cx, |s| {
|
||||||
s.select_ranges([position..position])
|
s.select_clamped_ranges([position..position])
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -259,7 +259,7 @@ impl Rope {
|
||||||
.map_or(0, |chunk| chunk.point_to_offset(overshoot))
|
.map_or(0, |chunk| chunk.point_to_offset(overshoot))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn point_utf16_to_offset(&self, point: PointUtf16, clamp: bool) -> usize {
|
pub fn point_utf16_to_offset_clamped(&self, point: PointUtf16) -> usize {
|
||||||
if point >= self.summary().lines_utf16() {
|
if point >= self.summary().lines_utf16() {
|
||||||
return self.summary().len;
|
return self.summary().len;
|
||||||
}
|
}
|
||||||
|
@ -269,7 +269,7 @@ impl Rope {
|
||||||
cursor.start().1
|
cursor.start().1
|
||||||
+ cursor
|
+ cursor
|
||||||
.item()
|
.item()
|
||||||
.map_or(0, |chunk| chunk.point_utf16_to_offset(overshoot, clamp))
|
.map_or(0, |chunk| chunk.point_utf16_to_offset_clamped(overshoot))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn point_utf16_to_point(&self, point: PointUtf16) -> Point {
|
pub fn point_utf16_to_point(&self, point: PointUtf16) -> Point {
|
||||||
|
@ -711,7 +711,7 @@ impl Chunk {
|
||||||
point_utf16
|
point_utf16
|
||||||
}
|
}
|
||||||
|
|
||||||
fn point_utf16_to_offset(&self, target: PointUtf16, clamp: bool) -> usize {
|
fn point_utf16_to_offset_clamped(&self, target: PointUtf16) -> usize {
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
let mut point = PointUtf16::new(0, 0);
|
let mut point = PointUtf16::new(0, 0);
|
||||||
for ch in self.0.chars() {
|
for ch in self.0.chars() {
|
||||||
|
@ -724,26 +724,19 @@ impl Chunk {
|
||||||
point.column = 0;
|
point.column = 0;
|
||||||
|
|
||||||
if point.row > target.row {
|
if point.row > target.row {
|
||||||
if clamp {
|
//point is beyond the end of the line
|
||||||
//Return the offset up to but not including the newline
|
//Return the offset up to but not including the newline
|
||||||
return offset;
|
return offset;
|
||||||
}
|
|
||||||
panic!(
|
|
||||||
"point {:?} is beyond the end of a line with length {}",
|
|
||||||
target, point.column
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
point.column += ch.len_utf16() as u32;
|
point.column += ch.len_utf16() as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
if point > target {
|
if point > target {
|
||||||
if clamp {
|
//point is inside of a codepoint
|
||||||
//Return the offset before adding the len of the codepoint which
|
//Return the offset before adding the len of the codepoint which
|
||||||
//we have landed within, bias left
|
//we have landed within, bias left
|
||||||
return offset;
|
return offset;
|
||||||
}
|
|
||||||
panic!("point {:?} is inside of character {:?}", target, ch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += ch.len_utf8();
|
offset += ch.len_utf8();
|
||||||
|
@ -1222,7 +1215,7 @@ mod tests {
|
||||||
point
|
point
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
actual.point_utf16_to_offset(point_utf16, false),
|
actual.point_utf16_to_offset_clamped(point_utf16),
|
||||||
ix,
|
ix,
|
||||||
"point_utf16_to_offset({:?})",
|
"point_utf16_to_offset({:?})",
|
||||||
point_utf16
|
point_utf16
|
||||||
|
@ -1262,9 +1255,9 @@ mod tests {
|
||||||
let left_point = actual.clip_point_utf16(point_utf16, Bias::Left);
|
let left_point = actual.clip_point_utf16(point_utf16, Bias::Left);
|
||||||
let right_point = actual.clip_point_utf16(point_utf16, Bias::Right);
|
let right_point = actual.clip_point_utf16(point_utf16, Bias::Right);
|
||||||
assert!(right_point >= left_point);
|
assert!(right_point >= left_point);
|
||||||
// Ensure translating valid UTF-16 points to offsets doesn't panic.
|
// Ensure translating UTF-16 points to offsets doesn't panic.
|
||||||
actual.point_utf16_to_offset(left_point, false);
|
actual.point_utf16_to_offset_clamped(left_point);
|
||||||
actual.point_utf16_to_offset(right_point, false);
|
actual.point_utf16_to_offset_clamped(right_point);
|
||||||
|
|
||||||
offset_utf16.0 += 1;
|
offset_utf16.0 += 1;
|
||||||
if unit == b'\n' as u16 {
|
if unit == b'\n' as u16 {
|
||||||
|
|
|
@ -1590,12 +1590,8 @@ impl BufferSnapshot {
|
||||||
self.visible_text.point_to_offset(point)
|
self.visible_text.point_to_offset(point)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
|
|
||||||
self.visible_text.point_utf16_to_offset(point, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn point_utf16_to_offset_clamped(&self, point: PointUtf16) -> usize {
|
pub fn point_utf16_to_offset_clamped(&self, point: PointUtf16) -> usize {
|
||||||
self.visible_text.point_utf16_to_offset(point, true)
|
self.visible_text.point_utf16_to_offset_clamped(point)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn point_utf16_to_point(&self, point: PointUtf16) -> Point {
|
pub fn point_utf16_to_point(&self, point: PointUtf16) -> Point {
|
||||||
|
@ -2425,18 +2421,22 @@ impl ToPoint for usize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToPoint for PointUtf16 {
|
|
||||||
fn to_point<'a>(&self, snapshot: &BufferSnapshot) -> Point {
|
|
||||||
snapshot.point_utf16_to_point(*self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToPoint for Point {
|
impl ToPoint for Point {
|
||||||
fn to_point<'a>(&self, _: &BufferSnapshot) -> Point {
|
fn to_point<'a>(&self, _: &BufferSnapshot) -> Point {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ToPointClamped {
|
||||||
|
fn to_point_clamped(&self, snapshot: &BufferSnapshot) -> Point;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToPointClamped for PointUtf16 {
|
||||||
|
fn to_point_clamped<'a>(&self, snapshot: &BufferSnapshot) -> Point {
|
||||||
|
snapshot.point_utf16_to_point(*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ToPointUtf16 {
|
pub trait ToPointUtf16 {
|
||||||
fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> PointUtf16;
|
fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> PointUtf16;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue