@@ -213,6 +213,77 @@ impl<'a> Paragraph<'a> {
213
213
self . alignment = alignment;
214
214
self
215
215
}
216
+
217
+ /// Calculates the number of lines needed to fully render.
218
+ ///
219
+ /// Given a max line width, this method calculates the number of lines that a paragraph will
220
+ /// need in order to be fully rendered. For paragraphs that do not use wrapping, this count is
221
+ /// simply the number of lines present in the paragraph.
222
+ ///
223
+ /// # Example
224
+ ///
225
+ /// ```ignore
226
+ /// # use ratatui::{prelude::*, widgets::*};
227
+ /// let paragraph = Paragraph::new("Hello World")
228
+ /// .wrap(Wrap { trim: false });
229
+ /// assert_eq!(paragraph.line_count(20), 1);
230
+ /// assert_eq!(paragraph.line_count(10), 2);
231
+ /// ```
232
+ #[ stability:: unstable(
233
+ feature = "rendered-line-info" ,
234
+ reason = "The design for text wrapping is not stable and might affect this API." ,
235
+ issue = "https://github.com/ratatui-org/ratatui/issues/293"
236
+ ) ]
237
+ pub fn line_count ( & self , width : u16 ) -> usize {
238
+ if width < 1 {
239
+ return 0 ;
240
+ }
241
+
242
+ if let Some ( Wrap { trim } ) = self . wrap {
243
+ let styled = self . text . lines . iter ( ) . map ( |line| {
244
+ let graphemes = line
245
+ . spans
246
+ . iter ( )
247
+ . flat_map ( |span| span. styled_graphemes ( self . style ) ) ;
248
+ let alignment = line. alignment . unwrap_or ( self . alignment ) ;
249
+ ( graphemes, alignment)
250
+ } ) ;
251
+ let mut line_composer = WordWrapper :: new ( styled, width, trim) ;
252
+ let mut count = 0 ;
253
+ while line_composer. next_line ( ) . is_some ( ) {
254
+ count += 1 ;
255
+ }
256
+ count
257
+ } else {
258
+ self . text . lines . len ( )
259
+ }
260
+ }
261
+
262
+ /// Calculates the shortest line width needed to avoid any word being wrapped or truncated.
263
+ ///
264
+ /// # Example
265
+ ///
266
+ /// ```ignore
267
+ /// # use ratatui::{prelude::*, widgets::*};
268
+ /// let paragraph = Paragraph::new("Hello World");
269
+ /// assert_eq!(paragraph.line_width(), 11);
270
+ ///
271
+ /// let paragraph = Paragraph::new("Hello World\nhi\nHello World!!!");
272
+ /// assert_eq!(paragraph.line_width(), 14);
273
+ /// ```
274
+ #[ stability:: unstable(
275
+ feature = "rendered-line-info" ,
276
+ reason = "The design for text wrapping is not stable and might affect this API." ,
277
+ issue = "https://github.com/ratatui-org/ratatui/issues/293"
278
+ ) ]
279
+ pub fn line_width ( & self ) -> usize {
280
+ self . text
281
+ . lines
282
+ . iter ( )
283
+ . map ( |l| l. width ( ) )
284
+ . max ( )
285
+ . unwrap_or_default ( )
286
+ }
216
287
}
217
288
218
289
impl < ' a > Widget for Paragraph < ' a > {
@@ -815,4 +886,46 @@ mod test {
815
886
. remove_modifier( Modifier :: DIM )
816
887
)
817
888
}
889
+
890
+ #[ test]
891
+ fn widgets_paragraph_count_rendered_lines ( ) {
892
+ let paragraph = Paragraph :: new ( "Hello World" ) ;
893
+ assert_eq ! ( paragraph. line_count( 20 ) , 1 ) ;
894
+ assert_eq ! ( paragraph. line_count( 10 ) , 1 ) ;
895
+ let paragraph = Paragraph :: new ( "Hello World" ) . wrap ( Wrap { trim : false } ) ;
896
+ assert_eq ! ( paragraph. line_count( 20 ) , 1 ) ;
897
+ assert_eq ! ( paragraph. line_count( 10 ) , 2 ) ;
898
+ let paragraph = Paragraph :: new ( "Hello World" ) . wrap ( Wrap { trim : true } ) ;
899
+ assert_eq ! ( paragraph. line_count( 20 ) , 1 ) ;
900
+ assert_eq ! ( paragraph. line_count( 10 ) , 2 ) ;
901
+
902
+ let text = "Hello World " . repeat ( 100 ) ;
903
+ let paragraph = Paragraph :: new ( text. trim ( ) ) ;
904
+ assert_eq ! ( paragraph. line_count( 11 ) , 1 ) ;
905
+ assert_eq ! ( paragraph. line_count( 6 ) , 1 ) ;
906
+ let paragraph = paragraph. wrap ( Wrap { trim : false } ) ;
907
+ assert_eq ! ( paragraph. line_count( 11 ) , 100 ) ;
908
+ assert_eq ! ( paragraph. line_count( 6 ) , 200 ) ;
909
+ let paragraph = paragraph. wrap ( Wrap { trim : true } ) ;
910
+ assert_eq ! ( paragraph. line_count( 11 ) , 100 ) ;
911
+ assert_eq ! ( paragraph. line_count( 6 ) , 200 ) ;
912
+ }
913
+
914
+ #[ test]
915
+ fn widgets_paragraph_line_width ( ) {
916
+ let paragraph = Paragraph :: new ( "Hello World" ) ;
917
+ assert_eq ! ( paragraph. line_width( ) , 11 ) ;
918
+ let paragraph = Paragraph :: new ( "Hello World" ) . wrap ( Wrap { trim : false } ) ;
919
+ assert_eq ! ( paragraph. line_width( ) , 11 ) ;
920
+ let paragraph = Paragraph :: new ( "Hello World" ) . wrap ( Wrap { trim : true } ) ;
921
+ assert_eq ! ( paragraph. line_width( ) , 11 ) ;
922
+
923
+ let text = "Hello World " . repeat ( 100 ) ;
924
+ let paragraph = Paragraph :: new ( text) ;
925
+ assert_eq ! ( paragraph. line_width( ) , 1200 ) ;
926
+ let paragraph = paragraph. wrap ( Wrap { trim : false } ) ;
927
+ assert_eq ! ( paragraph. line_width( ) , 1200 ) ;
928
+ let paragraph = paragraph. wrap ( Wrap { trim : true } ) ;
929
+ assert_eq ! ( paragraph. line_width( ) , 1200 ) ;
930
+ }
818
931
}
0 commit comments