use std::io::{Result, Write};
use url::{Host, Url};
pub fn write_osc<W: Write>(writer: &mut W, command: &str) -> Result<()> {
writer.write_all(&[0x1b, 0x5d])?;
writer.write_all(command.as_bytes())?;
writer.write_all(&[0x07])?;
Ok(())
}
pub struct OSC8Links {
hostname: String,
}
fn url_needs_explicit_host(url: &Url) -> bool {
if url.scheme() == "file" {
match url.host() {
None => true,
Some(Host::Domain("localhost")) => true,
Some(Host::Ipv4(addr)) if addr.is_loopback() => true,
Some(Host::Ipv6(addr)) if addr.is_loopback() => true,
_ => false,
}
} else {
false
}
}
impl OSC8Links {
pub fn for_localhost() -> OSC8Links {
use gethostname::gethostname;
OSC8Links {
hostname: gethostname().to_string_lossy().into_owned(),
}
}
pub fn set_link_url<W: Write>(&self, writer: &mut W, mut destination: Url) -> Result<()> {
if url_needs_explicit_host(&destination) {
destination.set_host(Some(&self.hostname)).unwrap();
}
self.set_link(writer, destination.as_str())
}
pub fn clear_link<W: Write>(&self, writer: &mut W) -> Result<()> {
self.set_link(writer, "")
}
fn set_link<W: Write>(&self, writer: &mut W, destination: &str) -> Result<()> {
write_osc(writer, &format!("8;;{}", destination))
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
#[test]
fn url_needs_explicit_host() {
let checks = [
("http://example.com/foo/bar", false),
("file:///foo/bar", true),
("file://localhost/foo/bar", true),
("file://127.0.0.1/foo/bar", true),
("file://[::1]/foo/bar", true),
];
for (url, expected) in checks.iter() {
let parsed = super::Url::parse(url).unwrap();
let needs_host = super::url_needs_explicit_host(&parsed);
assert_eq!(
needs_host, *expected,
"{:?} needs host? {}, but got {}",
parsed, expected, needs_host
);
}
}
}