use osc8::Hyperlink;
pub use supports_hyperlinks::{Stream, on as supports_hyperlinks};
pub fn hyperlink_stdout(url: &str, text: &str) -> String {
if supports_hyperlinks(Stream::Stdout) {
format!("{}{}{}", Hyperlink::new(url), text, Hyperlink::END)
} else {
text.to_string()
}
}
pub fn strip_osc8_hyperlinks(s: &str) -> String {
let mut result = s.to_string();
while let Ok(Some((_, range))) = Hyperlink::parse(&result) {
let after_open = range.end;
if let Ok(Some((_, close_range))) = Hyperlink::parse(&result[after_open..]) {
let text_between = result[after_open..after_open + close_range.start].to_string();
let full_end = after_open + close_range.end;
result.replace_range(range.start..full_end, &text_between);
} else {
result.replace_range(range.clone(), "");
break;
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hyperlink_returns_text_when_not_tty() {
let result = hyperlink_stdout("https://example.com", "link");
assert!(result == "link" || result.contains("https://example.com"));
}
#[test]
fn test_strip_osc8_hyperlinks_removes_hyperlink() {
let url = "https://example.com";
let text = "link text";
let input = format!(
"before {}{}{}after",
Hyperlink::new(url),
text,
Hyperlink::END
);
let result = strip_osc8_hyperlinks(&input);
assert_eq!(result, "before link textafter");
}
#[test]
fn test_strip_osc8_hyperlinks_preserves_sgr_codes() {
let url = "https://example.com";
let text = "link";
let input = format!(
"\u{1b}[1m{}{}{}bold\u{1b}[0m",
Hyperlink::new(url),
text,
Hyperlink::END
);
let result = strip_osc8_hyperlinks(&input);
assert_eq!(result, "\u{1b}[1mlinkbold\u{1b}[0m");
}
#[test]
fn test_strip_osc8_hyperlinks_handles_no_hyperlinks() {
let input = "plain text with no hyperlinks";
let result = strip_osc8_hyperlinks(input);
assert_eq!(result, input);
}
#[test]
fn test_strip_osc8_hyperlinks_handles_multiple() {
let input = format!(
"{}first{} and {}second{}",
Hyperlink::new("url1"),
Hyperlink::END,
Hyperlink::new("url2"),
Hyperlink::END
);
let result = strip_osc8_hyperlinks(&input);
assert_eq!(result, "first and second");
}
}