@@ -9,6 +9,7 @@ use cursive::{
99 views:: { Dialog , EditView , NamedView , OnEventView } ,
1010 wrap_impl,
1111} ;
12+ use regex:: Regex ;
1213use std:: collections:: { HashMap , hash_map:: DefaultHasher } ;
1314use std:: fs;
1415use std:: hash:: { Hash , Hasher } ;
@@ -216,9 +217,10 @@ pub struct LogViewBase {
216217 scroll_core : scroll:: Core ,
217218
218219 search_direction_forward : bool ,
219- search_term : String ,
220+ search_regex : Option < Regex > ,
220221 matched_row : Option < usize > ,
221222 matched_col : Option < usize > ,
223+ matched_len : usize ,
222224 skip_scroll : bool ,
223225
224226 cluster : bool ,
@@ -252,9 +254,10 @@ impl Default for LogViewBase {
252254 update_content : false ,
253255 scroll_core : scroll:: Core :: default ( ) ,
254256 search_direction_forward : false ,
255- search_term : String :: new ( ) ,
257+ search_regex : None ,
256258 matched_row : None ,
257259 matched_col : None ,
260+ matched_len : 0 ,
258261 skip_scroll : false ,
259262 cluster : false ,
260263 wrap : false ,
@@ -459,7 +462,7 @@ impl LogViewBase {
459462 }
460463
461464 fn search_in_direction ( & mut self , forward : bool ) -> bool {
462- if self . search_term . is_empty ( ) {
465+ if self . search_regex . is_none ( ) {
463466 return false ;
464467 }
465468
@@ -549,14 +552,18 @@ impl LogViewBase {
549552 current_row : usize ,
550553 forward : bool ,
551554 ) -> bool {
555+ let re = match & self . search_regex {
556+ Some ( re) => re,
557+ None => return false ,
558+ } ;
552559 let mut x = 0 ;
553560 for span in row. resolve_stream ( styled) {
554- if let Some ( pos ) = span . content . find ( & self . search_term ) {
561+ if let Some ( m ) = re . find ( span . content ) {
555562 self . matched_row = Some ( current_row) ;
556- self . matched_col = Some ( x + pos) ;
563+ self . matched_col = Some ( x + span. content [ ..m. start ( ) ] . width ( ) ) ;
564+ self . matched_len = m. as_str ( ) . width ( ) ;
557565 log:: trace!(
558- "search_term: {}, matched_row: {:?} ({}-search)" ,
559- & self . search_term,
566+ "search regex matched_row: {:?} ({}-search)" ,
560567 self . matched_row,
561568 if forward { "forward" } else { "reverse" }
562569 ) ;
@@ -788,29 +795,26 @@ impl LogViewBase {
788795 let mut x = 0 ;
789796
790797 for span in row. resolve_stream ( & styled) {
791- // Check if the span contains the search term
792- if !self . search_term . is_empty ( ) && span. content . contains ( & self . search_term )
793- {
798+ if let Some ( ref re) = self . search_regex {
794799 let content = span. content ;
795- let search_term = & self . search_term ;
796800 let mut last_pos = 0 ;
801+ let mut has_match = false ;
797802
798- for ( match_start , _ ) in content . match_indices ( search_term ) {
799- // Print text before match with normal style
800- if match_start > last_pos {
801- let before = & content[ last_pos..match_start ] ;
803+ for m in re . find_iter ( content ) {
804+ has_match = true ;
805+ if m . start ( ) > last_pos {
806+ let before = & content[ last_pos..m . start ( ) ] ;
802807 printer. with_style ( * span. attr , |printer| {
803808 printer. print ( ( x, y) , before) ;
804809 } ) ;
805810 x += before. width ( ) ;
806811 }
807812
813+ let matched = m. as_str ( ) ;
808814 // Use the same highlight theme as less(1):
809815 // - Always use black as text color
810816 // - Use original text color as background
811817 // - For no-style use white as background
812- let matched =
813- & content[ match_start..match_start + search_term. len ( ) ] ;
814818 let bg_color = if * span. attr == Style :: default ( ) {
815819 Color :: Rgb ( 255 , 255 , 255 ) . into ( )
816820 } else {
@@ -822,16 +826,22 @@ impl LogViewBase {
822826 } ) ;
823827 x += matched. width ( ) ;
824828
825- last_pos = match_start + search_term . len ( ) ;
829+ last_pos = m . end ( ) ;
826830 }
827831
828- // Print remaining text after last match
829- if last_pos < content. len ( ) {
830- let after = & content[ last_pos..] ;
832+ if has_match {
833+ if last_pos < content. len ( ) {
834+ let after = & content[ last_pos..] ;
835+ printer. with_style ( * span. attr , |printer| {
836+ printer. print ( ( x, y) , after) ;
837+ } ) ;
838+ x += after. width ( ) ;
839+ }
840+ } else {
831841 printer. with_style ( * span. attr , |printer| {
832- printer. print ( ( x, y) , after ) ;
842+ printer. print ( ( x, y) , span . content ) ;
833843 } ) ;
834- x += after . width ( ) ;
844+ x += span . content . width ( ) ;
835845 }
836846 } else {
837847 // No match in this span or row, print normally
@@ -1033,10 +1043,19 @@ impl LogView {
10331043
10341044 let search_prompt_impl = |siv : & mut Cursive , forward : bool | {
10351045 let find = move |siv : & mut Cursive , text : & str | {
1046+ let re = match Regex :: new ( text) {
1047+ Ok ( re) => re,
1048+ Err ( err) => {
1049+ siv. pop_layer ( ) ;
1050+ siv. add_layer ( Dialog :: info ( format ! ( "Invalid regex: {err}" ) ) ) ;
1051+ return ;
1052+ }
1053+ } ;
10361054 let found = siv. call_on_name ( "logs" , |base : & mut LogViewBase | {
1037- base. search_term = text . to_string ( ) ;
1055+ base. search_regex = Some ( re ) ;
10381056 base. matched_row = None ;
10391057 base. matched_col = None ;
1058+ base. matched_len = 0 ;
10401059 base. skip_scroll = false ;
10411060
10421061 base. search_direction_forward = forward;
@@ -1314,7 +1333,7 @@ impl View for LogViewBase {
13141333 self . skip_scroll = false ;
13151334 } else if let Some ( matched_row) = self . matched_row {
13161335 let match_start = self . matched_col . unwrap_or ( 0 ) ;
1317- let match_end = match_start + self . search_term . len ( ) ;
1336+ let match_end = match_start + self . matched_len ;
13181337 let viewport_width = self . scroll_core . last_available_size ( ) . x ;
13191338 let current_offset = self . scroll_core . content_viewport ( ) . left ( ) ;
13201339
0 commit comments