mirror of
https://github.com/wez/wezterm.git
synced 2024-12-26 06:42:12 +03:00
use termwiz::Hyperlink
This commit is contained in:
parent
f37de9cbe5
commit
1ec83706e7
@ -124,10 +124,10 @@ impl<'a> term::TerminalHost for TabHost<'a> {
|
||||
fn click_link(&mut self, link: &Rc<Hyperlink>) {
|
||||
// TODO: make this configurable
|
||||
let mut cmd = Command::new("xdg-open");
|
||||
cmd.arg(&link.url);
|
||||
cmd.arg(&link.uri());
|
||||
match cmd.spawn() {
|
||||
Ok(_) => {}
|
||||
Err(err) => eprintln!("failed to spawn xdg-open {}: {:?}", link.url, err),
|
||||
Err(err) => eprintln!("failed to spawn xdg-open {}: {:?}", link.uri(), err),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,60 +12,7 @@ use std::collections::HashMap;
|
||||
use std::ops::Range;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Hyperlink {
|
||||
/// The target
|
||||
pub url: String,
|
||||
/// The identifier. This can be used by the render layer to determine
|
||||
/// which cells to underline on hover. This is for the usecase where
|
||||
/// an application has drawn windows in the window and the URL has
|
||||
/// wrapped lines within such a window.
|
||||
pub id: String,
|
||||
/// If the link was produced by an implicit or matching rule,
|
||||
/// this field will be set to true.
|
||||
pub implicit: bool,
|
||||
}
|
||||
|
||||
impl Hyperlink {
|
||||
pub fn new(url: &str, params: &HashMap<&str, &str>) -> Self {
|
||||
let id = params.get("id").unwrap_or(&"");
|
||||
Self {
|
||||
url: url.into(),
|
||||
id: (**id).into(),
|
||||
implicit: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_id(url: &str, id: &str) -> Self {
|
||||
Self {
|
||||
url: url.into(),
|
||||
id: id.into(),
|
||||
implicit: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The spec says that the escape sequence is of the form:
|
||||
/// OSC 8 ; params ; URI BEL|ST
|
||||
/// params is an optional list of key=value assignments,
|
||||
/// separated by the : character. Example: id=xyz123:foo=bar:baz=quux.
|
||||
/// This function parses such a string and returns the mapping
|
||||
/// of key to value. Malformed input causes subsequent key/value pairs
|
||||
/// to be skipped, returning the data successfully parsed out so far.
|
||||
pub fn parse_link_params(params: &str) -> HashMap<&str, &str> {
|
||||
let mut map = HashMap::new();
|
||||
for kv in params.split(':') {
|
||||
let mut iter = kv.splitn(2, '=');
|
||||
let key = iter.next();
|
||||
let value = iter.next();
|
||||
match (key, value) {
|
||||
(Some(key), Some(value)) => map.insert(key, value),
|
||||
_ => break,
|
||||
};
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
pub use termwiz::escape::osc::Hyperlink;
|
||||
|
||||
/// In addition to handling explicit escape sequences to enable
|
||||
/// hyperlinks, we also support defining rules that match text
|
||||
@ -174,11 +121,10 @@ impl Rule {
|
||||
.into_iter()
|
||||
.map(|m| {
|
||||
let url = m.expand();
|
||||
let link = Rc::new(Hyperlink {
|
||||
let link = Rc::new(Hyperlink::new_with_params(
|
||||
url,
|
||||
id: "".to_owned(),
|
||||
implicit: true,
|
||||
});
|
||||
hashmap!{"implicit".into() => "1".into()},
|
||||
));
|
||||
RuleMatch {
|
||||
link,
|
||||
range: m.range(),
|
||||
@ -203,11 +149,10 @@ mod test {
|
||||
Rule::match_hyperlinks(" http://example.com", &rules),
|
||||
vec![RuleMatch {
|
||||
range: 2..20,
|
||||
link: Rc::new(Hyperlink {
|
||||
url: "http://example.com".to_owned(),
|
||||
id: "".to_owned(),
|
||||
implicit: true,
|
||||
}),
|
||||
link: Rc::new(Hyperlink::new_with_params(
|
||||
"http://example.com",
|
||||
hashmap!{"implicit".into()=>"1".into()},
|
||||
)),
|
||||
}]
|
||||
);
|
||||
|
||||
@ -217,47 +162,19 @@ mod test {
|
||||
// Longest match first
|
||||
RuleMatch {
|
||||
range: 18..34,
|
||||
link: Rc::new(Hyperlink {
|
||||
url: "mailto:woot@example.com".to_owned(),
|
||||
id: "".to_owned(),
|
||||
implicit: true,
|
||||
}),
|
||||
link: Rc::new(Hyperlink::new_with_params(
|
||||
"mailto:woot@example.com",
|
||||
hashmap!{"implicit".into()=>"1".into()},
|
||||
)),
|
||||
},
|
||||
RuleMatch {
|
||||
range: 2..17,
|
||||
link: Rc::new(Hyperlink {
|
||||
url: "mailto:foo@example.com".to_owned(),
|
||||
id: "".to_owned(),
|
||||
implicit: true,
|
||||
}),
|
||||
link: Rc::new(Hyperlink::new_with_params(
|
||||
"mailto:foo@example.com",
|
||||
hashmap!{"implicit".into()=>"1".into()},
|
||||
)),
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_link() {
|
||||
assert_eq!(parse_link_params(""), hashmap!{});
|
||||
assert_eq!(parse_link_params("foo"), hashmap!{});
|
||||
assert_eq!(
|
||||
parse_link_params("foo=bar=baz"),
|
||||
hashmap!{"foo" => "bar=baz"}
|
||||
);
|
||||
assert_eq!(parse_link_params("foo=bar"), hashmap!{"foo" => "bar"});
|
||||
|
||||
assert_eq!(
|
||||
parse_link_params("id=1234:foo=bar"),
|
||||
hashmap!{
|
||||
"id" => "1234",
|
||||
"foo" => "bar"
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
parse_link_params("id=1234:foo=bar:"),
|
||||
hashmap!{
|
||||
"id" => "1234",
|
||||
"foo" => "bar"
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
extern crate bitflags;
|
||||
#[macro_use]
|
||||
extern crate failure;
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate maplit;
|
||||
extern crate palette;
|
||||
|
@ -165,7 +165,7 @@ impl Line {
|
||||
for mut cell in &mut self.cells {
|
||||
let link = cell.attrs.hyperlink.take();
|
||||
cell.attrs.hyperlink = match link.as_ref() {
|
||||
Some(link) if link.implicit => None,
|
||||
Some(link) if link.params().contains_key("implicit") => None,
|
||||
Some(link) => Some(Rc::clone(link)),
|
||||
None => None,
|
||||
};
|
||||
|
@ -1,5 +1,4 @@
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
use termwiz::escape::csi::{
|
||||
Cursor, DecPrivateMode, DecPrivateModeCode, Device, Edit, EraseInDisplay, EraseInLine, Mode,
|
||||
@ -1532,19 +1531,15 @@ impl<'a> Performer<'a> {
|
||||
self.host.set_title(&title);
|
||||
}
|
||||
OperatingSystemCommand::SetIconName(_) => {}
|
||||
OperatingSystemCommand::SetHyperlink(Some(link)) => {
|
||||
let params: HashMap<_, _> = link
|
||||
.params()
|
||||
.iter()
|
||||
.map(|(a, b)| (a.as_str(), b.as_str()))
|
||||
.collect();
|
||||
self.set_hyperlink(Some(Hyperlink::new(link.uri(), ¶ms)));
|
||||
}
|
||||
OperatingSystemCommand::SetHyperlink(None) => {
|
||||
self.set_hyperlink(None);
|
||||
OperatingSystemCommand::SetHyperlink(link) => {
|
||||
self.set_hyperlink(link);
|
||||
}
|
||||
OperatingSystemCommand::Unspecified(unspec) => {
|
||||
eprintln!("Unhandled {:?}", unspec);
|
||||
eprint!("Unhandled OSC ");
|
||||
for item in unspec {
|
||||
eprint!(" {}", String::from_utf8_lossy(&item));
|
||||
}
|
||||
eprintln!("");
|
||||
}
|
||||
|
||||
OperatingSystemCommand::ClearSelection(_) => {
|
||||
|
@ -7,7 +7,7 @@ mod c1;
|
||||
mod csi;
|
||||
mod selection;
|
||||
use termwiz::escape::csi::{Edit, EraseInDisplay, EraseInLine};
|
||||
use termwiz::escape::CSI;
|
||||
use termwiz::escape::{OperatingSystemCommand, CSI};
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct TestHost {
|
||||
@ -100,7 +100,8 @@ impl TestTerm {
|
||||
}
|
||||
|
||||
fn hyperlink(&mut self, link: &Rc<Hyperlink>) {
|
||||
self.print(format!("\x1b]8;id={};{}\x1b\\", link.id, link.url));
|
||||
let osc = OperatingSystemCommand::SetHyperlink(Some(link.as_ref().clone()));
|
||||
self.print(format!("{}", osc));
|
||||
}
|
||||
|
||||
fn hyperlink_off(&mut self) {
|
||||
@ -465,7 +466,7 @@ fn test_scrollup() {
|
||||
#[test]
|
||||
fn test_hyperlinks() {
|
||||
let mut term = TestTerm::new(3, 5, 0);
|
||||
let link = Rc::new(Hyperlink::with_id("http://example.com", ""));
|
||||
let link = Rc::new(Hyperlink::new("http://example.com"));
|
||||
term.hyperlink(&link);
|
||||
term.print("hello");
|
||||
term.hyperlink_off();
|
||||
@ -499,7 +500,7 @@ fn test_hyperlinks() {
|
||||
Compare::TEXT | Compare::ATTRS,
|
||||
);
|
||||
|
||||
let otherlink = Rc::new(Hyperlink::with_id("http://example.com/other", "w00t"));
|
||||
let otherlink = Rc::new(Hyperlink::new_with_id("http://example.com/other", "w00t"));
|
||||
|
||||
// Switching link and turning it off
|
||||
term.hyperlink(&otherlink);
|
||||
|
Loading…
Reference in New Issue
Block a user