use std::{
collections::{HashMap, HashSet},
fs, io,
path::PathBuf,
};
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum ConfigError {
#[error("no configuration directory known for your system; please adjust XDG_CONFIG_HOME")]
NoConfigDir,
#[error("cannot read configuration: {err}")]
CannotReadConfig { err: io::Error },
#[error("cannot parse configuration: {err}")]
CannotParseConfig { err: String },
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Config {
pub highlight: HighlightConfig,
#[serde(flatten)]
pub languages: LanguagesConfig,
}
impl Config {
pub fn load_from_xdg() -> Result<Config, ConfigError> {
let dir = dirs::config_dir().ok_or(ConfigError::NoConfigDir)?;
let path = dir.join("kak-tree-sitter/config.toml");
let content = fs::read_to_string(path).map_err(|err| ConfigError::CannotReadConfig { err })?;
toml::from_str(&content).map_err(|err| ConfigError::CannotParseConfig {
err: err.to_string(),
})
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct HighlightConfig {
pub groups: HashSet<String>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct LanguagesConfig {
pub language: HashMap<String, LanguageConfig>,
}
impl LanguagesConfig {
pub fn get_lang_conf(&self, lang: impl AsRef<str>) -> Option<&LanguageConfig> {
self.language.get(lang.as_ref())
}
pub fn get_grammars_dir() -> Option<PathBuf> {
dirs::data_dir().map(|dir| dir.join("kak-tree-sitter/grammars"))
}
pub fn get_grammar_path(lang: impl AsRef<str>) -> Option<PathBuf> {
let lang = lang.as_ref();
dirs::data_dir().map(|dir| dir.join(format!("kak-tree-sitter/grammars/{lang}.so")))
}
pub fn get_queries_dir(lang: impl AsRef<str>) -> Option<PathBuf> {
let lang = lang.as_ref();
dirs::data_dir().map(|dir| dir.join(format!("kak-tree-sitter/queries/{lang}")))
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct LanguageConfig {
pub grammar: LanguageGrammarConfig,
pub queries: LanguageQueriesConfig,
#[serde(default)]
pub remove_default_highlighter: RemoveDefaultHighlighter,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct RemoveDefaultHighlighter(pub bool);
impl Default for RemoveDefaultHighlighter {
fn default() -> Self {
RemoveDefaultHighlighter(true)
}
}
impl RemoveDefaultHighlighter {
pub fn to_bool(self) -> bool {
self.0
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct LanguageGrammarConfig {
pub url: String,
pub pin: Option<String>,
pub path: PathBuf,
pub compile: String,
pub compile_args: Vec<String>,
pub compile_flags: Vec<String>,
pub link: String,
pub link_args: Vec<String>,
pub link_flags: Vec<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct LanguageQueriesConfig {
pub url: Option<String>,
pub pin: Option<String>,
pub path: PathBuf,
}