summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2021-05-09 17:45:11 +0200
committerCanop <cano.petrole@gmail.com>2021-05-09 17:45:11 +0200
commit88410cdf95881aaa1df67c4bddd171a9b61c0be7 (patch)
tree7e0b0537fd5d5a8b7ee262e05fc42a4137378b84 /src
parent8932923694f5890a7ad0cb8e90679e4246d8617a (diff)
match line count in selection on content searches
when a content search has been done, opening a file with a compatible command (like the standard `:edit`) opens on the first line with a match
Diffstat (limited to 'src')
-rw-r--r--src/browser/browser_state.rs7
-rw-r--r--src/content_search/mod.rs17
-rw-r--r--src/display/displayable_tree.rs3
-rw-r--r--src/pattern/composite_pattern.rs27
-rw-r--r--src/pattern/content_pattern.rs12
-rw-r--r--src/pattern/content_regex_pattern.rs24
-rw-r--r--src/pattern/exact_pattern.rs34
-rw-r--r--src/pattern/pattern.rs13
8 files changed, 134 insertions, 3 deletions
diff --git a/src/browser/browser_state.rs b/src/browser/browser_state.rs
index e41b93a..33fc2c4 100644
--- a/src/browser/browser_state.rs
+++ b/src/browser/browser_state.rs
@@ -175,7 +175,12 @@ impl PanelState for BrowserState {
}
fn selection(&self) -> Option<Selection<'_>> {
- Some(self.displayed_tree().selected_line().as_selection())
+ let tree = self.displayed_tree();
+ let mut selection = tree.selected_line().as_selection();
+ selection.line = tree.options.pattern.pattern
+ .get_match_line_count(&selection.path)
+ .unwrap_or(0);
+ Some(selection)
}
fn tree_options(&self) -> TreeOptions {
diff --git a/src/content_search/mod.rs b/src/content_search/mod.rs
index 9e2ca51..362672b 100644
--- a/src/content_search/mod.rs
+++ b/src/content_search/mod.rs
@@ -9,6 +9,7 @@ pub use {
content_match::ContentMatch,
content_search_result::ContentSearchResult,
needle::Needle,
+ std::io::{ BufRead, BufReader},
};
use {
@@ -53,3 +54,19 @@ pub fn is_path_binary<P: AsRef<Path>>(path: P) -> bool {
_ => true,
}
}
+
+pub fn line_count_at_pos<P: AsRef<Path>>(path: P, pos: usize) -> io::Result<usize> {
+ let mut reader = BufReader::new(File::open(path)?);
+ let mut line = String::new();
+ let mut line_count = 1;
+ let mut bytes_count = 0;
+ while reader.read_line(&mut line)? > 0 {
+ bytes_count += line.len();
+ if bytes_count >= pos {
+ return Ok(line_count);
+ }
+ line_count += 1;
+ line.clear();
+ }
+ Err(io::Error::new(io::ErrorKind::UnexpectedEof, "too short".to_string()))
+}
diff --git a/src/display/displayable_tree.rs b/src/display/displayable_tree.rs
index ca8e9ab..28ab478 100644
--- a/src/display/displayable_tree.rs
+++ b/src/display/displayable_tree.rs
@@ -567,7 +567,8 @@ impl<'a, 's, 't> DisplayableTree<'a, 's, 't> {
}
if cw.allowed > 8 && pattern_object.content {
- let extract = tree.options.pattern.pattern.search_content(&line.path, cw.allowed - 2);
+ let extract = tree.options.pattern.pattern
+ .search_content(&line.path, cw.allowed - 2);
if let Some(extract) = extract {
self.write_content_extract(cw, extract, selected)?;
}
diff --git a/src/pattern/composite_pattern.rs b/src/pattern/composite_pattern.rs
index 4d093f5..e573b6a 100644
--- a/src/pattern/composite_pattern.rs
+++ b/src/pattern/composite_pattern.rs
@@ -137,6 +137,33 @@ impl CompositePattern {
})
}
+ pub fn get_match_line_count(
+ &self,
+ candidate: &Path,
+ ) -> Option<usize> {
+ use PatternOperator::*;
+ let composite_result: Option<Option<usize>> = self.expr.eval(
+ // score evaluation
+ |pat| pat.get_match_line_count(candidate),
+ // operator
+ |op, a, b| match (op, a, b) {
+ (Not, Some(_), _) => None,
+ (_, Some(ma), _) => Some(ma),
+ (_, None, Some(omb)) => omb,
+ _ => None,
+ },
+ |op, a| match (op, a) {
+ (Or, Some(_)) => true,
+ _ => false,
+ },
+ );
+ composite_result
+ .unwrap_or_else(||{
+ warn!("unexpectedly missing result ");
+ None
+ })
+ }
+
pub fn has_real_scores(&self) -> bool {
self.expr.iter_atoms()
.fold(false, |r, p| match p {
diff --git a/src/pattern/content_pattern.rs b/src/pattern/content_pattern.rs
index be7014a..3521eec 100644
--- a/src/pattern/content_pattern.rs
+++ b/src/pattern/content_pattern.rs
@@ -61,6 +61,18 @@ impl ContentExactPattern {
}
}
+ /// get the line of the first match, if any
+ pub fn get_match_line_count(
+ &self,
+ path: &Path,
+ ) -> Option<usize> {
+ if let Ok(ContentSearchResult::Found { pos }) = self.needle.search(path) {
+ line_count_at_pos(path, pos).ok()
+ } else {
+ None
+ }
+ }
+
pub fn get_content_match(
&self,
path: &Path,
diff --git a/src/pattern/content_regex_pattern.rs b/src/pattern/content_regex_pattern.rs
index 9ca9858..3a27767 100644
--- a/src/pattern/content_regex_pattern.rs
+++ b/src/pattern/content_regex_pattern.rs
@@ -86,6 +86,30 @@ impl ContentRegexPattern {
Ok(None)
}
+ /// get the line of the first match, if any
+ pub fn try_get_match_line_count(
+ &self,
+ path: &Path,
+ ) -> io::Result<Option<usize>> {
+ let mut line_count = 1;
+ for line in BufReader::new(File::open(path)?).lines() {
+ let line = line?;
+ if self.rex.is_match(line.as_str()) {
+ return Ok(Some(line_count));
+ }
+ line_count += 1;
+ }
+ Ok(None)
+ }
+ /// get the line of the first match, if any
+ pub fn get_match_line_count(
+ &self,
+ path: &Path,
+ ) -> Option<usize> {
+ self.try_get_match_line_count(path)
+ .unwrap_or(None)
+ }
+
pub fn get_content_match(
&self,
path: &Path,
diff --git a/src/pattern/exact_pattern.rs b/src/pattern/exact_pattern.rs
index ae2fae1..f129e9f 100644
--- a/src/pattern/exact_pattern.rs
+++ b/src/pattern/exact_pattern.rs
@@ -5,7 +5,12 @@
use {
super::NameMatch,
smallvec::SmallVec,
- std::fmt,
+ std::{
+ fmt,
+ fs::File,
+ io::{self, BufRead, BufReader},
+ path::Path,
+ },
};
// weights used in match score computing
@@ -87,6 +92,33 @@ impl ExactPattern {
})
}
+ /// get the line of the first match, if any
+ /// (not used today, we use content_pattern to search in files)
+ pub fn try_get_match_line_count(
+ &self,
+ path: &Path,
+ ) -> io::Result<Option<usize>> {
+ let mut line_count = 1; // first line in text editors is 1
+ for line in BufReader::new(File::open(path)?).lines() {
+ let line = line?;
+ if line.contains(&self.pattern) {
+ return Ok(Some(line_count));
+ }
+ line_count = 1;
+ }
+ Ok(None)
+ }
+
+ /// get the line of the first match, if any
+ /// (not used today, we use content_pattern to search in files)
+ pub fn get_match_line_count(
+ &self,
+ path: &Path,
+ ) -> Option<usize> {
+ self.try_get_match_line_count(path)
+ .unwrap_or(None)
+ }
+
/// compute the score of the best match
pub fn score_of(&self, candidate: &str) -> Option<i32> {
candidate
diff --git a/src/pattern/pattern.rs b/src/pattern/pattern.rs
index d479995..36feb21 100644
--- a/src/pattern/pattern.rs
+++ b/src/pattern/pattern.rs
@@ -142,6 +142,19 @@ impl Pattern {
}
}
+ /// get the line of the first match, if any
+ pub fn get_match_line_count(
+ &self,
+ path: &Path,
+ ) -> Option<usize> {
+ match self {
+ Self::ContentExact(cp) => cp.get_match_line_count(path),
+ Self::ContentRegex(cp) => cp.get_match_line_count(path),
+ Self::Composite(cp) => cp.get_match_line_count(path),
+ _ => None,
+ }
+ }
+
pub fn score_of(&self, candidate: Candidate) -> Option<i32> {
match self {
Self::NameExact(ep) => ep.score_of(&candidate.name),