Compare commits

...
1 Commits
Author SHA1 Message Date
CodeWhale BotandClaude Sonnet 5.5 84c1224963 fix(tui): show the referral disclosure under the featured OrcaRouter row
The provider and model pickers drew the featured "Recommended" row with no
disclosure beside it; the line only appeared after opening the offer. The
row now carries the existing OrcaRouterOfferDisclosure text, wrapped by
display width on the lines directly under it, in every locale pack. When
the row plus its disclosure cannot fit with three list rows, the whole row
is hidden rather than shown without its line. zh-Hans and the mainland
China gate are unchanged. No provider or ranking change.

Regression: featured_offer_* tests render every shipped locale at 100, 56,
48 and 30 columns and check the disclosure is complete and the list area
is not overprinted.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-11-12 18:23:08 -08:00
+112 -2
View File
@@ -119,8 +119,22 @@ impl ProviderOffer {
}
pub(crate) fn render(&self, locale: Locale, area: Rect, buf: &mut Buffer) -> Rect {
self.render_if(crate::tui::orca_offer::available(locale), locale, area, buf)
}
fn render_if(&self, available: bool, locale: Locale, area: Rect, buf: &mut Buffer) -> Rect {
self.clear();
if area.height < 4 || area.width < 20 || !crate::tui::orca_offer::available(locale) {
if area.height < 4 || area.width < 20 || !available {
return area;
}
let disclosure = wrap_to_width(
&tr(locale, MessageId::OrcaRouterOfferDisclosure),
usize::from(area.width),
);
let rows = u16::try_from(disclosure.len())
.unwrap_or(u16::MAX)
.saturating_add(1);
if rows > area.height.saturating_sub(3) {
return area;
}
let chord = crate::tui::shell_key_routing::display_chord(
@@ -143,10 +157,51 @@ impl ProviderOffer {
Style::default().fg(palette::WHALE_ACTION).underlined()
})
.render(row, buf);
Rect::new(area.x, area.y + 1, area.width, area.height - 1)
for (index, line) in disclosure.into_iter().enumerate() {
let y = area.y + 1 + u16::try_from(index).unwrap_or(0);
Paragraph::new(line)
.style(Style::default().fg(palette::TEXT_MUTED))
.render(Rect::new(area.x, y, area.width, 1), buf);
}
Rect::new(area.x, area.y + rows, area.width, area.height - rows)
}
}
fn wrap_to_width(text: &str, width: usize) -> Vec<String> {
use unicode_width::UnicodeWidthChar;
let width = width.max(1);
let mut lines = Vec::new();
let mut line = String::new();
let mut line_width = 0;
let mut last_space: Option<usize> = None;
for ch in text.chars() {
let w = ch.width().unwrap_or(0);
if line_width + w > width {
if let Some(at) = last_space {
let rest = line.split_off(at);
lines.push(line.trim_end().to_owned());
line = rest.trim_start().to_owned();
} else {
lines.push(std::mem::take(&mut line));
}
line_width = unicode_width::UnicodeWidthStr::width(line.as_str());
last_space = None;
}
if ch == ' ' {
if line.is_empty() {
continue;
}
last_space = Some(line.len());
}
line.push(ch);
line_width += w;
}
if !line.is_empty() {
lines.push(line);
}
lines
}
const DS4_PROVIDER_ID: &str = "ds4";
const LM_STUDIO_PROVIDER_ID: &str = "lm_studio";
/// Rows a PageUp/PageDown travels in the provider lists. Both views are
@@ -5890,6 +5945,61 @@ mod tests {
.join("\n")
}
#[test]
fn featured_offer_row_is_followed_by_its_disclosure_in_every_locale_and_width() {
for locale in Locale::shipped_complete() {
let disclosure = tr(*locale, MessageId::OrcaRouterOfferDisclosure).into_owned();
let label = tr(*locale, MessageId::OrcaRouterOfferRecommended).into_owned();
for width in [100u16, 56, 48, 30] {
let area = Rect::new(0, 0, width, 24);
let mut buf = Buffer::empty(area);
let offer = ProviderOffer::default();
let rest = offer.render_if(true, *locale, area, &mut buf);
let lines: Vec<String> = (0..24)
.map(|y| {
(0..width)
.map(|x| buf[(x, y)].symbol())
.collect::<String>()
.trim_end()
.to_owned()
})
.collect();
let squash = |text: &str| text.split_whitespace().collect::<String>();
assert!(
squash(&lines[0]).starts_with(&squash(&label)),
"{} {width}: {:?}",
locale.tag(),
lines[0]
);
let shown = lines[1..usize::from(rest.y)].concat();
assert_eq!(
squash(&shown),
squash(&disclosure),
"{} {width}",
locale.tag()
);
assert!(
lines[usize::from(rest.y)..].iter().all(String::is_empty),
"{} {width}: list area overprinted",
locale.tag()
);
}
}
}
#[test]
fn featured_offer_shows_neither_row_nor_disclosure_when_unavailable() {
let area = Rect::new(0, 0, 100, 24);
let mut buf = Buffer::empty(area);
let offer = ProviderOffer::default();
assert_eq!(offer.render(Locale::ZhHans, area, &mut buf), area);
assert_eq!(offer.render_if(false, Locale::En, area, &mut buf), area);
assert!(
(0..24).all(|y| (0..100).all(|x| buf[(x, y)].symbol() == " ")),
"nothing may be drawn"
);
}
#[test]
fn failed_live_catalog_refresh_names_the_working_fallback() {
assert_eq!(