@@ -42,7 +42,8 @@ public HelpAction(IEnumerable<TypeAttributePair> actions, Func<Type, IAction> cr
42
42
Type = type ,
43
43
Contexts = attributes . Select ( a => a . Context ) ,
44
44
SubContexts = attributes . Select ( a => a . SubContext ) ,
45
- Names = attributes . Select ( a => a . Name )
45
+ Names = attributes . Select ( a => a . Name ) ,
46
+ ParentCommandName = attributes . Select ( a => a . ParentCommandName )
46
47
} ;
47
48
} ) ;
48
49
}
@@ -187,7 +188,8 @@ private void DisplayGeneralHelp()
187
188
. WriteLine ( "Usage: func [context] <action> [-/--options]" )
188
189
. WriteLine ( ) ;
189
190
DisplayContextsHelp ( contexts ) ;
190
- var actions = _actionTypes . Where ( a => a . Contexts . Contains ( Context . None ) ) ;
191
+ var actions = _actionTypes
192
+ . Where ( a => a . Contexts . Contains ( Context . None ) ) ;
191
193
DisplayActionsHelp ( actions ) ;
192
194
}
193
195
@@ -211,40 +213,88 @@ private void DisplayActionsHelp(IEnumerable<ActionType> actions)
211
213
if ( actions . Any ( ) )
212
214
{
213
215
ColoredConsole . WriteLine ( TitleColor ( "Actions: " ) ) ;
216
+
217
+ // Group actions by parent command
218
+ var parentCommands = actions
219
+ . Where ( a => a . ParentCommandName . All ( p => string . IsNullOrEmpty ( p ) ) ) // Actions with no parent
220
+ . ToList ( ) ;
221
+
222
+ var subCommands = actions
223
+ . Where ( a => a . ParentCommandName . Any ( p => ! string . IsNullOrEmpty ( p ) ) ) // Actions with a parent
224
+ . ToList ( ) ;
225
+
214
226
var longestName = actions . Select ( a => a . Names ) . SelectMany ( n => n ) . Max ( n => n . Length ) ;
215
227
longestName += 2 ; // for coloring chars
216
- foreach ( var action in actions )
228
+
229
+ // Display parent commands first
230
+ foreach ( var parentAction in parentCommands )
217
231
{
218
- ColoredConsole . WriteLine ( GetActionHelp ( action , longestName ) ) ;
219
- DisplaySwitches ( action ) ;
220
- }
232
+ // Display parent command
233
+ ColoredConsole . WriteLine ( GetActionHelp ( parentAction , longestName ) ) ;
234
+ DisplaySwitches ( parentAction ) ;
221
235
222
- ColoredConsole . WriteLine ( ) ;
236
+ // Find and display child commands for this parent
237
+ var parentName = parentAction . Names . First ( ) ;
238
+ var childCommands = subCommands
239
+ . Where ( s => s . ParentCommandName . Any ( p => p . Equals ( parentName , StringComparison . OrdinalIgnoreCase ) ) )
240
+ . ToList ( ) ;
241
+
242
+ if ( childCommands . Any ( ) )
243
+ {
244
+ ColoredConsole . WriteLine ( ) ; // Add spacing before subcommands
245
+
246
+ foreach ( var childCommand in childCommands )
247
+ {
248
+ DisplaySubCommandHelp ( childCommand ) ;
249
+ }
250
+ }
251
+
252
+ ColoredConsole . WriteLine ( ) ;
253
+ }
223
254
}
224
255
}
225
256
226
- private void DisplaySwitches ( ActionType actionType )
257
+ private void DisplaySubCommandHelp ( ActionType subCommand )
258
+ {
259
+ // Extract the runtime name from the full command name
260
+ // E.g., "pack dotnet" -> "Dotnet"
261
+ var fullCommandName = subCommand . Names . First ( ) ;
262
+ var parts = fullCommandName . Split ( ' ' , StringSplitOptions . RemoveEmptyEntries ) ;
263
+ var runtimeName = parts . Length > 1 ?
264
+ char . ToUpper ( parts [ 1 ] [ 0 ] ) + parts [ 1 ] . Substring ( 1 ) . ToLower ( ) :
265
+ fullCommandName ;
266
+
267
+ var description = subCommand . Type . GetCustomAttributes < ActionAttribute > ( ) ? . FirstOrDefault ( ) ? . HelpText ;
268
+
269
+ // Display indented subcommand header
270
+ ColoredConsole . WriteLine ( $ " { runtimeName . DarkCyan ( ) } { description } ") ;
271
+
272
+ // Display subcommand switches with extra indentation
273
+ DisplaySwitches ( subCommand , true ) ;
274
+ }
275
+
276
+ private void DisplaySwitches ( ActionType actionType , bool addExtraIndent = false )
227
277
{
228
278
var action = _createAction . Invoke ( actionType . Type ) ;
229
279
try
230
280
{
231
281
var options = action . ParseArgs ( Array . Empty < string > ( ) ) ;
232
282
if ( options . UnMatchedOptions . Any ( ) )
233
283
{
234
- DisplayOptions ( options . UnMatchedOptions ) ;
284
+ DisplayOptions ( options . UnMatchedOptions , addExtraIndent ) ;
235
285
ColoredConsole . WriteLine ( ) ;
236
286
}
237
287
}
238
288
catch ( CliArgumentsException e )
239
289
{
240
290
if ( e . Arguments . Any ( ) )
241
291
{
242
- DisplayPositionalArguments ( e . Arguments ) ;
292
+ DisplayPositionalArguments ( e . Arguments , addExtraIndent ) ;
243
293
}
244
294
245
295
if ( e . ParseResults != null && e . ParseResults . UnMatchedOptions . Any ( ) )
246
296
{
247
- DisplayOptions ( e . ParseResults . UnMatchedOptions ) ;
297
+ DisplayOptions ( e . ParseResults . UnMatchedOptions , addExtraIndent ) ;
248
298
}
249
299
250
300
ColoredConsole . WriteLine ( ) ;
@@ -255,13 +305,13 @@ private void DisplaySwitches(ActionType actionType)
255
305
}
256
306
}
257
307
258
- private void DisplayPositionalArguments ( IEnumerable < CliArgument > arguments )
308
+ private void DisplayPositionalArguments ( IEnumerable < CliArgument > arguments , bool addExtraIndent )
259
309
{
260
310
var longestName = arguments . Max ( o => o . Name . Length ) ;
261
311
longestName += 4 ; // 4 for coloring and <> characters
262
312
foreach ( var argument in arguments )
263
313
{
264
- var helpLine = string . Format ( $ " {{0, { - longestName } }} {{1}}", $ "<{ argument . Name } >". DarkGray ( ) , argument . Description ) ;
314
+ var helpLine = string . Format ( $ "{ ( addExtraIndent ? " " : " " ) } {{0, { - longestName } }} {{1}}", $ "<{ argument . Name } >". DarkGray ( ) , argument . Description ) ;
265
315
if ( helpLine . Length < SafeConsole . BufferWidth )
266
316
{
267
317
ColoredConsole . WriteLine ( helpLine ) ;
@@ -277,7 +327,7 @@ private void DisplayPositionalArguments(IEnumerable<CliArgument> arguments)
277
327
}
278
328
}
279
329
280
- private static void DisplayOptions ( IEnumerable < ICommandLineOption > options )
330
+ private static void DisplayOptions ( IEnumerable < ICommandLineOption > options , bool addExtraIndent = false )
281
331
{
282
332
var longestName = options . Max ( o =>
283
333
{
@@ -311,7 +361,7 @@ private static void DisplayOptions(IEnumerable<ICommandLineOption> options)
311
361
stringBuilder . Append ( $ " [-{ option . ShortName } ]") ;
312
362
}
313
363
314
- var helpSwitch = string . Format ( $ " {{0, { - longestName } }} ", stringBuilder . ToString ( ) . DarkGray ( ) ) ;
364
+ var helpSwitch = string . Format ( $ "{ ( addExtraIndent ? " " : " " ) } {{0, { - longestName } }} ", stringBuilder . ToString ( ) . DarkGray ( ) ) ;
315
365
var helpSwitchLength = helpSwitch . Length - 2 ; // helpSwitch contains 2 formatting characters.
316
366
var helpText = option . Description ;
317
367
if ( string . IsNullOrWhiteSpace ( helpText ) )
0 commit comments