mirror of
https://github.com/openai/codex.git
synced 2026-04-24 14:45:27 +00:00
feat(tui): harden theme lock recovery and ordering
This commit is contained in:
@@ -665,6 +665,8 @@ fn wrap_styled_spans(spans: &[RtSpan<'static>], max_cols: usize) -> Vec<Vec<RtSp
|
||||
};
|
||||
let ch_len = ch.len_utf8();
|
||||
current_line.push(RtSpan::styled(remaining[..ch_len].to_string(), style));
|
||||
// Use fallback width 1 (not 0) so this branch always advances
|
||||
// even if `ch` has unknown/zero display width.
|
||||
col = ch.width().unwrap_or(if ch == '\t' { TAB_WIDTH } else { 1 });
|
||||
remaining = &remaining[ch_len..];
|
||||
continue;
|
||||
|
||||
@@ -226,9 +226,11 @@ fn theme_lock() -> &'static RwLock<Theme> {
|
||||
|
||||
/// Swap the active syntax theme at runtime (for live preview).
|
||||
pub(crate) fn set_syntax_theme(theme: Theme) {
|
||||
if let Ok(mut guard) = theme_lock().write() {
|
||||
*guard = theme;
|
||||
}
|
||||
let mut guard = match theme_lock().write() {
|
||||
Ok(guard) => guard,
|
||||
Err(poisoned) => poisoned.into_inner(),
|
||||
};
|
||||
*guard = theme;
|
||||
}
|
||||
|
||||
/// Clone the current syntax theme (e.g. to save for cancel-restore).
|
||||
@@ -317,6 +319,9 @@ pub(crate) fn list_available_themes(codex_home: Option<&Path>) -> Vec<ThemeEntry
|
||||
}
|
||||
}
|
||||
|
||||
// Keep picker ordering stable across platforms/filesystems.
|
||||
entries.sort_by(|a, b| (a.is_custom, a.name.as_str()).cmp(&(b.is_custom, b.name.as_str())));
|
||||
|
||||
entries
|
||||
}
|
||||
|
||||
@@ -999,6 +1004,30 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_available_themes_returns_stable_sorted_order() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let themes_dir = dir.path().join("themes");
|
||||
std::fs::create_dir(&themes_dir).unwrap();
|
||||
write_minimal_tmtheme(&themes_dir.join("zzz-custom.tmTheme"));
|
||||
write_minimal_tmtheme(&themes_dir.join("aaa-custom.tmTheme"));
|
||||
write_minimal_tmtheme(&themes_dir.join("mmm-custom.tmTheme"));
|
||||
|
||||
let entries = list_available_themes(Some(dir.path()));
|
||||
let actual: Vec<(bool, String)> = entries
|
||||
.iter()
|
||||
.map(|entry| (entry.is_custom, entry.name.clone()))
|
||||
.collect();
|
||||
|
||||
let mut expected = actual.clone();
|
||||
expected.sort_by(|a, b| (a.0, a.1.as_str()).cmp(&(b.0, b.1.as_str())));
|
||||
|
||||
assert_eq!(
|
||||
actual, expected,
|
||||
"theme entries should be stable and sorted (builtins first, then custom by name)"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_theme_name_is_exhaustive() {
|
||||
use two_face::theme::EmbeddedLazyThemeSet;
|
||||
|
||||
Reference in New Issue
Block a user