summaryrefslogtreecommitdiff
path: root/makima/src/daemon/tui/ui.rs
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-21 15:58:34 +0000
committersoryu <soryu@soryu.co>2026-01-21 15:58:34 +0000
commitda246c4c4e23c9ad976705f9a3fa80e0d75b4425 (patch)
treeddc3b93ed269e60dac1aa9113000daeac4a1b6e6 /makima/src/daemon/tui/ui.rs
parent7155e6cd7ddf25a5a4d4f6d6abecd49f0cf519dc (diff)
downloadsoryu-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.rs87
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()