Implement embedded Git synchronization TUI

This commit is contained in:
Hermes Agent
2026-08-10 10:39:31 +00:00
parent ce3e4a9f79
commit 1850846696
8 changed files with 1402 additions and 36 deletions

View File

@@ -170,6 +170,9 @@ fn render_content(frame: &mut Frame, app: &App, area: Rect) {
))
},
),
Mode::Browser if app.git_view().is_some() => {
Paragraph::new(git_lines(app.git_view().expect("checked Git view")))
}
Mode::Browser if app.grep_view().is_some() => Paragraph::new(grep_lines(
app.grep_view().expect("checked decrypted search results"),
)),
@@ -434,6 +437,88 @@ fn grep_lines(view: &crate::search::GrepView) -> Vec<Line<'_>> {
lines
}
fn git_lines(view: &crate::app::GitView) -> Vec<Line<'_>> {
let snapshot = view.snapshot();
let status = snapshot.status();
let mut lines = vec![
Line::styled(
view.message(),
Style::default()
.fg(Color::Cyan)
.add_modifier(Modifier::BOLD),
),
Line::raw(format!("repository: {}", snapshot.root().display())),
Line::raw(format!("branch: {}", snapshot.branch())),
Line::raw(format!(
"worktree: {}",
if status.is_clean() {
"clean".to_owned()
} else {
format!(
"{} staged, {} unstaged",
status.staged().len(),
status.unstaged().len()
)
}
)),
];
if let Some(remote) = snapshot.remote() {
lines.push(Line::raw(format!(
"remote: {} {}",
remote.name(),
remote.url()
)));
lines.push(Line::raw(format!(
"relation: {} ahead, {} behind",
remote.ahead(),
remote.behind()
)));
} else {
lines.push(Line::styled(
"remote: not configured",
Style::default().fg(Color::Yellow),
));
}
if !view.conflicts().is_empty() {
lines.push(Line::styled(
"merge conflicts:",
Style::default().fg(Color::Red).add_modifier(Modifier::BOLD),
));
lines.extend(view.conflicts().iter().map(|conflict| {
Line::raw(format!(
" {:?}: {}",
conflict.kind(),
conflict.path().display()
))
}));
lines.push(Line::raw(
"Use :git resolve-local or :git resolve-remote for all listed paths.",
));
}
if let Some(details) = view.details() {
lines.push(Line::raw(""));
lines.extend(
String::from_utf8_lossy(details.expose())
.lines()
.map(|line| Line::raw(line.to_owned())),
);
} else if !snapshot.recent().is_empty() {
lines.push(Line::raw(""));
lines.push(Line::styled(
"recent commits:",
Style::default().add_modifier(Modifier::BOLD),
));
lines.extend(snapshot.recent().iter().map(|entry| {
Line::raw(format!(
" {} {}",
&entry.id()[..entry.id().len().min(12)],
entry.message()
))
}));
}
lines
}
fn mode_title(mode: Mode) -> &'static str {
match mode {
Mode::Browser => "Browser",