webbrowser/
common.rs

1use super::{BrowserOptions, Error, ErrorKind, Result};
2use log::debug;
3use std::process::{Command, Stdio};
4
5/// Parses `line` to find tokens (including quoted strings), and invokes `op`
6/// on each token
7pub(crate) fn for_each_token<F>(line: &str, mut op: F)
8where
9    F: FnMut(&str),
10{
11    let mut start: Option<usize> = None;
12    let mut in_quotes = false;
13    let mut idx = 0;
14    for ch in line.chars() {
15        idx += 1;
16        match ch {
17            '"' => {
18                if let Some(start_idx) = start {
19                    op(&line[start_idx..idx - 1]);
20                    start = None;
21                    in_quotes = false;
22                } else {
23                    start = Some(idx);
24                    in_quotes = true;
25                }
26            }
27            ' ' => {
28                if !in_quotes {
29                    if let Some(start_idx) = start {
30                        op(&line[start_idx..idx - 1]);
31                        start = None;
32                    }
33                }
34            }
35            _ => {
36                if start.is_none() {
37                    start = Some(idx - 1);
38                }
39            }
40        }
41    }
42    if let Some(start_idx) = start {
43        op(&line[start_idx..idx]);
44    }
45}
46
47/// Run the specified command in foreground/background
48pub(crate) fn run_command(
49    cmd: &mut Command,
50    background: bool,
51    options: &BrowserOptions,
52) -> Result<()> {
53    // if dry_run, we return a true, as executable existence check has
54    // already been done
55    if options.dry_run {
56        debug!("dry-run enabled, so not running: {:?}", &cmd);
57        return Ok(());
58    }
59
60    if background {
61        debug!("background spawn: {:?}", &cmd);
62        // if we're in background, set stdin/stdout to null and spawn a child, as we're
63        // not supposed to have any interaction.
64        if options.suppress_output {
65            cmd.stdin(Stdio::null())
66                .stdout(Stdio::null())
67                .stderr(Stdio::null())
68        } else {
69            cmd
70        }
71        .spawn()
72        .map(|_| ())
73    } else {
74        debug!("foreground exec: {:?}", &cmd);
75        // if we're in foreground, use status() instead of spawn(), as we'd like to wait
76        // till completion.
77        // We also specifically don't suppress anything here, because we're running here
78        // most likely because of a text browser
79        cmd.status().and_then(|status| {
80            if status.success() {
81                Ok(())
82            } else {
83                Err(Error::new(
84                    ErrorKind::Other,
85                    "command present but exited unsuccessfully",
86                ))
87            }
88        })
89    }
90}