aboutsummaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/dialogs.rs84
1 files changed, 76 insertions, 8 deletions
diff --git a/src/ui/dialogs.rs b/src/ui/dialogs.rs
index 31275282..51e5fb15 100644
--- a/src/ui/dialogs.rs
+++ b/src/ui/dialogs.rs
@@ -2,7 +2,7 @@ use ratatui::{
layout::{Constraint, Layout, Rect},
style::{Modifier, Style},
text::{Line, Span},
- widgets::{Clear, Paragraph},
+ widgets::{Clear, Paragraph, Wrap},
Frame,
};
@@ -12,6 +12,9 @@ use super::widgets::{
};
use crate::app::{state::WorktreeOpenState, AppState, Mode};
+const NEW_LINKED_WORKTREE_POPUP_WIDTH: u16 = 68;
+const NEW_LINKED_WORKTREE_POPUP_HEIGHT: u16 = 12;
+
fn truncate_text(text: &str, max_width: usize) -> String {
let len = text.chars().count();
if len <= max_width {
@@ -126,7 +129,12 @@ pub(super) fn render_rename_overlay(app: &AppState, frame: &mut Frame, area: Rec
}
pub(crate) fn new_linked_worktree_inner_rect(area: Rect) -> Option<Rect> {
- centered_popup_rect(area, 68, 10).map(|popup| {
+ centered_popup_rect(
+ area,
+ NEW_LINKED_WORKTREE_POPUP_WIDTH,
+ NEW_LINKED_WORKTREE_POPUP_HEIGHT,
+ )
+ .map(|popup| {
Rect::new(
popup.x + 1,
popup.y + 1,
@@ -240,10 +248,16 @@ pub(super) fn render_new_linked_worktree_overlay(app: &AppState, frame: &mut Fra
};
super::dim_background(frame, area);
- let Some(inner) = render_modal_shell(frame, area, 68, 10, &app.palette) else {
+ let Some(inner) = render_modal_shell(
+ frame,
+ area,
+ NEW_LINKED_WORKTREE_POPUP_WIDTH,
+ NEW_LINKED_WORKTREE_POPUP_HEIGHT,
+ &app.palette,
+ ) else {
return;
};
- if inner.height < 7 {
+ if inner.height < 9 {
return;
}
@@ -253,7 +267,7 @@ pub(super) fn render_new_linked_worktree_overlay(app: &AppState, frame: &mut Fra
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
- Constraint::Length(1),
+ Constraint::Length(3),
Constraint::Length(1),
Constraint::Min(0),
])
@@ -293,7 +307,9 @@ pub(super) fn render_new_linked_worktree_overlay(app: &AppState, frame: &mut Fra
);
} else if let Some(error) = &create.error {
frame.render_widget(
- Paragraph::new(format!(" {error}")).style(Style::default().fg(app.palette.red)),
+ Paragraph::new(format!(" {error}"))
+ .style(Style::default().fg(app.palette.red))
+ .wrap(Wrap { trim: false }),
rows[5],
);
}
@@ -755,9 +771,13 @@ pub(crate) fn confirm_close_button_rects(inner: Rect) -> (Rect, Rect) {
#[cfg(test)]
mod tests {
- use crate::{app::AppState, workspace::Workspace};
+ use crate::{
+ app::{state::WorktreeCreateState, AppState},
+ workspace::Workspace,
+ };
+ use ratatui::{backend::TestBackend, layout::Rect, Terminal};
- use super::confirm_close_overlay_text;
+ use super::{confirm_close_overlay_text, render_new_linked_worktree_overlay};
#[test]
fn confirm_close_text_reports_parent_group_scope() {
@@ -786,4 +806,52 @@ mod tests {
assert_eq!(title, "Close worktree group?");
assert_eq!(detail, "main — 2 workspaces, 2 panes");
}
+
+ #[test]
+ fn new_worktree_error_renders_fatal_stderr_line() {
+ let mut app = AppState::test_new();
+ app.name_input = "foo".into();
+ app.worktree_create = Some(WorktreeCreateState {
+ source_workspace_id: "source".into(),
+ source_checkout_path: "/repo/herdr".into(),
+ source_existing_membership: None,
+ source_repo_root: "/repo/herdr".into(),
+ repo_key: "repo-key".into(),
+ repo_name: "herdr".into(),
+ branch: "foo".into(),
+ checkout_path: "/repo/.worktrees/herdr/foo".into(),
+ error: Some(
+ "Preparing worktree (new branch 'foo')\nfatal: a branch named 'foo' already exists"
+ .into(),
+ ),
+ creating: false,
+ });
+
+ let mut terminal =
+ Terminal::new(TestBackend::new(100, 30)).expect("test terminal should initialize");
+ terminal
+ .draw(|frame| render_new_linked_worktree_overlay(&app, frame, Rect::new(0, 0, 100, 30)))
+ .expect("new worktree overlay should render");
+ let rendered = terminal
+ .backend()
+ .buffer()
+ .content()
+ .iter()
+ .map(|cell| cell.symbol())
+ .collect::<String>();
+
+ assert!(rendered.contains("fatal: a branch named 'foo' already exists"));
+ }
+
+ #[test]
+ fn new_worktree_hit_test_geometry_matches_modal_size() {
+ let area = Rect::new(0, 0, 100, 30);
+ let inner = super::new_linked_worktree_inner_rect(area).unwrap();
+ let (create, cancel) = super::new_linked_worktree_button_rects(inner);
+
+ assert_eq!(inner.width, super::NEW_LINKED_WORKTREE_POPUP_WIDTH - 2);
+ assert_eq!(inner.height, super::NEW_LINKED_WORKTREE_POPUP_HEIGHT - 2);
+ assert_eq!(create.y, inner.y + inner.height - 1);
+ assert_eq!(cancel.y, inner.y + inner.height - 1);
+ }
}