Download codex-rs/cli/src/doctor/title.rs from SaylorTwift/codex: direct link, hf CLI and curl.
- Browser
- Download file 13.9 kB
-
https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/cli/src/doctor/title.rs
- Command line
-
hf download hf://SaylorTwift/codex/codex-rs/cli/src/doctor/title.rs
-
curl -L -o title.rs https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/cli/src/doctor/title.rs
13.9 kB
| use std::collections::HashSet; | |
| use std::path::Path; | |
| use std::path::PathBuf; | |
| use codex_config::ConfigLayerSource; | |
| use codex_core::config::Config; | |
| use codex_git_utils::get_git_repo_root; | |
| use unicode_segmentation::UnicodeSegmentation; | |
| use super::CheckStatus; | |
| use super::DoctorCheck; | |
| const DEFAULT_TERMINAL_TITLE_ITEMS: &[&str] = &["activity", "project-name"]; | |
| const PROJECT_TITLE_MAX_CHARS: usize = 24; | |
| struct TerminalTitleInputs { | |
| configured_items: Option<Vec<String>>, | |
| cwd: PathBuf, | |
| project_root: Option<ProjectTitleRoot>, | |
| } | |
| struct ProjectTitleRoot { | |
| source: &'static str, | |
| path: PathBuf, | |
| } | |
| pub(super) fn terminal_title_check(config: &Config) -> DoctorCheck { | |
| terminal_title_check_from_inputs(TerminalTitleInputs { | |
| configured_items: config.tui_terminal_title.clone(), | |
| cwd: config.cwd.to_path_buf(), | |
| project_root: terminal_title_project_root(config, &config.cwd), | |
| }) | |
| } | |
| fn terminal_title_check_from_inputs(inputs: TerminalTitleInputs) -> DoctorCheck { | |
| let (source, items, invalid_items) = match inputs.configured_items { | |
| Some(items) if items.is_empty() => ("disabled", Vec::new(), Vec::new()), | |
| Some(items) => { | |
| let (items, invalid_items) = parse_terminal_title_items(items); | |
| ("configured", items, invalid_items) | |
| } | |
| None => ( | |
| "default", | |
| DEFAULT_TERMINAL_TITLE_ITEMS | |
| .iter() | |
| .map(ToString::to_string) | |
| .collect(), | |
| Vec::new(), | |
| ), | |
| }; | |
| let mut details = vec![ | |
| format!("terminal title source: {source}"), | |
| format!( | |
| "terminal title items: {}", | |
| if items.is_empty() { | |
| "none".to_string() | |
| } else { | |
| items.join(", ") | |
| } | |
| ), | |
| format!("terminal title activity: {}", activity_enabled(&items)), | |
| ]; | |
| if !invalid_items.is_empty() { | |
| details.push(format!( | |
| "terminal title invalid items: {}", | |
| invalid_items.join(", ") | |
| )); | |
| } | |
| if project_title_selected(&items) { | |
| let (project_source, project_value) = | |
| project_title_candidate(inputs.project_root, &inputs.cwd); | |
| details.push(format!("terminal title project source: {project_source}")); | |
| if let Some(project_value) = project_value { | |
| details.push(format!("terminal title project value: {project_value}")); | |
| } | |
| } | |
| let status = if invalid_items.is_empty() { | |
| CheckStatus::Ok | |
| } else { | |
| CheckStatus::Warning | |
| }; | |
| let summary = if invalid_items.is_empty() { | |
| format!("terminal title {source}") | |
| } else { | |
| format!("terminal title {source} with invalid items") | |
| }; | |
| let mut check = DoctorCheck::new("terminal.title", "title", status, summary).details(details); | |
| if !invalid_items.is_empty() { | |
| check = check.issue( | |
| super::DoctorIssue::new( | |
| CheckStatus::Warning, | |
| "terminal title configuration contains unknown item identifiers", | |
| ) | |
| .measured(invalid_items.join(", ")) | |
| .expected("known terminal title item identifiers") | |
| .remedy("Remove or replace the unknown entries in [tui].terminal_title.") | |
| .field("terminal title invalid items"), | |
| ); | |
| } | |
| check | |
| } | |
| fn parse_terminal_title_items(items: Vec<String>) -> (Vec<String>, Vec<String>) { | |
| let mut invalid = Vec::new(); | |
| let mut invalid_seen = HashSet::new(); | |
| let mut parsed = Vec::new(); | |
| for item in items { | |
| match terminal_title_item_id(&item) { | |
| Some(id) => parsed.push(id.to_string()), | |
| None => { | |
| if invalid_seen.insert(item.clone()) { | |
| invalid.push(format!(r#""{item}""#)); | |
| } | |
| } | |
| } | |
| } | |
| (parsed, invalid) | |
| } | |
| fn terminal_title_item_id(item: &str) -> Option<&'static str> { | |
| match item { | |
| "app-name" => Some("app-name"), | |
| "project-name" | "project" => Some("project-name"), | |
| "current-dir" => Some("current-dir"), | |
| "activity" | "spinner" => Some("activity"), | |
| "run-state" | "status" => Some("run-state"), | |
| "thread-title" | "thread" => Some("thread-title"), | |
| "git-branch" => Some("git-branch"), | |
| "context-remaining" => Some("context-remaining"), | |
| "context-used" | "context-usage" => Some("context-used"), | |
| "five-hour-limit" => Some("five-hour-limit"), | |
| "weekly-limit" => Some("weekly-limit"), | |
| "thread-credits" => Some("thread-credits"), | |
| "estimated-thread-cost" => Some("estimated-thread-cost"), | |
| "codex-version" => Some("codex-version"), | |
| "used-tokens" => Some("used-tokens"), | |
| "total-input-tokens" => Some("total-input-tokens"), | |
| "total-output-tokens" => Some("total-output-tokens"), | |
| "thread-id" | "session-id" => Some("thread-id"), | |
| "fast-mode" => Some("fast-mode"), | |
| "model" | "model-name" => Some("model"), | |
| "model-with-reasoning" => Some("model-with-reasoning"), | |
| "reasoning" => Some("reasoning"), | |
| "task-progress" => Some("task-progress"), | |
| _ => None, | |
| } | |
| } | |
| fn activity_enabled(items: &[String]) -> bool { | |
| items | |
| .iter() | |
| .any(|item| item == "activity" || item == "spinner") | |
| } | |
| fn project_title_selected(items: &[String]) -> bool { | |
| items | |
| .iter() | |
| .any(|item| item == "project-name" || item == "project") | |
| } | |
| fn terminal_title_project_root(config: &Config, cwd: &Path) -> Option<ProjectTitleRoot> { | |
| if let Some(repo_root) = get_git_repo_root(cwd) { | |
| return Some(ProjectTitleRoot { | |
| source: "git repo root", | |
| path: repo_root, | |
| }); | |
| } | |
| config | |
| .config_layer_stack | |
| .all_layers_low_to_high() | |
| .find_map(|layer| match &layer.name { | |
| ConfigLayerSource::Project { dot_codex_folder } => dot_codex_folder | |
| .as_path() | |
| .parent() | |
| .map(|root| ProjectTitleRoot { | |
| source: "project config", | |
| path: root.to_path_buf(), | |
| }), | |
| _ => None, | |
| }) | |
| } | |
| fn project_title_candidate( | |
| project_root: Option<ProjectTitleRoot>, | |
| cwd: &Path, | |
| ) -> (&'static str, Option<String>) { | |
| if let Some(project_root) = project_root { | |
| return ( | |
| project_root.source, | |
| Some(truncate_title_part(path_display_name(&project_root.path))), | |
| ); | |
| } | |
| ("cwd", Some(truncate_title_part(path_display_name(cwd)))) | |
| } | |
| fn path_display_name(path: &Path) -> String { | |
| path.file_name() | |
| .map(|name| name.to_string_lossy().to_string()) | |
| .unwrap_or_else(|| path.display().to_string()) | |
| } | |
| fn truncate_title_part(value: String) -> String { | |
| let mut graphemes = value.graphemes(true); | |
| let head = graphemes | |
| .by_ref() | |
| .take(PROJECT_TITLE_MAX_CHARS) | |
| .collect::<String>(); | |
| if graphemes.next().is_none() || PROJECT_TITLE_MAX_CHARS <= 3 { | |
| return head; | |
| } | |
| let mut truncated = head | |
| .graphemes(true) | |
| .take(PROJECT_TITLE_MAX_CHARS - 3) | |
| .collect::<String>(); | |
| truncated.push_str("..."); | |
| truncated | |
| } | |
| mod tests { | |
| use pretty_assertions::assert_eq; | |
| use super::*; | |
| fn terminal_title_reports_default_items_and_git_project_name() { | |
| let check = terminal_title_check_from_inputs(TerminalTitleInputs { | |
| configured_items: None, | |
| cwd: PathBuf::from("/repo/subdir"), | |
| project_root: Some(ProjectTitleRoot { | |
| source: "git repo root", | |
| path: PathBuf::from("/repo"), | |
| }), | |
| }); | |
| assert_eq!(check.summary, "terminal title default"); | |
| assert!( | |
| check | |
| .details | |
| .contains(&"terminal title items: activity, project-name".to_string()) | |
| ); | |
| assert!( | |
| check | |
| .details | |
| .contains(&"terminal title project source: git repo root".to_string()) | |
| ); | |
| assert!( | |
| check | |
| .details | |
| .contains(&"terminal title project value: repo".to_string()) | |
| ); | |
| } | |
| fn terminal_title_reports_disabled_configuration() { | |
| let check = terminal_title_check_from_inputs(TerminalTitleInputs { | |
| configured_items: Some(Vec::new()), | |
| cwd: PathBuf::from("/workspace"), | |
| project_root: None, | |
| }); | |
| assert_eq!(check.summary, "terminal title disabled"); | |
| assert!( | |
| check | |
| .details | |
| .contains(&"terminal title items: none".to_string()) | |
| ); | |
| assert!( | |
| check | |
| .details | |
| .contains(&"terminal title activity: false".to_string()) | |
| ); | |
| assert!( | |
| !check | |
| .details | |
| .iter() | |
| .any(|detail| detail.starts_with("terminal title project ")) | |
| ); | |
| } | |
| fn terminal_title_reports_project_config_fallback() { | |
| let check = terminal_title_check_from_inputs(TerminalTitleInputs { | |
| configured_items: Some(vec!["project".to_string()]), | |
| cwd: PathBuf::from("/workspace/project/subdir"), | |
| project_root: Some(ProjectTitleRoot { | |
| source: "project config", | |
| path: PathBuf::from("/workspace/project"), | |
| }), | |
| }); | |
| assert_eq!(check.summary, "terminal title configured"); | |
| assert!( | |
| check | |
| .details | |
| .contains(&"terminal title project source: project config".to_string()) | |
| ); | |
| assert!( | |
| check | |
| .details | |
| .contains(&"terminal title project value: project".to_string()) | |
| ); | |
| } | |
| fn terminal_title_accepts_thread_usage_items() { | |
| let check = terminal_title_check_from_inputs(TerminalTitleInputs { | |
| configured_items: Some(vec![ | |
| "thread-credits".to_string(), | |
| "estimated-thread-cost".to_string(), | |
| ]), | |
| cwd: PathBuf::from("/workspace/project"), | |
| project_root: None, | |
| }); | |
| assert_eq!(check.status, CheckStatus::Ok); | |
| assert_eq!(check.summary, "terminal title configured"); | |
| assert!( | |
| check.details.contains( | |
| &"terminal title items: thread-credits, estimated-thread-cost".to_string() | |
| ) | |
| ); | |
| assert!(check.issues.is_empty()); | |
| } | |
| fn terminal_title_omits_project_when_project_item_is_not_selected() { | |
| let check = terminal_title_check_from_inputs(TerminalTitleInputs { | |
| configured_items: Some(vec!["model".to_string()]), | |
| cwd: PathBuf::from("/workspace/project"), | |
| project_root: Some(ProjectTitleRoot { | |
| source: "project config", | |
| path: PathBuf::from("/workspace/project"), | |
| }), | |
| }); | |
| assert_eq!(check.summary, "terminal title configured"); | |
| assert!( | |
| !check | |
| .details | |
| .iter() | |
| .any(|detail| detail.starts_with("terminal title project ")) | |
| ); | |
| } | |
| fn terminal_title_warns_for_invalid_configured_items() { | |
| let check = terminal_title_check_from_inputs(TerminalTitleInputs { | |
| configured_items: Some(vec![ | |
| "project".to_string(), | |
| "bogus".to_string(), | |
| "activity".to_string(), | |
| "bogus".to_string(), | |
| ]), | |
| cwd: PathBuf::from("/workspace/project"), | |
| project_root: Some(ProjectTitleRoot { | |
| source: "project config", | |
| path: PathBuf::from("/workspace/project"), | |
| }), | |
| }); | |
| assert_eq!(check.status, CheckStatus::Warning); | |
| assert_eq!( | |
| check.summary, | |
| "terminal title configured with invalid items" | |
| ); | |
| assert!( | |
| check | |
| .details | |
| .contains(&"terminal title items: project-name, activity".to_string()) | |
| ); | |
| assert!( | |
| check | |
| .details | |
| .contains(&r#"terminal title invalid items: "bogus""#.to_string()) | |
| ); | |
| assert_eq!(check.issues.len(), 1); | |
| } | |
| fn terminal_title_warns_when_all_configured_items_are_invalid() { | |
| let check = terminal_title_check_from_inputs(TerminalTitleInputs { | |
| configured_items: Some(vec!["bogus".to_string()]), | |
| cwd: PathBuf::from("/workspace/project"), | |
| project_root: None, | |
| }); | |
| assert_eq!(check.status, CheckStatus::Warning); | |
| assert!( | |
| check | |
| .details | |
| .contains(&"terminal title items: none".to_string()) | |
| ); | |
| assert!( | |
| check | |
| .details | |
| .contains(&r#"terminal title invalid items: "bogus""#.to_string()) | |
| ); | |
| } | |
| fn terminal_title_project_value_uses_tui_truncation_shape() { | |
| let check = terminal_title_check_from_inputs(TerminalTitleInputs { | |
| configured_items: Some(vec!["project".to_string()]), | |
| cwd: PathBuf::from("/workspace/abcdefghijklmnopqrstuvwxyz"), | |
| project_root: Some(ProjectTitleRoot { | |
| source: "project config", | |
| path: PathBuf::from("/workspace/abcdefghijklmnopqrstuvwxyz"), | |
| }), | |
| }); | |
| assert!( | |
| check | |
| .details | |
| .contains(&"terminal title project value: abcdefghijklmnopqrstu...".to_string()) | |
| ); | |
| } | |
| } | |