Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ insta = "1.43.2"
unicode-width = "0.2.0"
temp-env = "0.3.6"

[profile.profiling]
inherits = "dev"
opt-level = 1

[profile.release]
strip = true

Expand Down
1 change: 1 addition & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ impl App {
cmd.stderr(Stdio::piped());

let log_entry = self.state.current_cmd_log.push_cmd(&cmd);

term.draw(|frame| ui::ui(frame, &mut self.state))
.map_err(Error::Term)?;

Expand Down
40 changes: 21 additions & 19 deletions src/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ pub(crate) struct Item {
}

impl Item {
pub fn to_line<'a>(&'a self, config: Rc<Config>) -> Line<'a> {
match &self.data {
pub fn to_line(&'_ self, config: Rc<Config>) -> Line<'_> {
match self.data.clone() {
ItemData::Raw(content) => Line::raw(content),
ItemData::AllUnstaged(count) => Line::from(vec![
Span::styled("Unstaged changes", &config.style.section_header),
Expand All @@ -52,7 +52,7 @@ impl Item {
RefKind::Remote(remote) => (remote, &config.style.remote),
};

Line::from(vec![Span::raw(*prefix), Span::styled(reference, style)])
Line::from(vec![Span::raw(prefix), Span::styled(reference, style)])
}
ItemData::Commit {
short_id,
Expand All @@ -63,7 +63,7 @@ impl Item {
iter::once(Span::styled(short_id, &config.style.hash))
.chain(
associated_references
.iter()
.into_iter()
.map(|reference| match reference {
RefKind::Tag(tag) => Span::styled(tag, &config.style.tag),
RefKind::Branch(branch) => {
Expand All @@ -77,20 +77,23 @@ impl Item {
.chain([Span::raw(summary)]),
Span::raw(" "),
)),
ItemData::File(path) => Line::styled(path.to_string_lossy(), &config.style.file_header),
ItemData::File(path) => Line::styled(
path.to_string_lossy().into_owned(),
&config.style.file_header,
),
ItemData::Delta { diff, file_i } => {
let file_diff = &diff.file_diffs[*file_i];
let file_diff = &diff.file_diffs[file_i];

let content = format!(
"{:8} {}",
format!("{:?}", file_diff.header.status).to_lowercase(),
match file_diff.header.status {
Status::Renamed => format!(
"{} -> {}",
&Rc::clone(diff).text[file_diff.header.old_file.clone()],
&Rc::clone(diff).text[file_diff.header.new_file.clone()]
&Rc::clone(&diff).text[file_diff.header.old_file.clone()],
&Rc::clone(&diff).text[file_diff.header.new_file.clone()]
),
_ => Rc::clone(diff).text[file_diff.header.new_file.clone()].to_string(),
_ => Rc::clone(&diff).text[file_diff.header.new_file.clone()].to_string(),
}
);

Expand All @@ -101,12 +104,11 @@ impl Item {
file_i,
hunk_i,
} => {
let file_diff = &diff.file_diffs[*file_i];
let hunk = &file_diff.hunks[*hunk_i];

let file_diff = &diff.file_diffs[file_i];
let hunk = &file_diff.hunks[hunk_i];
let content = &diff.text[hunk.header.range.clone()];

Line::styled(content, &config.style.hunk_header)
Line::styled(content.to_string(), &config.style.hunk_header)
}
ItemData::HunkLine {
diff,
Expand All @@ -116,12 +118,12 @@ impl Item {
line_i,
} => {
let hunk_highlights =
highlight::highlight_hunk(self.id, &config, &Rc::clone(diff), *file_i, *hunk_i);
highlight::highlight_hunk(self.id, &config, &Rc::clone(&diff), file_i, hunk_i);

let hunk_content = &diff.hunk_content(*file_i, *hunk_i);
let hunk_content = &diff.hunk_content(file_i, hunk_i);
let hunk_line = &hunk_content[line_range.clone()];

let line_highlights = hunk_highlights.get_line_highlights(*line_i);
let line_highlights = hunk_highlights.get_line_highlights(line_i);

Line::from_iter(line_highlights.iter().map(|(highlight_range, style)| {
Span::styled(
Expand Down Expand Up @@ -155,11 +157,11 @@ impl Item {
Line::styled(content, &config.style.section_header)
}
ItemData::BranchStatus(upstream, ahead, behind) => {
let content = if *ahead == 0 && *behind == 0 {
let content = if ahead == 0 && behind == 0 {
format!("Your branch is up to date with '{upstream}'.")
} else if *ahead > 0 && *behind == 0 {
} else if ahead > 0 && behind == 0 {
format!("Your branch is ahead of '{upstream}' by {ahead} commit(s).",)
} else if *ahead == 0 && *behind > 0 {
} else if ahead == 0 && behind > 0 {
format!("Your branch is behind '{upstream}' by {behind} commit(s).",)
} else {
format!(
Expand Down
122 changes: 74 additions & 48 deletions src/screen/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use crate::item_data::ItemData;
use ratatui::{
buffer::Buffer,
layout::{Rect, Size},
text::Line,
widgets::Widget,
};
use crate::ui::layout::{LayoutTree, OPTS};
use crate::ui::layout_span;
use crate::{item_data::ItemData, ui};
use ratatui::{layout::Size, style::Style, text::Line};

use crate::{Res, config::Config, items::hash};

use super::Item;
use std::borrow::Cow;
use std::{collections::HashSet, rc::Rc};

pub(crate) mod log;
Expand Down Expand Up @@ -338,7 +336,7 @@ impl Screen {
self.nav_filter(target_line_i, NavMode::IncludeHunkLines)
}

fn line_views(&self, area: Size) -> impl Iterator<Item = LineView<'_>> {
fn line_views(&'_ self, area: Size) -> impl Iterator<Item = LineView<'_>> {
let scan_start = self.scroll.min(self.cursor);
let scan_end = (self.scroll + area.height as usize).min(self.line_index.len());
let scan_highlight_range = scan_start..(scan_end);
Expand All @@ -357,7 +355,6 @@ impl Screen {

Some(LineView {
item_index: *item_index,
item,
display,
highlighted: highlight_depth.is_some(),
})
Expand All @@ -368,54 +365,83 @@ impl Screen {

struct LineView<'a> {
item_index: usize,
item: &'a Item,
display: Line<'a>,
highlighted: bool,
}

impl Widget for &Screen {
fn render(self, area: Rect, buf: &mut Buffer) {
let style = &self.config.style;

for (line_index, line) in self.line_views(area.as_size()).enumerate() {
let line_area = Rect {
x: 0,
y: line_index as u16,
width: buf.area.width,
height: 1,
};

let indented_line_area = Rect { x: 1, ..line_area };

if line.highlighted {
buf.set_style(line_area, &style.selection_area);

if self.line_index[self.cursor] == line.item_index {
buf.set_style(line_area, &style.selection_line);
pub(crate) fn layout_screen<'a>(
layout: &mut LayoutTree<(Cow<'a, str>, Style)>,
size: Size,
screen: &'a Screen,
) {
let style = &screen.config.style;

layout.vertical(OPTS, |layout| {
for line in screen.line_views(size) {
layout.horizontal(OPTS, |layout| {
let selected_line = screen.line_index[screen.cursor] == line.item_index;
let area_highlight = area_selection_highlgiht(style, &line);
let line_highlight = line_selection_highlight(style, &line, selected_line);
let gutter_char = if line.highlighted {
gutter_char(style, selected_line, area_highlight, line_highlight)
} else {
buf[(0, line_index as u16)]
.set_char(style.selection_bar.symbol)
.set_style(&style.selection_bar);
}
}
(" ".into(), Style::new())
};

let line_width = line.display.width();
layout_span(layout, gutter_char);

line.display.render(indented_line_area, buf);
let overflow = line_width > line_area.width as usize;
line.display.spans.into_iter().for_each(|span| {
let style = span.style.patch(area_highlight).patch(line_highlight);
ui::layout_span(layout, (span.content, style));
});

// TODO Do something about this
// if screen.is_collapsed(line.item) && line_width > 0 || overflow {
// let line_end = (indented_line_area.x + line_width).min(size.width - 1);
// buf[(line_end, line_index as u16)].set_char('…');
// }
});
}
});
}

let line_width = line_width as u16;
fn gutter_char<'a>(
style: &'a crate::config::StyleConfig,
selected_line: bool,
area_highlight: Style,
line_highlight: Style,
) -> (Cow<'a, str>, Style) {
if selected_line {
(
style.cursor.symbol.to_string().into(),
Style::from(&style.cursor)
.patch(area_highlight)
.patch(line_highlight),
)
} else {
(
style.selection_bar.symbol.to_string().into(),
area_highlight,
)
}
}

if self.is_collapsed(line.item) && line_width > 0 || overflow {
let line_end = (indented_line_area.x + line_width).min(area.width - 1);
buf[(line_end, line_index as u16)].set_char('…');
}
fn line_selection_highlight(
style: &crate::config::StyleConfig,
line: &LineView,
selected_line: bool,
) -> Style {
if line.highlighted && selected_line {
Style::from(&style.selection_line)
} else {
Style::new()
}
}

if self.line_index[self.cursor] == line.item_index {
buf[(0, line_index as u16)]
.set_char(style.cursor.symbol)
.set_style(&style.cursor);
}
}
fn area_selection_highlgiht(style: &crate::config::StyleConfig, line: &LineView) -> Style {
if line.highlighted {
Style::from(&style.selection_area)
} else {
Style::new()
}
}
Loading
Loading