use gpui::SharedString; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, enum_iterator::Sequence)] pub enum Language { Plain, Bash, C, CMake, CSharp, Cpp, Css, Diff, Ejs, Elixir, Erb, Go, GraphQL, Html, Java, JavaScript, JsDoc, Json, Make, Markdown, MarkdownInline, Proto, Python, Ruby, Rust, Scala, Sql, Swift, Toml, Tsx, TypeScript, Yaml, Zig, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct LanguageConfig { pub name: SharedString, pub language: tree_sitter::Language, pub injection_languages: Vec, pub highlights: SharedString, pub injections: SharedString, pub locals: SharedString, } impl LanguageConfig { pub fn new( name: impl Into, language: tree_sitter::Language, injection_languages: Vec, highlights: &str, injections: &str, locals: &str, ) -> Self { Self { name: name.into(), language, injection_languages, highlights: SharedString::from(highlights.to_string()), injections: SharedString::from(injections.to_string()), locals: SharedString::from(locals.to_string()), } } } impl From for SharedString { fn from(language: Language) -> Self { language.name().into() } } impl Language { pub fn all() -> impl Iterator { enum_iterator::all::() } pub fn name(&self) -> &'static str { match self { Self::Plain => "text", Self::Bash => "bash", Self::C => "c", Self::CMake => "cmake", Self::CSharp => "csharp", Self::Cpp => "cpp", Self::Css => "css", Self::Diff => "diff", Self::Ejs => "ejs", Self::Elixir => "elixir", Self::Erb => "erb", Self::Go => "go", Self::GraphQL => "graphql", Self::Html => "html", Self::Java => "java", Self::JavaScript => "javascript", Self::JsDoc => "jsdoc", Self::Json => "json", Self::Make => "make", Self::Markdown => "markdown", Self::MarkdownInline => "markdown_inline", Self::Proto => "proto", Self::Python => "python", Self::Ruby => "ruby", Self::Rust => "rust", Self::Scala => "scala", Self::Sql => "sql", Self::Swift => "swift", Self::Toml => "toml", Self::Tsx => "tsx", Self::TypeScript => "typescript", Self::Yaml => "yaml", Self::Zig => "zig", } } pub fn from_str(s: &str) -> Self { match s { "bash" | "sh" => Self::Bash, "c" => Self::C, "cmake" => Self::CMake, "cpp" | "c++" => Self::Cpp, "csharp" | "cs" => Self::CSharp, "css" | "scss" => Self::Css, "diff" => Self::Diff, "ejs" => Self::Ejs, "elixir" | "ex" => Self::Elixir, "erb" => Self::Erb, "go" => Self::Go, "graphql" => Self::GraphQL, "html" => Self::Html, "java" => Self::Java, "javascript" | "js" => Self::JavaScript, "jsdoc" => Self::JsDoc, "json" | "jsonc" => Self::Json, "make" | "makefile" => Self::Make, "markdown" | "md" | "mdx" => Self::Markdown, "markdown_inline" | "markdown-inline" => Self::MarkdownInline, "proto" | "protobuf" => Self::Proto, "python" | "py" => Self::Python, "ruby" | "rb" => Self::Ruby, "rust" | "rs" => Self::Rust, "scala" => Self::Scala, "sql" => Self::Sql, "swift" => Self::Swift, "toml" => Self::Toml, "tsx" => Self::Tsx, "typescript" | "ts" => Self::TypeScript, "yaml" | "yml" => Self::Yaml, "zig" => Self::Zig, _ => Self::Plain, } } #[allow(unused)] pub(super) fn injection_languages(&self) -> Vec { match self { Self::Markdown => vec!["markdown-inline", "html", "toml", "yaml"], Self::MarkdownInline => vec![], Self::Html => vec!["javascript", "css"], Self::Rust => vec!["rust"], Self::JavaScript | Self::TypeScript => vec![ "jsdoc", "json", "css", "html", "sql", "typescript", "javascript", "tsx", "yaml", "graphql", ], _ => vec![], } .into_iter() .map(|s| s.into()) .collect() } /// Return the language info for the language. /// /// (language, query, injection, locals) pub(super) fn config(&self) -> LanguageConfig { let (language, query, injection, locals) = match self { Self::Plain => (tree_sitter_json::LANGUAGE, "", "", ""), Self::Json => ( tree_sitter_json::LANGUAGE, include_str!("languages/json/highlights.scm"), "", "", ), Self::Markdown => ( tree_sitter_md::LANGUAGE, include_str!("languages/markdown/highlights.scm"), include_str!("languages/markdown/injections.scm"), "", ), Self::MarkdownInline => ( tree_sitter_md::INLINE_LANGUAGE, include_str!("languages/markdown_inline/highlights.scm"), "", "", ), Self::Toml => ( tree_sitter_toml_ng::LANGUAGE, tree_sitter_toml_ng::HIGHLIGHTS_QUERY, "", "", ), Self::Yaml => ( tree_sitter_yaml::LANGUAGE, tree_sitter_yaml::HIGHLIGHTS_QUERY, "", "", ), Self::Rust => ( tree_sitter_rust::LANGUAGE, include_str!("languages/rust/highlights.scm"), include_str!("languages/rust/injections.scm"), "", ), Self::Go => ( tree_sitter_go::LANGUAGE, include_str!("languages/go/highlights.scm"), "", "", ), Self::C => ( tree_sitter_c::LANGUAGE, tree_sitter_c::HIGHLIGHT_QUERY, "", "", ), Self::Cpp => ( tree_sitter_cpp::LANGUAGE, tree_sitter_cpp::HIGHLIGHT_QUERY, "", "", ), Self::JavaScript => ( tree_sitter_javascript::LANGUAGE, include_str!("languages/javascript/highlights.scm"), include_str!("languages/javascript/injections.scm"), tree_sitter_javascript::LOCALS_QUERY, ), Self::JsDoc => ( tree_sitter_jsdoc::LANGUAGE, tree_sitter_jsdoc::HIGHLIGHTS_QUERY, "", "", ), Self::Zig => ( tree_sitter_zig::LANGUAGE, include_str!("languages/zig/highlights.scm"), include_str!("languages/zig/injections.scm"), "", ), Self::Java => ( tree_sitter_java::LANGUAGE, tree_sitter_java::HIGHLIGHTS_QUERY, "", "", ), Self::Python => ( tree_sitter_python::LANGUAGE, tree_sitter_python::HIGHLIGHTS_QUERY, "", "", ), Self::Ruby => ( tree_sitter_ruby::LANGUAGE, tree_sitter_ruby::HIGHLIGHTS_QUERY, "", tree_sitter_ruby::LOCALS_QUERY, ), Self::Bash => ( tree_sitter_bash::LANGUAGE, tree_sitter_bash::HIGHLIGHT_QUERY, "", "", ), Self::Html => ( tree_sitter_html::LANGUAGE, include_str!("languages/html/highlights.scm"), include_str!("languages/html/injections.scm"), "", ), Self::Css => ( tree_sitter_css::LANGUAGE, tree_sitter_css::HIGHLIGHTS_QUERY, "", "", ), Self::Swift => (tree_sitter_swift::LANGUAGE, "", "", ""), Self::Scala => ( tree_sitter_scala::LANGUAGE, tree_sitter_scala::HIGHLIGHTS_QUERY, "", tree_sitter_scala::LOCALS_QUERY, ), Self::Sql => ( tree_sitter_sequel::LANGUAGE, tree_sitter_sequel::HIGHLIGHTS_QUERY, "", "", ), Self::CSharp => (tree_sitter_c_sharp::LANGUAGE, "", "", ""), Self::GraphQL => (tree_sitter_graphql::LANGUAGE, "", "", ""), Self::Proto => (tree_sitter_proto::LANGUAGE, "", "", ""), Self::Make => ( tree_sitter_make::LANGUAGE, tree_sitter_make::HIGHLIGHTS_QUERY, "", "", ), Self::CMake => (tree_sitter_cmake::LANGUAGE, "", "", ""), Self::TypeScript => ( tree_sitter_typescript::LANGUAGE_TYPESCRIPT, include_str!("languages/typescript/highlights.scm"), include_str!("languages/javascript/injections.scm"), tree_sitter_typescript::LOCALS_QUERY, ), Self::Tsx => ( tree_sitter_typescript::LANGUAGE_TSX, tree_sitter_typescript::HIGHLIGHTS_QUERY, "", tree_sitter_typescript::LOCALS_QUERY, ), Self::Diff => ( tree_sitter_diff::LANGUAGE, tree_sitter_diff::HIGHLIGHTS_QUERY, "", "", ), Self::Elixir => ( tree_sitter_elixir::LANGUAGE, tree_sitter_elixir::HIGHLIGHTS_QUERY, tree_sitter_elixir::INJECTIONS_QUERY, "", ), Self::Erb => ( tree_sitter_embedded_template::LANGUAGE, tree_sitter_embedded_template::HIGHLIGHTS_QUERY, tree_sitter_embedded_template::INJECTIONS_EJS_QUERY, "", ), Self::Ejs => ( tree_sitter_embedded_template::LANGUAGE, tree_sitter_embedded_template::HIGHLIGHTS_QUERY, tree_sitter_embedded_template::INJECTIONS_EJS_QUERY, "", ), }; let language = tree_sitter::Language::new(language); LanguageConfig::new( self.name(), language, self.injection_languages(), query, injection, locals, ) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_language_name() { assert_eq!(Language::MarkdownInline.name(), "markdown_inline"); assert_eq!(Language::Markdown.name(), "markdown"); assert_eq!(Language::Json.name(), "json"); assert_eq!(Language::Yaml.name(), "yaml"); assert_eq!(Language::Rust.name(), "rust"); assert_eq!(Language::Go.name(), "go"); assert_eq!(Language::C.name(), "c"); assert_eq!(Language::Cpp.name(), "cpp"); assert_eq!(Language::Sql.name(), "sql"); assert_eq!(Language::JavaScript.name(), "javascript"); assert_eq!(Language::Zig.name(), "zig"); assert_eq!(Language::CSharp.name(), "csharp"); assert_eq!(Language::TypeScript.name(), "typescript"); assert_eq!(Language::Tsx.name(), "tsx"); assert_eq!(Language::Diff.name(), "diff"); assert_eq!(Language::Elixir.name(), "elixir"); assert_eq!(Language::Erb.name(), "erb"); assert_eq!(Language::Ejs.name(), "ejs"); } }