@@ -215,7 +215,7 @@ pub use advanced::{HighlightError, HighlightQueryErrorKind};
215215/// Source text to highlight at runtime.
216216///
217217/// Available with the `runtime` feature. Build one with [`SourceCode::new`],
218- /// then pass it to [`Code()`].
218+ /// or with [`SourceCode::builder`], then pass it to [`Code()`].
219219///
220220/// ```rust
221221/// use dioxus_code::{Language, SourceCode};
@@ -230,11 +230,39 @@ pub struct SourceCode {
230230}
231231
232232/// Source-first builder for [`SourceCode`].
233+ ///
234+ /// Call [`SourceCodeBuilder::with_language`] to set the language, then
235+ /// `build()` to produce [`SourceCode`]. With the `detection` feature enabled,
236+ /// `build()` may also be called without an explicit language to detect from
237+ /// the source text.
238+ ///
239+ /// ```rust
240+ /// use dioxus_code::{Language, SourceCode};
241+ ///
242+ /// let _src = SourceCode::builder("fn main() {}")
243+ /// .with_language(Language::Rust)
244+ /// .build();
245+ /// ```
233246#[ cfg( feature = "runtime" ) ]
234247#[ cfg_attr( docsrs, doc( cfg( feature = "runtime" ) ) ) ]
235248#[ derive( Debug , Clone , PartialEq , Eq ) ]
236- pub struct SourceCodeBuilder {
249+ pub struct SourceCodeBuilder < State = SourceCodeBuilderMissingLanguage > {
237250 source : String ,
251+ state : State ,
252+ }
253+
254+ /// Builder state before a [`SourceCodeBuilder`] has a language.
255+ #[ cfg( feature = "runtime" ) ]
256+ #[ cfg_attr( docsrs, doc( cfg( feature = "runtime" ) ) ) ]
257+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
258+ pub struct SourceCodeBuilderMissingLanguage ;
259+
260+ /// Builder state after a [`SourceCodeBuilder`] has a language.
261+ #[ cfg( feature = "runtime" ) ]
262+ #[ cfg_attr( docsrs, doc( cfg( feature = "runtime" ) ) ) ]
263+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
264+ pub struct SourceCodeBuilderWithLanguage {
265+ language : Language ,
238266}
239267
240268#[ cfg( feature = "runtime" ) ]
@@ -257,6 +285,7 @@ impl SourceCode {
257285 pub fn builder ( source : impl ToString ) -> SourceCodeBuilder {
258286 SourceCodeBuilder {
259287 source : source. to_string ( ) ,
288+ state : SourceCodeBuilderMissingLanguage ,
260289 }
261290 }
262291
@@ -294,10 +323,38 @@ impl SourceCode {
294323
295324#[ cfg( feature = "runtime" ) ]
296325#[ 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 )
326+ impl SourceCodeBuilder < SourceCodeBuilderMissingLanguage > {
327+ /// Set the language that will be used to highlight this source.
328+ pub fn with_language (
329+ self ,
330+ language : Language ,
331+ ) -> SourceCodeBuilder < SourceCodeBuilderWithLanguage > {
332+ SourceCodeBuilder {
333+ source : self . source ,
334+ state : SourceCodeBuilderWithLanguage { language } ,
335+ }
336+ }
337+
338+ /// Finish the builder, detecting the language from the source text.
339+ #[ cfg( feature = "detection" ) ]
340+ #[ cfg_attr( docsrs, doc( cfg( feature = "detection" ) ) ) ]
341+ pub fn build ( self ) -> SourceCode {
342+ SourceCode :: new ( Language :: Auto , self . source )
343+ }
344+ }
345+
346+ #[ cfg( feature = "runtime" ) ]
347+ #[ cfg_attr( docsrs, doc( cfg( feature = "runtime" ) ) ) ]
348+ impl SourceCodeBuilder < SourceCodeBuilderWithLanguage > {
349+ /// Replace the language that will be used to highlight this source.
350+ pub fn with_language ( mut self , language : Language ) -> Self {
351+ self . state . language = language;
352+ self
353+ }
354+
355+ /// Finish the builder.
356+ pub fn build ( self ) -> SourceCode {
357+ SourceCode :: new ( self . state . language , self . source )
301358 }
302359}
303360
@@ -501,6 +558,25 @@ mod tests {
501558 } ) ) ;
502559 }
503560
561+ #[ cfg( feature = "runtime" ) ]
562+ #[ test]
563+ fn source_code_builder_builds_after_language_is_set ( ) {
564+ let tree: advanced:: HighlightedSource = SourceCode :: builder ( "fn main() {}" )
565+ . with_language ( Language :: Rust )
566+ . build ( )
567+ . into ( ) ;
568+ assert_eq ! ( tree. language( ) , Language :: Rust ) ;
569+ assert_eq ! ( tree. source( ) , "fn main() {}" ) ;
570+ }
571+
572+ #[ cfg( feature = "detection" ) ]
573+ #[ test]
574+ fn source_code_builder_can_detect_language_when_enabled ( ) {
575+ let tree: advanced:: HighlightedSource = SourceCode :: builder ( "fn main() {}" ) . build ( ) . into ( ) ;
576+ assert_eq ! ( tree. language( ) , Language :: Rust ) ;
577+ assert_eq ! ( tree. source( ) , "fn main() {}" ) ;
578+ }
579+
504580 #[ cfg( feature = "macro" ) ]
505581 #[ test]
506582 fn code_str_macro_highlights_inline_source ( ) {
0 commit comments