feat: implement first-line-regex

This commit is contained in:
Bedis Nbiba 2024-02-13 07:51:41 +01:00 committed by GitHub
parent 1f196dc67d
commit 7dd096c5f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 162 additions and 7 deletions

View file

@ -87,7 +87,7 @@ const BUILD_TARGET: &str = env!("BUILD_TARGET");
pub struct LanguageConfiguration<'a> {
pub scope: Option<String>,
pub content_regex: Option<Regex>,
pub _first_line_regex: Option<Regex>,
pub first_line_regex: Option<Regex>,
pub injection_regex: Option<Regex>,
pub file_types: Vec<String>,
pub root_path: PathBuf,
@ -109,6 +109,7 @@ pub struct Loader {
language_configurations: Vec<LanguageConfiguration<'static>>,
language_configuration_ids_by_file_type: HashMap<String, Vec<usize>>,
language_configuration_in_current_path: Option<usize>,
language_configuration_ids_by_first_line_regex: HashMap<String, Vec<usize>>,
highlight_names: Box<Mutex<Vec<String>>>,
use_all_highlight_names: bool,
debug_build: bool,
@ -140,6 +141,7 @@ impl Loader {
language_configurations: Vec::new(),
language_configuration_ids_by_file_type: HashMap::new(),
language_configuration_in_current_path: None,
language_configuration_ids_by_first_line_regex: HashMap::new(),
highlight_names: Box::new(Mutex::new(Vec::new())),
use_all_highlight_names: true,
debug_build: false,
@ -241,6 +243,26 @@ impl Loader {
.and_then(|extension| {
self.language_configuration_ids_by_file_type.get(extension)
})
})
.or_else(|| {
let Ok(file) = fs::File::open(path) else {
return None;
};
let reader = BufReader::new(file);
let Some(Ok(first_line)) = std::io::BufRead::lines(reader).next() else {
return None;
};
self.language_configuration_ids_by_first_line_regex
.iter()
.find(|(regex, _)| {
if let Some(regex) = Self::regex(Some(regex)) {
regex.is_match(&first_line)
} else {
false
}
})
.map(|(_, ids)| ids)
});
if let Some(configuration_ids) = configuration_ids {
@ -871,9 +893,9 @@ impl Loader {
scope: config_json.scope,
language_id,
file_types: config_json.file_types.unwrap_or(Vec::new()),
content_regex: Self::regex(config_json.content_regex),
_first_line_regex: Self::regex(config_json.first_line_regex),
injection_regex: Self::regex(config_json.injection_regex),
content_regex: Self::regex(config_json.content_regex.as_deref()),
first_line_regex: Self::regex(config_json.first_line_regex.as_deref()),
injection_regex: Self::regex(config_json.injection_regex.as_deref()),
injections_filenames: config_json.injections.into_vec(),
locals_filenames: config_json.locals.into_vec(),
tags_filenames: config_json.tags.into_vec(),
@ -890,6 +912,12 @@ impl Loader {
.or_default()
.push(self.language_configurations.len());
}
if let Some(first_line_regex) = &configuration.first_line_regex {
self.language_configuration_ids_by_first_line_regex
.entry(first_line_regex.to_string())
.or_default()
.push(self.language_configurations.len());
}
self.language_configurations
.push(unsafe { mem::transmute(configuration) });
@ -920,7 +948,7 @@ impl Loader {
file_types: Vec::new(),
scope: None,
content_regex: None,
_first_line_regex: None,
first_line_regex: None,
injection_regex: None,
injections_filenames: None,
locals_filenames: None,
@ -940,8 +968,8 @@ impl Loader {
Ok(&self.language_configurations[initial_language_configuration_count..])
}
fn regex(pattern: Option<String>) -> Option<Regex> {
pattern.and_then(|r| RegexBuilder::new(&r).multi_line(true).build().ok())
fn regex(pattern: Option<&str>) -> Option<Regex> {
pattern.and_then(|r| RegexBuilder::new(r).multi_line(true).build().ok())
}
pub fn select_language(