From 2a2848f55ccd1b98123b47eee898ac4972b9d5fd Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Thu, 2 Dec 2021 22:47:11 +0530 Subject: [PATCH] Handle early selection on fzf (#307) --- CHANGELOG.md | 3 ++- src/app/query.rs | 16 ++++++++++++---- src/app/remove.rs | 22 ++++++++++++++-------- src/fzf.rs | 23 ++++++++--------------- 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a6fef7..dab3c6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,12 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Better defaults for `fzf`. +- fzf: better default options. ### Fixed - PowerShell: use global scope for aliases. - Zsh: fix errors with `set -eu`. +- fzf: handle early selection. ## [0.7.9] - 2021-11-02 diff --git a/src/app/query.rs b/src/app/query.rs index cb1de83..53e7f09 100644 --- a/src/app/query.rs +++ b/src/app/query.rs @@ -32,11 +32,19 @@ impl Query { if self.interactive { let mut fzf = Fzf::new(false)?; - while let Some(dir) = stream.next() { - writeln!(fzf.stdin(), "{}", dir.display_score(now)).pipe_exit("fzf")?; - } + let selection = loop { + let dir = match stream.next() { + Some(dir) => dir, + None => break fzf.select()?, + }; + + match writeln!(fzf.stdin(), "{}", dir.display_score(now)) { + Ok(()) => (()), + Err(e) if e.kind() == io::ErrorKind::BrokenPipe => break fzf.select()?, + Err(e) => Err(e).context("could not write to fzf")?, + } + }; - let selection = fzf.wait_select()?; if self.score { print!("{}", selection); } else { diff --git a/src/app/remove.rs b/src/app/remove.rs index 1833471..60f475f 100644 --- a/src/app/remove.rs +++ b/src/app/remove.rs @@ -1,10 +1,9 @@ -use std::io::Write; +use std::io::{self, Write}; -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use crate::app::{Remove, Run}; use crate::db::DatabaseFile; -use crate::error::BrokenPipeHandler; use crate::fzf::Fzf; use crate::{config, util}; @@ -14,18 +13,25 @@ impl Run for Remove { let mut db = DatabaseFile::new(data_dir); let mut db = db.open()?; - let selection; match &self.interactive { Some(keywords) => { let now = util::current_time()?; let mut stream = db.stream(now).with_keywords(keywords); let mut fzf = Fzf::new(true)?; - while let Some(dir) = stream.next() { - writeln!(fzf.stdin(), "{}", dir.display_score(now)).pipe_exit("fzf")?; - } + let selection = loop { + let dir = match stream.next() { + Some(dir) => dir, + None => break fzf.select()?, + }; + + match writeln!(fzf.stdin(), "{}", dir.display_score(now)) { + Ok(()) => (()), + Err(e) if e.kind() == io::ErrorKind::BrokenPipe => break fzf.select()?, + Err(e) => Err(e).context("could not write to fzf")?, + } + }; - selection = fzf.wait_select()?; let paths = selection.lines().filter_map(|line| line.get(5..)); for path in paths { if !db.remove(path) { diff --git a/src/fzf.rs b/src/fzf.rs index 8b3711a..8e21d24 100644 --- a/src/fzf.rs +++ b/src/fzf.rs @@ -1,4 +1,4 @@ -use std::io; +use std::io::{self, Read}; use std::process::{Child, ChildStdin, Command, Stdio}; use anyhow::{bail, Context, Result}; @@ -46,28 +46,21 @@ impl Fzf { } pub fn stdin(&mut self) -> &mut ChildStdin { - // unwrap is safe here because command.stdin() has been piped. self.child.stdin.as_mut().unwrap() } - pub fn wait_select(self) -> Result { - let output = self.child.wait_with_output().context("wait failed on fzf")?; + pub fn select(mut self) -> Result { + let mut output = String::new(); + let stdout = self.child.stdout.as_mut().unwrap(); + stdout.read_to_string(&mut output).context("failed to read from fzf")?; - match output.status.code() { - // normal exit - Some(0) => String::from_utf8(output.stdout).context("invalid unicode in fzf output"), - - // no match + let status = self.child.wait().context("wait failed on fzf")?; + match status.code() { + Some(0) => Ok(output), Some(1) => bail!("no match found"), - - // error Some(2) => bail!("fzf returned an error"), - - // terminated by a signal Some(code @ 130) => bail!(SilentExit { code }), Some(128..=254) | None => bail!("fzf was terminated"), - - // unknown _ => bail!("fzf returned an unknown error"), } }