highlighter: Avoid crash when language not registered. (#954)
Close #952 Fallback to use plain text to display.
This commit is contained in:
parent
1032881103
commit
89c210c4ca
3 changed files with 64 additions and 51 deletions
|
|
@ -118,11 +118,12 @@ impl Example {
|
|||
&language_state,
|
||||
|this, state, _: &DropdownEvent<Vec<SharedString>>, cx| {
|
||||
if let Some(val) = state.read(cx).selected_value() {
|
||||
if let Some(language) = Language::from_str(&val) {
|
||||
this.language = Lang::BuiltIn(language);
|
||||
} else {
|
||||
if val == "navi" {
|
||||
this.language = Lang::External("navi");
|
||||
} else {
|
||||
this.language = Lang::BuiltIn(Language::from_str(&val));
|
||||
}
|
||||
|
||||
this.need_update = true;
|
||||
cx.notify();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use super::HighlightTheme;
|
||||
use crate::highlighter::LanguageRegistry;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use gpui::{App, HighlightStyle, SharedString};
|
||||
use indexset::BTreeMap;
|
||||
use std::{
|
||||
|
|
@ -44,21 +45,34 @@ pub struct SyntaxHighlighter {
|
|||
impl SyntaxHighlighter {
|
||||
/// Create a new SyntaxHighlighter for HTML.
|
||||
pub fn new(lang: &str, cx: &App) -> Self {
|
||||
Self::build_combined_injections_query(&lang, cx).unwrap_or_else(|| panic!(
|
||||
"failed to build language {}, please make sure have registered the language in LanguageRegistry",
|
||||
lang
|
||||
))
|
||||
match Self::build_combined_injections_query(&lang, cx) {
|
||||
Ok(result) => result,
|
||||
Err(err) => {
|
||||
tracing::warn!(
|
||||
"SyntaxHighlighter init failed, fallback to use `text`, {}",
|
||||
err
|
||||
);
|
||||
Self::build_combined_injections_query("text", cx).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the combined injections query for the given language.
|
||||
///
|
||||
/// https://github.com/tree-sitter/tree-sitter/blob/v0.25.5/highlight/src/lib.rs#L336
|
||||
fn build_combined_injections_query(lang: &str, cx: &App) -> Option<Self> {
|
||||
fn build_combined_injections_query(lang: &str, cx: &App) -> Result<Self> {
|
||||
let registry = LanguageRegistry::global(cx);
|
||||
let config = registry.language(&lang)?;
|
||||
let Some(config) = registry.language(&lang) else {
|
||||
return Err(anyhow!(
|
||||
"language {:?} is not registered in `LanguageRegistry`",
|
||||
lang
|
||||
));
|
||||
};
|
||||
|
||||
let mut parser = Parser::new();
|
||||
_ = parser.set_language(&config.language);
|
||||
parser
|
||||
.set_language(&config.language)
|
||||
.context("parse set_language")?;
|
||||
|
||||
// Concatenate the query strings, keeping track of the start offset of each section.
|
||||
let mut query_source = String::new();
|
||||
|
|
@ -70,12 +84,7 @@ impl SyntaxHighlighter {
|
|||
|
||||
// Construct a single query by concatenating the three query strings, but record the
|
||||
// range of pattern indices that belong to each individual string.
|
||||
let query = match Query::new(&config.language, &query_source) {
|
||||
Ok(query) => Some(query),
|
||||
Err(err) => {
|
||||
panic!("failed create Query for language {}, err: {}", lang, err);
|
||||
}
|
||||
}?;
|
||||
let query = Query::new(&config.language, &query_source).context("new query")?;
|
||||
|
||||
let mut locals_pattern_index = 0;
|
||||
let mut highlights_pattern_index = 0;
|
||||
|
|
@ -164,7 +173,7 @@ impl SyntaxHighlighter {
|
|||
|
||||
// let highlight_indices = vec![None; query.capture_names().len()];
|
||||
|
||||
Some(Self {
|
||||
Ok(Self {
|
||||
language: config.name.clone(),
|
||||
query: Some(query),
|
||||
injection_queries,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use gpui::SharedString;
|
|||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, enum_iterator::Sequence)]
|
||||
pub enum Language {
|
||||
Plain,
|
||||
Bash,
|
||||
C,
|
||||
CMake,
|
||||
|
|
@ -78,6 +79,7 @@ impl Language {
|
|||
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Plain => "text",
|
||||
Self::Bash => "bash",
|
||||
Self::C => "c",
|
||||
Self::CMake => "cmake",
|
||||
|
|
@ -113,41 +115,41 @@ impl Language {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_str(s: &str) -> Option<Self> {
|
||||
pub fn from_str(s: &str) -> Self {
|
||||
match s {
|
||||
"bash" | "sh" => Some(Self::Bash),
|
||||
"c" => Some(Self::C),
|
||||
"cmake" => Some(Self::CMake),
|
||||
"cpp" | "c++" => Some(Self::Cpp),
|
||||
"csharp" | "cs" => Some(Self::CSharp),
|
||||
"css" | "scss" => Some(Self::Css),
|
||||
"diff" => Some(Self::Diff),
|
||||
"ejs" => Some(Self::Ejs),
|
||||
"elixir" | "ex" => Some(Self::Elixir),
|
||||
"erb" => Some(Self::Erb),
|
||||
"go" => Some(Self::Go),
|
||||
"graphql" => Some(Self::GraphQL),
|
||||
"html" => Some(Self::Html),
|
||||
"java" => Some(Self::Java),
|
||||
"javascript" | "js" => Some(Self::JavaScript),
|
||||
"jsdoc" => Some(Self::JsDoc),
|
||||
"json" | "jsonc" => Some(Self::Json),
|
||||
"make" | "makefile" => Some(Self::Make),
|
||||
"markdown" | "md" | "mdx" => Some(Self::Markdown),
|
||||
"markdown_inline" | "markdown-inline" => Some(Self::MarkdownInline),
|
||||
"proto" | "protobuf" => Some(Self::Proto),
|
||||
"python" | "py" => Some(Self::Python),
|
||||
"ruby" | "rb" => Some(Self::Ruby),
|
||||
"rust" | "rs" => Some(Self::Rust),
|
||||
"scala" => Some(Self::Scala),
|
||||
"sql" => Some(Self::Sql),
|
||||
"swift" => Some(Self::Swift),
|
||||
"toml" => Some(Self::Toml),
|
||||
"tsx" => Some(Self::Tsx),
|
||||
"typescript" | "ts" => Some(Self::TypeScript),
|
||||
"yaml" | "yml" => Some(Self::Yaml),
|
||||
"zig" => Some(Self::Zig),
|
||||
_ => None,
|
||||
"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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -182,6 +184,7 @@ impl 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"),
|
||||
|
|
|
|||
Loading…
Reference in a new issue