Skip to content

Commit 5d193d5

Browse files
engalarclaude
authored andcommitted
feat: HELP command with topic parameters (Phase 3)
HELP WORKFLOW; HELP WORKFLOW USER TASK; HELP SECURITY ENTITY ACCESS; all now query the syntax feature registry. Greedy path resolver merges space-separated words into hyphenated registry paths. Grammar extended: helpStatement accepts optional identifierOrKeyword*. AST HelpStmt gains Topic []string field. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 87cb96c commit 5d193d5

8 files changed

Lines changed: 600 additions & 475 deletions

File tree

mdl/ast/ast_query.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,10 @@ type SetStmt struct {
436436

437437
func (s *SetStmt) isStatement() {}
438438

439-
// HelpStmt represents: HELP or ?
440-
type HelpStmt struct{}
439+
// HelpStmt represents: HELP [topic words...]
440+
type HelpStmt struct {
441+
Topic []string // e.g., ["workflow", "user-task"] for HELP WORKFLOW USER-TASK
442+
}
441443

442444
func (s *HelpStmt) isStatement() {}
443445

mdl/executor/cmd_misc.go

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"path/filepath"
1111
"strings"
1212

13+
"github.com/mendixlabs/mxcli/cmd/mxcli/syntax"
1314
"github.com/mendixlabs/mxcli/mdl/ast"
1415
mdlerrors "github.com/mendixlabs/mxcli/mdl/errors"
1516
"github.com/mendixlabs/mxcli/mdl/visitor"
@@ -50,8 +51,22 @@ func execSet(ctx *ExecContext, s *ast.SetStmt) error {
5051
return nil
5152
}
5253

53-
// execHelp handles HELP statements.
54-
func execHelp(ctx *ExecContext) error {
54+
// execHelp handles HELP statements. With topic words, queries the syntax registry.
55+
func execHelp(ctx *ExecContext, s *ast.HelpStmt) error {
56+
if len(s.Topic) > 0 {
57+
path := resolveHelpPath(s.Topic)
58+
features := syntax.ByPrefix(path)
59+
if len(features) == 0 {
60+
fmt.Fprintf(ctx.Output, "No syntax help found for: %s\n", path)
61+
fmt.Fprintln(ctx.Output, "Use HELP; for a command overview.")
62+
return nil
63+
}
64+
if ctx.Format == FormatJSON {
65+
return syntax.WriteJSON(ctx.Output, features)
66+
}
67+
syntax.WriteText(ctx.Output, features)
68+
return nil
69+
}
5570
help := `MDL Commands:
5671
5772
Connection:
@@ -328,6 +343,32 @@ Statement Terminator:
328343
return nil
329344
}
330345

346+
// resolveHelpPath converts space-separated words like ["workflow", "user", "task"]
347+
// into a registry path like "workflow.user-task" by greedily merging adjacent words
348+
// with hyphens to find the longest matching prefix at each level.
349+
func resolveHelpPath(words []string) string {
350+
var segments []string
351+
i := 0
352+
for i < len(words) {
353+
matched := false
354+
for j := len(words); j > i; j-- {
355+
candidate := strings.Join(words[i:j], "-")
356+
testPath := strings.Join(append(segments, candidate), ".")
357+
if syntax.HasPrefix(testPath) {
358+
segments = append(segments, candidate)
359+
i = j
360+
matched = true
361+
break
362+
}
363+
}
364+
if !matched {
365+
segments = append(segments, words[i])
366+
i++
367+
}
368+
}
369+
return strings.Join(segments, ".")
370+
}
371+
331372
// listVersion displays Mendix project version information.
332373
func listVersion(ctx *ExecContext) error {
333374
if !ctx.Connected() {

mdl/executor/executor_dispatch.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ func (e *Executor) newExecContext(ctx context.Context) *ExecContext {
3333
executor: e,
3434
}
3535
}
36+
37+
// Ensure ast import is used via executeInner's stmt parameter.
38+
var _ ast.Statement = (*ast.HelpStmt)(nil)

mdl/executor/register_stubs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ func registerSessionHandlers(r *Registry) {
376376
return execSet(ctx, stmt.(*ast.SetStmt))
377377
})
378378
r.Register(&ast.HelpStmt{}, func(ctx *ExecContext, stmt ast.Statement) error {
379-
return execHelp(ctx)
379+
return execHelp(ctx, stmt.(*ast.HelpStmt))
380380
})
381381
r.Register(&ast.ExitStmt{}, func(ctx *ExecContext, stmt ast.Statement) error {
382382
return execExit(ctx)

mdl/grammar/MDLParser.g4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3483,7 +3483,7 @@ linkMapping
34833483
;
34843484

34853485
helpStatement
3486-
: IDENTIFIER // HELP command
3486+
: IDENTIFIER (identifierOrKeyword)* // HELP [topic words...]
34873487
;
34883488

34893489
/**

mdl/grammar/parser/MDLParser.interp

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

mdl/grammar/parser/mdl_parser.go

Lines changed: 541 additions & 466 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mdl/visitor/visitor_query.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,13 +1004,17 @@ func (b *Builder) ExitExecuteScriptStatement(ctx *parser.ExecuteScriptStatementC
10041004
}
10051005

10061006
// ExitHelpStatement handles help/exit/quit commands
1007-
// Grammar: helpStatement: IDENTIFIER
1007+
// Grammar: helpStatement: IDENTIFIER (identifierOrKeyword)*
10081008
func (b *Builder) ExitHelpStatement(ctx *parser.HelpStatementContext) {
10091009
if id := ctx.IDENTIFIER(); id != nil {
10101010
cmd := strings.ToLower(id.GetText())
10111011
switch cmd {
10121012
case "help", "?":
1013-
b.statements = append(b.statements, &ast.HelpStmt{})
1013+
stmt := &ast.HelpStmt{}
1014+
for _, tok := range ctx.AllIdentifierOrKeyword() {
1015+
stmt.Topic = append(stmt.Topic, strings.ToLower(tok.GetText()))
1016+
}
1017+
b.statements = append(b.statements, stmt)
10141018
case "exit", "quit":
10151019
b.statements = append(b.statements, &ast.ExitStmt{})
10161020
case "status":

0 commit comments

Comments
 (0)