use sley_core::{GitError, Result};
use sley_grep::{Regex, RegexMode};
pub struct CompiledFuncname {
patterns: Vec<(bool, Regex)>,
}
const FUNCNAME_BUFFER: usize = 80;
impl CompiledFuncname {
pub fn compile(spec: &[u8], extended: bool, icase: bool) -> Result<Self> {
let lines: Vec<&[u8]> = spec.split(|&b| b == b'\n').collect();
let mut patterns = Vec::new();
for (idx, line) in lines.iter().enumerate() {
let negate = line.first() == Some(&b'!');
if negate && idx == lines.len() - 1 {
let suffix: Vec<u8> = lines[idx..].join(&b'\n');
eprintln!(
"fatal: Last expression must not be negated: {}",
String::from_utf8_lossy(&suffix)
);
return Err(GitError::Exit(128));
}
let expression = if negate { &line[1..] } else { line };
let mode = if extended {
RegexMode::Ere
} else {
RegexMode::Bre
};
let regex = Regex::compile_bytes(expression, mode, icase, false).map_err(|_| {
eprintln!(
"fatal: Invalid regexp to look for hunk header: {}",
String::from_utf8_lossy(expression)
);
GitError::Exit(128)
})?;
patterns.push((negate, regex));
}
Ok(Self { patterns })
}
pub fn match_line(&self, line: &[u8]) -> Option<Vec<u8>> {
let mut len = line.len();
if len > 0 && line[len - 1] == b'\n' {
if len > 1 && line[len - 2] == b'\r' {
len -= 2;
} else {
len -= 1;
}
}
let line = &line[..len];
let mut matched: Option<Vec<Option<(usize, usize)>>> = None;
for (negate, regex) in &self.patterns {
if let Some(captures) = regex.find_captures(line) {
if *negate {
return None;
}
matched = Some(captures);
break;
}
}
let captures = matched?;
let (start, end) = captures
.get(1)
.copied()
.flatten()
.unwrap_or_else(|| captures[0].expect("whole-match span present"));
let heading = &line[start..end];
let mut result = heading.len().min(FUNCNAME_BUFFER);
while result > 0 && heading[result - 1].is_ascii_whitespace() {
result -= 1;
}
Some(heading[..result].to_vec())
}
}
pub fn default_funcname_heading(line: &[u8]) -> Option<Vec<u8>> {
let first = line.first()?;
if !(first.is_ascii_alphabetic() || *first == b'_' || *first == b'$') {
return None;
}
let mut len = line.len().min(FUNCNAME_BUFFER);
while len > 0 && line[len - 1].is_ascii_whitespace() {
len -= 1;
}
Some(line[..len].to_vec())
}