返回 DeepSeek-TUI-2026
api_key.rs
根目录 / crates / tui / src / tui / onboarding / api_key.rs
1 //! API key entry screen for onboarding.
2
3 use ratatui::style::{Modifier, Style};
4 use ratatui::text::{Line, Span};
5
6 use crate::palette;
7 use crate::tui::app::App;
8
9 pub fn lines(app: &App) -> Vec<Line<'static>> {
10 let mut lines = vec![
11 Line::from(Span::styled(
12 "Connect your DeepSeek API key",
13 Style::default()
14 .fg(palette::DEEPSEEK_SKY)
15 .add_modifier(Modifier::BOLD),
16 )),
17 Line::from(""),
18 Line::from(Span::styled(
19 "Step 1. Open https://platform.deepseek.com/api_keys and create a key.",
20 Style::default().fg(palette::TEXT_PRIMARY),
21 )),
22 Line::from(Span::styled(
23 "Step 2. Paste it below and press Enter.",
24 Style::default().fg(palette::TEXT_PRIMARY),
25 )),
26 Line::from(""),
27 Line::from(Span::styled(
28 "Saved to ~/.deepseek/config.toml so it works from any folder.",
29 Style::default().fg(palette::TEXT_MUTED),
30 )),
31 Line::from(Span::styled(
32 "Paste the full key exactly as issued (no spaces or newlines).",
33 Style::default().fg(palette::TEXT_MUTED),
34 )),
35 Line::from(""),
36 ];
37
38 let masked = mask_key(&app.api_key_input);
39 let display = if masked.is_empty() {
40 "(paste key here)"
41 } else {
42 masked.as_str()
43 };
44 lines.push(Line::from(vec![
45 Span::styled("Key: ", Style::default().fg(palette::TEXT_MUTED)),
46 Span::styled(
47 display.to_string(),
48 Style::default()
49 .fg(palette::TEXT_PRIMARY)
50 .add_modifier(Modifier::BOLD),
51 ),
52 ]));
53 lines.push(Line::from(""));
54
55 if let Some(message) = app.status_message.as_deref() {
56 lines.push(Line::from(Span::styled(
57 message.to_string(),
58 Style::default().fg(palette::STATUS_WARNING),
59 )));
60 lines.push(Line::from(""));
61 }
62
63 lines.push(Line::from(""));
64 lines.push(Line::from(Span::styled(
65 "Press Enter to save, Esc to go back.",
66 Style::default().fg(palette::TEXT_MUTED),
67 )));
68
69 lines
70 }
71
72 fn mask_key(input: &str) -> String {
73 let trimmed = input.trim();
74 let len = trimmed.chars().count();
75 if len == 0 {
76 return String::new();
77 }
78 if len <= 4 {
79 return "*".repeat(len);
80 }
81 let visible: String = trimmed
82 .chars()
83 .rev()
84 .take(4)
85 .collect::<String>()
86 .chars()
87 .rev()
88 .collect();
89 format!("{}{}", "*".repeat(len - 4), visible)
90 }
91
91 lines RUST