1- use std:: fmt:: Write ;
1+ use std:: { collections :: HashMap , fmt:: Write } ;
22
33use regex:: Regex ;
44use serde:: { Deserialize , Deserializer } ;
@@ -9,6 +9,7 @@ pub struct Pass {
99 #[ serde( deserialize_with = "pass_regex" ) ]
1010 pub regex : Regex ,
1111 pub stem : String ,
12+ pub keep_query : Option < Vec < String > > ,
1213}
1314
1415/// An enum representing the spoiler tags on a link.
@@ -25,7 +26,10 @@ pub enum SpoilerTags {
2526}
2627
2728impl Pass {
28- pub fn extract < ' a > ( & ' a self , content : & ' a str ) -> impl Iterator < Item = ( & ' a str , SpoilerTags ) > {
29+ pub fn extract < ' a > (
30+ & ' a self ,
31+ content : & ' a str ,
32+ ) -> impl Iterator < Item = ( & ' a str , & ' a str , SpoilerTags ) > {
2933 self . regex . captures_iter ( content) . map ( |capture| {
3034 let ( _, [ sp_open, path, sp_close] ) = capture. extract ( ) ;
3135 let spoiler_marker = match ( !sp_open. is_empty ( ) , !sp_close. is_empty ( ) ) {
@@ -34,28 +38,36 @@ impl Pass {
3438 _ => SpoilerTags :: Mismatched ,
3539 } ;
3640
37- ( path, spoiler_marker)
41+ let ( path, query) = path. split_once ( '?' ) . unwrap_or ( ( path, "" ) ) ;
42+
43+ ( path, query, spoiler_marker)
3844 } )
3945 }
4046
4147 pub fn apply < ' a > ( & ' a self , content : & ' a str ) -> Option < String > {
4248 let Self { label, stem, .. } = self ;
4349
44- let out = self
45- . extract ( content)
46- . fold ( String :: new ( ) , |mut out, ( path, spoiler_tags) | {
47- let spoil = spoiler_tags != SpoilerTags :: None ;
50+ let out =
51+ self . extract ( content)
52+ . fold ( String :: new ( ) , |mut out, ( path, query, spoiler_tags) | {
53+ let spoil = spoiler_tags != SpoilerTags :: None ;
54+
55+ let query_string = match & self . keep_query {
56+ None => format ! ( "?{query}" ) ,
57+ Some ( keep) if !keep. is_empty ( ) => filter_query ( query, keep) ,
58+ _ => String :: new ( ) ,
59+ } ;
4860
49- if spoil {
50- let _ = write ! ( & mut out, "||" ) ;
51- }
52- let _ = write ! ( & mut out, "[`{label}`]({stem}{path}) " ) ;
53- if spoil {
54- let _ = write ! ( & mut out, "|| " ) ;
55- }
61+ if spoil {
62+ let _ = write ! ( & mut out, "||" ) ;
63+ }
64+ let _ = write ! ( & mut out, "[`{label}`]({stem}{path}{query_string }) " ) ;
65+ if spoil {
66+ let _ = write ! ( & mut out, "|| " ) ;
67+ }
5668
57- out
58- } ) ;
69+ out
70+ } ) ;
5971
6072 ( !out. is_empty ( ) ) . then_some ( out)
6173 }
@@ -81,3 +93,16 @@ fn pass_regex<'de, D: Deserializer<'de>>(de: D) -> Result<Regex, D::Error> {
8193 Regex :: new ( & [ "(?:^|\\ s)" , "(\\ |\\ ||)" , & core, "(/\\ S+)" , "(\\ s?\\ |\\ ||)" ] . concat ( ) )
8294 . map_err ( D :: Error :: custom)
8395}
96+
97+ /// Removes all query parameters from a query string except those in the provided list
98+ fn filter_query ( qs : & str , keep : & Vec < String > ) -> String {
99+ let query_map: HashMap < _ , _ > = qs. split ( '&' ) . filter_map ( |p| p. split_once ( '=' ) ) . collect ( ) ;
100+
101+ let params = query_map
102+ . iter ( )
103+ . filter_map ( |( k, v) | keep. contains ( & k. to_string ( ) ) . then ( || format ! ( "{k}={v}" ) ) )
104+ . collect :: < Vec < _ > > ( )
105+ . join ( "&" ) ;
106+
107+ format ! ( "?{params}" )
108+ }
0 commit comments