1use std::{collections::HashMap, ffi::OsString, path::Path};
2
3use serde::Deserialize;
4
5use crate::{
6 error::LinguistError,
7 resolver::{HeuristicRule, Language, Scope},
8};
9
10#[derive(Debug, Clone)]
11pub struct StaticLanguage<'src> {
12 pub name: &'src str,
13 pub scope: &'src str,
14 pub aliases: Option<&'src [&'src str]>,
15 pub extensions: Option<&'src [&'src str]>,
16 pub filenames: Option<&'src [&'src str]>,
17 pub interpreters: Option<&'src [&'src str]>,
18 pub color: Option<&'src str>,
19 pub parent: Option<&'src str>,
20}
21
22impl<'src> From<&'src StaticLanguage<'src>> for Language {
23 fn from(value: &'src StaticLanguage<'src>) -> Self {
24 let parent = value.parent.map(String::from);
25 let name = String::from(value.name);
26 let aliases = value
27 .aliases
28 .map(|aliases| aliases.iter().map(|alias| String::from(*alias)).collect());
29 let scope = Scope::from(value.scope);
30 let extensions = value
31 .extensions
32 .map(|extensions| extensions.iter().map(|ext| OsString::from(*ext)).collect());
33 let filenames = value.filenames.map(|filenames| {
34 filenames
35 .iter()
36 .map(|filename| OsString::from(*filename))
37 .collect()
38 });
39 let interpreters = value.interpreters.map(|interpreters| {
40 interpreters
41 .iter()
42 .map(|interp| String::from(*interp))
43 .collect()
44 });
45 let color = value.color.map(String::from);
46
47 Language {
48 parent,
49 name,
50 aliases: aliases.unwrap_or_default(),
51 scope,
52 extensions: extensions.unwrap_or_default(),
53 filenames: filenames.unwrap_or_default(),
54 interpreters: interpreters.unwrap_or_default(),
55 color,
56 }
57 }
58}
59
60#[derive(Debug, Clone)]
61pub struct StaticHeuristicRule<'a> {
62 pub language: &'a str,
63 pub extensions: &'a [&'a str],
64 pub patterns: &'a [&'a str],
65}
66
67impl<'a> From<&'a StaticHeuristicRule<'a>> for HeuristicRule {
68 fn from(value: &'a StaticHeuristicRule<'a>) -> Self {
69 Self {
70 language: String::from(value.language),
71 extensions: value
72 .extensions
73 .iter()
74 .map(|ext| OsString::from(*ext))
75 .collect(),
76 patterns: value.patterns.iter().map(|&s| String::from(s)).collect(),
77 }
78 }
79}
80pub fn deserialize_languages<T>(path: impl AsRef<Path>) -> Result<Vec<Language>, LinguistError>
85where
86 for<'de> T: Deserialize<'de>,
87 T: TryInto<Language>,
88{
89 let content = std::fs::read_to_string(path).unwrap_or_default();
90 let data: HashMap<String, T> = match serde_yaml::from_str(&content) {
91 Ok(result) => result,
92 Err(_) => {
93 return Err(LinguistError::DeserializationError);
94 }
95 };
96
97 let mut languages: Vec<Language> = Vec::new();
98 for (name, item) in data.into_iter() {
99 match item.try_into() {
100 Ok(mut lang) => {
101 lang.name = name;
102 languages.push(lang)
103 }
104 Err(_) => {
105 return Err(LinguistError::DeserializationError);
106 }
107 };
108 }
109
110 Ok(languages)
111}
112
113pub fn deserialize_strings(path: impl AsRef<Path>) -> Result<Vec<String>, LinguistError> {
115 let content = std::fs::read_to_string(path).unwrap_or_default();
116 let data: Vec<String> = match serde_yaml::from_str(&content) {
117 Ok(result) => result,
118 Err(_) => {
119 return Err(LinguistError::DeserializationError);
120 }
121 };
122
123 Ok(data)
124}