@@ -3,173 +3,173 @@ cli.__index = cli
33
44type ArgKind = "positional" | "flag" | "option"
55type ArgOptions = {
6- help : string ? ,
7- aliases : { string }? ,
8- default : string ? ,
9- required : boolean ? ,
6+ help : string ? ,
7+ aliases : { string }? ,
8+ default : string ? ,
9+ required : boolean ? ,
1010}
1111
1212type ArgData = {
13- name : string ,
14- kind : ArgKind ,
15- options : ArgOptions ,
13+ name : string ,
14+ kind : ArgKind ,
15+ options : ArgOptions ,
1616}
1717
1818type ParseResult = {
19- values : { [string ]: string },
20- flags : { [string ]: boolean },
21- fwdArgs : { string },
19+ values : { [string ]: string },
20+ flags : { [string ]: boolean },
21+ fwdArgs : { string },
2222}
2323
2424type ParserData = {
25- arguments : { [number ]: ArgData },
26- positional : { [number ] : ArgData },
27- parsed : ParseResult ,
25+ arguments : { [number ]: ArgData },
26+ positional : { [number ]: ArgData },
27+ parsed : ParseResult ,
2828}
2929
3030type ParserInterface = typeof (cli )
3131export type Parser = setmetatable <ParserData , ParserInterface >
3232
3333function cli .parser (): Parser
34- local self = {
35- arguments = {},
36- positional = {},
37- parsed = { values = {}, flags = {}, fwdArgs = {} },
38- }
34+ local self = {
35+ arguments = {},
36+ positional = {},
37+ parsed = { values = {}, flags = {}, fwdArgs = {} },
38+ }
3939
40- return setmetatable (self , cli )
40+ return setmetatable (self , cli )
4141end
4242
4343function cli .add (self : Parser , name : string , kind : ArgKind , options : ArgOptions ): ()
44- local argument = {
45- name = name ,
46- kind = kind ,
47- options = options or { aliases = {}, required = false },
48- }
49-
50- table.insert (self .arguments , argument )
51- if kind == "positional" then
52- table.insert (self .positional , argument )
53- end
44+ local argument = {
45+ name = name ,
46+ kind = kind ,
47+ options = options or { aliases = {}, required = false },
48+ }
49+
50+ table.insert (self .arguments , argument )
51+ if kind == "positional" then
52+ table.insert (self .positional , argument )
53+ end
5454end
5555
56- function cli .parse (self : Parser , args : {string }): ()
57- local i = 0
58- local pos_index = 1
59-
60- while i < # args do
61- i += 1
62-
63- local arg = args [i ]
64-
65- -- if the argument is exactly "--", we pass everything along
66- if arg == "--" then
67- table.move (args , i + 1 , # args , 1 , self .parsed .fwdArgs )
68- break
69- end
70-
71- -- if the argument starts with two dashes, we're parsing either a flag or an option
72- if string.sub (arg , 1 , 2 ) == "--" then
73- local name = string.sub (arg , 3 )
74- local found = false
75-
76- for _ , argument in self .arguments do
77- local aliases = argument .options .aliases or {}
78-
79- if argument .name == name or table.find (aliases , name ) then
80- found = true
81-
82- if argument .kind == "option" then
83- -- advance past the argument
84- i += 1
85-
86- assert (i <= # args , "Missing value for argument: " .. argument .name )
87- self .parsed .values [argument .name ] = args [i ]
88-
89- break
90- end
91-
92- self .parsed .flags [argument .name ] = true
93- break
94- end
95- end
96-
97- assert (found , "Unknown argument: " .. name )
98- continue
99- end
100-
101- -- if the argument starts with a single dash, we're parsing a flag
102- if string.sub (arg , 1 , 1 ) == "-" then
103- local flags = string.sub (arg , 2 )
104-
105- for j = 1 , # flags do
106- local name = string.sub (flags , j , j )
107- local found = false
108- for _ , argument in self .arguments do
109- local aliases = argument .options .aliases or {}
110- if argument .name == name or table.find (aliases , name ) then
111- found = true
112- if argument .kind == "option" then
113- i += 1
114- assert (i <= # args , "Missing value for argument: " .. argument .name )
115- self .parsed .values [argument .name ] = args [i ]
116- else
117- self .parsed .flags [argument .name ] = true
118- end
119- break
120- end
121- end
122-
123- assert (found , "Unknown argument: " .. name )
124- end
125-
126- continue
127- end
128-
129- -- if we have positional arguments left, we can take this argument as one
130- if pos_index <= # self .positional then
131- self .parsed .values [self .positional [pos_index ].name ] = arg
132- pos_index += 1
133- continue
134- end
135-
136- -- otherwise, the argument is forwarded on
137- table.insert (self .parsed .fwdArgs , arg )
138- end
139-
140- -- check that all required arguments are present, and set any default values as needed
141- for _ , argument in self .arguments do
142- assert (argument )
143-
144- if argument .options .required and self .parsed .values [argument .name ] == nil then
145- assert (self .parsed .values [argument .name ], "Missing required argument: " .. argument .name )
146- end
147-
148- if self .parsed .values [argument .name ] == nil and argument .options .default then
149- self .parsed .values [argument .name ] = argument .options .default
150- end
151- end
56+ function cli .parse (self : Parser , args : { string }): ()
57+ local i = 0
58+ local pos_index = 1
59+
60+ while i < # args do
61+ i += 1
62+
63+ local arg = args [i ]
64+
65+ -- if the argument is exactly "--", we pass everything along
66+ if arg == "--" then
67+ table.move (args , i + 1 , # args , 1 , self .parsed .fwdArgs )
68+ break
69+ end
70+
71+ -- if the argument starts with two dashes, we're parsing either a flag or an option
72+ if string.sub (arg , 1 , 2 ) == "--" then
73+ local name = string.sub (arg , 3 )
74+ local found = false
75+
76+ for _ , argument in self .arguments do
77+ local aliases = argument .options .aliases or {}
78+
79+ if argument .name == name or table.find (aliases , name ) then
80+ found = true
81+
82+ if argument .kind == "option" then
83+ -- advance past the argument
84+ i += 1
85+
86+ assert (i <= # args , "Missing value for argument: " .. argument .name )
87+ self .parsed .values [argument .name ] = args [i ]
88+
89+ break
90+ end
91+
92+ self .parsed .flags [argument .name ] = true
93+ break
94+ end
95+ end
96+
97+ assert (found , "Unknown argument: " .. name )
98+ continue
99+ end
100+
101+ -- if the argument starts with a single dash, we're parsing a flag
102+ if string.sub (arg , 1 , 1 ) == "-" then
103+ local flags = string.sub (arg , 2 )
104+
105+ for j = 1 , # flags do
106+ local name = string.sub (flags , j , j )
107+ local found = false
108+ for _ , argument in self .arguments do
109+ local aliases = argument .options .aliases or {}
110+ if argument .name == name or table.find (aliases , name ) then
111+ found = true
112+ if argument .kind == "option" then
113+ i += 1
114+ assert (i <= # args , "Missing value for argument: " .. argument .name )
115+ self .parsed .values [argument .name ] = args [i ]
116+ else
117+ self .parsed .flags [argument .name ] = true
118+ end
119+ break
120+ end
121+ end
122+
123+ assert (found , "Unknown argument: " .. name )
124+ end
125+
126+ continue
127+ end
128+
129+ -- if we have positional arguments left, we can take this argument as one
130+ if pos_index <= # self .positional then
131+ self .parsed .values [self .positional [pos_index ].name ] = arg
132+ pos_index += 1
133+ continue
134+ end
135+
136+ -- otherwise, the argument is forwarded on
137+ table.insert (self .parsed .fwdArgs , arg )
138+ end
139+
140+ -- check that all required arguments are present, and set any default values as needed
141+ for _ , argument in self .arguments do
142+ assert (argument )
143+
144+ if argument .options .required and self .parsed .values [argument .name ] == nil then
145+ assert (self .parsed .values [argument .name ], "Missing required argument: " .. argument .name )
146+ end
147+
148+ if self .parsed .values [argument .name ] == nil and argument .options .default then
149+ self .parsed .values [argument .name ] = argument .options .default
150+ end
151+ end
152152end
153153
154154function cli .get (self : Parser , name : string ): boolean
155- return self .parsed .values [name ]
155+ return self .parsed .values [name ]
156156end
157157
158158function cli .has (self : Parser , name : string ): boolean
159- return self .parsed .flags [name ] ~= nil
159+ return self .parsed .flags [name ] ~= nil
160160end
161161
162162function cli .forwaded (): { string }?
163- return self .parsed .fwdArgs
163+ return self .parsed .fwdArgs
164164end
165165
166166function cli .help (self : Parser ): ()
167- print ("Usage:" )
168- for _ , argument in self .arguments do
169- local aliasStr = table.concat (argument .options .aliases or {}, ", " )
170- local reqStr = if argument .options .required then "(required) " else ""
171- print (string.format (" --%s (-%s) - %s%s" , argument .name , aliasStr , reqStr , argument .options .help or "" ))
172- end
167+ print ("Usage:" )
168+ for _ , argument in self .arguments do
169+ local aliasStr = table.concat (argument .options .aliases or {}, ", " )
170+ local reqStr = if argument .options .required then "(required) " else ""
171+ print (string.format (" --%s (-%s) - %s%s" , argument .name , aliasStr , reqStr , argument .options .help or "" ))
172+ end
173173end
174174
175175return table.freeze (cli )
0 commit comments