mirror of
https://github.com/openai/codex.git
synced 2026-05-01 20:02:05 +03:00
feat(tui): add /statusline command for interactive status line configuration (#10546)
## Summary - Adds a new `/statusline` command to configure TUI footer status line - Introduces reusable `MultiSelectPicker` component with keyboard navigation, optional ordering and toggle support - Implement status line setup modal that persist configuration to config.toml ## Status Line Items The following items can be displayed in the status line: - **Model**: Current model name (with optional reasoning level) - **Context**: Remaining/used context window percentage - **Rate Limits**: 5-day and weekly usage limits - **Git**: Current branch (with optimized lookups) - **Tokens**: Used tokens, input/output token counts - **Session**: Session ID (full or shortened prefix) - **Paths**: Current directory, project root - **Version**: Codex version ## Features - Live preview while configuring status line items - Fuzzy search filtering in the picker - Intelligent truncation when items don't fit - Items gracefully omit when data is unavailable - Configuration persists to `config.toml` - Validates and warns about invalid status line items ## Test plan - [x] Run `/statusline` and verify picker UI appears - [x] Toggle items on/off and verify live preview updates - [x] Confirm selection persists after restart - [x] Verify truncation behavior with many items selected - [x] Test git branch detection in and out of git repos --------- Co-authored-by: Josh McKinney <joshka@openai.com>
This commit is contained in:
@@ -327,6 +327,33 @@ pub(crate) fn center_truncate_path(path: &str, max_width: usize) -> String {
|
||||
front_truncate(path, max_width)
|
||||
}
|
||||
|
||||
/// Join a list of strings with proper English punctuation.
|
||||
/// Examples:
|
||||
/// - [] -> ""
|
||||
/// - ["apple"] -> "apple"
|
||||
/// - ["apple", "banana"] -> "apple and banana"
|
||||
/// - ["apple", "banana", "cherry"] -> "apple, banana and cherry"
|
||||
pub(crate) fn proper_join<T: AsRef<str>>(items: &[T]) -> String {
|
||||
match items.len() {
|
||||
0 => String::new(),
|
||||
1 => items[0].as_ref().to_string(),
|
||||
2 => format!("{} and {}", items[0].as_ref(), items[1].as_ref()),
|
||||
_ => {
|
||||
let last = items[items.len() - 1].as_ref();
|
||||
let mut result = String::new();
|
||||
|
||||
for (i, item) in items.iter().take(items.len() - 1).enumerate() {
|
||||
if i > 0 {
|
||||
result.push_str(", ");
|
||||
}
|
||||
result.push_str(item.as_ref());
|
||||
}
|
||||
|
||||
format!("{result} and {last}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -534,4 +561,20 @@ mod tests {
|
||||
assert_eq!(format_json_compact("null").unwrap(), "null");
|
||||
assert_eq!(format_json_compact(r#""string""#).unwrap(), r#""string""#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_proper_join() {
|
||||
let empty: Vec<String> = vec![];
|
||||
assert_eq!(proper_join(&empty), "");
|
||||
assert_eq!(proper_join(&["apple"]), "apple");
|
||||
assert_eq!(proper_join(&["apple", "banana"]), "apple and banana");
|
||||
assert_eq!(
|
||||
proper_join(&["apple", "banana", "cherry"]),
|
||||
"apple, banana and cherry"
|
||||
);
|
||||
assert_eq!(
|
||||
proper_join(&["apple", "banana", "cherry", "date"]),
|
||||
"apple, banana, cherry and date"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user