use std::collections::HashMap;
use anyhow::{Result, anyhow};
use super::builtins::{builtin_languages, builtin_lsp};
use super::{FormatterConfig, Language, LanguageConfig, LspConfig, LspToml};
pub(super) fn resolve_lsp_table(
user: HashMap<String, LspToml>,
) -> Result<HashMap<String, LspConfig>> {
let mut merged = builtin_lsp();
for (name, user_entry) in user {
if let Some(existing) = merged.get_mut(&name) {
existing.overlay(user_entry);
} else {
merged.insert(name.clone(), LspConfig::from_user(&name, user_entry)?);
}
}
Ok(merged)
}
pub(super) fn resolve(
user_languages: HashMap<String, LanguageConfig>,
lsp_table: &HashMap<String, LspConfig>,
) -> Result<HashMap<String, Language>> {
let mut merged = builtin_languages();
for (name, user_lang) in user_languages {
merged
.entry(name)
.and_modify(|d| d.overlay(user_lang.clone()))
.or_insert(user_lang);
}
let mut out = HashMap::new();
for (name, cfg) in merged {
let lang = build_language(&name, cfg, lsp_table)?;
out.insert(name, lang);
}
Ok(out)
}
fn build_language(
name: &str,
c: LanguageConfig,
lsp_table: &HashMap<String, LspConfig>,
) -> Result<Language> {
let mut lsp = Vec::new();
if let Some(refs) = c.lsp {
for server_name in refs {
let entry = lsp_table.get(&server_name).ok_or_else(|| {
anyhow!(
"[languages.{}] references unknown server `{}` — add a \
`[lsp.{}]` table or use one of the built-in names",
name,
server_name,
server_name
)
})?;
lsp.push(entry.clone());
}
}
let formatter = match c.formatter {
Some(f) => Some(FormatterConfig {
command: f.command.ok_or_else(|| {
anyhow!("[languages.{}.formatter] requires a `command` field", name)
})?,
args: f.args.unwrap_or_default(),
}),
None => None,
};
Ok(Language {
name: name.to_string(),
extensions: c.extensions.unwrap_or_default(),
filenames: c.filenames.unwrap_or_default(),
grammar: c.grammar.unwrap_or_else(|| name.to_string()),
grammar_dir: c.grammar_dir,
query_dir: c.query_dir,
comment_token: c.comment_token,
block_comment_token: c.block_comment_token,
editor: c.editor,
lsp,
formatter,
})
}
pub(super) fn build_extension_index(langs: &HashMap<String, Language>) -> HashMap<String, String> {
let mut idx = HashMap::new();
for (name, lang) in langs {
for ext in &lang.extensions {
idx.insert(ext.clone(), name.clone());
}
}
idx
}
pub(super) fn build_filename_index(langs: &HashMap<String, Language>) -> HashMap<String, String> {
let mut idx = HashMap::new();
for (name, lang) in langs {
for fname in &lang.filenames {
idx.insert(fname.clone(), name.clone());
}
}
idx
}