use gpui::{Bounds, HighlightStyle, point, px, rgb, size};
use super::{
DiffSide,
document::fixture,
selection::{clip_highlight, line_distance, merge_highlights, word_range},
};
#[test]
fn source_selection_maps_expanded_tabs_and_multibyte_text_without_losing_line_endings() {
let source = "\tα\tx\r\nnext\n";
let document = fixture::document(None, Some(("text", source)));
let first = &document.lines(DiffSide::Modified)[0];
assert_eq!(first.display().as_ref(), " α x");
for ix in 0..4 {
assert_eq!(first.source_offset(ix), 0);
}
for ix in 6..9 {
assert_eq!(first.source_offset(ix), 3);
}
assert_eq!(first.display_range(1..3), 4..6);
assert_eq!(first.display_range(3..4), 6..9);
assert_eq!(
first.source_offset(first.display().len()),
first.text().len()
);
let next = &document.lines(DiffSide::Modified)[1];
let anchor = first.source().start + first.source_offset(4);
let cursor = next.source().start + next.source_offset(2);
assert_eq!(
&document.source(DiffSide::Modified)[anchor..cursor],
"α\tx\r\nne"
);
}
#[test]
fn overlapping_inline_and_selection_highlights_preserve_syntax_and_precedence() {
let syntax_color = rgb(0x336699).into();
let inline_color = rgb(0x884422).into();
let selection_color = rgb(0x225588).into();
let highlights = merge_highlights(
8,
vec![
(
0..8,
HighlightStyle {
color: Some(syntax_color),
..Default::default()
},
),
(
2..7,
HighlightStyle {
background_color: Some(inline_color),
..Default::default()
},
),
(
4..6,
HighlightStyle {
background_color: Some(selection_color),
..Default::default()
},
),
],
);
assert_eq!(
highlights
.iter()
.map(|(range, _)| range.clone())
.collect::<Vec<_>>(),
vec![0..2, 2..4, 4..6, 6..7, 7..8]
);
assert!(
highlights
.iter()
.all(|(_, style)| style.color == Some(syntax_color))
);
assert_eq!(
highlights
.iter()
.map(|(_, style)| style.background_color)
.collect::<Vec<_>>(),
vec![
None,
Some(inline_color),
Some(selection_color),
Some(inline_color),
None
]
);
assert!(merge_highlights(0, vec![]).is_empty());
}
#[test]
fn multi_click_line_top_prefers_current_line_over_previous_bottom() {
let previous = Bounds::new(point(px(20.), px(30.)), size(px(100.), px(20.)));
let current = Bounds::new(point(px(20.), px(50.)), size(px(100.), px(20.)));
let endpoint = point(px(40.), px(50.));
assert!(line_distance(endpoint, current) < line_distance(endpoint, previous));
let endpoint = point(px(400.), px(50.));
assert!(line_distance(endpoint, current) < line_distance(endpoint, previous));
}
#[test]
fn highlight_sweep_restores_lower_precedence_after_edges_and_clamps_invalid_ranges() {
let layers = vec![
(
0..12,
HighlightStyle {
fade_out: Some(0.2),
..Default::default()
},
),
(
4..8,
HighlightStyle {
fade_out: Some(0.7),
..Default::default()
},
),
(
2..6,
HighlightStyle {
fade_out: Some(0.9),
..Default::default()
},
),
(
7..7,
HighlightStyle {
fade_out: Some(1.),
..Default::default()
},
),
(
11..15,
HighlightStyle {
fade_out: Some(1.),
..Default::default()
},
),
];
let merged = merge_highlights(10, layers);
assert_eq!(
merged
.iter()
.map(|(range, style)| (range.clone(), style.fade_out))
.collect::<Vec<_>>(),
vec![
(0..2, Some(0.2)),
(2..4, Some(0.9)),
(4..6, Some(0.9)),
(6..8, Some(0.7)),
(8..10, Some(0.2)),
]
);
}
#[test]
fn highlight_chunks_clip_and_rebase_without_duplicating_adjacent_boundaries() {
assert_eq!(clip_highlight(4..12, &(8..16)), Some(0..4));
assert_eq!(clip_highlight(12..20, &(8..16)), Some(4..8));
assert_eq!(clip_highlight(8..16, &(8..16)), Some(0..8));
assert_eq!(clip_highlight(4..8, &(8..16)), None);
assert_eq!(clip_highlight(16..20, &(8..16)), None);
}
#[test]
fn native_word_selection_crosses_render_chunks_and_respects_unicode_and_flank_bounds() {
let token = "a".repeat(1024);
assert_eq!(word_range(&token, 512), Some(384..641));
assert_eq!(word_range(" foo_bar !", 4), Some(2..9));
assert_eq!(word_range(" foo_bar !", 9), Some(9..11));
assert_eq!(word_range(" foo_bar !", 11), Some(11..12));
let text = "éяa\u{0301}界";
assert_eq!(word_range(text, 2), Some(0..7));
assert_eq!(word_range(text, 7), Some(7..10));
assert_eq!(word_range(text, text.len()), None);
}