@@ -158,13 +158,37 @@ impl UsageParser {
158158 } )
159159 }
160160
161+ /// Extract positional argument names in order from USAGE line
162+ fn extract_arg_order_from_usage ( & self ) -> Vec < String > {
163+ let mut arg_order = Vec :: new ( ) ;
164+
165+ // Find the main usage line (not --help line)
166+ if let Some ( usage_line) = self
167+ . usage_text
168+ . lines ( )
169+ . skip_while ( |l| !l. contains ( "Usage:" ) )
170+ . skip ( 1 ) // Skip "Usage:" line
171+ . find ( |l| !l. trim ( ) . ends_with ( "--help" ) && l. contains ( "qsv" ) )
172+ {
173+ // Extract all <arg> and [<arg>] patterns in order
174+ let re = regex:: Regex :: new ( r"(?:\[)?<([^>]+)>(?:\])?" ) . unwrap ( ) ;
175+ for cap in re. captures_iter ( usage_line) {
176+ if let Some ( arg_name) = cap. get ( 1 ) {
177+ arg_order. push ( arg_name. as_str ( ) . to_string ( ) ) ;
178+ }
179+ }
180+ }
181+
182+ arg_order
183+ }
184+
161185 /// Parse USAGE text using qsv-docopt Parser for robust parsing
162186 fn parse_with_docopt ( & self ) -> Result < ( Vec < Argument > , Vec < Option_ > ) , String > {
163187 // Parse USAGE text with docopt
164188 let parser =
165189 Parser :: new ( & self . usage_text ) . map_err ( |e| format ! ( "Docopt parsing failed: {e}" ) ) ?;
166190
167- let mut args = Vec :: new ( ) ;
191+ let mut args_map = std :: collections :: HashMap :: new ( ) ;
168192 let mut options = Vec :: new ( ) ;
169193
170194 // Also parse manually to get descriptions
@@ -304,13 +328,16 @@ impl UsageParser {
304328
305329 let arg_type = self . infer_argument_type ( & arg_name, & description) ;
306330
307- args. push ( Argument {
308- name : arg_name. clone ( ) ,
309- arg_type,
310- required : !opts. arg . has_default ( ) , // If it has a default, it's optional
311- description,
312- examples : Vec :: new ( ) ,
313- } ) ;
331+ args_map. insert (
332+ arg_name. clone ( ) ,
333+ Argument {
334+ name : arg_name. clone ( ) ,
335+ arg_type,
336+ required : !opts. arg . has_default ( ) , // If it has a default, it's optional
337+ description,
338+ examples : Vec :: new ( ) ,
339+ } ,
340+ ) ;
314341 } ,
315342 Atom :: Command ( _) => {
316343 // Skip commands - we're only interested in args/options
@@ -319,8 +346,16 @@ impl UsageParser {
319346 }
320347 }
321348
322- // Sort for consistent output
323- args. sort_by ( |a, b| a. name . cmp ( & b. name ) ) ;
349+ // Reorder args based on their appearance in the USAGE line
350+ let arg_order = self . extract_arg_order_from_usage ( ) ;
351+ let mut args = Vec :: new ( ) ;
352+ for arg_name in arg_order {
353+ if let Some ( arg) = args_map. remove ( & arg_name) {
354+ args. push ( arg) ;
355+ }
356+ }
357+
358+ // Sort options for consistent output
324359 options. sort_by ( |a, b| a. flag . cmp ( & b. flag ) ) ;
325360
326361 Ok ( ( args, options) )
0 commit comments