@@ -54,6 +54,7 @@ struct Options {
54
54
clean_print : bool ,
55
55
from_line : usize ,
56
56
lines : Option < u16 > ,
57
+ pattern : Option < String > ,
57
58
print_over : bool ,
58
59
silent : bool ,
59
60
squeeze : bool ,
@@ -75,10 +76,14 @@ impl Options {
75
76
Some ( number) if number > 1 => number - 1 ,
76
77
_ => 0 ,
77
78
} ;
79
+ let pattern = matches
80
+ . get_one :: < String > ( options:: PATTERN )
81
+ . map ( |s| s. to_owned ( ) ) ;
78
82
Self {
79
83
clean_print : matches. get_flag ( options:: CLEAN_PRINT ) ,
80
84
from_line,
81
85
lines,
86
+ pattern,
82
87
print_over : matches. get_flag ( options:: PRINT_OVER ) ,
83
88
silent : matches. get_flag ( options:: SILENT ) ,
84
89
squeeze : matches. get_flag ( options:: SQUEEZE ) ,
@@ -206,6 +211,15 @@ pub fn uu_app() -> Command {
206
211
. action ( ArgAction :: SetTrue )
207
212
. hide ( true ) ,
208
213
)
214
+ . arg (
215
+ Arg :: new ( options:: PATTERN )
216
+ . short ( 'P' )
217
+ . long ( options:: PATTERN )
218
+ . allow_hyphen_values ( true )
219
+ . required ( false )
220
+ . value_name ( "pattern" )
221
+ . help ( "Display file beginning from pattern match" ) ,
222
+ )
209
223
. arg (
210
224
Arg :: new ( options:: FROM_LINE )
211
225
. short ( 'F' )
@@ -245,14 +259,6 @@ pub fn uu_app() -> Command {
245
259
.long(options::NO_PAUSE)
246
260
.help("Suppress pause after form feed"),
247
261
)
248
- .arg(
249
- Arg::new(options::PATTERN)
250
- .short('P')
251
- .allow_hyphen_values(true)
252
- .required(false)
253
- .takes_value(true)
254
- .help("Display file beginning from pattern match"),
255
- )
256
262
*/
257
263
. arg (
258
264
Arg :: new ( options:: FILES )
@@ -307,6 +313,17 @@ fn more(
307
313
308
314
let mut pager = Pager :: new ( rows, lines, next_file, options) ;
309
315
316
+ if options. pattern . is_some ( ) {
317
+ match search_pattern_in_file ( & pager. lines , & options. pattern ) {
318
+ Some ( number) => pager. upper_mark = number,
319
+ None => {
320
+ execute ! ( stdout, terminal:: Clear ( terminal:: ClearType :: CurrentLine ) ) ?;
321
+ stdout. write_all ( "\r Pattern not found\n " . as_bytes ( ) ) ?;
322
+ pager. content_rows -= 1 ;
323
+ }
324
+ }
325
+ }
326
+
310
327
if multiple_file {
311
328
execute ! ( stdout, terminal:: Clear ( terminal:: ClearType :: CurrentLine ) ) . unwrap ( ) ;
312
329
stdout. write_all (
@@ -592,6 +609,19 @@ impl<'a> Pager<'a> {
592
609
}
593
610
}
594
611
612
+ fn search_pattern_in_file ( lines : & [ String ] , pattern : & Option < String > ) -> Option < usize > {
613
+ let pattern = pattern. clone ( ) . unwrap_or_default ( ) ;
614
+ if lines. is_empty ( ) || pattern. is_empty ( ) {
615
+ return None ;
616
+ }
617
+ for ( line_number, line) in lines. iter ( ) . enumerate ( ) {
618
+ if line. contains ( pattern. as_str ( ) ) {
619
+ return Some ( line_number) ;
620
+ }
621
+ }
622
+ None
623
+ }
624
+
595
625
fn paging_add_back_message ( options : & Options , stdout : & mut std:: io:: Stdout ) -> UResult < ( ) > {
596
626
if options. lines . is_some ( ) {
597
627
execute ! ( stdout, MoveUp ( 1 ) ) ?;
@@ -640,7 +670,7 @@ fn break_line(line: &str, cols: usize) -> Vec<String> {
640
670
641
671
#[ cfg( test) ]
642
672
mod tests {
643
- use super :: break_line;
673
+ use super :: { break_line, search_pattern_in_file } ;
644
674
use unicode_width:: UnicodeWidthStr ;
645
675
646
676
#[ test]
@@ -688,4 +718,53 @@ mod tests {
688
718
// Each 👩🏻🔬 is 6 character width it break line to the closest number to 80 => 6 * 13 = 78
689
719
assert_eq ! ( ( 78 , 42 ) , ( widths[ 0 ] , widths[ 1 ] ) ) ;
690
720
}
721
+
722
+ #[ test]
723
+ fn test_search_pattern_empty_lines ( ) {
724
+ let lines = vec ! [ ] ;
725
+ let pattern = Some ( String :: from ( "pattern" ) ) ;
726
+ assert_eq ! ( None , search_pattern_in_file( & lines, & pattern) ) ;
727
+ }
728
+
729
+ #[ test]
730
+ fn test_search_pattern_empty_pattern ( ) {
731
+ let lines = vec ! [ String :: from( "line1" ) , String :: from( "line2" ) ] ;
732
+ let pattern = None ;
733
+ assert_eq ! ( None , search_pattern_in_file( & lines, & pattern) ) ;
734
+ }
735
+
736
+ #[ test]
737
+ fn test_search_pattern_found_pattern ( ) {
738
+ let lines = vec ! [
739
+ String :: from( "line1" ) ,
740
+ String :: from( "line2" ) ,
741
+ String :: from( "pattern" ) ,
742
+ ] ;
743
+ let lines2 = vec ! [
744
+ String :: from( "line1" ) ,
745
+ String :: from( "line2" ) ,
746
+ String :: from( "pattern" ) ,
747
+ String :: from( "pattern2" ) ,
748
+ ] ;
749
+ let lines3 = vec ! [
750
+ String :: from( "line1" ) ,
751
+ String :: from( "line2" ) ,
752
+ String :: from( "other_pattern" ) ,
753
+ ] ;
754
+ let pattern = Some ( String :: from ( "pattern" ) ) ;
755
+ assert_eq ! ( 2 , search_pattern_in_file( & lines, & pattern) . unwrap( ) ) ;
756
+ assert_eq ! ( 2 , search_pattern_in_file( & lines2, & pattern) . unwrap( ) ) ;
757
+ assert_eq ! ( 2 , search_pattern_in_file( & lines3, & pattern) . unwrap( ) ) ;
758
+ }
759
+
760
+ #[ test]
761
+ fn test_search_pattern_not_found_pattern ( ) {
762
+ let lines = vec ! [
763
+ String :: from( "line1" ) ,
764
+ String :: from( "line2" ) ,
765
+ String :: from( "something" ) ,
766
+ ] ;
767
+ let pattern = Some ( String :: from ( "pattern" ) ) ;
768
+ assert_eq ! ( None , search_pattern_in_file( & lines, & pattern) ) ;
769
+ }
691
770
}
0 commit comments