summaryrefslogtreecommitdiffstats
path: root/src/fzf.rs
blob: 2a6c08d41dbc9492eaa38c30f6526245ec813dce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use {
  super::{
    argparse::Mode,
    subprocess::{stream_subproc, SubprocCommand},
    types::Die,
  },
  futures::stream::{Stream, StreamExt},
  std::{
    collections::HashMap,
    env::{self, current_exe},
    ffi::OsString,
    path::PathBuf,
    process::Stdio,
  },
  tokio::{io::ErrorKind, process::Command},
  which::which,
};

async fn reset_term() -> Result<(), Die> {
  if let Ok(path) = which("tput") {
    let status = Command::new(&path)
      .kill_on_drop(true)
      .stdin(Stdio::null())
      .arg("reset")
      .status()
      .await
      .map_err(|e| Die::IO(path, e.kind()))?;

    if status.success() {
      return Ok(());
    }
  }
  if let Ok(path) = which("reset") {
    let status = Command::new(&path)
      .kill_on_drop(true)
      .stdin(Stdio::null())
      .status()
      .await
      .map_err(|e| Die::IO(path, e.kind()))?;
    if status.success() {
      return Ok(());
    }
  }
  Err(Die::IO(PathBuf::from("reset"), ErrorKind::NotFound))
}

pub fn stream_fzf_proc(
  bin: PathBuf,
  args: Vec<String>,
  stream: impl Stream<Item = Result<OsString, Die>> + Unpin,
) -> impl Stream<Item = Result<(), Die>> {
  let execute = format!("abort+execute:{}\x04{{+f}}", Mode::PATCH);
  let mut arguments = vec![
    "--read0".to_owned(),
    "--print0".to_owned(),
    "-m".to_owned(),
    "--ansi".to_owned(),
    "--preview-window=70%:wrap".to_owned(),
    format!("--bind=enter:{execute}"),
    format!("--bind=double-click:{execute}"),
    format!("--preview={}\x04{{+f}}", Mode::PREVIEW),
  ];
  arguments.extend(args);

  let mut fzf_env = HashMap::new();
  fzf_env.insert(
    Mode::ARGV.to_owned(),
    env::args().collect::<Vec<_>>().join("\x04"),
  );
  fzf_env.insert(
    "SHELL".to_owned(),
    current_exe()
      .or_else(|_| which(env!("CARGO_PKG_NAME")))
      .map_or_else(
        |_| env!("CARGO_PKG_NAME").to_owned(),
        |path| format!("{}", path.display()),
      ),
  );
  fzf_env.insert("LC_ALL".to_owned(), "C-UTF8".to_owned());

  let cmd = SubprocCommand {
    prog: bin,
    args: arguments,
    env: fzf_env,
  };
  stream_subproc(cmd, stream).then(|row| async {
    match row {
      Ok(o) => Ok(o),
      Err(Die::BadExit(_, 130)) => Err(Die::Interrupt),
      e => {
        let _ = reset_term().await;
        e
      }
    }
  })
}