synd_term/interact/
process.rs1use std::{
2 io::{self, ErrorKind},
3 path::PathBuf,
4 process::{Command, Stdio},
5};
6
7use itertools::Itertools;
8use url::Url;
9
10use crate::interact::{Interact, OpenBrowserError, OpenEditor, OpenTextBrowser, OpenWebBrowser};
11
12pub struct ProcessInteractor {
13 text_browser: TextBrowserInteractor,
14}
15
16impl ProcessInteractor {
17 pub fn new(text_browser: TextBrowserInteractor) -> Self {
18 Self { text_browser }
19 }
20}
21
22impl OpenWebBrowser for ProcessInteractor {
23 fn open_browser(&self, url: url::Url) -> Result<(), super::OpenBrowserError> {
24 open::that(url.as_str()).map_err(OpenBrowserError::from)
25 }
26}
27
28impl OpenTextBrowser for ProcessInteractor {
29 fn open_text_browser(&self, url: Url) -> Result<(), super::OpenBrowserError> {
30 self.text_browser.open_text_browser(url)
31 }
32}
33
34impl OpenEditor for ProcessInteractor {
35 fn open_editor(&self, initial_content: &str) -> Result<String, super::OpenEditorError> {
36 edit::edit(initial_content).map_err(|err| super::OpenEditorError {
37 message: err.to_string(),
38 })
39 }
40}
41
42impl Interact for ProcessInteractor {}
43
44pub struct TextBrowserInteractor {
45 command: PathBuf,
46 args: Vec<String>,
47}
48
49impl TextBrowserInteractor {
50 pub fn new(command: PathBuf, args: Vec<String>) -> Self {
51 Self { command, args }
52 }
53}
54
55impl OpenTextBrowser for TextBrowserInteractor {
56 #[tracing::instrument(skip(self))]
57 fn open_text_browser(&self, url: Url) -> Result<(), OpenBrowserError> {
58 let status = Command::new(self.command.as_os_str())
59 .args(self.args.iter())
60 .arg(url.as_str())
61 .stdin(Stdio::inherit())
62 .stdout(Stdio::inherit())
63 .stderr(Stdio::inherit())
64 .output()
65 .map_err(|err| {
66 if err.kind() == ErrorKind::NotFound {
67 OpenBrowserError::CommandNotFound {
68 command: self.command.clone(),
69 }
70 } else {
71 err.into()
72 }
73 })?
74 .status;
75
76 if status.success() {
77 Ok(())
78 } else {
79 let full_command = if self.args.is_empty() {
80 format!("{} {}", self.command.display(), url,)
81 } else {
82 format!(
83 "{} {} {}",
84 self.command.display(),
85 self.args.iter().join(" "),
86 url,
87 )
88 };
89 Err(io::Error::new(io::ErrorKind::Other, full_command).into())
90 }
91 }
92}