diff options
| author | soryu <soryu@soryu.co> | 2026-01-21 15:58:34 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-01-21 15:58:34 +0000 |
| commit | da246c4c4e23c9ad976705f9a3fa80e0d75b4425 (patch) | |
| tree | ddc3b93ed269e60dac1aa9113000daeac4a1b6e6 /makima/src/daemon/tui/ui.rs | |
| parent | 7155e6cd7ddf25a5a4d4f6d6abecd49f0cf519dc (diff) | |
| download | soryu-da246c4c4e23c9ad976705f9a3fa80e0d75b4425.tar.gz soryu-da246c4c4e23c9ad976705f9a3fa80e0d75b4425.zip | |
Update CLI to show repo suggestions
Diffstat (limited to 'makima/src/daemon/tui/ui.rs')
| -rw-r--r-- | makima/src/daemon/tui/ui.rs | 87 |
1 files changed, 77 insertions, 10 deletions
diff --git a/makima/src/daemon/tui/ui.rs b/makima/src/daemon/tui/ui.rs index de15320..2a5a6ce 100644 --- a/makima/src/daemon/tui/ui.rs +++ b/makima/src/daemon/tui/ui.rs @@ -362,10 +362,21 @@ fn render_edit_dialog(frame: &mut Frame, app: &App) { /// Render the create contract dialog fn render_create_dialog(frame: &mut Frame, app: &App) { - // Calculate popup size and position + // Calculate popup size and position - make it taller if suggestions are shown let area = frame.area(); + let state = &app.create_state; + let current_field = state.current_field(); + // Show suggestions whenever we have them (like the frontend does) + let show_suggestions = state.show_suggestions && !state.repo_suggestions.is_empty(); + let popup_width = 70.min(area.width.saturating_sub(4)); - let popup_height = 20; + let base_height = 20; + let suggestion_height = if show_suggestions { + (state.repo_suggestions.len().min(5) + 2) as u16 + } else { + 0 + }; + let popup_height = base_height + suggestion_height; let popup_x = (area.width.saturating_sub(popup_width)) / 2; let popup_y = (area.height.saturating_sub(popup_height)) / 2; @@ -380,8 +391,6 @@ fn render_create_dialog(frame: &mut Frame, app: &App) { // Clear the area behind the popup frame.render_widget(Clear, popup_area); - let state = &app.create_state; - let current_field = state.current_field(); let max_field_width = (popup_width as usize).saturating_sub(18); // Styles @@ -389,6 +398,8 @@ fn render_create_dialog(frame: &mut Frame, app: &App) { let inactive_style = Style::default().fg(Color::White); let label_style = Style::default().fg(Color::DarkGray); let hint_style = Style::default().fg(Color::DarkGray).add_modifier(Modifier::ITALIC); + let suggestion_style = Style::default().fg(Color::White); + let selected_suggestion_style = Style::default().fg(Color::Black).bg(Color::Cyan); // Helper to build text field with cursor let build_field = |value: &str, cursor: usize, is_active: bool| -> String { @@ -435,7 +446,7 @@ fn render_create_dialog(frame: &mut Frame, app: &App) { ] }; - let text = vec![ + let mut text = vec![ Line::from(""), Line::from(Span::styled( " New Contract", @@ -486,9 +497,65 @@ fn render_create_dialog(frame: &mut Frame, app: &App) { ), ]), Line::from(Span::styled(" Git repository URL (optional)", hint_style)), - Line::from(""), - // Help line - Line::from(vec![ + ]; + + // Add suggestions section + if show_suggestions { + text.push(Line::from("")); + text.push(Line::from(Span::styled( + " Recent repositories (↑/↓ to select, Enter to apply):", + Style::default().fg(Color::Cyan), + ))); + + for (i, suggestion) in state.repo_suggestions.iter().take(5).enumerate() { + let is_selected = i == state.selected_suggestion; + let url_or_path = suggestion.repository_url.as_ref() + .or(suggestion.local_path.as_ref()) + .map(|s| s.as_str()) + .unwrap_or(""); + + // Truncate if too long + let display_url = if url_or_path.len() > max_field_width - 10 { + format!("...{}", &url_or_path[url_or_path.len().saturating_sub(max_field_width - 13)..]) + } else { + url_or_path.to_string() + }; + + let prefix = if is_selected { " → " } else { " " }; + let count_suffix = format!(" ({}×)", suggestion.use_count); + + text.push(Line::from(vec![ + Span::styled( + format!("{}{}{}", prefix, display_url, count_suffix), + if is_selected { selected_suggestion_style } else { suggestion_style }, + ), + ])); + } + } else if state.suggestions_loaded && state.repo_suggestions.is_empty() { + // Show message when suggestions loaded but empty + text.push(Line::from("")); + text.push(Line::from(Span::styled( + " (No recent repositories - add repos to contracts to see suggestions here)", + hint_style, + ))); + } + + text.push(Line::from("")); + + // Help line - show different help when suggestions are visible + if show_suggestions { + text.push(Line::from(vec![ + Span::styled(" ↑/↓", Style::default().fg(Color::Green).add_modifier(Modifier::BOLD)), + Span::raw(": select "), + Span::styled("Enter", Style::default().fg(Color::Green).add_modifier(Modifier::BOLD)), + Span::raw(": apply "), + Span::styled("Tab", Style::default().fg(Color::Green).add_modifier(Modifier::BOLD)), + Span::raw(": next field "), + Span::styled("Esc", Style::default().fg(Color::Red).add_modifier(Modifier::BOLD)), + Span::raw(": cancel"), + ])); + } else { + text.push(Line::from(vec![ Span::styled(" Tab/↑↓", Style::default().fg(Color::Green).add_modifier(Modifier::BOLD)), Span::raw(": switch "), Span::styled("Enter", Style::default().fg(Color::Green).add_modifier(Modifier::BOLD)), @@ -497,8 +564,8 @@ fn render_create_dialog(frame: &mut Frame, app: &App) { Span::raw(": toggle type "), Span::styled("Esc", Style::default().fg(Color::Red).add_modifier(Modifier::BOLD)), Span::raw(": cancel"), - ]), - ]; + ])); + } let popup = Paragraph::new(text) .block(Block::default() |
