@@ -902,6 +902,28 @@ fn builtin_string_methods<'a, L: TemplateLanguage<'a> + ?Sized>(
902
902
Ok ( out_property. into_dyn_wrapped ( ) )
903
903
} ,
904
904
) ;
905
+ map. insert (
906
+ "match" ,
907
+ |_language, _diagnostics, _build_ctx, self_property, function| {
908
+ let [ needle_node] = function. expect_exact_arguments ( ) ?;
909
+ let needle = template_parser:: expect_string_pattern ( needle_node) ?;
910
+
911
+ let out_property = self_property. and_then ( move |haystack| {
912
+ let regex = needle. to_regex ( ) ;
913
+ let match_ = regex. find ( haystack. as_bytes ( ) ) ;
914
+
915
+ if let Some ( m) = match_ {
916
+ Ok ( String :: from_utf8 ( m. as_bytes ( ) . to_owned ( ) ) ?)
917
+ } else {
918
+ // FIXME(jade): maybe suboptimal to return string
919
+ // unconditionally but we don't have an Option<String> type
920
+ // yet.
921
+ Ok ( String :: new ( ) )
922
+ }
923
+ } ) ;
924
+ Ok ( out_property. into_dyn_wrapped ( ) )
925
+ } ,
926
+ ) ;
905
927
map. insert (
906
928
"starts_with" ,
907
929
|language, diagnostics, build_ctx, self_property, function| {
@@ -2804,6 +2826,35 @@ mod tests {
2804
2826
insta:: assert_snapshot!(
2805
2827
env. render_ok( r#""foo".contains(separate("o", "f", bad_string))"# ) , @"<Error: Bad>" ) ;
2806
2828
2829
+ insta:: assert_snapshot!( env. render_ok( r#""fooo".match(regex:'[a-f]o+')"# ) , @"fooo" ) ;
2830
+ insta:: assert_snapshot!( env. render_ok( r#""fa".match(regex:'[a-f]o+')"# ) , @"" ) ;
2831
+ insta:: assert_snapshot!( env. render_ok( r#""hello".match(regex:"h(ell)o")"# ) , @"hello" ) ;
2832
+ insta:: assert_snapshot!( env. render_ok( r#""HEllo".match(regex-i:"h(ell)o")"# ) , @"HEllo" ) ;
2833
+ insta:: assert_snapshot!( env. render_ok( r#""hEllo".match(glob:"h*o")"# ) , @"hEllo" ) ;
2834
+ insta:: assert_snapshot!( env. render_ok( r#""Hello".match(glob:"h*o")"# ) , @"" ) ;
2835
+ insta:: assert_snapshot!( env. render_ok( r#""HEllo".match(glob-i:"h*o")"# ) , @"HEllo" ) ;
2836
+ insta:: assert_snapshot!( env. render_ok( r#""hello".match("he")"# ) , @"he" ) ;
2837
+ insta:: assert_snapshot!( env. render_ok( r#""hello".match(substring:"he")"# ) , @"he" ) ;
2838
+ insta:: assert_snapshot!( env. render_ok( r#""hello".match(exact:"he")"# ) , @"" ) ;
2839
+
2840
+ // NOTE: this is asserting that we are still parsing as string regex
2841
+ // before reparsing as a bytes regex. We will plausibly stop doing that
2842
+ // (https://github.com/jj-vcs/jj/pull/6899#discussion_r2214764968).
2843
+ // If we stop doing that, this test should instead confirm that a bad
2844
+ // regex still generates a good error when the invalid utf-8 is
2845
+ // converted to a string.
2846
+ insta:: assert_snapshot!( env. parse_err( r#""🥺".match(regex:'^(?-u:.).+$')"# ) , @r#"
2847
+ --> 1:11
2848
+ |
2849
+ 1 | "🥺".match(regex:'^(?-u:.).+$')
2850
+ | ^-----------------^
2851
+ |
2852
+ = Bad string pattern: regex parse error:
2853
+ ^(?-u:.).+$
2854
+ ^
2855
+ error: pattern can match invalid UTF-8
2856
+ "# ) ;
2857
+
2807
2858
insta:: assert_snapshot!( env. render_ok( r#""".first_line()"# ) , @"" ) ;
2808
2859
insta:: assert_snapshot!( env. render_ok( r#""foo\nbar".first_line()"# ) , @"foo" ) ;
2809
2860
0 commit comments