1use crate::config::{Config, EnvConfig};
2use crate::error::{Error, ErrorKind, Result};
3use crate::page::parse_page;
4use crate::service;
5use std::process::{Command, ExitStatus, Stdio};
6
7pub fn build_url(cfg: &Config) -> Result<String> {
8 let page = parse_page(&cfg)?;
9 service::build_page_url(&page, &cfg)
10}
11
12fn browse_with_cmd(url: &str, cmd: &str) -> Result<()> {
13 let out = Command::new(cmd)
14 .arg(url)
15 .stdout(Stdio::inherit())
16 .output()?;
17 if out.status.success() {
18 Ok(())
19 } else {
20 Error::err(ErrorKind::UserBrowseCommandFailed {
21 cmd: cmd.to_string(),
22 url: url.to_string(),
23 msg: String::from_utf8_lossy(&out.stderr)
24 .trim()
25 .replace('\n', " "),
26 })
27 }
28}
29
30#[cfg(unix)]
31fn error_without_status(status: ExitStatus) -> String {
32 use std::os::unix::process::ExitStatusExt;
33 if let Some(sig) = status.signal() {
34 format!("Command terminated by signal {}", sig)
35 } else {
36 "Command terminated by signal".to_string()
37 }
38}
39
40#[cfg(not(unix))]
41fn error_without_status(_status: ExitStatus) -> String {
42 "Command terminated by signal".to_string()
43}
44
45pub fn browse(url: &str, env: &EnvConfig) -> Result<()> {
46 if let Some(cmd) = &env.browse_command {
47 return browse_with_cmd(url, cmd);
48 }
49
50 match open::that(url) {
51 Ok(status) if status.success() => Ok(()),
52 Ok(status) => {
53 let url = url.to_string();
54 let msg = if let Some(code) = status.code() {
55 format!("Command exited with non-zero status {}", code)
56 } else {
57 error_without_status(status)
58 };
59 Error::err(ErrorKind::OpenUrlFailure { url, msg })
60 }
61 Err(e) => Error::err(ErrorKind::OpenUrlFailure {
62 url: url.to_string(),
63 msg: format!("{}", e),
64 }),
65 }
66}