@@ -22,7 +22,7 @@ use std::borrow::Cow;
2222#[ derive( Debug ) ]
2323pub struct DefaultSkimItem {
2424 /// The text that will be shown on screen.
25- text : String ,
25+ text : Box < str > ,
2626
2727 /// The index, for use in matching
2828 index : usize ,
@@ -37,11 +37,11 @@ pub struct DefaultSkimItemMetadata {
3737 /// The text that will be output when user press `enter`
3838 /// `Some(..)` => the original input is transformed, could not output `text` directly
3939 /// `None` => that it is safe to output `text` directly
40- orig_text : Option < String > ,
40+ orig_text : Option < Box < str > > ,
4141
4242 /// The text stripped of all ansi sequences, used for matching
4343 /// Will be Some when ANSI is enabled, None otherwise
44- stripped_text : Option < String > ,
44+ stripped_text : Option < Box < str > > ,
4545
4646 /// A mapping of positions from stripped text to original text.
4747 /// Each element is (byte_position, char_position) in the original raw text.
@@ -55,14 +55,15 @@ pub struct DefaultSkimItemMetadata {
5555impl DefaultSkimItem {
5656 /// Create a new DefaultSkimItem from text
5757 pub fn new (
58- orig_text : String ,
58+ orig_text : & str ,
5959 ansi_enabled : bool ,
6060 trans_fields : & [ FieldRange ] ,
6161 matching_fields : & [ FieldRange ] ,
6262 delimiter : & Regex ,
6363 index : usize ,
6464 ) -> Self {
6565 let using_transform_fields = !trans_fields. is_empty ( ) ;
66+ let contains_ansi = Self :: contains_ansi_escape ( orig_text) ;
6667
6768 // transformed | ANSI | output
6869 //------------------------------------------------------
@@ -74,36 +75,37 @@ impl DefaultSkimItem {
7475 // | |
7576 // +- F -> orig | orig
7677
77- let ( mut orig_text, mut text ) = match ( using_transform_fields, ansi_enabled) {
78+ let ( mut orig_text, mut temp_text ) : ( Option < String > , Box < str > ) = match ( using_transform_fields, ansi_enabled) {
7879 ( true , true ) => {
7980 let transformed = parse_transform_fields ( delimiter, & orig_text, trans_fields) ;
80- ( Some ( orig_text) , transformed)
81+ ( Some ( orig_text. into ( ) ) , Box :: from ( transformed) )
8182 }
8283 ( true , false ) => {
8384 let transformed = parse_transform_fields ( delimiter, & escape_ansi ( & orig_text) , trans_fields) ;
84- ( Some ( orig_text) , transformed)
85+ ( Some ( orig_text. into ( ) ) , Box :: from ( transformed) )
8586 }
86- ( false , true ) => ( None , orig_text) ,
87- ( false , false ) => ( None , escape_ansi ( & orig_text) ) ,
87+ ( false , true ) => ( None , Box :: from ( orig_text) ) ,
88+ ( false , false ) if contains_ansi => ( None , escape_ansi ( & orig_text) . into ( ) ) ,
89+ ( false , false ) => ( None , Box :: from ( orig_text) ) ,
8890 } ;
8991
9092 // Keep track of whether we have null bytes for special handling
91- let has_null_bytes = text . contains ( '\0' ) ;
93+ let has_null_bytes = temp_text . contains ( '\0' ) ;
9294
9395 // Preserve original text with null bytes for output if needed
9496 if has_null_bytes && orig_text. is_none ( ) {
95- orig_text = Some ( text . clone ( ) ) ;
97+ orig_text = Some ( temp_text . to_string ( ) ) ;
9698 }
9799
98100 // Strip null bytes from text used for display and matching
99101 // Null bytes are control characters that cause rendering issues (zero-width)
100102 // They are preserved in orig_text for output
101103 if has_null_bytes {
102- text = text . replace ( '\0' , "" ) ;
104+ temp_text = temp_text . to_string ( ) . replace ( '\0' , "" ) . into_boxed_str ( ) ;
103105 }
104106
105- let ( stripped_text, ansi_info) = if ansi_enabled {
106- let ( stripped, info) = strip_ansi ( & text ) ;
107+ let ( stripped_text, ansi_info) = if ansi_enabled && contains_ansi {
108+ let ( stripped, info) = strip_ansi ( & temp_text ) ;
107109 ( Some ( stripped) , Some ( info) )
108110 } else {
109111 ( None , None )
@@ -116,15 +118,15 @@ impl DefaultSkimItem {
116118 let text_for_matching = if ansi_enabled {
117119 stripped_text. as_ref ( ) . unwrap ( )
118120 } else {
119- & text
121+ temp_text . as_ref ( )
120122 } ;
121123
122124 // Parse the original text with null bytes to determine field boundaries
123125 // Then extract those fields, strip null bytes, and recalculate positions
124126 let orig_text_for_fields = if has_null_bytes {
125- orig_text. as_ref ( ) . unwrap ( )
127+ orig_text. as_deref ( ) . unwrap ( )
126128 } else {
127- text_for_matching
129+ & text_for_matching
128130 } ;
129131
130132 if has_null_bytes {
@@ -134,7 +136,7 @@ impl DefaultSkimItem {
134136
135137 for field in matching_fields {
136138 // Get the field text from original (with null bytes)
137- if let Some ( field_text) = crate :: field:: get_string_by_field ( delimiter, orig_text_for_fields, field)
139+ if let Some ( field_text) = crate :: field:: get_string_by_field ( delimiter, & orig_text_for_fields, field)
138140 {
139141 // Strip null bytes from this field
140142 let cleaned_field = field_text. replace ( '\0' , "" ) ;
@@ -156,34 +158,43 @@ impl DefaultSkimItem {
156158 let metadata =
157159 if orig_text. is_some ( ) || stripped_text. is_some ( ) || ansi_info. is_some ( ) || matching_ranges. is_some ( ) {
158160 Some ( Box :: new ( DefaultSkimItemMetadata {
159- orig_text,
160- stripped_text,
161+ orig_text : orig_text . map ( |inner| inner . into_boxed_str ( ) ) ,
162+ stripped_text : stripped_text . map ( |inner| inner . into_boxed_str ( ) ) ,
161163 ansi_info,
162164 matching_ranges,
163165 } ) )
164166 } else {
165167 None
166168 } ;
167169
168- DefaultSkimItem { text, index, metadata }
170+ DefaultSkimItem {
171+ text : temp_text,
172+ index,
173+ metadata,
174+ }
175+ }
176+
177+ fn contains_ansi_escape ( s : & str ) -> bool {
178+ s. contains ( '\x1b' )
169179 }
180+
170181 /// Getter for stripped_text stored in the metadata
171- pub fn stripped_text ( & self ) -> Option < & String > {
182+ pub fn stripped_text ( & self ) -> Option < & str > {
172183 if let Some ( meta) = & self . metadata
173184 && let Some ( stripped_text) = & meta. stripped_text
174185 {
175- Some ( stripped_text)
186+ Some ( stripped_text. as_ref ( ) )
176187 } else {
177188 None
178189 }
179190 }
180191
181192 /// Getter for orig_text stored in metadata
182- pub fn orig_text ( & self ) -> Option < & String > {
193+ pub fn orig_text ( & self ) -> Option < & str > {
183194 if let Some ( meta) = & self . metadata
184195 && let Some ( orig) = & meta. orig_text
185196 {
186- Some ( orig)
197+ Some ( orig. as_ref ( ) )
187198 } else {
188199 None
189200 }
@@ -636,7 +647,7 @@ mod test {
636647 let input = "\x1b [32mgreen\x1b [0m text" ;
637648 let delimiter = Regex :: new ( r"\s+" ) . unwrap ( ) ;
638649 let item = DefaultSkimItem :: new (
639- input. to_string ( ) ,
650+ input,
640651 true , // ansi_enabled
641652 & [ ] ,
642653 & [ ] ,
@@ -678,7 +689,7 @@ mod test {
678689 let input = "😀\x1b [32mtext\x1b [0m" ;
679690 let delimiter = Regex :: new ( r"\s+" ) . unwrap ( ) ;
680691 let item = DefaultSkimItem :: new (
681- input. to_string ( ) ,
692+ input,
682693 true , // ansi_enabled
683694 & [ ] ,
684695 & [ ] ,
@@ -712,7 +723,7 @@ mod test {
712723
713724 // Test with ANSI enabled
714725 let item_ansi = DefaultSkimItem :: new (
715- "\x1b [31mred\x1b [0m" . to_string ( ) ,
726+ "\x1b [31mred\x1b [0m" ,
716727 true , // ansi_enabled
717728 & [ ] ,
718729 & [ ] ,
@@ -727,7 +738,7 @@ mod test {
727738
728739 // Test with ANSI disabled
729740 let item_no_ansi = DefaultSkimItem :: new (
730- "\x1b [31mred\x1b [0m" . to_string ( ) ,
741+ "\x1b [31mred\x1b [0m" ,
731742 false , // ansi_enabled
732743 & [ ] ,
733744 & [ ] ,
@@ -751,7 +762,7 @@ mod test {
751762
752763 // Create item with ANSI codes: "\x1b[32mgreen\x1b[0m"
753764 let item = DefaultSkimItem :: new (
754- "\x1b [32mgreen\x1b [0m" . to_string ( ) ,
765+ "\x1b [32mgreen\x1b [0m" ,
755766 true , // ansi_enabled
756767 & [ ] ,
757768 & [ ] ,
@@ -790,7 +801,7 @@ mod test {
790801
791802 // Create item with ANSI codes: "\x1b[32mgreen\x1b[0m"
792803 let item = DefaultSkimItem :: new (
793- "\x1b [32mgreen\x1b [0m" . to_string ( ) ,
804+ "\x1b [32mgreen\x1b [0m" ,
794805 true , // ansi_enabled
795806 & [ ] ,
796807 & [ ] ,
@@ -831,7 +842,7 @@ mod test {
831842
832843 // Create item with ANSI codes: "\x1b[32mgreen\x1b[0m"
833844 let item = DefaultSkimItem :: new (
834- "\x1b [32mgreen\x1b [0m" . to_string ( ) ,
845+ "\x1b [32mgreen\x1b [0m" ,
835846 true , // ansi_enabled
836847 & [ ] ,
837848 & [ ] ,
@@ -871,7 +882,7 @@ mod test {
871882
872883 // Create item with ANSI codes: "\x1b[32mgreen_text\x1b[0m"
873884 let item = DefaultSkimItem :: new (
874- "\x1b [32mgreen_text\x1b [0m" . to_string ( ) ,
885+ "\x1b [32mgreen_text\x1b [0m" ,
875886 true , // ansi_enabled
876887 & [ ] ,
877888 & [ ] , // no matching fields restriction
@@ -903,7 +914,7 @@ mod test {
903914
904915 // Create item with matching field 2
905916 let item = DefaultSkimItem :: new (
906- text. to_string ( ) ,
917+ text,
907918 false , // no ansi
908919 & [ ] , // no transform fields
909920 & [ FieldRange :: Single ( 2 ) ] , // match field 2
0 commit comments