vtcode_core/utils/ansi/
links.rs1use crate::ui::tui::InlineMessageKind;
4use std::sync::{Mutex, OnceLock};
5use unicode_width::UnicodeWidthStr;
6use url::Url;
7use vtcode_commons::{parse_editor_target, resolve_editor_path};
8
9static FILE_OPENER: OnceLock<Mutex<vtcode_config::FileOpener>> = OnceLock::new();
10
11pub fn apply_file_opener_config(file_opener: vtcode_config::FileOpener) {
12 let cell = FILE_OPENER.get_or_init(|| Mutex::new(vtcode_config::FileOpener::None));
13 if let Ok(mut guard) = cell.lock() {
14 *guard = file_opener;
15 }
16}
17
18pub(super) fn current_file_opener() -> vtcode_config::FileOpener {
19 FILE_OPENER
20 .get()
21 .map(|cell| *cell.lock().unwrap_or_else(|e| e.into_inner()))
22 .unwrap_or(vtcode_config::FileOpener::None)
23}
24
25pub(super) fn make_clickable_target(target: &str) -> Option<String> {
26 let trimmed = target.trim();
27 if trimmed.is_empty() {
28 return None;
29 }
30 if is_remote_link_target(trimmed) {
31 return Some(trimmed.to_string());
32 }
33
34 let opener = current_file_opener();
35 let scheme = opener.scheme()?;
36 let target = parse_editor_target(trimmed)?;
37 let cwd = std::env::current_dir().ok()?;
38 let file_url = Url::from_file_path(resolve_editor_path(target.path(), &cwd)).ok()?;
39 let suffix = target.location_suffix().unwrap_or("");
40 Some(format!("{scheme}://file{}{}", file_url.as_str().trim_start_matches("file://"), suffix))
41}
42
43pub(super) fn should_strip_inline_local_link_underline(target: &str) -> bool {
44 let trimmed = target.trim();
45 if trimmed.is_empty() {
46 return false;
47 }
48 if is_remote_link_target(trimmed) {
49 return false;
50 }
51 match Url::parse(trimmed) {
52 Ok(url) => url.scheme() == "file",
53 Err(_) => true,
54 }
55}
56
57fn is_remote_link_target(target: &str) -> bool {
58 target.starts_with("http://") || target.starts_with("https://")
59}
60
61pub(super) fn terminal_table_content_width(indent: &str) -> Option<usize> {
62 crossterm::terminal::size()
63 .ok()
64 .map(|(width, _)| usize::from(width).saturating_sub(UnicodeWidthStr::width(indent)))
65}
66
67pub(super) fn transcript_table_frame_width(kind: InlineMessageKind, agent_label_frame_width: usize) -> usize {
68 match kind {
69 InlineMessageKind::Agent => UnicodeWidthStr::width(" • ") + agent_label_frame_width,
73 InlineMessageKind::Tool => UnicodeWidthStr::width(" "),
74 InlineMessageKind::Pty => UnicodeWidthStr::width(" "),
75 InlineMessageKind::Policy
76 | InlineMessageKind::User
77 | InlineMessageKind::Info
78 | InlineMessageKind::Error
79 | InlineMessageKind::Warning => 0,
80 }
81}