This PR for fix some incorrect changes in #1204 ## Before <img width="854" height="864" alt="image" src="https://github.com/user-attachments/assets/eebd07e5-3437-444d-a55d-2941228e3b08" /> ## After <img width="954" height="962" alt="image" src="https://github.com/user-attachments/assets/60761848-8d4f-4fe9-88b9-f0b0f0985d2f" /> <img width="1515" height="867" alt="image" src="https://github.com/user-attachments/assets/3d4654a7-f977-4919-9c9e-f013fcdd8fde" />
This commit is contained in:
parent
78dccd4d79
commit
a9e6b49a15
2 changed files with 99 additions and 50 deletions
|
|
@ -49,11 +49,19 @@ impl Lang {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const LANGUAGES: [(Lang, &'static str); 10] = [
|
const LANGUAGES: [(Lang, &'static str); 12] = [
|
||||||
(
|
(
|
||||||
Lang::BuiltIn(Language::Rust),
|
Lang::BuiltIn(Language::Rust),
|
||||||
include_str!("./fixtures/test.rs"),
|
include_str!("./fixtures/test.rs"),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
Lang::BuiltIn(Language::Markdown),
|
||||||
|
include_str!("./fixtures/test.md"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Lang::BuiltIn(Language::Html),
|
||||||
|
include_str!("./fixtures/test.html"),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
Lang::BuiltIn(Language::JavaScript),
|
Lang::BuiltIn(Language::JavaScript),
|
||||||
include_str!("./fixtures/test.js"),
|
include_str!("./fixtures/test.js"),
|
||||||
|
|
@ -90,8 +98,17 @@ const LANGUAGES: [(Lang, &'static str); 10] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
impl Example {
|
impl Example {
|
||||||
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
pub fn new(default: Option<String>, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||||
let default_language = LANGUAGES[0].clone();
|
let default_language = if let Some(name) = default {
|
||||||
|
LANGUAGES
|
||||||
|
.iter()
|
||||||
|
.find(|s| s.0.name().starts_with(name.trim()))
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or(LANGUAGES[0].clone())
|
||||||
|
} else {
|
||||||
|
LANGUAGES[0].clone()
|
||||||
|
};
|
||||||
|
|
||||||
let editor = cx.new(|cx| {
|
let editor = cx.new(|cx| {
|
||||||
InputState::new(window, cx)
|
InputState::new(window, cx)
|
||||||
.code_editor(default_language.0.name().to_string())
|
.code_editor(default_language.0.name().to_string())
|
||||||
|
|
@ -147,10 +164,6 @@ impl Example {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(window: &mut Window, cx: &mut App) -> Entity<Self> {
|
|
||||||
cx.new(|cx| Self::new(window, cx))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_markers(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
fn set_markers(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
if self.language.name() != "rust" {
|
if self.language.name() != "rust" {
|
||||||
return;
|
return;
|
||||||
|
|
@ -310,11 +323,18 @@ impl Render for Example {
|
||||||
fn main() {
|
fn main() {
|
||||||
let app = Application::new().with_assets(Assets);
|
let app = Application::new().with_assets(Assets);
|
||||||
|
|
||||||
|
// Parse `cargo run -- <story_name>`
|
||||||
|
let name = std::env::args().nth(1);
|
||||||
|
|
||||||
app.run(move |cx| {
|
app.run(move |cx| {
|
||||||
story::init(cx);
|
story::init(cx);
|
||||||
init(cx);
|
init(cx);
|
||||||
cx.activate(true);
|
cx.activate(true);
|
||||||
|
|
||||||
story::create_new_window("Code Editor", Example::view, cx);
|
story::create_new_window(
|
||||||
|
"Code Editor",
|
||||||
|
|window, cx| cx.new(|cx| Example::new(name, window, cx)),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -579,7 +579,6 @@ impl SyntaxHighlighter {
|
||||||
});
|
});
|
||||||
filter.next();
|
filter.next();
|
||||||
|
|
||||||
let mut last_range = start_offset..start_offset;
|
|
||||||
// let mut iter_count = 0;
|
// let mut iter_count = 0;
|
||||||
while let Some(item) = filter.item() {
|
while let Some(item) = filter.item() {
|
||||||
// iter_count += 1;
|
// iter_count += 1;
|
||||||
|
|
@ -592,18 +591,7 @@ impl SyntaxHighlighter {
|
||||||
node_range.end = node_range.start;
|
node_range.end = node_range.start;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure every range is connected.
|
styles.push((node_range, theme.style(name.as_ref()).unwrap_or_default()));
|
||||||
if last_range.end < node_range.start {
|
|
||||||
styles.push((last_range.end..node_range.start, HighlightStyle::default()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let start = node_range.start.max(last_range.end);
|
|
||||||
styles.push((
|
|
||||||
start..node_range.end,
|
|
||||||
theme.style(name.as_ref()).unwrap_or_default(),
|
|
||||||
));
|
|
||||||
last_range = node_range;
|
|
||||||
|
|
||||||
filter.next();
|
filter.next();
|
||||||
}
|
}
|
||||||
// dbg!(iter_count);
|
// dbg!(iter_count);
|
||||||
|
|
@ -613,12 +601,7 @@ impl SyntaxHighlighter {
|
||||||
return vec![(start_offset..range.end, HighlightStyle::default())];
|
return vec![(start_offset..range.end, HighlightStyle::default())];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the last range is connected to the end of the line.
|
let styles = unique_styles(&range, styles);
|
||||||
if last_range.end < range.end {
|
|
||||||
styles.push((last_range.end..range.end, HighlightStyle::default()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let styles = unique_styles(styles);
|
|
||||||
|
|
||||||
// NOTE: DO NOT remove this comment, it is used for debugging.
|
// NOTE: DO NOT remove this comment, it is used for debugging.
|
||||||
// for style in &styles {
|
// for style in &styles {
|
||||||
|
|
@ -645,44 +628,58 @@ impl SyntaxHighlighter {
|
||||||
///
|
///
|
||||||
/// AABCCDDCEEEE
|
/// AABCCDDCEEEE
|
||||||
pub(crate) fn unique_styles(
|
pub(crate) fn unique_styles(
|
||||||
|
total_range: &Range<usize>,
|
||||||
styles: Vec<(Range<usize>, HighlightStyle)>,
|
styles: Vec<(Range<usize>, HighlightStyle)>,
|
||||||
) -> Vec<(Range<usize>, HighlightStyle)> {
|
) -> Vec<(Range<usize>, HighlightStyle)> {
|
||||||
if styles.is_empty() {
|
if styles.is_empty() {
|
||||||
return styles;
|
return styles;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect all boundary points and track which are "significant" (range endpoints)
|
let mut intervals = BTreeSet::new();
|
||||||
let mut boundaries = BTreeSet::new();
|
let mut significant_intervals = BTreeSet::new();
|
||||||
let mut significant_boundaries = BTreeSet::new();
|
|
||||||
|
|
||||||
|
// For example
|
||||||
|
//
|
||||||
|
// from: [(6..11), (6..11), (11..17), (17..25), (16..19), (25..59))]
|
||||||
|
// to: [6, 11, 16, 17, 19, 25, 59]
|
||||||
|
intervals.insert(total_range.start);
|
||||||
|
intervals.insert(total_range.end);
|
||||||
for (range, _) in &styles {
|
for (range, _) in &styles {
|
||||||
boundaries.insert(range.start);
|
intervals.insert(range.start);
|
||||||
boundaries.insert(range.end);
|
intervals.insert(range.end);
|
||||||
significant_boundaries.insert(range.end); // End points are significant for merging decisions
|
significant_intervals.insert(range.end); // End points are significant for merging decisions
|
||||||
}
|
}
|
||||||
|
|
||||||
let boundaries: Vec<usize> = boundaries.into_iter().collect();
|
let intervals: Vec<usize> = intervals.into_iter().collect();
|
||||||
let mut result = Vec::with_capacity(boundaries.len().saturating_sub(1));
|
let mut result = Vec::with_capacity(intervals.len().saturating_sub(1));
|
||||||
|
|
||||||
// For each interval between boundaries, find the top-most style
|
// For each interval between boundaries, find the top-most style
|
||||||
for i in 0..boundaries.len().saturating_sub(1) {
|
//
|
||||||
let interval_start = boundaries[i];
|
// Result e.g.:
|
||||||
let interval_end = boundaries[i + 1];
|
//
|
||||||
|
// [(6..11, red), (11..16, green), (16..17, blue), (17..19, red), (19..25, clean), (25..59, blue)]
|
||||||
if interval_start >= interval_end {
|
for i in 0..intervals.len().saturating_sub(1) {
|
||||||
|
let interval = intervals[i]..intervals[i + 1];
|
||||||
|
if interval.start >= interval.end {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the last (top-most) style that covers this interval
|
// Find the last (top-most) style that covers this interval
|
||||||
let mut top_style: Option<&HighlightStyle> = None;
|
let mut top_style: Option<HighlightStyle> = None;
|
||||||
for (range, style) in &styles {
|
for (range, style) in &styles {
|
||||||
if range.start <= interval_start && interval_end <= range.end {
|
if range.start <= interval.start && interval.end <= range.end {
|
||||||
top_style = Some(style);
|
if let Some(top_style) = &mut top_style {
|
||||||
|
merge_highlight_style(top_style, style);
|
||||||
|
} else {
|
||||||
|
top_style = Some(*style);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(style) = top_style {
|
if let Some(style) = top_style {
|
||||||
result.push((interval_start..interval_end, *style));
|
result.push((interval, style));
|
||||||
|
} else {
|
||||||
|
result.push((interval, HighlightStyle::default()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -692,7 +689,7 @@ pub(crate) fn unique_styles(
|
||||||
if let Some((last_range, last_style)) = merged.last_mut() {
|
if let Some((last_range, last_style)) = merged.last_mut() {
|
||||||
if last_range.end == range.start
|
if last_range.end == range.start
|
||||||
&& *last_style == style
|
&& *last_style == style
|
||||||
&& !significant_boundaries.contains(&range.start)
|
&& !significant_intervals.contains(&range.start)
|
||||||
{
|
{
|
||||||
// Merge adjacent ranges with same style, but not across significant boundaries
|
// Merge adjacent ranges with same style, but not across significant boundaries
|
||||||
last_range.end = range.end;
|
last_range.end = range.end;
|
||||||
|
|
@ -705,6 +702,31 @@ pub(crate) fn unique_styles(
|
||||||
merged
|
merged
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Merge other style (Other on top)
|
||||||
|
fn merge_highlight_style(style: &mut HighlightStyle, other: &HighlightStyle) {
|
||||||
|
if let Some(color) = other.color {
|
||||||
|
style.color = Some(color);
|
||||||
|
}
|
||||||
|
if let Some(font_weight) = other.font_weight {
|
||||||
|
style.font_weight = Some(font_weight);
|
||||||
|
}
|
||||||
|
if let Some(font_style) = other.font_style {
|
||||||
|
style.font_style = Some(font_style);
|
||||||
|
}
|
||||||
|
if let Some(background_color) = other.background_color {
|
||||||
|
style.background_color = Some(background_color);
|
||||||
|
}
|
||||||
|
if let Some(underline) = other.underline {
|
||||||
|
style.underline = Some(underline);
|
||||||
|
}
|
||||||
|
if let Some(strikethrough) = other.strikethrough {
|
||||||
|
style.strikethrough = Some(strikethrough);
|
||||||
|
}
|
||||||
|
if let Some(fade_out) = other.fade_out {
|
||||||
|
style.fade_out = Some(fade_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use gpui::Hsla;
|
use gpui::Hsla;
|
||||||
|
|
@ -720,6 +742,7 @@ mod tests {
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn assert_unique_styles(
|
fn assert_unique_styles(
|
||||||
|
range: Range<usize>,
|
||||||
left: Vec<(Range<usize>, HighlightStyle)>,
|
left: Vec<(Range<usize>, HighlightStyle)>,
|
||||||
right: Vec<(Range<usize>, HighlightStyle)>,
|
right: Vec<(Range<usize>, HighlightStyle)>,
|
||||||
) {
|
) {
|
||||||
|
|
@ -740,7 +763,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let left = unique_styles(left);
|
let left = unique_styles(&range, left);
|
||||||
if left.len() != right.len() {
|
if left.len() != right.len() {
|
||||||
println!("\n---------------------------------------------");
|
println!("\n---------------------------------------------");
|
||||||
for (range, style) in left.iter() {
|
for (range, style) in left.iter() {
|
||||||
|
|
@ -770,18 +793,21 @@ mod tests {
|
||||||
let clean = HighlightStyle::default();
|
let clean = HighlightStyle::default();
|
||||||
|
|
||||||
assert_unique_styles(
|
assert_unique_styles(
|
||||||
|
0..65,
|
||||||
vec![
|
vec![
|
||||||
(0..10, clean),
|
(2..10, clean),
|
||||||
(0..10, clean),
|
(2..10, clean),
|
||||||
(5..11, red),
|
(5..11, red),
|
||||||
(0..6, clean),
|
(2..6, clean),
|
||||||
(10..15, green),
|
(10..15, green),
|
||||||
(15..30, clean),
|
(15..30, clean),
|
||||||
(29..35, blue),
|
(29..35, blue),
|
||||||
(35..40, green),
|
(35..40, green),
|
||||||
|
(45..60, blue),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
(0..6, clean),
|
(0..5, clean),
|
||||||
|
(5..6, red),
|
||||||
(6..10, red),
|
(6..10, red),
|
||||||
(10..11, green),
|
(10..11, green),
|
||||||
(11..15, green),
|
(11..15, green),
|
||||||
|
|
@ -789,6 +815,9 @@ mod tests {
|
||||||
(29..30, blue),
|
(29..30, blue),
|
||||||
(30..35, blue),
|
(30..35, blue),
|
||||||
(35..40, green),
|
(35..40, green),
|
||||||
|
(40..45, clean),
|
||||||
|
(45..60, blue),
|
||||||
|
(60..65, clean),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue