Handle early selection on fzf (#307)

This commit is contained in:
Ajeet D'Souza 2021-12-02 22:47:11 +05:30 committed by GitHub
parent 3e03ccccd6
commit 2a2848f55c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 28 deletions

View File

@ -11,12 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Better defaults for `fzf`. - fzf: better default options.
### Fixed ### Fixed
- PowerShell: use global scope for aliases. - PowerShell: use global scope for aliases.
- Zsh: fix errors with `set -eu`. - Zsh: fix errors with `set -eu`.
- fzf: handle early selection.
## [0.7.9] - 2021-11-02 ## [0.7.9] - 2021-11-02

View File

@ -32,11 +32,19 @@ impl Query {
if self.interactive { if self.interactive {
let mut fzf = Fzf::new(false)?; let mut fzf = Fzf::new(false)?;
while let Some(dir) = stream.next() { let selection = loop {
writeln!(fzf.stdin(), "{}", dir.display_score(now)).pipe_exit("fzf")?; 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 { if self.score {
print!("{}", selection); print!("{}", selection);
} else { } else {

View File

@ -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::app::{Remove, Run};
use crate::db::DatabaseFile; use crate::db::DatabaseFile;
use crate::error::BrokenPipeHandler;
use crate::fzf::Fzf; use crate::fzf::Fzf;
use crate::{config, util}; use crate::{config, util};
@ -14,18 +13,25 @@ impl Run for Remove {
let mut db = DatabaseFile::new(data_dir); let mut db = DatabaseFile::new(data_dir);
let mut db = db.open()?; let mut db = db.open()?;
let selection;
match &self.interactive { match &self.interactive {
Some(keywords) => { Some(keywords) => {
let now = util::current_time()?; let now = util::current_time()?;
let mut stream = db.stream(now).with_keywords(keywords); let mut stream = db.stream(now).with_keywords(keywords);
let mut fzf = Fzf::new(true)?; let mut fzf = Fzf::new(true)?;
while let Some(dir) = stream.next() { let selection = loop {
writeln!(fzf.stdin(), "{}", dir.display_score(now)).pipe_exit("fzf")?; 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..)); let paths = selection.lines().filter_map(|line| line.get(5..));
for path in paths { for path in paths {
if !db.remove(path) { if !db.remove(path) {

View File

@ -1,4 +1,4 @@
use std::io; use std::io::{self, Read};
use std::process::{Child, ChildStdin, Command, Stdio}; use std::process::{Child, ChildStdin, Command, Stdio};
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
@ -46,28 +46,21 @@ impl Fzf {
} }
pub fn stdin(&mut self) -> &mut ChildStdin { pub fn stdin(&mut self) -> &mut ChildStdin {
// unwrap is safe here because command.stdin() has been piped.
self.child.stdin.as_mut().unwrap() self.child.stdin.as_mut().unwrap()
} }
pub fn wait_select(self) -> Result<String> { pub fn select(mut self) -> Result<String> {
let output = self.child.wait_with_output().context("wait failed on fzf")?; 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() { let status = self.child.wait().context("wait failed on fzf")?;
// normal exit match status.code() {
Some(0) => String::from_utf8(output.stdout).context("invalid unicode in fzf output"), Some(0) => Ok(output),
// no match
Some(1) => bail!("no match found"), Some(1) => bail!("no match found"),
// error
Some(2) => bail!("fzf returned an error"), Some(2) => bail!("fzf returned an error"),
// terminated by a signal
Some(code @ 130) => bail!(SilentExit { code }), Some(code @ 130) => bail!(SilentExit { code }),
Some(128..=254) | None => bail!("fzf was terminated"), Some(128..=254) | None => bail!("fzf was terminated"),
// unknown
_ => bail!("fzf returned an unknown error"), _ => bail!("fzf returned an unknown error"),
} }
} }