languages.rs

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