@@ -17,7 +17,7 @@ struct Config {
1717 delta : bool ,
1818 prefix_only : bool ,
1919 color : bool ,
20- unbuffered : bool ,
20+ buffered : bool ,
2121 timezone : Option < String > ,
2222}
2323
@@ -36,7 +36,7 @@ impl Config {
3636 delta : false ,
3737 prefix_only : false ,
3838 color : false ,
39- unbuffered : true ,
39+ buffered : false , // Default to unbuffered for real-time output
4040 timezone : None ,
4141 } ;
4242
@@ -63,7 +63,7 @@ impl Config {
6363 "--delta" => config. delta = true ,
6464 "--prefix-only" => config. prefix_only = true ,
6565 "--color" => config. color = true ,
66- "--buffered" => config. unbuffered = false ,
66+ "--buffered" => config. buffered = true ,
6767 "-s" | "--separator" => {
6868 i += 1 ;
6969 if i >= args. len ( ) {
@@ -105,6 +105,10 @@ impl Config {
105105 eprintln ! ( "Error: Cannot use both --relative and --epoch" ) ;
106106 std:: process:: exit ( 1 ) ;
107107 }
108+ if config. relative && config. delta {
109+ eprintln ! ( "Error: Cannot use both --relative and --delta" ) ;
110+ std:: process:: exit ( 1 ) ;
111+ }
108112
109113 Ok ( config)
110114 }
@@ -155,7 +159,9 @@ Examples:
155159 tail -f app.log | {} -r -m # Relative monotonic
156160 cat file.txt | {} --delta # Show time between lines
157161 ping host | {} --color --microseconds # Colored with microseconds
158- command | {} --prefix-only # Only timestamps" ,
162+ command | {} --prefix-only # Only timestamps
163+
164+ Note: --relative and --delta are mutually exclusive" ,
159165 program_name, program_name, program_name, program_name, program_name,
160166 program_name, program_name, program_name, program_name, program_name, program_name
161167 ) ;
@@ -228,6 +234,8 @@ struct TimeFormatter {
228234 custom_format : Option < String > ,
229235 timestamp_buf : String ,
230236 color : bool ,
237+ color_prefix : & ' static str ,
238+ color_suffix : & ' static str ,
231239}
232240
233241impl TimeFormatter {
@@ -240,6 +248,12 @@ impl TimeFormatter {
240248 None
241249 } ;
242250
251+ let ( color_prefix, color_suffix) = if config. color {
252+ ( "\x1b [36m" , "\x1b [0m" ) // Cyan color
253+ } else {
254+ ( "" , "" )
255+ } ;
256+
243257 Self {
244258 format_type,
245259 utc : config. utc ,
@@ -251,25 +265,32 @@ impl TimeFormatter {
251265 custom_format,
252266 timestamp_buf : String :: with_capacity ( 128 ) ,
253267 color : config. color ,
268+ color_prefix,
269+ color_suffix,
254270 }
255271 }
256272
257273 #[ inline]
258274 fn format_timestamp ( & mut self , monotonic : bool ) -> & str {
259275 self . timestamp_buf . clear ( ) ;
260276
261- if self . color {
262- self . timestamp_buf . push_str ( "\x1b [36m" ) ; // Cyan color
263- }
264-
265277 match & self . format_type {
266278 FormatType :: Delta => {
267279 let duration = if monotonic {
268280 let instant = Instant :: now ( ) ;
269281 let duration = if let Some ( last) = self . last_instant {
270282 instant. duration_since ( last)
271283 } else {
272- std:: time:: Duration :: ZERO
284+ // Initialize with current time for first call
285+ self . last_instant = Some ( instant) ;
286+ return if self . color {
287+ self . timestamp_buf . push_str ( self . color_prefix ) ;
288+ self . timestamp_buf . push_str ( "0.000000" ) ;
289+ self . timestamp_buf . push_str ( self . color_suffix ) ;
290+ & self . timestamp_buf
291+ } else {
292+ "0.000000"
293+ } ;
273294 } ;
274295 self . last_instant = Some ( instant) ;
275296 duration
@@ -278,7 +299,16 @@ impl TimeFormatter {
278299 let duration = if let Some ( last) = self . last_time {
279300 time. duration_since ( last) . unwrap_or_default ( )
280301 } else {
281- std:: time:: Duration :: ZERO
302+ // Initialize with current time for first call
303+ self . last_time = Some ( time) ;
304+ return if self . color {
305+ self . timestamp_buf . push_str ( self . color_prefix ) ;
306+ self . timestamp_buf . push_str ( "0.000000" ) ;
307+ self . timestamp_buf . push_str ( self . color_suffix ) ;
308+ & self . timestamp_buf
309+ } else {
310+ "0.000000"
311+ } ;
282312 } ;
283313 self . last_time = Some ( time) ;
284314 duration
@@ -414,13 +444,13 @@ impl TimeFormatter {
414444 if let Some ( ref fmt) = self . custom_format {
415445 // For relative timestamps, create a time from the duration
416446 let total_secs = duration. as_secs ( ) ;
417- let subsec_millis = duration. subsec_millis ( ) ;
447+ let subsec_nanos = duration. subsec_nanos ( ) ;
418448 let hours = ( total_secs / 3600 ) as u32 ;
419449 let mins = ( ( total_secs % 3600 ) / 60 ) as u32 ;
420450 let secs = ( total_secs % 60 ) as u32 ;
421451
422452 let dt = Utc . with_ymd_and_hms ( 1970 , 1 , 1 , hours, mins, secs) . unwrap ( )
423- . with_nanosecond ( subsec_millis * 1_000_000 ) . unwrap ( ) ;
453+ . with_nanosecond ( subsec_nanos ) . unwrap ( ) ;
424454
425455 use std:: fmt:: Write ;
426456 let _ = write ! ( self . timestamp_buf, "{}" , dt. format( fmt) ) ;
@@ -448,8 +478,12 @@ impl TimeFormatter {
448478 } ,
449479 }
450480
481+ // Add color codes if needed - do this outside the timestamp buffer
482+ // to avoid reallocation on every call
451483 if self . color {
452- self . timestamp_buf . push_str ( "\x1b [0m" ) ; // Reset color
484+ // Create a temporary string with color codes
485+ let colored = format ! ( "{}{}{}" , self . color_prefix, self . timestamp_buf, self . color_suffix) ;
486+ self . timestamp_buf = colored;
453487 }
454488
455489 & self . timestamp_buf
@@ -463,14 +497,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
463497 let stdin = io:: stdin ( ) ;
464498 let stdout = io:: stdout ( ) ;
465499
466- // Use larger buffers for better performance unless unbuffered
467- let buffer_size = if config. unbuffered { 0 } else { 256 * 1024 } ;
500+ // Use appropriate buffer sizes based on configuration
501+ let buffer_size = if config. buffered { 256 * 1024 } else { 0 } ;
468502 let reader = BufReader :: with_capacity ( 128 * 1024 , stdin) ;
469- let mut writer = if config. unbuffered {
470- BufWriter :: with_capacity ( 0 , stdout)
471- } else {
472- BufWriter :: with_capacity ( buffer_size, stdout)
473- } ;
503+ let mut writer = BufWriter :: with_capacity ( buffer_size, stdout) ;
474504
475505 let separator_bytes = config. separator . as_bytes ( ) ;
476506 let newline = b"\n " ;
@@ -489,8 +519,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
489519
490520 writer. write_all ( newline) ?;
491521
492- // Always flush when unbuffered (which is now default)
493- if config. unbuffered {
522+ // Flush when unbuffered
523+ if ! config. buffered {
494524 writer. flush ( ) ?;
495525 }
496526 }
0 commit comments