Skip to content

Commit fb61478

Browse files
engalarclaude
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 c5e756b commit fb61478

10 files changed

Lines changed: 601 additions & 478 deletions

File tree

mdl/ast/ast_query.go

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

407407
func (s *SetStmt) isStatement() {}
408408

409-
// HelpStmt represents: HELP or ?
410-
type HelpStmt struct{}
409+
// HelpStmt represents: HELP [topic words...]
410+
type HelpStmt struct {
411+
Topic []string // e.g., ["workflow", "user-task"] for HELP WORKFLOW USER-TASK
412+
}
411413

412414
func (s *HelpStmt) isStatement() {}
413415

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
"github.com/mendixlabs/mxcli/mdl/visitor"
1516
)
@@ -42,8 +43,22 @@ func (e *Executor) execSet(s *ast.SetStmt) error {
4243
return nil
4344
}
4445

45-
// execHelp handles HELP statements.
46-
func (e *Executor) execHelp() error {
46+
// execHelp handles HELP statements. With topic words, queries the syntax registry.
47+
func (e *Executor) execHelp(s *ast.HelpStmt) error {
48+
if len(s.Topic) > 0 {
49+
path := resolveHelpPath(s.Topic)
50+
features := syntax.ByPrefix(path)
51+
if len(features) == 0 {
52+
fmt.Fprintf(e.output, "No syntax help found for: %s\n", path)
53+
fmt.Fprintln(e.output, "Use HELP; for a command overview.")
54+
return nil
55+
}
56+
if e.format == FormatJSON {
57+
return syntax.WriteJSON(e.output, features)
58+
}
59+
syntax.WriteText(e.output, features)
60+
return nil
61+
}
4762
help := `MDL Commands:
4863
4964
Connection:
@@ -320,6 +335,32 @@ Statement Terminator:
320335
return nil
321336
}
322337

338+
// resolveHelpPath converts space-separated words like ["workflow", "user", "task"]
339+
// into a registry path like "workflow.user-task" by greedily merging adjacent words
340+
// with hyphens to find the longest matching prefix at each level.
341+
func resolveHelpPath(words []string) string {
342+
var segments []string
343+
i := 0
344+
for i < len(words) {
345+
matched := false
346+
for j := len(words); j > i; j-- {
347+
candidate := strings.Join(words[i:j], "-")
348+
testPath := strings.Join(append(segments, candidate), ".")
349+
if syntax.HasPrefix(testPath) {
350+
segments = append(segments, candidate)
351+
i = j
352+
matched = true
353+
break
354+
}
355+
}
356+
if !matched {
357+
segments = append(segments, words[i])
358+
i++
359+
}
360+
}
361+
return strings.Join(segments, ".")
362+
}
363+
323364
// showVersion displays Mendix project version information.
324365
func (e *Executor) showVersion() error {
325366
if e.reader == nil {

mdl/executor/executor_dispatch.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ func (e *Executor) executeInner(stmt ast.Statement) error {
251251
case *ast.SetStmt:
252252
return e.execSet(s)
253253
case *ast.HelpStmt:
254-
return e.execHelp()
254+
return e.execHelp(s)
255255
case *ast.ExitStmt:
256256
return e.execExit()
257257
case *ast.ExecuteScriptStmt:

mdl/grammar/MDLParser.g4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3350,7 +3350,7 @@ linkMapping
33503350
;
33513351

33523352
helpStatement
3353-
: IDENTIFIER // HELP command
3353+
: IDENTIFIER (identifierOrKeyword)* // HELP [topic words...]
33543354
;
33553355

33563356
/**

mdl/grammar/parser/MDLParser.interp

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

mdl/grammar/parser/mdl_lexer.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mdl/grammar/parser/mdl_parser.go

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

mdl/grammar/parser/mdlparser_base_listener.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mdl/grammar/parser/mdlparser_listener.go

Lines changed: 1 addition & 1 deletion
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
@@ -916,13 +916,17 @@ func (b *Builder) ExitExecuteScriptStatement(ctx *parser.ExecuteScriptStatementC
916916
}
917917

918918
// ExitHelpStatement handles help/exit/quit commands
919-
// Grammar: helpStatement: IDENTIFIER
919+
// Grammar: helpStatement: IDENTIFIER (identifierOrKeyword)*
920920
func (b *Builder) ExitHelpStatement(ctx *parser.HelpStatementContext) {
921921
if id := ctx.IDENTIFIER(); id != nil {
922922
cmd := strings.ToLower(id.GetText())
923923
switch cmd {
924924
case "help", "?":
925-
b.statements = append(b.statements, &ast.HelpStmt{})
925+
stmt := &ast.HelpStmt{}
926+
for _, tok := range ctx.AllIdentifierOrKeyword() {
927+
stmt.Topic = append(stmt.Topic, strings.ToLower(tok.GetText()))
928+
}
929+
b.statements = append(b.statements, stmt)
926930
case "exit", "quit":
927931
b.statements = append(b.statements, &ast.ExitStmt{})
928932
case "status":

0 commit comments

Comments
 (0)