Skip to main content

git_tailor/views/
drop.rs

1// Copyright 2026 Thomas Johannesson
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Drop commit confirmation dialog
16
17use super::dialog::{inner_width, render_centered_dialog, wrap_text};
18use crate::app::{AppAction, AppMode, AppState, KeyCommand};
19use ratatui::{
20    Frame,
21    layout::Alignment,
22    style::{Color, Modifier, Style},
23    text::{Line, Span},
24};
25
26/// Handle an action while in DropConfirm mode.
27pub fn handle_confirm_key(action: KeyCommand, app: &mut AppState) -> AppAction {
28    match action {
29        KeyCommand::Confirm => {
30            if let AppMode::DropConfirm(pending) =
31                std::mem::replace(&mut app.mode, AppMode::CommitList)
32            {
33                AppAction::ExecuteDrop {
34                    commit_oid: pending.commit_oid,
35                    head_oid: pending.head_oid,
36                }
37            } else {
38                AppAction::Handled
39            }
40        }
41        KeyCommand::ShowHelp => {
42            app.toggle_help();
43            AppAction::Handled
44        }
45        KeyCommand::Quit => {
46            app.cancel_drop_confirm();
47            AppAction::Handled
48        }
49        _ => AppAction::Handled,
50    }
51}
52
53/// Render the drop confirmation dialog as a centered overlay.
54pub fn render_drop_confirm(app: &AppState, frame: &mut Frame) {
55    let pending = match &app.mode {
56        AppMode::DropConfirm(p) => p,
57        _ => return,
58    };
59
60    let short_oid = if pending.commit_oid.len() >= 10 {
61        &pending.commit_oid[..10]
62    } else {
63        &pending.commit_oid
64    };
65
66    const PREFERRED_WIDTH: u16 = 60;
67    let iw = inner_width(PREFERRED_WIDTH, frame.area().width);
68
69    // Pre-wrap the summary so that lines.len() reflects the real rendered
70    // height and dialog_height is computed accurately.
71    let summary_chunks = wrap_text(&pending.commit_summary, iw.saturating_sub(1));
72
73    let mut lines: Vec<Line> = vec![
74        Line::from(""),
75        Line::from(Span::styled(
76            " Drop this commit?",
77            Style::default()
78                .fg(Color::Yellow)
79                .add_modifier(Modifier::BOLD),
80        )),
81        Line::from(""),
82        Line::from(Span::styled(
83            format!(" {short_oid}"),
84            Style::default().fg(Color::Cyan),
85        )),
86    ];
87    for chunk in &summary_chunks {
88        lines.push(Line::from(Span::raw(format!(" {chunk}"))));
89    }
90    lines.push(Line::from(""));
91    lines.push(
92        Line::from(vec![
93            Span::styled("Enter ", Style::default().fg(Color::Cyan)),
94            Span::raw("Confirm   "),
95            Span::styled("Esc ", Style::default().fg(Color::Cyan)),
96            Span::raw("Cancel"),
97        ])
98        .alignment(Alignment::Center),
99    );
100    lines.push(Line::from(""));
101
102    render_centered_dialog(
103        frame,
104        " Confirm Drop ",
105        Color::Yellow,
106        PREFERRED_WIDTH,
107        lines,
108    );
109}