Skip to content

Commit e4ac5e8

Browse files
committed
restore language auto
1 parent 63f9b19 commit e4ac5e8

3 files changed

Lines changed: 50 additions & 0 deletions

File tree

src/advanced.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ use std::{borrow::Cow, fmt, ops::Range};
2222
#[derive(Debug, Clone, PartialEq, Eq)]
2323
#[non_exhaustive]
2424
pub enum HighlightError {
25+
/// [`Language::Auto`] could not detect a supported language.
26+
#[cfg(feature = "detection")]
27+
LanguageDetectionFailed,
2528
/// The tree-sitter parser rejected the selected grammar.
2629
GrammarLoad {
2730
/// The language whose grammar failed to load.
@@ -92,6 +95,8 @@ impl HighlightError {
9295
impl fmt::Display for HighlightError {
9396
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
9497
match self {
98+
#[cfg(feature = "detection")]
99+
Self::LanguageDetectionFailed => write!(f, "could not detect language"),
95100
Self::GrammarLoad { language, message } => {
96101
write!(
97102
f,
@@ -624,6 +629,7 @@ impl Buffer {
624629
/// ```
625630
pub fn new(language: Language, source: impl ToString) -> Result<Self, HighlightError> {
626631
let source = source.to_string();
632+
let language = resolve_language(language, &source)?;
627633
let (mut parser, incremental) = Self::parser_for(language)?;
628634
let mut cursor = arborium_tree_sitter::QueryCursor::new();
629635
let (tree, spans) = Self::parse_source(
@@ -733,6 +739,7 @@ impl Buffer {
733739
/// assert_eq!(buffer.language(), Language::Rust);
734740
/// ```
735741
pub fn set_language(&mut self, language: Language) -> Result<(), HighlightError> {
742+
let language = resolve_language(language, &self.source)?;
736743
if self.language == language {
737744
return Ok(());
738745
}
@@ -853,11 +860,23 @@ fn collect_spans(
853860
normalize_spans(raw)
854861
}
855862

863+
#[cfg(feature = "runtime")]
864+
fn resolve_language(language: Language, _source: &str) -> Result<Language, HighlightError> {
865+
#[cfg(feature = "detection")]
866+
if language == Language::Auto {
867+
return Language::detect(_source).ok_or(HighlightError::LanguageDetectionFailed);
868+
}
869+
870+
Ok(language)
871+
}
872+
856873
#[cfg(feature = "runtime")]
857874
fn grammar_for(language: Language) -> (arborium_tree_sitter::LanguageFn, &'static str) {
858875
// Rust is bundled with the `runtime` feature; everything else is opt-in via
859876
// its `lang-*` cargo feature (or the `all-languages` umbrella).
860877
match language {
878+
#[cfg(feature = "detection")]
879+
Language::Auto => unreachable!("auto language must be resolved before loading a grammar"),
861880
Language::Rust => (
862881
arborium::lang_rust::language(),
863882
arborium::lang_rust::HIGHLIGHTS_QUERY,

src/language.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ macro_rules! define_languages {
2626
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2727
#[non_exhaustive]
2828
pub enum Language {
29+
/// Automatically detect the language from the source text.
30+
#[cfg(feature = "detection")]
31+
Auto,
2932
$(
3033
$(#[$attr])*
3134
#[doc = concat!("Arborium slug `\"", $slug, "\"`.")]
@@ -44,6 +47,8 @@ macro_rules! define_languages {
4447
/// assert!(Language::ALL.contains(&Language::Rust));
4548
/// ```
4649
pub const ALL: &'static [Language] = &[
50+
#[cfg(feature = "detection")]
51+
Self::Auto,
4752
$(
4853
$(#[$attr])*
4954
Self::$variant,
@@ -53,6 +58,8 @@ macro_rules! define_languages {
5358
/// Arborium slug for this language.
5459
pub const fn slug(self) -> &'static str {
5560
match self {
61+
#[cfg(feature = "detection")]
62+
Self::Auto => "auto",
5663
$(
5764
$(#[$attr])*
5865
Self::$variant => $slug,

src/lib.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,14 @@ pub struct SourceCode {
229229
language: Language,
230230
}
231231

232+
/// Source-first builder for [`SourceCode`].
233+
#[cfg(feature = "runtime")]
234+
#[cfg_attr(docsrs, doc(cfg(feature = "runtime")))]
235+
#[derive(Debug, Clone, PartialEq, Eq)]
236+
pub struct SourceCodeBuilder {
237+
source: String,
238+
}
239+
232240
#[cfg(feature = "runtime")]
233241
#[cfg_attr(docsrs, doc(cfg(feature = "runtime")))]
234242
impl SourceCode {
@@ -245,6 +253,13 @@ impl SourceCode {
245253
}
246254
}
247255

256+
/// Start a source-first builder.
257+
pub fn builder(source: impl ToString) -> SourceCodeBuilder {
258+
SourceCodeBuilder {
259+
source: source.to_string(),
260+
}
261+
}
262+
248263
/// Replace the language used to highlight this source.
249264
///
250265
/// To set the language from a runtime slug, use [`Language::from_slug`]
@@ -277,6 +292,15 @@ impl SourceCode {
277292
}
278293
}
279294

295+
#[cfg(feature = "runtime")]
296+
#[cfg_attr(docsrs, doc(cfg(feature = "runtime")))]
297+
impl SourceCodeBuilder {
298+
/// Finish the builder with an explicit language.
299+
pub fn with_language(self, language: Language) -> SourceCode {
300+
SourceCode::new(language, self.source)
301+
}
302+
}
303+
280304
#[cfg(feature = "runtime")]
281305
pub(crate) struct RawHighlightSpan {
282306
pub(crate) start: u32,

0 commit comments

Comments
 (0)