mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-25 06:42:52 +08:00
refactor(tui): extract shared setting edit overlay (#1776)
The draw_edit_overlay function in sandbox_settings and global_settings was nearly identical — the only difference was which settings slice the entry was resolved from (app.sandbox_settings vs app.global_settings). Extract the common rendering logic into draw_setting_edit_overlay in ui/mod.rs, taking key/kind/edit/area/theme as parameters. Each pane now resolves its own entry and delegates to the single implementation. Net: -75 lines, +61 lines across the three files.
This commit is contained in:
@@ -120,46 +120,10 @@ fn draw_edit_overlay(
|
||||
edit: &crate::app::SettingEditState,
|
||||
area: Rect,
|
||||
) {
|
||||
let t = &app.theme;
|
||||
let Some(entry) = app.global_settings.get(edit.index) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let title = format!(" Edit: {} ({}) ", entry.key, entry.kind.as_str());
|
||||
let mut lines = vec![
|
||||
Line::from(Span::styled(&title, t.heading)),
|
||||
Line::from(""),
|
||||
Line::from(vec![
|
||||
Span::styled("Value: ", t.muted),
|
||||
Span::styled(&edit.input, t.text),
|
||||
Span::styled("_", t.accent),
|
||||
]),
|
||||
];
|
||||
|
||||
if let Some(ref err) = edit.error {
|
||||
lines.push(Line::from(""));
|
||||
lines.push(Line::from(Span::styled(err, t.status_err)));
|
||||
}
|
||||
|
||||
lines.push(Line::from(""));
|
||||
lines.push(Line::from(vec![
|
||||
Span::styled("[Enter]", t.key_hint),
|
||||
Span::styled(" Confirm ", t.muted),
|
||||
Span::styled("[Esc]", t.key_hint),
|
||||
Span::styled(" Cancel", t.muted),
|
||||
]));
|
||||
|
||||
// content lines + 2 for border
|
||||
let popup_height = u16::try_from(lines.len() + 2).unwrap_or(u16::MAX);
|
||||
let popup = centered_rect(50, popup_height, area);
|
||||
frame.render_widget(Clear, popup);
|
||||
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_style(t.border_focused)
|
||||
.padding(Padding::horizontal(1));
|
||||
|
||||
frame.render_widget(Paragraph::new(lines).block(block), popup);
|
||||
super::draw_setting_edit_overlay(frame, &entry.key, entry.kind, edit, area, &app.theme);
|
||||
}
|
||||
|
||||
fn draw_confirm_set(frame: &mut Frame<'_>, app: &App, idx: usize, area: Rect) {
|
||||
|
||||
@@ -18,9 +18,10 @@ use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
||||
use ratatui::style::Style;
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, Borders, Paragraph};
|
||||
use ratatui::widgets::{Block, Borders, Clear, Padding, Paragraph};
|
||||
|
||||
use crate::app::{self, App, Focus, InputMode, Screen};
|
||||
use crate::app::{self, App, Focus, InputMode, Screen, SettingEditState};
|
||||
use crate::theme::Theme;
|
||||
|
||||
pub fn draw(frame: &mut Frame<'_>, app: &mut App) {
|
||||
// Splash screen is a full-screen takeover — no chrome.
|
||||
@@ -512,6 +513,62 @@ pub fn centered_rect(width: u16, height: u16, area: Rect) -> Rect {
|
||||
horiz[1]
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Shared setting-edit overlay (used by both global and sandbox settings panes)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Render the generic setting-edit text-input overlay.
|
||||
///
|
||||
/// Both the global-settings and sandbox-settings panes show the same editor
|
||||
/// overlay — an input box with the setting key/type in the title, an error
|
||||
/// line when validation fails, and `[Enter]`/`[Esc]` hints. This function
|
||||
/// is the single implementation; each pane resolves its own entry and then
|
||||
/// delegates here.
|
||||
fn draw_setting_edit_overlay(
|
||||
frame: &mut Frame<'_>,
|
||||
key: &str,
|
||||
kind: openshell_core::settings::SettingValueKind,
|
||||
edit: &SettingEditState,
|
||||
area: Rect,
|
||||
theme: &Theme,
|
||||
) {
|
||||
let t = theme;
|
||||
let title = format!(" Edit: {} ({}) ", key, kind.as_str());
|
||||
let mut lines = vec![
|
||||
Line::from(Span::styled(&title, t.heading)),
|
||||
Line::from(""),
|
||||
Line::from(vec![
|
||||
Span::styled("Value: ", t.muted),
|
||||
Span::styled(&edit.input, t.text),
|
||||
Span::styled("_", t.accent),
|
||||
]),
|
||||
];
|
||||
|
||||
if let Some(ref err) = edit.error {
|
||||
lines.push(Line::from(""));
|
||||
lines.push(Line::from(Span::styled(err.as_str(), t.status_err)));
|
||||
}
|
||||
|
||||
lines.push(Line::from(""));
|
||||
lines.push(Line::from(vec![
|
||||
Span::styled("[Enter]", t.key_hint),
|
||||
Span::styled(" Confirm ", t.muted),
|
||||
Span::styled("[Esc]", t.key_hint),
|
||||
Span::styled(" Cancel", t.muted),
|
||||
]));
|
||||
|
||||
let popup_height = u16::try_from(lines.len() + 2).unwrap_or(u16::MAX);
|
||||
let popup = centered_popup(50, popup_height, area);
|
||||
frame.render_widget(Clear, popup);
|
||||
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_style(t.border_focused)
|
||||
.padding(Padding::horizontal(1));
|
||||
|
||||
frame.render_widget(Paragraph::new(lines).block(block), popup);
|
||||
}
|
||||
|
||||
/// Center a popup rectangle within `area` using percentage-based width and
|
||||
/// an absolute height (in rows).
|
||||
pub fn centered_popup(percent_x: u16, height: u16, area: Rect) -> Rect {
|
||||
|
||||
@@ -128,45 +128,10 @@ fn draw_edit_overlay(
|
||||
edit: &crate::app::SettingEditState,
|
||||
area: Rect,
|
||||
) {
|
||||
let t = &app.theme;
|
||||
let Some(entry) = app.sandbox_settings.get(edit.index) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let title = format!(" Edit: {} ({}) ", entry.key, entry.kind.as_str());
|
||||
let mut lines = vec![
|
||||
Line::from(Span::styled(&title, t.heading)),
|
||||
Line::from(""),
|
||||
Line::from(vec![
|
||||
Span::styled("Value: ", t.muted),
|
||||
Span::styled(&edit.input, t.text),
|
||||
Span::styled("_", t.accent),
|
||||
]),
|
||||
];
|
||||
|
||||
if let Some(ref err) = edit.error {
|
||||
lines.push(Line::from(""));
|
||||
lines.push(Line::from(Span::styled(err, t.status_err)));
|
||||
}
|
||||
|
||||
lines.push(Line::from(""));
|
||||
lines.push(Line::from(vec![
|
||||
Span::styled("[Enter]", t.key_hint),
|
||||
Span::styled(" Confirm ", t.muted),
|
||||
Span::styled("[Esc]", t.key_hint),
|
||||
Span::styled(" Cancel", t.muted),
|
||||
]));
|
||||
|
||||
let popup_height = u16::try_from(lines.len() + 2).unwrap_or(u16::MAX);
|
||||
let popup = centered_rect(50, popup_height, area);
|
||||
frame.render_widget(Clear, popup);
|
||||
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_style(t.border_focused)
|
||||
.padding(Padding::horizontal(1));
|
||||
|
||||
frame.render_widget(Paragraph::new(lines).block(block), popup);
|
||||
super::draw_setting_edit_overlay(frame, &entry.key, entry.kind, edit, area, &app.theme);
|
||||
}
|
||||
|
||||
fn draw_confirm_set(frame: &mut Frame<'_>, app: &App, idx: usize, area: Rect) {
|
||||
|
||||
Reference in New Issue
Block a user