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}