|
|
@ -2184,7 +2184,10 @@ fn global_search(cx: &mut Context) {
|
|
|
|
let searcher = SearcherBuilder::new()
|
|
|
|
let searcher = SearcherBuilder::new()
|
|
|
|
.binary_detection(BinaryDetection::quit(b'\x00'))
|
|
|
|
.binary_detection(BinaryDetection::quit(b'\x00'))
|
|
|
|
.build();
|
|
|
|
.build();
|
|
|
|
WalkBuilder::new(search_root)
|
|
|
|
|
|
|
|
|
|
|
|
let mut walk_builder = WalkBuilder::new(search_root);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
walk_builder
|
|
|
|
.hidden(file_picker_config.hidden)
|
|
|
|
.hidden(file_picker_config.hidden)
|
|
|
|
.parents(file_picker_config.parents)
|
|
|
|
.parents(file_picker_config.parents)
|
|
|
|
.ignore(file_picker_config.ignore)
|
|
|
|
.ignore(file_picker_config.ignore)
|
|
|
@ -2195,73 +2198,77 @@ fn global_search(cx: &mut Context) {
|
|
|
|
.max_depth(file_picker_config.max_depth)
|
|
|
|
.max_depth(file_picker_config.max_depth)
|
|
|
|
.filter_entry(move |entry| {
|
|
|
|
.filter_entry(move |entry| {
|
|
|
|
filter_picker_entry(entry, &absolute_root, dedup_symlinks)
|
|
|
|
filter_picker_entry(entry, &absolute_root, dedup_symlinks)
|
|
|
|
})
|
|
|
|
});
|
|
|
|
.build_parallel()
|
|
|
|
|
|
|
|
.run(|| {
|
|
|
|
|
|
|
|
let mut searcher = searcher.clone();
|
|
|
|
|
|
|
|
let matcher = matcher.clone();
|
|
|
|
|
|
|
|
let injector = injector_.clone();
|
|
|
|
|
|
|
|
let documents = &documents;
|
|
|
|
|
|
|
|
Box::new(move |entry: Result<DirEntry, ignore::Error>| -> WalkState {
|
|
|
|
|
|
|
|
let entry = match entry {
|
|
|
|
|
|
|
|
Ok(entry) => entry,
|
|
|
|
|
|
|
|
Err(_) => return WalkState::Continue,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match entry.file_type() {
|
|
|
|
|
|
|
|
Some(entry) if entry.is_file() => {}
|
|
|
|
|
|
|
|
// skip everything else
|
|
|
|
|
|
|
|
_ => return WalkState::Continue,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut stop = false;
|
|
|
|
|
|
|
|
let sink = sinks::UTF8(|line_num, _| {
|
|
|
|
|
|
|
|
stop = injector
|
|
|
|
|
|
|
|
.push(FileResult::new(entry.path(), line_num as usize - 1))
|
|
|
|
|
|
|
|
.is_err();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(!stop)
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
let doc = documents.iter().find(|&(doc_path, _)| {
|
|
|
|
|
|
|
|
doc_path
|
|
|
|
|
|
|
|
.as_ref()
|
|
|
|
|
|
|
|
.map_or(false, |doc_path| doc_path == entry.path())
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let result = if let Some((_, doc)) = doc {
|
|
|
|
|
|
|
|
// there is already a buffer for this file
|
|
|
|
|
|
|
|
// search the buffer instead of the file because it's faster
|
|
|
|
|
|
|
|
// and captures new edits without requiring a save
|
|
|
|
|
|
|
|
if searcher.multi_line_with_matcher(&matcher) {
|
|
|
|
|
|
|
|
// in this case a continous buffer is required
|
|
|
|
|
|
|
|
// convert the rope to a string
|
|
|
|
|
|
|
|
let text = doc.to_string();
|
|
|
|
|
|
|
|
searcher.search_slice(&matcher, text.as_bytes(), sink)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
searcher.search_reader(
|
|
|
|
|
|
|
|
&matcher,
|
|
|
|
|
|
|
|
RopeReader::new(doc.slice(..)),
|
|
|
|
|
|
|
|
sink,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
searcher.search_path(&matcher, entry.path(), sink)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if let Err(err) = result {
|
|
|
|
walk_builder
|
|
|
|
log::error!(
|
|
|
|
.add_custom_ignore_filename(helix_loader::config_dir().join("ignore"));
|
|
|
|
"Global search error: {}, {}",
|
|
|
|
walk_builder.add_custom_ignore_filename(".helix/ignore");
|
|
|
|
entry.path().display(),
|
|
|
|
|
|
|
|
err
|
|
|
|
walk_builder.build_parallel().run(|| {
|
|
|
|
);
|
|
|
|
let mut searcher = searcher.clone();
|
|
|
|
}
|
|
|
|
let matcher = matcher.clone();
|
|
|
|
if stop {
|
|
|
|
let injector = injector_.clone();
|
|
|
|
WalkState::Quit
|
|
|
|
let documents = &documents;
|
|
|
|
|
|
|
|
Box::new(move |entry: Result<DirEntry, ignore::Error>| -> WalkState {
|
|
|
|
|
|
|
|
let entry = match entry {
|
|
|
|
|
|
|
|
Ok(entry) => entry,
|
|
|
|
|
|
|
|
Err(_) => return WalkState::Continue,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match entry.file_type() {
|
|
|
|
|
|
|
|
Some(entry) if entry.is_file() => {}
|
|
|
|
|
|
|
|
// skip everything else
|
|
|
|
|
|
|
|
_ => return WalkState::Continue,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut stop = false;
|
|
|
|
|
|
|
|
let sink = sinks::UTF8(|line_num, _| {
|
|
|
|
|
|
|
|
stop = injector
|
|
|
|
|
|
|
|
.push(FileResult::new(entry.path(), line_num as usize - 1))
|
|
|
|
|
|
|
|
.is_err();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(!stop)
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
let doc = documents.iter().find(|&(doc_path, _)| {
|
|
|
|
|
|
|
|
doc_path
|
|
|
|
|
|
|
|
.as_ref()
|
|
|
|
|
|
|
|
.map_or(false, |doc_path| doc_path == entry.path())
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let result = if let Some((_, doc)) = doc {
|
|
|
|
|
|
|
|
// there is already a buffer for this file
|
|
|
|
|
|
|
|
// search the buffer instead of the file because it's faster
|
|
|
|
|
|
|
|
// and captures new edits without requiring a save
|
|
|
|
|
|
|
|
if searcher.multi_line_with_matcher(&matcher) {
|
|
|
|
|
|
|
|
// in this case a continous buffer is required
|
|
|
|
|
|
|
|
// convert the rope to a string
|
|
|
|
|
|
|
|
let text = doc.to_string();
|
|
|
|
|
|
|
|
searcher.search_slice(&matcher, text.as_bytes(), sink)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
WalkState::Continue
|
|
|
|
searcher.search_reader(
|
|
|
|
|
|
|
|
&matcher,
|
|
|
|
|
|
|
|
RopeReader::new(doc.slice(..)),
|
|
|
|
|
|
|
|
sink,
|
|
|
|
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
});
|
|
|
|
searcher.search_path(&matcher, entry.path(), sink)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if let Err(err) = result {
|
|
|
|
|
|
|
|
log::error!(
|
|
|
|
|
|
|
|
"Global search error: {}, {}",
|
|
|
|
|
|
|
|
entry.path().display(),
|
|
|
|
|
|
|
|
err
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if stop {
|
|
|
|
|
|
|
|
WalkState::Quit
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
WalkState::Continue
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
cx.jobs.callback(async move {
|
|
|
|
cx.jobs.callback(async move {
|
|
|
|