@@ -4,6 +4,9 @@ package help
4
4
import (
5
5
"bufio"
6
6
"strings"
7
+ "unicode/utf8"
8
+
9
+ "codeberg.org/anaseto/goal/scan"
7
10
)
8
11
9
12
// Wrap produces a help function suitable for use in cmd.Config by combining
@@ -50,67 +53,88 @@ func initHelp() map[string]string {
50
53
help ["time" ] = helpTime // for the builtin name
51
54
help ["rt" ] = helpRuntime
52
55
help ["io" ] = helpIO
53
- const scols = 12 // syntax
54
- const vcols = 4 // verbs
55
- const acols = 5 // adverbs
56
- const nvcols = 10 // named verbs
57
- help [":" ] = getBuiltin (helpSyntax , "assign" , scols ) + getBuiltin (helpVerbs , ":" , vcols )
58
- help ["::" ] = getBuiltin (helpSyntax , "assign" , scols ) + getBuiltin (helpVerbs , "::" , vcols )
59
- help ["rx" ] = getBuiltin (helpSyntax , "regexp" , scols ) + getBuiltin (helpNamedVerbs , "rx" , nvcols )
60
- help ["qq" ] = getBuiltin (helpSyntax , "strings" , scols )
61
- help ["rq" ] = getBuiltin (helpSyntax , "raw strings" , scols )
62
- help ["»" ] = getBuiltin (helpVerbs , "»" , vcols )
56
+ parseBuiltins (help , getSyntaxKey , helpSyntax , 16 )
57
+ help ["::" ] = help [":" ] // for syntax assign entry
58
+ parseBuiltins (help , getVerb , helpVerbs , 4 )
63
59
help ["rshift" ] = help ["»" ]
64
- help ["«" ] = getBuiltin (helpVerbs , "«" , vcols )
65
60
help ["shift" ] = help ["«" ]
66
- for _ , v := range []string {"+" , "-" , "*" , "%" , "!" , "&" , "|" , "<" , ">" , "=" , "~" , "," , "^" ,
67
- "#" , "_" , "$" , "?" , "@" , "." } {
68
- help [v ] = getBuiltin (helpVerbs , v , vcols )
69
- }
70
- for _ , v := range []string {"'" , "/" , "\\ " } {
71
- help [v ] = getBuiltin (helpAdverbs , v , acols )
72
- }
73
- for _ , v := range []string {"abs" , "bytes" , "uc" , "error" , "eval" , "firsts" , "json" , "ocount" , "panic" ,
74
- "sign" , "csv" , "in" , "mod" , "nan" , "rotate" , "sub" , "utf8" ,
75
- "atan" , "cos" , "exp" , "log" , "round" , "sin" , "sqrt" } {
76
- help [v ] = getBuiltin (helpNamedVerbs , v , nvcols )
77
- }
61
+ parseBuiltins (help , getVerb , helpAdverbs , 7 )
62
+ parseBuiltins (help , getNamedVerb , helpNamedVerbs , 11 )
78
63
help ["¿" ] = help ["firsts" ] + help ["in" ]
79
- for _ , v := range []string {"rt.get" , "rt.log" , "rt.seed" , "rt.time" , "rt.try" } {
80
- help [v ] = getBuiltin (helpRuntime , v , nvcols )
81
- }
82
- for _ , v := range []string {"abspath" , "chdir" , "close" , "dirfs" , "env" , "flush" , "glob" , "import" , "mkdir" , "open" , "print" ,
83
- "read" , "remove" , "rename" , "run" , "say" , "shell" , "stat" , "ARGS" , "STDIN" , "STDOUT" , "STDERR" } {
84
- help [v ] = getBuiltin (helpIO , v , nvcols )
85
- }
64
+ parseBuiltins (help , getNamedVerb , helpRuntime , 16 )
65
+ parseBuiltins (help , getNamedVerb , helpIO , 12 )
86
66
help ["subfs" ] = help ["dirfs" ]
87
67
return help
88
68
}
89
69
90
- func getBuiltin (s string , v string , n int ) string {
91
- var sb strings.Builder
92
- r := strings .NewReader (s )
93
- sc := bufio .NewScanner (r )
94
- match := false
70
+ func parseBuiltins (help map [string ]string , f func (string ) string , s string , n int ) {
71
+ sc := bufio .NewScanner (strings .NewReader (s ))
72
+ var verb string // current verb
95
73
blanks := strings .Repeat (" " , n )
96
74
for sc .Scan () {
97
75
ln := sc .Text ()
98
- if len (ln ) < n {
99
- match = false
76
+ if len (ln ) < n || strings . HasSuffix ( ln , " HELP" ) {
77
+ verb = ""
100
78
continue
101
79
}
102
- if strings .Contains (ln [:n ], v ) || ln [:n ] == blanks && match {
103
- // NOTE: currently no builtin name is a substring of
104
- // another. Otherwise, this could match more names than
105
- // wanted.
106
- match = true
107
- sb .WriteString (ln )
108
- sb .WriteByte ('\n' )
80
+ v := f (ln [:n ])
81
+ if v != "" {
82
+ verb = v
83
+ }
84
+ if v != "" || ln [:n ] == blanks && verb != "" {
85
+ help [verb ] += ln + "\n "
109
86
continue
110
87
}
111
- match = false
88
+ verb = ""
89
+ }
90
+ }
91
+
92
+ // getNamedVerb returns the first multi-letter word in the string.
93
+ func getNamedVerb (s string ) string {
94
+ from , to := 0 , len (s )
95
+ for i , r := range s {
96
+ if ! scan .IsLetter (r ) && r != '.' {
97
+ if i - from > 1 {
98
+ // multi-letter word
99
+ to = i
100
+ break
101
+ }
102
+ from = i + utf8 .RuneLen (r )
103
+ }
104
+ }
105
+ return s [from :to ]
106
+ }
107
+
108
+ // getVerb returns the first non-letter non-space symbol in the string
109
+ // (possibly a digraph, for ::).
110
+ func getVerb (s string ) string {
111
+ from , to := 0 , len (s )
112
+ for i , r := range s {
113
+ if scan .IsLetter (r ) || r == ' ' || r == '[' || r == ';' || r == ']' {
114
+ if i - from > 0 {
115
+ to = i
116
+ break
117
+ }
118
+ from = i + utf8 .RuneLen (r )
119
+ }
120
+ }
121
+ return s [from :to ]
122
+ }
123
+
124
+ // getSyntaxKey returns a help key for a few syntax entries.
125
+ func getSyntaxKey (s string ) string {
126
+ switch {
127
+ case strings .Contains (s , "assign" ):
128
+ return ":"
129
+ case strings .Contains (s , "regexp" ):
130
+ return "rx"
131
+ case strings .Contains (s , "raw strings" ):
132
+ return "rq"
133
+ case strings .Contains (s , "strings" ):
134
+ return "qq"
135
+ default :
136
+ return ""
112
137
}
113
- return sb .String ()
114
138
}
115
139
116
140
func Map () map [string ]string {
0 commit comments