mirror of
https://github.com/gitui-org/gitui
synced 2026-05-24 09:28:21 +00:00
145 lines
3.3 KiB
Rust
145 lines
3.3 KiB
Rust
use git2::{DiffFormat, DiffOptions, Repository, StatusOptions, StatusShow};
|
|
use std::path::Path;
|
|
use tui::layout::{Constraint, Direction, Layout, Rect};
|
|
|
|
///
|
|
#[derive(Copy, Clone, PartialEq)]
|
|
pub enum DiffLineType {
|
|
None,
|
|
Header,
|
|
Add,
|
|
Delete,
|
|
}
|
|
|
|
impl Default for DiffLineType {
|
|
fn default() -> Self {
|
|
DiffLineType::None
|
|
}
|
|
}
|
|
|
|
///
|
|
#[derive(Default, PartialEq)]
|
|
pub struct DiffLine {
|
|
pub content: String,
|
|
pub line_type: DiffLineType,
|
|
}
|
|
|
|
///
|
|
#[derive(Default, PartialEq)]
|
|
pub struct Diff(pub Vec<DiffLine>);
|
|
|
|
///
|
|
pub fn get_diff(p: &Path) -> Diff {
|
|
let repo = repo();
|
|
|
|
let mut opt = DiffOptions::new();
|
|
opt.pathspec(p);
|
|
|
|
let diff = repo.diff_index_to_workdir(None, Some(&mut opt)).unwrap();
|
|
|
|
let mut res = Vec::new();
|
|
|
|
diff.print(DiffFormat::Patch, |_delta, _hunk, line| {
|
|
let origin = line.origin();
|
|
|
|
if origin != 'F' {
|
|
let line_type = match origin {
|
|
'H' => DiffLineType::Header,
|
|
'<' | '-' => DiffLineType::Delete,
|
|
'>' | '+' => DiffLineType::Add,
|
|
_ => DiffLineType::None,
|
|
};
|
|
|
|
let diff_line = DiffLine {
|
|
content: String::from_utf8_lossy(line.content()).to_string(),
|
|
line_type,
|
|
};
|
|
|
|
if line_type == DiffLineType::Header && res.len() > 0 {
|
|
res.push(DiffLine {
|
|
content: "\n".to_string(),
|
|
line_type: DiffLineType::None,
|
|
});
|
|
}
|
|
|
|
res.push(diff_line);
|
|
}
|
|
true
|
|
})
|
|
.unwrap();
|
|
|
|
Diff(res)
|
|
}
|
|
|
|
///
|
|
pub fn repo() -> Repository {
|
|
let repo = Repository::init("./").unwrap();
|
|
|
|
if repo.is_bare() {
|
|
panic!("bare repo")
|
|
}
|
|
|
|
repo
|
|
}
|
|
|
|
///
|
|
pub fn commit(msg: &String) {
|
|
let repo = repo();
|
|
|
|
let signature = repo.signature().unwrap();
|
|
let reference = repo.head().unwrap();
|
|
let mut index = repo.index().unwrap();
|
|
let tree_id = index.write_tree().unwrap();
|
|
|
|
let tree = repo.find_tree(tree_id).unwrap();
|
|
let parent = repo.find_commit(reference.target().unwrap()).unwrap();
|
|
|
|
repo.commit(
|
|
Some("HEAD"),
|
|
&signature,
|
|
&signature,
|
|
msg.as_str(),
|
|
&tree,
|
|
&[&parent],
|
|
)
|
|
.unwrap();
|
|
}
|
|
|
|
/// use layouts to create a rects that
|
|
/// centers inside `r` and sizes `percent_x`/`percent_x` of `r`
|
|
pub fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
|
|
let popup_layout = Layout::default()
|
|
.direction(Direction::Vertical)
|
|
.constraints(
|
|
[
|
|
Constraint::Percentage((100 - percent_y) / 2),
|
|
Constraint::Percentage(percent_y),
|
|
Constraint::Percentage((100 - percent_y) / 2),
|
|
]
|
|
.as_ref(),
|
|
)
|
|
.split(r);
|
|
|
|
Layout::default()
|
|
.direction(Direction::Horizontal)
|
|
.constraints(
|
|
[
|
|
Constraint::Percentage((100 - percent_x) / 2),
|
|
Constraint::Percentage(percent_x),
|
|
Constraint::Percentage((100 - percent_x) / 2),
|
|
]
|
|
.as_ref(),
|
|
)
|
|
.split(popup_layout[1])[1]
|
|
}
|
|
|
|
///
|
|
pub fn index_empty() -> bool {
|
|
let repo = repo();
|
|
|
|
let statuses = repo
|
|
.statuses(Some(StatusOptions::default().show(StatusShow::Index)))
|
|
.unwrap();
|
|
|
|
statuses.is_empty()
|
|
}
|