mirror of https://github.com/sharkdp/fd.git
Highlight matches, see #46
This commit is contained in:
parent
8073635177
commit
8b175c1146
70
src/main.rs
70
src/main.rs
|
@ -112,7 +112,11 @@ static ROOT_DIR : &'static str = "/";
|
|||
static PARENT_DIR : &'static str = "..";
|
||||
|
||||
/// Print a search result to the console.
|
||||
fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) {
|
||||
fn print_entry(base: &Path,
|
||||
entry: &PathBuf,
|
||||
match_start: usize,
|
||||
match_end: usize,
|
||||
config: &FdOptions) {
|
||||
let path_full = base.join(entry);
|
||||
|
||||
let path_str = entry.to_string_lossy();
|
||||
|
@ -138,6 +142,9 @@ fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) {
|
|||
print!("{}", ls_colors.directory.paint(ROOT_DIR));
|
||||
}
|
||||
|
||||
let mut output_length = 0;
|
||||
let mut within_match = false;
|
||||
|
||||
// Traverse the path and colorize each component
|
||||
for component in entry.components() {
|
||||
let comp_str = match component {
|
||||
|
@ -178,11 +185,48 @@ fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) {
|
|||
}
|
||||
};
|
||||
|
||||
write!(handle, "{}", style.paint(comp_str)).ok();
|
||||
let comp_len = comp_str.len();
|
||||
if match_start >= output_length && match_start < output_length + comp_len {
|
||||
let (first, second) = comp_str.split_at(match_start - output_length);
|
||||
write!(handle, "{}", style.paint(first)).ok();
|
||||
if match_end < output_length + comp_len {
|
||||
let (second_, third_) = second.split_at(match_end - match_start);
|
||||
write!(handle, "{}", style.underline().paint(second_)).ok();
|
||||
write!(handle, "{}", style.paint(third_)).ok();
|
||||
}
|
||||
else {
|
||||
write!(handle, "{}", style.underline().paint(second)).ok();
|
||||
within_match = true;
|
||||
}
|
||||
} else {
|
||||
|
||||
if within_match {
|
||||
if match_end >= output_length && match_end < output_length + comp_len {
|
||||
let (first, second) = comp_str.split_at(match_end - output_length);
|
||||
write!(handle, "{}", style.underline().paint(first)).ok();
|
||||
write!(handle, "{}", style.paint(second)).ok();
|
||||
within_match = false;
|
||||
} else {
|
||||
write!(handle, "{}", style.underline().paint(comp_str)).ok();
|
||||
}
|
||||
} else {
|
||||
write!(handle, "{}", style.paint(comp_str)).ok();
|
||||
};
|
||||
}
|
||||
output_length += comp_len;
|
||||
|
||||
if match_end == output_length {
|
||||
within_match = false;
|
||||
}
|
||||
|
||||
if is_directory && component_path != path_full {
|
||||
let sep = std::path::MAIN_SEPARATOR.to_string();
|
||||
write!(handle, "{}", style.paint(sep)).ok();
|
||||
output_length += sep.len();
|
||||
if within_match {
|
||||
write!(handle, "{}", style.underline().paint(sep)).ok();
|
||||
} else {
|
||||
write!(handle, "{}", style.paint(sep)).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,7 +256,7 @@ fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) {
|
|||
|
||||
/// Recursively scan the given search path and search for files / pathnames matching the pattern.
|
||||
fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions>) {
|
||||
let (tx, rx) = channel();
|
||||
let (tx, rx) = channel::<(PathBuf, usize, usize)>();
|
||||
|
||||
let walker = WalkBuilder::new(root)
|
||||
.hidden(config.ignore_hidden)
|
||||
|
@ -241,16 +285,16 @@ fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions>) {
|
|||
let max_buffer_time = rx_config.max_buffer_time
|
||||
.unwrap_or_else(|| time::Duration::from_millis(100));
|
||||
|
||||
for value in rx {
|
||||
for (path, match_start, match_end) in rx {
|
||||
match mode {
|
||||
ReceiverMode::Buffering => {
|
||||
buffer.push(value);
|
||||
buffer.push((path, match_start, match_end));
|
||||
|
||||
// Have we reached the maximum time?
|
||||
if time::Instant::now() - start > max_buffer_time {
|
||||
// Flush the buffer
|
||||
for v in &buffer {
|
||||
print_entry(&rx_base, v, &rx_config);
|
||||
for &(ref p, m_s, m_e) in &buffer {
|
||||
print_entry(&rx_base, &p, m_s, m_e, &rx_config);
|
||||
}
|
||||
buffer.clear();
|
||||
|
||||
|
@ -259,7 +303,7 @@ fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions>) {
|
|||
}
|
||||
},
|
||||
ReceiverMode::Streaming => {
|
||||
print_entry(&rx_base, &value, &rx_config);
|
||||
print_entry(&rx_base, &path, match_start, match_end, &rx_config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -267,9 +311,9 @@ fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions>) {
|
|||
// If we have finished fast enough (faster than max_buffer_time), we haven't streamed
|
||||
// anything to the console, yet. In this case, sort the results and print them:
|
||||
if !buffer.is_empty() {
|
||||
buffer.sort();
|
||||
for value in buffer {
|
||||
print_entry(&rx_base, &value, &rx_config);
|
||||
buffer.sort_unstable_by_key(|t| t.0.to_owned());
|
||||
for (path, match_start, match_end) in buffer {
|
||||
print_entry(&rx_base, &path, match_start, match_end, &rx_config);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -318,7 +362,7 @@ fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions>) {
|
|||
if let Some(search_str) = search_str_o {
|
||||
// TODO: take care of the unwrap call
|
||||
pattern.find(&*search_str)
|
||||
.map(|_| tx_thread.send(path_rel_buf.to_owned()).unwrap());
|
||||
.map(|m| tx_thread.send((path_rel_buf.to_owned(), m.start(), m.end())).unwrap());
|
||||
}
|
||||
|
||||
ignore::WalkState::Continue
|
||||
|
|
Loading…
Reference in New Issue