@@ -29,6 +29,7 @@ pub struct PreparedMdx {
2929 pub code_blocks : Vec < CodeBlock > ,
3030 pub dependencies : Vec < PathBuf > ,
3131 pub diagnostics : Vec < Diagnostic > ,
32+ pub reading_words : usize ,
3233 pub ( crate ) tree : mdxjs:: hast:: Node ,
3334}
3435
@@ -94,6 +95,7 @@ pub fn prepare_mdx(
9495 let options = mdx_options ( file, config) ;
9596 let mdast = mdxjs:: mdast_util_from_mdx ( body, & options)
9697 . map_err ( |error| vec ! [ mdx_diagnostic( file, error) ] ) ?;
98+ let reading_words = reading_units ( & mdast) ;
9799 let mut code_blocks = Vec :: new ( ) ;
98100 if highlight {
99101 collect_code_blocks ( & mdast, document_id, & mut code_blocks) ;
@@ -108,10 +110,47 @@ pub fn prepare_mdx(
108110 code_blocks,
109111 dependencies : media. dependencies ,
110112 diagnostics : media. diagnostics ,
113+ reading_words,
111114 tree,
112115 } )
113116}
114117
118+ fn reading_units ( node : & markdown:: mdast:: Node ) -> usize {
119+ match node {
120+ markdown:: mdast:: Node :: Code ( _) | markdown:: mdast:: Node :: InlineCode ( _) => 0 ,
121+ markdown:: mdast:: Node :: Text ( text) => count_reading_units ( & text. value ) ,
122+ _ => node
123+ . children ( )
124+ . map ( |children| children. iter ( ) . map ( reading_units) . sum ( ) )
125+ . unwrap_or_default ( ) ,
126+ }
127+ }
128+
129+ fn count_reading_units ( text : & str ) -> usize {
130+ let mut count = 0 ;
131+ let mut in_english_word = false ;
132+ for character in text. chars ( ) {
133+ if matches ! (
134+ character,
135+ '\u{4e00}' ..='\u{9fff}'
136+ | '\u{3040}' ..='\u{309f}'
137+ | '\u{30a0}' ..='\u{30ff}'
138+ | '\u{ac00}' ..='\u{d7af}'
139+ ) {
140+ count += 1 ;
141+ in_english_word = false ;
142+ } else if character. is_ascii_alphabetic ( ) {
143+ if !in_english_word {
144+ count += 1 ;
145+ in_english_word = true ;
146+ }
147+ } else {
148+ in_english_word = false ;
149+ }
150+ }
151+ count
152+ }
153+
115154pub fn finish_mdx (
116155 prepared : PreparedMdx ,
117156 file : & str ,
0 commit comments