Git · DiffViewer: rows move to their own file; shorter comments
This commit is contained in:
5 files changed
+110
-94
No files matched your search
+2
-2
@@ -152,7 +152,7 @@ pub(crate) fn pair_places(lines: &[DiffLine]) -> Vec<(Option<usize>, Option<usiz
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A hunk's lines side by side: unchanged lines on both sides, each run of removals beside the additions after it.
|
/// A hunk's lines side by side: removals beside following additions.
|
||||||
pub fn pairs(lines: &[DiffLine]) -> Vec<(Option<&DiffLine>, Option<&DiffLine>)> {
|
pub fn pairs(lines: &[DiffLine]) -> Vec<(Option<&DiffLine>, Option<&DiffLine>)> {
|
||||||
pair_places(lines)
|
pair_places(lines)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -160,7 +160,7 @@ pub fn pairs(lines: &[DiffLine]) -> Vec<(Option<&DiffLine>, Option<&DiffLine>)>
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks the words each removal and the addition beside it changed.
|
/// Marks words changed between each removal and its addition.
|
||||||
pub fn mark_words(lines: &mut [DiffLine]) {
|
pub fn mark_words(lines: &mut [DiffLine]) {
|
||||||
for (left, right) in pair_places(lines) {
|
for (left, right) in pair_places(lines) {
|
||||||
let (Some(left), Some(right)) = (left, right) else {
|
let (Some(left), Some(right)) = (left, right) else {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ mod merge;
|
|||||||
mod merging;
|
mod merging;
|
||||||
mod refs;
|
mod refs;
|
||||||
mod review;
|
mod review;
|
||||||
|
mod rows;
|
||||||
mod tags;
|
mod tags;
|
||||||
#[cfg(all(test, feature = "test-support"))]
|
#[cfg(all(test, feature = "test-support"))]
|
||||||
mod tests;
|
mod tests;
|
||||||
@@ -25,5 +26,6 @@ pub use merge::{ConflictResolver, ThreeWayMerge};
|
|||||||
pub use merging::{Conflict, Region, RegionKind, Take, conflicts, regions, resolve, result};
|
pub use merging::{Conflict, Region, RegionKind, Take, conflicts, regions, resolve, result};
|
||||||
pub use refs::{Branch, BranchList, BranchSelector};
|
pub use refs::{Branch, BranchList, BranchSelector};
|
||||||
pub use review::{PullRequest, PullRequestCard, PullState, ReviewComment, ReviewNote};
|
pub use review::{PullRequest, PullRequestCard, PullState, ReviewComment, ReviewNote};
|
||||||
|
pub use rows::Place;
|
||||||
pub use tags::{GitTag, Stash, StashAction, StashList, TagList};
|
pub use tags::{GitTag, Stash, StashAction, StashList, TagList};
|
||||||
pub use viewer::{DiffLayout, DiffViewer};
|
pub use viewer::{DiffLayout, DiffViewer};
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
//! The rows a diff viewer draws, and their colors.
|
||||||
|
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use gpui::{App, HighlightStyle, Hsla, SharedString, StyledText};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
diff::{DiffLine, LineKind, Stretch, pair_places},
|
||||||
|
viewer::DiffLayout,
|
||||||
|
};
|
||||||
|
use crate::{
|
||||||
|
editor::{code_colors, stack},
|
||||||
|
theme::Palette,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A line's place: its stretch, then its line there.
|
||||||
|
pub type Place = (usize, usize);
|
||||||
|
|
||||||
|
/// A row as the viewer draws it.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(super) enum Shown {
|
||||||
|
/// A hunk's header and its place among the stretches.
|
||||||
|
Header(usize, SharedString),
|
||||||
|
Line(Place, DiffLine),
|
||||||
|
Pair(Option<(Place, DiffLine)>, Option<(Place, DiffLine)>),
|
||||||
|
/// A folded stretch: its place among the stretches and how many lines it hides.
|
||||||
|
Fold(usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn shown(stretches: &[Stretch], layout: DiffLayout, open: &[usize]) -> Vec<Shown> {
|
||||||
|
let mut rows = Vec::new();
|
||||||
|
for (ix, stretch) in stretches.iter().enumerate() {
|
||||||
|
match stretch {
|
||||||
|
Stretch::Hunk { header, lines } => {
|
||||||
|
rows.push(Shown::Header(ix, header.clone()));
|
||||||
|
let at = |line: usize| ((ix, line), lines[line].clone());
|
||||||
|
match layout {
|
||||||
|
DiffLayout::Unified => rows.extend((0..lines.len()).map(|line| {
|
||||||
|
let (place, line) = at(line);
|
||||||
|
Shown::Line(place, line)
|
||||||
|
})),
|
||||||
|
DiffLayout::Split => rows.extend(
|
||||||
|
pair_places(lines)
|
||||||
|
.into_iter()
|
||||||
|
.map(|(left, right)| Shown::Pair(left.map(at), right.map(at))),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Stretch::Folded(lines) if open.contains(&ix) => {
|
||||||
|
rows.extend(lines.iter().enumerate().map(|(at, line)| {
|
||||||
|
let place = (ix, at);
|
||||||
|
match layout {
|
||||||
|
DiffLayout::Unified => Shown::Line(place, line.clone()),
|
||||||
|
DiffLayout::Split => {
|
||||||
|
Shown::Pair(Some((place, line.clone())), Some((place, line.clone())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Stretch::Folded(lines) => rows.push(Shown::Fold(ix, lines.len())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rows
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The wash behind a line, and behind its changed words.
|
||||||
|
pub(super) fn washes(kind: LineKind, colors: &Palette) -> (Option<Hsla>, Hsla) {
|
||||||
|
match kind {
|
||||||
|
LineKind::Same => (None, colors.hover),
|
||||||
|
LineKind::Added => (
|
||||||
|
Some(colors.success.opacity(0.08)),
|
||||||
|
colors.success.opacity(0.25),
|
||||||
|
),
|
||||||
|
LineKind::Removed => (
|
||||||
|
Some(colors.danger.opacity(0.08)),
|
||||||
|
colors.danger.opacity(0.25),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A line's code, colored as code, its changed words washed.
|
||||||
|
pub(super) fn code(line: &DiffLine, colors: &Palette, cx: &App) -> StyledText {
|
||||||
|
let (_, word) = washes(line.kind, colors);
|
||||||
|
let mut styles: Vec<(Range<usize>, HighlightStyle)> = code_colors(&line.text, cx);
|
||||||
|
styles.extend(line.words.iter().map(|range| {
|
||||||
|
(
|
||||||
|
range.clone(),
|
||||||
|
HighlightStyle {
|
||||||
|
background_color: Some(word),
|
||||||
|
..HighlightStyle::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}));
|
||||||
|
styles.sort_by_key(|(range, _)| range.start);
|
||||||
|
StyledText::new(line.text.clone()).with_highlights(stack(styles))
|
||||||
|
}
|
||||||
+2
-2
@@ -152,7 +152,7 @@ fn changed_lines_and_hunks_answer_presses(cx: &mut TestAppContext) {
|
|||||||
});
|
});
|
||||||
settle(cx);
|
settle(cx);
|
||||||
};
|
};
|
||||||
// Past the two layout segments: the hunk's button, then its lines.
|
// Past two layout segments: hunk button, then lines.
|
||||||
let next = |cx: &mut VisualTestContext| {
|
let next = |cx: &mut VisualTestContext| {
|
||||||
cx.update(|window, cx| window.focus_next(cx));
|
cx.update(|window, cx| window.focus_next(cx));
|
||||||
settle(cx);
|
settle(cx);
|
||||||
@@ -213,7 +213,7 @@ fn a_row_says_which_section_it_is_in(cx: &mut TestAppContext) {
|
|||||||
cx.update(|window, _| window.activate_window());
|
cx.update(|window, _| window.activate_window());
|
||||||
settle(cx);
|
settle(cx);
|
||||||
let mut rows = Vec::new();
|
let mut rows = Vec::new();
|
||||||
// Each row is a stop; its icons stay hidden until hover.
|
// Each row is a stop; icons hide until hover.
|
||||||
for _ in 0..12 {
|
for _ in 0..12 {
|
||||||
cx.update(|window, cx| window.focus_next(cx));
|
cx.update(|window, cx| window.focus_next(cx));
|
||||||
settle(cx);
|
settle(cx);
|
||||||
|
|||||||
+8
-90
@@ -1,21 +1,21 @@
|
|||||||
use std::{ops::Range, rc::Rc};
|
use std::rc::Rc;
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AnyElement, App, ElementId, FontWeight, HighlightStyle, Hsla, InteractiveElement, IntoElement,
|
AnyElement, App, ElementId, FontWeight, InteractiveElement, IntoElement, MouseButton,
|
||||||
MouseButton, ParentElement, RenderOnce, Role, SharedString, StatefulInteractiveElement, Styled,
|
ParentElement, RenderOnce, Role, SharedString, StatefulInteractiveElement, Styled, Window, div,
|
||||||
StyledText, Window, div, prelude::*, relative, transparent_black, uniform_list,
|
prelude::*, relative, transparent_black, uniform_list,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
badges::DiffStat,
|
badges::DiffStat,
|
||||||
diff::{DiffLine, LineKind, Stretch, diff, pair_places, side_numbers},
|
diff::{DiffLine, LineKind, Stretch, diff, side_numbers},
|
||||||
|
rows::{Place, Shown, code, shown, washes},
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
buttons::{Button, ButtonVariant, SegmentedControl},
|
buttons::{Button, ButtonVariant, SegmentedControl},
|
||||||
editor::{code_colors, stack},
|
|
||||||
i18n,
|
i18n,
|
||||||
primitives::FocusRing,
|
primitives::FocusRing,
|
||||||
theme::{ActiveTheme, ControlSize, Palette, TextSize},
|
theme::{ActiveTheme, ControlSize, TextSize},
|
||||||
typography::LEADING,
|
typography::LEADING,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -29,56 +29,6 @@ pub enum DiffLayout {
|
|||||||
/// Unchanged lines kept around each change.
|
/// Unchanged lines kept around each change.
|
||||||
const CONTEXT: usize = 3;
|
const CONTEXT: usize = 3;
|
||||||
|
|
||||||
/// A line's place: its stretch, then its line there.
|
|
||||||
pub type Place = (usize, usize);
|
|
||||||
|
|
||||||
/// A row as the viewer draws it.
|
|
||||||
#[derive(Clone)]
|
|
||||||
enum Shown {
|
|
||||||
/// A hunk's header and its place among the stretches.
|
|
||||||
Header(usize, SharedString),
|
|
||||||
Line(Place, DiffLine),
|
|
||||||
Pair(Option<(Place, DiffLine)>, Option<(Place, DiffLine)>),
|
|
||||||
/// A folded stretch: its place among the stretches and how many lines it hides.
|
|
||||||
Fold(usize, usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shown(stretches: &[Stretch], layout: DiffLayout, open: &[usize]) -> Vec<Shown> {
|
|
||||||
let mut rows = Vec::new();
|
|
||||||
for (ix, stretch) in stretches.iter().enumerate() {
|
|
||||||
match stretch {
|
|
||||||
Stretch::Hunk { header, lines } => {
|
|
||||||
rows.push(Shown::Header(ix, header.clone()));
|
|
||||||
let at = |line: usize| ((ix, line), lines[line].clone());
|
|
||||||
match layout {
|
|
||||||
DiffLayout::Unified => rows.extend((0..lines.len()).map(|line| {
|
|
||||||
let (place, line) = at(line);
|
|
||||||
Shown::Line(place, line)
|
|
||||||
})),
|
|
||||||
DiffLayout::Split => rows.extend(
|
|
||||||
pair_places(lines)
|
|
||||||
.into_iter()
|
|
||||||
.map(|(left, right)| Shown::Pair(left.map(at), right.map(at))),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Stretch::Folded(lines) if open.contains(&ix) => {
|
|
||||||
rows.extend(lines.iter().enumerate().map(|(at, line)| {
|
|
||||||
let place = (ix, at);
|
|
||||||
match layout {
|
|
||||||
DiffLayout::Unified => Shown::Line(place, line.clone()),
|
|
||||||
DiffLayout::Split => {
|
|
||||||
Shown::Pair(Some((place, line.clone())), Some((place, line.clone())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
Stretch::Folded(lines) => rows.push(Shown::Fold(ix, lines.len())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rows
|
|
||||||
}
|
|
||||||
|
|
||||||
type OnIndex = Rc<dyn Fn(usize, &mut Window, &mut App)>;
|
type OnIndex = Rc<dyn Fn(usize, &mut Window, &mut App)>;
|
||||||
type OnLayout = Rc<dyn Fn(DiffLayout, &mut Window, &mut App)>;
|
type OnLayout = Rc<dyn Fn(DiffLayout, &mut Window, &mut App)>;
|
||||||
type OnLine = Rc<dyn Fn(Place, bool, &mut Window, &mut App)>;
|
type OnLine = Rc<dyn Fn(Place, bool, &mut Window, &mut App)>;
|
||||||
@@ -163,7 +113,7 @@ impl DiffViewer {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A button on each hunk's header, given the hunk's place.
|
/// A button on each hunk header, given its place.
|
||||||
pub fn hunk_action(
|
pub fn hunk_action(
|
||||||
mut self,
|
mut self,
|
||||||
label: impl Into<SharedString>,
|
label: impl Into<SharedString>,
|
||||||
@@ -204,38 +154,6 @@ impl DiffViewer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The wash behind a line, and behind its changed words.
|
|
||||||
fn washes(kind: LineKind, colors: &Palette) -> (Option<Hsla>, Hsla) {
|
|
||||||
match kind {
|
|
||||||
LineKind::Same => (None, colors.hover),
|
|
||||||
LineKind::Added => (
|
|
||||||
Some(colors.success.opacity(0.08)),
|
|
||||||
colors.success.opacity(0.25),
|
|
||||||
),
|
|
||||||
LineKind::Removed => (
|
|
||||||
Some(colors.danger.opacity(0.08)),
|
|
||||||
colors.danger.opacity(0.25),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A line's code, colored as code, its changed words washed.
|
|
||||||
fn code(line: &DiffLine, colors: &Palette, cx: &App) -> StyledText {
|
|
||||||
let (_, word) = washes(line.kind, colors);
|
|
||||||
let mut styles: Vec<(Range<usize>, HighlightStyle)> = code_colors(&line.text, cx);
|
|
||||||
styles.extend(line.words.iter().map(|range| {
|
|
||||||
(
|
|
||||||
range.clone(),
|
|
||||||
HighlightStyle {
|
|
||||||
background_color: Some(word),
|
|
||||||
..HighlightStyle::default()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}));
|
|
||||||
styles.sort_by_key(|(range, _)| range.start);
|
|
||||||
StyledText::new(line.text.clone()).with_highlights(stack(styles))
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RenderOnce for DiffViewer {
|
impl RenderOnce for DiffViewer {
|
||||||
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
let theme = cx.theme();
|
let theme = cx.theme();
|
||||||
|
|||||||
Reference in new issue
Block a user