Skip to content

Commit d7c597a

Browse files
committed
build: make ui deps optional
1 parent 4c03594 commit d7c597a

File tree

5 files changed

+148
-13
lines changed

5 files changed

+148
-13
lines changed

implementations/rust/ockam/ockam_api/Cargo.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ storage = ["ockam/storage"]
4444
aws-lc = ["ockam_vault/aws-lc", "ockam_transport_tcp/aws-lc"]
4545
rust-crypto = ["ockam_vault/rust-crypto", "ockam_transport_tcp/ring"]
4646
privileged_portals = ["ockam_transport_tcp/privileged_portals"]
47+
ui = ["r3bl_rs_utils_core", "r3bl_tui", "r3bl_tuify"]
4748

4849
[[bin]]
4950
name = "node_control_api_schema"
@@ -92,9 +93,9 @@ opentelemetry-proto = { version = "0.27", features = ["full"] }
9293
opentelemetry-semantic-conventions = { version = "0.28", features = ["semconv_experimental"] }
9394
opentelemetry_sdk = { version = "0.27", features = ["logs", "metrics", "trace", "rt-tokio", "rt-tokio-current-thread", "testing"], default-features = false }
9495
petname = { version = "2.0.2", default-features = false, features = ["default-rng", "default-words"] }
95-
r3bl_rs_utils_core = "0.9"
96-
r3bl_tui = "0.5"
97-
r3bl_tuify = "0.1"
96+
r3bl_rs_utils_core = { version = "0.9", optional = true }
97+
r3bl_tui = { version = "0.5", optional = true }
98+
r3bl_tuify = { version = "0.1", optional = true }
9899
rand = "0.8"
99100
regex = "1.10.6"
100101
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls-native-roots"] }

implementations/rust/ockam/ockam_api/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
#[macro_use]
2020
extern crate tracing;
2121

22+
#[cfg(not(feature = "ui"))]
23+
// The color! macro is already exported at the crate root via #[macro_export] in ui::colors (fallback),
24+
// so we don't re-export it here to avoid duplicate definition and unused import warnings.
25+
2226
pub mod address;
2327
pub mod authenticator;
2428
pub mod cli_state;
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,91 @@
1+
#[cfg(feature = "ui")]
12
pub mod colors;
3+
4+
#[cfg(not(feature = "ui"))]
5+
pub mod colors {
6+
use colorful::{core::color_string::CString, Colorful, RGB};
7+
use std::fmt::Display;
8+
9+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
10+
pub enum OckamColor {
11+
OckamBlue,
12+
HeaderGradient,
13+
PrimaryResource,
14+
Success,
15+
Failure,
16+
FmtOKBackground,
17+
FmtINFOBackground,
18+
FmtWARNBackground,
19+
FmtERRORBackground,
20+
FmtLISTBackground,
21+
}
22+
23+
impl OckamColor {
24+
/// Hex string value for this color (kept consistent w/ full UI feature version).
25+
pub fn value(&self) -> &'static str {
26+
match self {
27+
OckamColor::OckamBlue => "#52c7ea",
28+
OckamColor::HeaderGradient => "#4FDAB8",
29+
OckamColor::PrimaryResource => "#4FDAB8",
30+
OckamColor::Success => "#A8C97D",
31+
OckamColor::Failure => "#ff0000",
32+
OckamColor::FmtOKBackground => "#A8C97D",
33+
OckamColor::FmtINFOBackground => "#0DCAF0",
34+
OckamColor::FmtWARNBackground => "#ff9a00",
35+
OckamColor::FmtERRORBackground => "#FF0000",
36+
OckamColor::FmtLISTBackground => "#0DCAF0",
37+
}
38+
}
39+
pub fn color(&self) -> RGB {
40+
// Provide simple, hard-coded fallback colors that don't require r3bl_* crates.
41+
match self {
42+
OckamColor::OckamBlue => RGB::new(0x52, 0xC7, 0xEA),
43+
OckamColor::HeaderGradient => RGB::new(0x4F, 0xDA, 0xB8),
44+
OckamColor::PrimaryResource => RGB::new(0x4F, 0xDA, 0xB8),
45+
OckamColor::Success => RGB::new(0xA8, 0xC9, 0x7D),
46+
OckamColor::Failure => RGB::new(0xFF, 0x00, 0x00),
47+
OckamColor::FmtOKBackground => RGB::new(0xA8, 0xC9, 0x7D),
48+
OckamColor::FmtINFOBackground => RGB::new(0x0D, 0xCA, 0xF0),
49+
OckamColor::FmtWARNBackground => RGB::new(0xFF, 0x9A, 0x00),
50+
OckamColor::FmtERRORBackground => RGB::new(0xFF, 0x00, 0x00),
51+
OckamColor::FmtLISTBackground => RGB::new(0x0D, 0xCA, 0xF0),
52+
}
53+
}
54+
}
55+
56+
// Re-exported macro to keep parity w/ full UI feature.
57+
#[macro_export]
58+
macro_rules! color {
59+
($text:expr, $color:expr) => {
60+
$text.to_string().color($color.color())
61+
};
62+
}
63+
64+
pub fn color_primary(input: impl Display) -> CString {
65+
input.to_string().color(OckamColor::PrimaryResource.color())
66+
}
67+
pub fn color_primary_alt(input: impl Display) -> String {
68+
// Fallback: no gradient, just plain text
69+
input.to_string()
70+
}
71+
pub fn color_ok(input: impl Display) -> CString {
72+
input.to_string().color(OckamColor::FmtOKBackground.color())
73+
}
74+
pub fn color_warn(input: impl Display) -> CString {
75+
input.to_string().color(OckamColor::FmtWARNBackground.color())
76+
}
77+
pub fn color_error(input: impl Display) -> CString {
78+
input.to_string().color(OckamColor::FmtERRORBackground.color())
79+
}
80+
pub fn color_email(input: impl Display) -> CString {
81+
input.to_string().color(OckamColor::PrimaryResource.color())
82+
}
83+
pub fn color_uri(input: impl Display) -> String {
84+
// Fallback: no gradient
85+
input.to_string()
86+
}
87+
}
88+
289
pub mod command;
390
pub mod output;
491
pub mod terminal;

implementations/rust/ockam/ockam_api/src/ui/terminal/fmt.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,24 @@ pub const MIETTE_PADDING: &str = " ";
88
pub const INDENTATION: &str = " ";
99

1010
pub fn get_separator_width() -> usize {
11-
// If we can't get the terminal width, use the default width
12-
let mut terminal_width = r3bl_tuify::get_terminal_width();
13-
if terminal_width == 0 {
14-
terminal_width = r3bl_tuify::DEFAULT_WIDTH;
11+
// When the full UI feature is enabled, use dynamic terminal sizing from r3bl_tuify.
12+
#[cfg(feature = "ui")]
13+
{
14+
let mut terminal_width = r3bl_tuify::get_terminal_width();
15+
if terminal_width == 0 {
16+
terminal_width = r3bl_tuify::DEFAULT_WIDTH;
17+
}
18+
let terminal_width = std::cmp::max(terminal_width, 2 * PADDING.len());
19+
return std::cmp::min(terminal_width - PADDING.len(), r3bl_tuify::DEFAULT_WIDTH);
20+
}
21+
22+
// Fallback when `ui` feature (and thus r3bl_tuify) is disabled: use a fixed width.
23+
#[cfg(not(feature = "ui"))]
24+
{
25+
// Pick a sane default (80 cols) minus left padding, but never under 10.
26+
let width = 80usize.saturating_sub(PADDING.len());
27+
std::cmp::max(width, 10)
1528
}
16-
// Make sure the separator width is at least twice the length of the padding.
17-
// We want to show a small separator even if the terminal is too narrow.
18-
let terminal_width = std::cmp::max(terminal_width, 2 * PADDING.len());
19-
// Limit the separator width to the default width
20-
std::cmp::min(terminal_width - PADDING.len(), r3bl_tuify::DEFAULT_WIDTH)
2129
}
2230

2331
#[test]

implementations/rust/ockam/ockam_api/src/ui/terminal/mod.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,23 @@ use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
1515
use jaq_interpret::{Ctx, FilterT, ParseCtx, RcIter, Val};
1616
use miette::{miette, IntoDiagnostic};
1717
use ockam_core::env::get_env_with_default;
18+
#[cfg(feature = "ui")]
1819
use r3bl_rs_utils_core::{ch, ChUnit};
20+
21+
22+
#[cfg(feature = "ui")]
1923
use r3bl_tuify::{get_size, select_from_list, SelectionMode, StyleSheet};
24+
#[cfg(not(feature = "ui"))]
25+
#[allow(dead_code)]
26+
pub(crate) fn get_size() -> (usize, usize) {
27+
(80, 24)
28+
}
29+
#[cfg(not(feature = "ui"))]
30+
#[allow(dead_code)]
31+
pub(crate) fn select_from_list<T: Clone>(_: &str, items: &[T]) -> Option<T> {
32+
items.first().cloned()
33+
}
34+
2035
use serde::Serialize;
2136
use std::fmt::Write as _;
2237
use std::fmt::{Debug, Display};
@@ -139,7 +154,13 @@ impl<W: TerminalWriter + Debug> Terminal<W> {
139154
let no_input = Self::should_disable_user_input(no_input);
140155
let stdout = W::stdout(no_color, OutputBranding::default());
141156
let stderr = W::stderr(no_color, OutputBranding::default());
142-
let max_width_col_count = get_size().map(|it| it.col_count).unwrap_or(ch!(80)).into();
157+
#[cfg(feature = "ui")]
158+
let max_width_col_count = get_size().map(|it| it.col_count).unwrap_or(80).into();
159+
#[cfg(not(feature = "ui"))]
160+
let max_width_col_count = {
161+
let (cols, _rows) = get_size();
162+
cols
163+
};
143164
Self {
144165
stdout,
145166
stderr,
@@ -186,6 +207,7 @@ impl<W: TerminalWriter + Debug> Terminal<W> {
186207
}
187208
}
188209

210+
#[cfg(feature = "ui")]
189211
pub fn confirm_interactively(&self, header: String) -> bool {
190212
let user_input = select_from_list(
191213
header,
@@ -202,8 +224,15 @@ impl<W: TerminalWriter + Debug> Terminal<W> {
202224
}
203225
}
204226

227+
#[cfg(not(feature = "ui"))]
228+
pub fn confirm_interactively(&self, header: String) -> bool {
229+
let user_input = select_from_list(&header, &["YES".to_string(), "NO".to_string()]);
230+
matches!(user_input, Some(ref it) if it == "YES")
231+
}
232+
205233
/// Returns the selected items by the user, or an empty `Vec` if the user did not select any item
206234
/// or if the user is not able to select an item (e.g. not a TTY, `--no-input` flag, etc.).
235+
#[cfg(feature = "ui")]
207236
pub fn select_multiple(&self, header: String, items: Vec<String>) -> Vec<String> {
208237
if !self.can_ask_for_user_input() {
209238
return Vec::new();
@@ -221,6 +250,12 @@ impl<W: TerminalWriter + Debug> Terminal<W> {
221250
user_selected_list.unwrap_or_default()
222251
}
223252

253+
#[cfg(not(feature = "ui"))]
254+
pub fn select_multiple(&self, _header: String, _items: Vec<String>) -> Vec<String> {
255+
// Fallback: interactive multi-selection unavailable without `ui` feature.
256+
Vec::new()
257+
}
258+
224259
pub fn can_ask_for_user_input(&self) -> bool {
225260
!self.no_input && self.stderr.is_tty() && !self.quiet
226261
}

0 commit comments

Comments
 (0)