@@ -10,10 +10,21 @@ pub trait LineNumbers {
1010
1111impl < T : AsRef < str > > LineNumbers for T {
1212 fn numbered_from ( & self , start : usize ) -> String {
13- self . as_ref ( )
14- . lines ( )
13+ let text = self . as_ref ( ) ;
14+ let lines: Vec < & str > = text. lines ( ) . collect ( ) ;
15+
16+ if lines. is_empty ( ) {
17+ return String :: new ( ) ;
18+ }
19+
20+ // Calculate the width needed for the largest line number
21+ let max_line_number = start + lines. len ( ) - 1 ;
22+ let width = max_line_number. to_string ( ) . len ( ) ;
23+
24+ lines
25+ . into_iter ( )
1526 . enumerate ( )
16- . map ( |( i, line) | format ! ( "{}:{}" , start + i, line) )
27+ . map ( |( i, line) | format ! ( "{:>width$ }:{}" , start + i, line, width = width ) )
1728 . collect :: < Vec < _ > > ( )
1829 . join ( "\n " )
1930 }
@@ -57,4 +68,51 @@ mod tests {
5768 let expected = "1:line1\n 2:\n 3:line3" ;
5869 assert_eq ! ( text. numbered( ) , expected) ;
5970 }
71+
72+ #[ test]
73+ fn test_numbered_right_aligned_single_digit ( ) {
74+ let text = "line1\n line2\n line3" ;
75+ let expected = "1:line1\n 2:line2\n 3:line3" ;
76+ assert_eq ! ( text. numbered( ) , expected) ;
77+ }
78+
79+ #[ test]
80+ fn test_numbered_right_aligned_two_digits ( ) {
81+ let text = "a\n b\n c\n d\n e\n f\n g\n h\n i\n j\n k" ;
82+ let expected = " 1:a\n 2:b\n 3:c\n 4:d\n 5:e\n 6:f\n 7:g\n 8:h\n 9:i\n 10:j\n 11:k" ;
83+ assert_eq ! ( text. numbered( ) , expected) ;
84+ }
85+
86+ #[ test]
87+ fn test_numbered_right_aligned_three_digits ( ) {
88+ let mut lines = Vec :: new ( ) ;
89+ for i in 1 ..=100 {
90+ lines. push ( format ! ( "line{}" , i) ) ;
91+ }
92+ let text = lines. join ( "\n " ) ;
93+ let actual = text. numbered ( ) ;
94+
95+ // Check first line has 2 leading spaces (001 -> " 1")
96+ assert ! ( actual. starts_with( " 1:line1" ) ) ;
97+ // Check line 10 has 1 leading space (010 -> " 10")
98+ assert ! ( actual. contains( "\n 10:line10\n " ) ) ;
99+ // Check line 100 has no leading spaces (100 -> "100")
100+ assert ! ( actual. contains( "\n 100:line100" ) ) ;
101+ }
102+
103+ #[ test]
104+ fn test_numbered_from_right_aligned ( ) {
105+ let text = "alpha\n beta\n gamma\n delta" ;
106+ // Starting from 98, so max is 101 (3 digits)
107+ let expected = " 98:alpha\n 99:beta\n 100:gamma\n 101:delta" ;
108+ assert_eq ! ( text. numbered_from( 98 ) , expected) ;
109+ }
110+
111+ #[ test]
112+ fn test_numbered_from_crosses_digit_boundary ( ) {
113+ let text = "line8\n line9\n line10\n line11" ;
114+ // Starting from 8, max is 11 (2 digits)
115+ let expected = " 8:line8\n 9:line9\n 10:line10\n 11:line11" ;
116+ assert_eq ! ( text. numbered_from( 8 ) , expected) ;
117+ }
60118}
0 commit comments