Skip to content

Commit

Permalink
Stream results when feasible.
Browse files Browse the repository at this point in the history
For example, when only a single file (or stdin) is being searched, then we
should be able to print directly to the terminal instead of intermediate
buffers. (The buffers are only necessary for parallelism.)

Closes #4.
  • Loading branch information
BurntSushi committed Sep 14, 2016
1 parent f11d9fb commit fdca741
Show file tree
Hide file tree
Showing 12 changed files with 488 additions and 645 deletions.
35 changes: 30 additions & 5 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,20 @@ use grep::{Grep, GrepBuilder};
use log;
use num_cpus;
use regex;
use term::Terminal;
use term::{self, Terminal};
#[cfg(windows)]
use term::WinConsole;
use walkdir::WalkDir;

use atty;
use gitignore::{Gitignore, GitignoreBuilder};
use ignore::Ignore;
use out::{Out, OutBuffer};
use out::{Out, ColoredTerminal};
use printer::Printer;
use search_buffer::BufferSearcher;
use search_stream::{InputBuffer, Searcher};
#[cfg(windows)]
use terminal_win::WindowsBuffer;
use types::{FileTypeDef, Types, TypesBuilder};
use walk;

Expand Down Expand Up @@ -442,7 +446,7 @@ impl Args {

/// Create a new printer of individual search results that writes to the
/// writer given.
pub fn printer<W: Send + Terminal>(&self, wtr: W) -> Printer<W> {
pub fn printer<W: Terminal + Send>(&self, wtr: W) -> Printer<W> {
let mut p = Printer::new(wtr)
.column(self.column)
.context_separator(self.context_separator.clone())
Expand All @@ -469,8 +473,29 @@ impl Args {
}

/// Create a new buffer for use with searching.
pub fn outbuf(&self) -> OutBuffer {
OutBuffer::new(self.color)
#[cfg(not(windows))]
pub fn outbuf(&self) -> ColoredTerminal<term::TerminfoTerminal<Vec<u8>>> {
ColoredTerminal::new(vec![], self.color)
}

/// Create a new buffer for use with searching.
#[cfg(windows)]
pub fn outbuf(&self) -> ColoredTerminal<WindowsBuffer> {
ColoredTerminal::new_buffer(self.color)
}

/// Create a new buffer for use with searching.
#[cfg(not(windows))]
pub fn stdout(
&self,
) -> ColoredTerminal<term::TerminfoTerminal<io::BufWriter<io::Stdout>>> {
ColoredTerminal::new(io::BufWriter::new(io::stdout()), self.color)
}

/// Create a new buffer for use with searching.
#[cfg(windows)]
pub fn stdout(&self) -> ColoredTerminal<WinConsole<io::Stdout>> {
ColoredTerminal::new_stdout(self.color)
}

/// Return the paths that should be searched.
Expand Down
22 changes: 3 additions & 19 deletions src/gitignore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ additional rules such as whitelists (prefix of `!`) or directory-only globs
// TODO(burntsushi): Implement something similar, but for Mercurial. We can't
// use this exact implementation because hgignore files are different.

use std::env;
use std::error::Error as StdError;
use std::fmt;
use std::fs::File;
Expand Down Expand Up @@ -89,21 +88,10 @@ pub struct Gitignore {
}

impl Gitignore {
/// Create a new gitignore glob matcher from the gitignore file at the
/// given path. The root of the gitignore file is the basename of path.
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Gitignore, Error> {
let root = match path.as_ref().parent() {
Some(parent) => parent.to_path_buf(),
None => env::current_dir().unwrap_or(Path::new("/").to_path_buf()),
};
let mut builder = GitignoreBuilder::new(root);
try!(builder.add_path(path));
builder.build()
}

/// Create a new gitignore glob matcher from the given root directory and
/// string containing the contents of a gitignore file.
pub fn from_str<P: AsRef<Path>>(
#[allow(dead_code)]
fn from_str<P: AsRef<Path>>(
root: P,
gitignore: &str,
) -> Result<Gitignore, Error> {
Expand Down Expand Up @@ -159,11 +147,6 @@ impl Gitignore {
pub fn num_ignores(&self) -> u64 {
self.num_ignores
}

/// Returns the total number of whitelisted patterns.
pub fn num_whitelist(&self) -> u64 {
self.num_whitelist
}
}

/// The result of a glob match.
Expand All @@ -182,6 +165,7 @@ pub enum Match<'a> {

impl<'a> Match<'a> {
/// Returns true if the match result implies the path should be ignored.
#[allow(dead_code)]
pub fn is_ignored(&self) -> bool {
match *self {
Match::Ignored(_) => true,
Expand Down
5 changes: 4 additions & 1 deletion src/glob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ impl Set {
}

/// Returns the number of glob patterns in this set.
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.set.len()
}
Expand Down Expand Up @@ -137,6 +138,7 @@ impl SetBuilder {
///
/// If the pattern could not be parsed as a glob, then an error is
/// returned.
#[allow(dead_code)]
pub fn add(&mut self, pat: &str) -> Result<(), Error> {
self.add_with(pat, &MatchOptions::default())
}
Expand Down Expand Up @@ -205,6 +207,7 @@ impl Pattern {
/// Convert this pattern to a string that is guaranteed to be a valid
/// regular expression and will represent the matching semantics of this
/// glob pattern. This uses a default set of options.
#[allow(dead_code)]
pub fn to_regex(&self) -> String {
self.to_regex_with(&MatchOptions::default())
}
Expand Down Expand Up @@ -315,7 +318,7 @@ impl<'a> Parser<'a> {
}
return Ok(());
}
let last = self.p.tokens.pop().unwrap();
self.p.tokens.pop().unwrap();
if prev != Some('/') {
return Err(Error::InvalidRecursive);
}
Expand Down

0 comments on commit fdca741

Please sign in to comment.