@@ -54,6 +54,7 @@ struct Options {
5454 clean_print : bool ,
5555 from_line : usize ,
5656 lines : Option < u16 > ,
57+ pattern : Option < String > ,
5758 print_over : bool ,
5859 silent : bool ,
5960 squeeze : bool ,
@@ -75,10 +76,14 @@ impl Options {
7576 Some ( number) if number > 1 => number - 1 ,
7677 _ => 0 ,
7778 } ;
79+ let pattern = matches
80+ . get_one :: < String > ( options:: PATTERN )
81+ . map ( |s| s. to_owned ( ) ) ;
7882 Self {
7983 clean_print : matches. get_flag ( options:: CLEAN_PRINT ) ,
8084 from_line,
8185 lines,
86+ pattern,
8287 print_over : matches. get_flag ( options:: PRINT_OVER ) ,
8388 silent : matches. get_flag ( options:: SILENT ) ,
8489 squeeze : matches. get_flag ( options:: SQUEEZE ) ,
@@ -206,6 +211,15 @@ pub fn uu_app() -> Command {
206211 . action ( ArgAction :: SetTrue )
207212 . hide ( true ) ,
208213 )
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+ )
209223 . arg (
210224 Arg :: new ( options:: FROM_LINE )
211225 . short ( 'F' )
@@ -245,14 +259,6 @@ pub fn uu_app() -> Command {
245259 .long(options::NO_PAUSE)
246260 .help("Suppress pause after form feed"),
247261 )
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- )
256262 */
257263 . arg (
258264 Arg :: new ( options:: FILES )
@@ -307,6 +313,17 @@ fn more(
307313
308314 let mut pager = Pager :: new ( rows, lines, next_file, options) ;
309315
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+
310327 if multiple_file {
311328 execute ! ( stdout, terminal:: Clear ( terminal:: ClearType :: CurrentLine ) ) . unwrap ( ) ;
312329 stdout. write_all (
@@ -592,6 +609,19 @@ impl<'a> Pager<'a> {
592609 }
593610}
594611
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+
595625fn paging_add_back_message ( options : & Options , stdout : & mut std:: io:: Stdout ) -> UResult < ( ) > {
596626 if options. lines . is_some ( ) {
597627 execute ! ( stdout, MoveUp ( 1 ) ) ?;
@@ -640,7 +670,7 @@ fn break_line(line: &str, cols: usize) -> Vec<String> {
640670
641671#[ cfg( test) ]
642672mod tests {
643- use super :: break_line;
673+ use super :: { break_line, search_pattern_in_file } ;
644674 use unicode_width:: UnicodeWidthStr ;
645675
646676 #[ test]
@@ -688,4 +718,53 @@ mod tests {
688718 // Each 👩🏻🔬 is 6 character width it break line to the closest number to 80 => 6 * 13 = 78
689719 assert_eq ! ( ( 78 , 42 ) , ( widths[ 0 ] , widths[ 1 ] ) ) ;
690720 }
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+ }
691770}
0 commit comments