136 lines
4.4 KiB
Rust
136 lines
4.4 KiB
Rust
use seal::pair::{AlignmentSet, MemoryMappedAlignmentMatrix, SmithWaterman, Step};
|
|
|
|
// (line pos, line pos)
|
|
pub fn match_lines(code: &str, start: &str, end: &str) -> Option<(usize, usize)> {
|
|
let code_chars: Vec<char> = code.chars().collect();
|
|
|
|
if code_chars.is_empty() || start.is_empty() || end.is_empty() {
|
|
return None;
|
|
}
|
|
|
|
let strategy = SmithWaterman::new(3, -1, -1, -1);
|
|
|
|
if start.ends_with(end) {
|
|
let pattern_chars: Vec<char> = start.chars().collect();
|
|
let set: AlignmentSet<MemoryMappedAlignmentMatrix> =
|
|
AlignmentSet::new(code_chars.len(), pattern_chars.len(), strategy, |x, y| {
|
|
code_chars[x] == pattern_chars[y]
|
|
})
|
|
.ok()?;
|
|
|
|
let alignment = set.local_alignment();
|
|
let mut start_char_pos = None;
|
|
let mut end_char_pos = None;
|
|
|
|
for step in alignment.steps() {
|
|
if let Step::Align { x, .. } = step {
|
|
if start_char_pos.is_none() {
|
|
start_char_pos = Some(x);
|
|
}
|
|
end_char_pos = Some(x);
|
|
}
|
|
}
|
|
|
|
let start_char = start_char_pos?;
|
|
let end_char = end_char_pos?;
|
|
|
|
let start_line = code[..start_char].lines().count().saturating_sub(1);
|
|
let end_line = code[..=end_char].lines().count().saturating_sub(1);
|
|
|
|
Some((start_line, end_line))
|
|
} else {
|
|
let start_chars: Vec<char> = start.chars().collect();
|
|
let start_set: AlignmentSet<MemoryMappedAlignmentMatrix> = AlignmentSet::new(
|
|
code_chars.len(),
|
|
start_chars.len(),
|
|
strategy.clone(),
|
|
|x, y| code_chars[x] == start_chars[y],
|
|
)
|
|
.ok()?;
|
|
|
|
let start_alignment = start_set.local_alignment();
|
|
let start_char_pos = start_alignment
|
|
.steps()
|
|
.filter_map(|step| {
|
|
if let Step::Align { x, .. } = step {
|
|
Some(x)
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.next()?;
|
|
|
|
let end_chars: Vec<char> = end.chars().collect();
|
|
let remaining_code: Vec<char> = code_chars[start_char_pos..].to_vec();
|
|
let end_set: AlignmentSet<MemoryMappedAlignmentMatrix> =
|
|
AlignmentSet::new(remaining_code.len(), end_chars.len(), strategy, |x, y| {
|
|
remaining_code[x] == end_chars[y]
|
|
})
|
|
.ok()?;
|
|
|
|
let end_char_pos_relative = end_set
|
|
.local_alignments()
|
|
.filter_map(|end_alignment| {
|
|
end_alignment
|
|
.steps()
|
|
.filter_map(|step| {
|
|
if let Step::Align { x, .. } = step {
|
|
Some(x)
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.last()
|
|
})
|
|
.min()?;
|
|
|
|
let end_char_pos = start_char_pos + end_char_pos_relative;
|
|
|
|
let start_line = code[..=start_char_pos].lines().count().saturating_sub(1);
|
|
let end_line = code[..=end_char_pos].lines().count().saturating_sub(1);
|
|
|
|
Some((start_line, end_line))
|
|
}
|
|
}
|
|
|
|
// (char pos, char pos)
|
|
pub fn match_content(code: &str, pattern: &str) -> Vec<(usize, usize)> {
|
|
let code_chars: Vec<char> = code.chars().collect();
|
|
|
|
if code_chars.is_empty() || pattern.is_empty() {
|
|
return vec![];
|
|
}
|
|
|
|
let strategy = SmithWaterman::new(3, -1, -1, -1);
|
|
|
|
let pattern_chars: Vec<char> = pattern.chars().collect();
|
|
let set: AlignmentSet<MemoryMappedAlignmentMatrix> =
|
|
match AlignmentSet::new(code_chars.len(), pattern_chars.len(), strategy, |x, y| {
|
|
code_chars[x] == pattern_chars[y]
|
|
}) {
|
|
Ok(set) => set,
|
|
Err(_) => return vec![],
|
|
};
|
|
|
|
set.local_alignments()
|
|
.filter_map(|alignment| {
|
|
let mut start_char_pos = None;
|
|
let mut end_char_pos = None;
|
|
|
|
for step in alignment.steps() {
|
|
if let Step::Align { x, .. } = step {
|
|
if start_char_pos.is_none() {
|
|
start_char_pos = Some(x);
|
|
}
|
|
end_char_pos = Some(x);
|
|
}
|
|
}
|
|
|
|
match (start_char_pos, end_char_pos) {
|
|
(Some(start), Some(end)) => Some((start, end)),
|
|
_ => None,
|
|
}
|
|
})
|
|
.collect()
|
|
}
|