DiffViewer: prose files (Markdown, plain text) read plain, not as code

This commit is contained in:
ZacharyZhang-NY committed 2026-10-09 03:24:12 -04:00
1 parent 0f468e8661
commit 7f2ac3e4eb
2 files changed
+45 -6

No files matched your search

+39 -3
View File
@@ -78,10 +78,29 @@ pub(super) fn washes(kind: LineKind, colors: &Palette) -> (Option<Hsla>, Hsla) {
} }
} }
/// A line's code, colored as code, its changed words washed. /// Extensions of prose and plain text.
pub(super) fn code(line: &DiffLine, colors: &Palette, cx: &App) -> StyledText { const PROSE: [&str; 13] = [
"md", "markdown", "mdown", "mkd", "txt", "text", "rst", "adoc", "asciidoc", "org", "csv",
"tsv", "log",
];
/// Whether `path` holds prose, read plain rather than as code.
pub(super) fn prose(path: &str) -> bool {
let name = path.rsplit_once('/').map_or(path, |(_, name)| name);
match name.rsplit_once('.') {
Some((stem, ext)) if !stem.is_empty() => PROSE.contains(&ext.to_ascii_lowercase().as_str()),
_ => true,
}
}
/// A line's text, colored as code unless prose, changed words washed.
pub(super) fn code(line: &DiffLine, colors: &Palette, prose: bool, cx: &App) -> StyledText {
let (_, word) = washes(line.kind, colors); let (_, word) = washes(line.kind, colors);
let mut styles: Vec<(Range<usize>, HighlightStyle)> = code_colors(&line.text, cx); let mut styles: Vec<(Range<usize>, HighlightStyle)> = if prose {
Vec::new()
} else {
code_colors(&line.text, cx)
};
styles.extend(line.words.iter().map(|range| { styles.extend(line.words.iter().map(|range| {
( (
range.clone(), range.clone(),
@@ -108,6 +127,23 @@ pub(super) fn spoken(line: &DiffLine) -> SharedString {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[test]
fn prose_reads_plain_and_code_reads_as_code() {
for path in [
"docs/README.md",
"notes.MARKDOWN",
"LICENSE",
".gitignore",
"a/b.txt",
"data.csv",
] {
assert!(super::prose(path), "{path}");
}
for path in ["src/main.rs", "web/app.js", "a.md/b.py", "Cargo.toml"] {
assert!(!super::prose(path), "{path}");
}
}
#[test] #[test]
fn a_line_speaks_its_number_change_and_text() { fn a_line_speaks_its_number_change_and_text() {
let stretches = super::super::diff::diff("a\nb\n", "a\nc\n", 1); let stretches = super::super::diff::diff("a\nb\n", "a\nc\n", 1);
+6 -3
View File
@@ -9,7 +9,7 @@ use gpui::{
use super::{ use super::{
badges::DiffStat, badges::DiffStat,
diff::{DiffLine, LineKind, Stretch, diff, side_numbers}, diff::{DiffLine, LineKind, Stretch, diff, side_numbers},
rows::{Place, Shown, code, shown, spoken, washes}, rows::{Place, Shown, code, prose, shown, spoken, washes},
}; };
use crate::{ use crate::{
buttons::{Button, ButtonVariant, SegmentedControl}, buttons::{Button, ButtonVariant, SegmentedControl},
@@ -194,6 +194,7 @@ impl RenderOnce for DiffViewer {
.len() .len()
.max(2); .max(2);
let (id, on_open) = (self.id.clone(), self.on_open.clone()); let (id, on_open) = (self.id.clone(), self.on_open.clone());
let prose = prose(&self.path);
let (button, button_height) = ( let (button, button_height) = (
self.hunk_action.is_some(), self.hunk_action.is_some(),
theme.control_height(ControlSize::Sm), theme.control_height(ControlSize::Sm),
@@ -269,7 +270,9 @@ impl RenderOnce for DiffViewer {
.when_some(wash, |side, wash| side.bg(wash)) .when_some(wash, |side, wash| side.bg(wash))
.child(number(shown)) .child(number(shown))
.children(line.map(|(_, line)| { .children(line.map(|(_, line)| {
div().whitespace_nowrap().child(code(line, &colors, cx)) div()
.whitespace_nowrap()
.child(code(line, &colors, prose, cx))
})); }));
match line { match line {
Some((place, line)) => { Some((place, line)) => {
@@ -328,7 +331,7 @@ impl RenderOnce for DiffViewer {
.flex_1() .flex_1()
.min_w_0() .min_w_0()
.overflow_hidden() .overflow_hidden()
.child(code(line, &colors, cx)), .child(code(line, &colors, prose, cx)),
) )
.into_any_element() .into_any_element()
} }