@@ -11,7 +11,10 @@ pub mod relabel;
1111pub mod second;
1212
1313pub fn find_command_start ( input : & str , bot : & str ) -> Option < usize > {
14- input. find ( & format ! ( "@{}" , bot) )
14+ [ & format ! ( "@{}" , bot) , "r?" , "R?" ]
15+ . iter ( )
16+ . map ( |s| input. find ( s) )
17+ . min_by_key ( |i| i. unwrap_or ( usize:: MAX ) ) ?
1518}
1619
1720#[ derive( Debug , PartialEq ) ]
@@ -65,51 +68,87 @@ impl<'a> Input<'a> {
6568
6669 fn parse_command ( & mut self ) -> Option < Command < ' a > > {
6770 let mut tok = Tokenizer :: new ( & self . all [ self . parsed ..] ) ;
68- assert_eq ! (
69- tok. next_token( ) . unwrap( ) ,
70- Some ( Token :: Word ( & format!( "@{}" , self . bot) ) )
71- ) ;
72- log:: info!( "identified potential command" ) ;
73-
71+ let review = match tok. next_token ( ) {
72+ Ok ( Some ( Token :: Word ( w) ) ) if w == & format ! ( "@{}" , self . bot) => false ,
73+ Ok ( Some ( Token :: Word ( w) ) ) if w == "r" || w == "R" => true ,
74+ other => {
75+ log:: trace!( "received odd review start token: {:?}" , other) ;
76+ return None ;
77+ }
78+ } ;
79+
7480 let mut success = vec ! [ ] ;
75-
76- let original_tokenizer = tok. clone ( ) ;
77-
78- success. extend ( parse_single_command (
79- relabel:: RelabelCommand :: parse,
80- Command :: Relabel ,
81- & original_tokenizer,
82- ) ) ;
83- success. extend ( parse_single_command (
84- assign:: AssignCommand :: parse,
85- Command :: Assign ,
86- & original_tokenizer,
87- ) ) ;
88- success. extend ( parse_single_command (
89- ping:: PingCommand :: parse,
90- Command :: Ping ,
91- & original_tokenizer,
92- ) ) ;
93- success. extend ( parse_single_command (
94- nominate:: NominateCommand :: parse,
95- Command :: Nominate ,
96- & original_tokenizer,
97- ) ) ;
98- success. extend ( parse_single_command (
99- prioritize:: PrioritizeCommand :: parse,
100- Command :: Prioritize ,
101- & original_tokenizer,
102- ) ) ;
103- success. extend ( parse_single_command (
104- second:: SecondCommand :: parse,
105- Command :: Second ,
106- & original_tokenizer,
107- ) ) ;
108- success. extend ( parse_single_command (
109- glacier:: GlacierCommand :: parse,
110- Command :: Glacier ,
111- & original_tokenizer,
112- ) ) ;
81+
82+ if review {
83+ match tok. next_token ( ) {
84+ Ok ( Some ( Token :: Question ) ) => { }
85+ other => {
86+ log:: trace!( "received odd review start token: {:?}" , other) ;
87+ return None ;
88+ }
89+ }
90+ log:: info!( "identified potential review request" ) ;
91+ match tok. next_token ( ) {
92+ Ok ( Some ( Token :: Word ( w) ) ) => {
93+ let mentions = crate :: mentions:: get_mentions ( w) ;
94+ if let [ a] = & mentions[ ..] {
95+ success. push ( (
96+ tok,
97+ Command :: Assign ( Ok ( assign:: AssignCommand :: User {
98+ username : ( * a) . to_owned ( ) ,
99+ } ) ) ,
100+ ) ) ;
101+ } else {
102+ log:: trace!( "{:?} had non-one mention: {:?}" , w, mentions) ;
103+ return None
104+ }
105+ }
106+ other => {
107+ log:: trace!( "received odd review start token: {:?}" , other) ;
108+ return None
109+ }
110+ }
111+ } else {
112+ log:: info!( "identified potential command" ) ;
113+
114+ let original_tokenizer = tok. clone ( ) ;
115+
116+ success. extend ( parse_single_command (
117+ relabel:: RelabelCommand :: parse,
118+ Command :: Relabel ,
119+ & original_tokenizer,
120+ ) ) ;
121+ success. extend ( parse_single_command (
122+ assign:: AssignCommand :: parse,
123+ Command :: Assign ,
124+ & original_tokenizer,
125+ ) ) ;
126+ success. extend ( parse_single_command (
127+ ping:: PingCommand :: parse,
128+ Command :: Ping ,
129+ & original_tokenizer,
130+ ) ) ;
131+ success. extend ( parse_single_command (
132+ nominate:: NominateCommand :: parse,
133+ Command :: Nominate ,
134+ & original_tokenizer,
135+ ) ) ;
136+ success. extend ( parse_single_command (
137+ prioritize:: PrioritizeCommand :: parse,
138+ Command :: Prioritize ,
139+ & original_tokenizer,
140+ ) ) ;
141+ success. extend ( parse_single_command (
142+ second:: SecondCommand :: parse,
143+ Command :: Second ,
144+ & original_tokenizer,
145+ ) ) ;
146+ success. extend ( parse_single_command (
147+ glacier:: GlacierCommand :: parse,
148+ Command :: Glacier ,
149+ & original_tokenizer,
150+ ) ) ;
151+ }
113152
114153 if success. len ( ) > 1 {
115154 panic ! (
@@ -119,6 +158,8 @@ impl<'a> Input<'a> {
119158 ) ;
120159 }
121160
161+ let ( mut tok, c) = success. pop ( ) ?;
162+
122163 if self
123164 . code
124165 . overlaps_code ( ( self . parsed ) ..( self . parsed + tok. position ( ) ) )
@@ -128,7 +169,6 @@ impl<'a> Input<'a> {
128169 return None ;
129170 }
130171
131- let ( mut tok, c) = success. pop ( ) ?;
132172 // if we errored out while parsing the command do not move the input forwards
133173 self . parsed += if c. is_ok ( ) {
134174 tok. position ( )
@@ -230,3 +270,25 @@ fn move_input_along_1() {
230270 // don't move input along if parsing the command fails
231271 assert_eq ! ( & input. all[ ..input. parsed] , "@bot" ) ;
232272}
273+
274+ #[ test]
275+ fn parse_assign_review ( ) {
276+ let input = "R? @user" ;
277+ let mut input = Input :: new ( input, "bot" ) ;
278+ match input. next ( ) . unwrap ( ) {
279+ Command :: Assign ( Ok ( x) ) => assert_eq ! (
280+ x,
281+ assign:: AssignCommand :: User {
282+ username: String :: from( "user" ) ,
283+ }
284+ ) ,
285+ o => panic ! ( "unknown: {:?}" , o) ,
286+ } ;
287+ }
288+
289+ #[ test]
290+ fn parse_assign_review_no_panic ( ) {
291+ let input = "R ?" ;
292+ let mut input = Input :: new ( input, "bot" ) ;
293+ assert ! ( input. next( ) . is_none( ) ) ;
294+ }
0 commit comments