languages.rs

  1use gpui::executor::Background;
  2pub use language::*;
  3use rust_embed::RustEmbed;
  4use std::{borrow::Cow, str, sync::Arc};
  5use util::ResultExt;
  6
  7mod c;
  8mod go;
  9mod installation;
 10mod language_plugin;
 11mod python;
 12mod rust;
 13mod typescript;
 14
 15#[derive(RustEmbed)]
 16#[folder = "src/languages"]
 17#[exclude = "*.rs"]
 18struct LanguageDir;
 19
 20pub async fn init(languages: Arc<LanguageRegistry>, executor: Arc<Background>) {
 21    for (name, grammar, lsp_adapter) in [
 22        (
 23            "c",
 24            tree_sitter_c::language(),
 25            Some(CachedLspAdapter::new(c::CLspAdapter).await),
 26        ),
 27        (
 28            "cpp",
 29            tree_sitter_cpp::language(),
 30            Some(CachedLspAdapter::new(c::CLspAdapter).await),
 31        ),
 32        (
 33            "go",
 34            tree_sitter_go::language(),
 35            Some(CachedLspAdapter::new(go::GoLspAdapter).await),
 36        ),
 37        (
 38            "json",
 39            tree_sitter_json::language(),
 40            match language_plugin::new_json(executor).await.log_err() {
 41                Some(lang) => Some(CachedLspAdapter::new(lang).await),
 42                None => None,
 43            },
 44        ),
 45        (
 46            "markdown",
 47            tree_sitter_markdown::language(),
 48            None, //
 49        ),
 50        (
 51            "python",
 52            tree_sitter_python::language(),
 53            Some(CachedLspAdapter::new(python::PythonLspAdapter).await),
 54        ),
 55        (
 56            "rust",
 57            tree_sitter_rust::language(),
 58            Some(CachedLspAdapter::new(rust::RustLspAdapter).await),
 59        ),
 60        (
 61            "toml",
 62            tree_sitter_toml::language(),
 63            None, //
 64        ),
 65        (
 66            "tsx",
 67            tree_sitter_typescript::language_tsx(),
 68            Some(CachedLspAdapter::new(typescript::TypeScriptLspAdapter).await),
 69        ),
 70        (
 71            "typescript",
 72            tree_sitter_typescript::language_typescript(),
 73            Some(CachedLspAdapter::new(typescript::TypeScriptLspAdapter).await),
 74        ),
 75        (
 76            "javascript",
 77            tree_sitter_typescript::language_tsx(),
 78            Some(CachedLspAdapter::new(typescript::TypeScriptLspAdapter).await),
 79        ),
 80    ] {
 81        languages.add(Arc::new(language(name, grammar, lsp_adapter)));
 82    }
 83}
 84
 85pub(crate) fn language(
 86    name: &str,
 87    grammar: tree_sitter::Language,
 88    lsp_adapter: Option<Arc<CachedLspAdapter>>,
 89) -> Language {
 90    let config = toml::from_slice(
 91        &LanguageDir::get(&format!("{}/config.toml", name))
 92            .unwrap()
 93            .data,
 94    )
 95    .unwrap();
 96    let mut language = Language::new(config, Some(grammar));
 97
 98    if let Some(query) = load_query(name, "/highlights") {
 99        language = language
100            .with_highlights_query(query.as_ref())
101            .expect("failed to evaluate highlights query");
102    }
103    if let Some(query) = load_query(name, "/brackets") {
104        language = language
105            .with_brackets_query(query.as_ref())
106            .expect("failed to load brackets query");
107    }
108    if let Some(query) = load_query(name, "/indents") {
109        language = language
110            .with_indents_query(query.as_ref())
111            .expect("failed to load indents query");
112    }
113    if let Some(query) = load_query(name, "/outline") {
114        language = language
115            .with_outline_query(query.as_ref())
116            .expect("failed to load outline query");
117    }
118    if let Some(lsp_adapter) = lsp_adapter {
119        language = language.with_lsp_adapter(lsp_adapter)
120    }
121    language
122}
123
124fn load_query(name: &str, filename_prefix: &str) -> Option<Cow<'static, str>> {
125    let mut result = None;
126    for path in LanguageDir::iter() {
127        if let Some(remainder) = path.strip_prefix(name) {
128            if remainder.starts_with(filename_prefix) {
129                let contents = match LanguageDir::get(path.as_ref()).unwrap().data {
130                    Cow::Borrowed(s) => Cow::Borrowed(str::from_utf8(s).unwrap()),
131                    Cow::Owned(s) => Cow::Owned(String::from_utf8(s).unwrap()),
132                };
133                match &mut result {
134                    None => result = Some(contents),
135                    Some(r) => r.to_mut().push_str(contents.as_ref()),
136                }
137            }
138        }
139    }
140    result
141}