You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

argparse.lua 57KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100
  1. -- The MIT License (MIT)
  2. -- Copyright (c) 2013 - 2018 Peter Melnichenko
  3. -- 2019 Paul Ouellette
  4. -- Permission is hereby granted, free of charge, to any person obtaining a copy of
  5. -- this software and associated documentation files (the "Software"), to deal in
  6. -- the Software without restriction, including without limitation the rights to
  7. -- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  8. -- the Software, and to permit persons to whom the Software is furnished to do so,
  9. -- subject to the following conditions:
  10. -- The above copyright notice and this permission notice shall be included in all
  11. -- copies or substantial portions of the Software.
  12. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  14. -- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  15. -- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  16. -- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  17. -- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. local function deep_update(t1, t2)
  19. for k, v in pairs(t2) do
  20. if type(v) == "table" then
  21. v = deep_update({}, v)
  22. end
  23. t1[k] = v
  24. end
  25. return t1
  26. end
  27. -- A property is a tuple {name, callback}.
  28. -- properties.args is number of properties that can be set as arguments
  29. -- when calling an object.
  30. local function class(prototype, properties, parent)
  31. -- Class is the metatable of its instances.
  32. local cl = {}
  33. cl.__index = cl
  34. if parent then
  35. cl.__prototype = deep_update(deep_update({}, parent.__prototype), prototype)
  36. else
  37. cl.__prototype = prototype
  38. end
  39. if properties then
  40. local names = {}
  41. -- Create setter methods and fill set of property names.
  42. for _, property in ipairs(properties) do
  43. local name, callback = property[1], property[2]
  44. cl[name] = function(self, value)
  45. if not callback(self, value) then
  46. self["_" .. name] = value
  47. end
  48. return self
  49. end
  50. names[name] = true
  51. end
  52. function cl.__call(self, ...)
  53. -- When calling an object, if the first argument is a table,
  54. -- interpret keys as property names, else delegate arguments
  55. -- to corresponding setters in order.
  56. if type((...)) == "table" then
  57. for name, value in pairs((...)) do
  58. if names[name] then
  59. self[name](self, value)
  60. end
  61. end
  62. else
  63. local nargs = select("#", ...)
  64. for i, property in ipairs(properties) do
  65. if i > nargs or i > properties.args then
  66. break
  67. end
  68. local arg = select(i, ...)
  69. if arg ~= nil then
  70. self[property[1]](self, arg)
  71. end
  72. end
  73. end
  74. return self
  75. end
  76. end
  77. -- If indexing class fails, fallback to its parent.
  78. local class_metatable = {}
  79. class_metatable.__index = parent
  80. function class_metatable.__call(self, ...)
  81. -- Calling a class returns its instance.
  82. -- Arguments are delegated to the instance.
  83. local object = deep_update({}, self.__prototype)
  84. setmetatable(object, self)
  85. return object(...)
  86. end
  87. return setmetatable(cl, class_metatable)
  88. end
  89. local function typecheck(name, types, value)
  90. for _, type_ in ipairs(types) do
  91. if type(value) == type_ then
  92. return true
  93. end
  94. end
  95. error(("bad property '%s' (%s expected, got %s)"):format(name, table.concat(types, " or "), type(value)))
  96. end
  97. local function typechecked(name, ...)
  98. local types = {...}
  99. return {name, function(_, value) typecheck(name, types, value) end}
  100. end
  101. local multiname = {"name", function(self, value)
  102. typecheck("name", {"string"}, value)
  103. for alias in value:gmatch("%S+") do
  104. self._name = self._name or alias
  105. table.insert(self._aliases, alias)
  106. table.insert(self._public_aliases, alias)
  107. -- If alias contains '_', accept '-' also.
  108. if alias:find("_", 1, true) then
  109. table.insert(self._aliases, (alias:gsub("_", "-")))
  110. end
  111. end
  112. -- Do not set _name as with other properties.
  113. return true
  114. end}
  115. local multiname_hidden = {"hidden_name", function(self, value)
  116. typecheck("hidden_name", {"string"}, value)
  117. for alias in value:gmatch("%S+") do
  118. table.insert(self._aliases, alias)
  119. if alias:find("_", 1, true) then
  120. table.insert(self._aliases, (alias:gsub("_", "-")))
  121. end
  122. end
  123. return true
  124. end}
  125. local function parse_boundaries(str)
  126. if tonumber(str) then
  127. return tonumber(str), tonumber(str)
  128. end
  129. if str == "*" then
  130. return 0, math.huge
  131. end
  132. if str == "+" then
  133. return 1, math.huge
  134. end
  135. if str == "?" then
  136. return 0, 1
  137. end
  138. if str:match "^%d+%-%d+$" then
  139. local min, max = str:match "^(%d+)%-(%d+)$"
  140. return tonumber(min), tonumber(max)
  141. end
  142. if str:match "^%d+%+$" then
  143. local min = str:match "^(%d+)%+$"
  144. return tonumber(min), math.huge
  145. end
  146. end
  147. local function boundaries(name)
  148. return {name, function(self, value)
  149. typecheck(name, {"number", "string"}, value)
  150. local min, max = parse_boundaries(value)
  151. if not min then
  152. error(("bad property '%s'"):format(name))
  153. end
  154. self["_min" .. name], self["_max" .. name] = min, max
  155. end}
  156. end
  157. local actions = {}
  158. local option_action = {"action", function(_, value)
  159. typecheck("action", {"function", "string"}, value)
  160. if type(value) == "string" and not actions[value] then
  161. error(("unknown action '%s'"):format(value))
  162. end
  163. end}
  164. local option_init = {"init", function(self)
  165. self._has_init = true
  166. end}
  167. local option_default = {"default", function(self, value)
  168. if type(value) ~= "string" then
  169. self._init = value
  170. self._has_init = true
  171. return true
  172. end
  173. end}
  174. local add_help = {"add_help", function(self, value)
  175. typecheck("add_help", {"boolean", "string", "table"}, value)
  176. if self._help_option_idx then
  177. table.remove(self._options, self._help_option_idx)
  178. self._help_option_idx = nil
  179. end
  180. if value then
  181. local help = self:flag()
  182. :description "Show this help message and exit."
  183. :action(function()
  184. print(self:get_help())
  185. os.exit(0)
  186. end)
  187. if value ~= true then
  188. help = help(value)
  189. end
  190. if not help._name then
  191. help "-h" "--help"
  192. end
  193. self._help_option_idx = #self._options
  194. end
  195. end}
  196. local Parser = class({
  197. _arguments = {},
  198. _options = {},
  199. _commands = {},
  200. _mutexes = {},
  201. _groups = {},
  202. _require_command = true,
  203. _handle_options = true
  204. }, {
  205. args = 3,
  206. typechecked("name", "string"),
  207. typechecked("description", "string"),
  208. typechecked("epilog", "string"),
  209. typechecked("usage", "string"),
  210. typechecked("help", "string"),
  211. typechecked("require_command", "boolean"),
  212. typechecked("handle_options", "boolean"),
  213. typechecked("action", "function"),
  214. typechecked("command_target", "string"),
  215. typechecked("help_vertical_space", "number"),
  216. typechecked("usage_margin", "number"),
  217. typechecked("usage_max_width", "number"),
  218. typechecked("help_usage_margin", "number"),
  219. typechecked("help_description_margin", "number"),
  220. typechecked("help_max_width", "number"),
  221. add_help
  222. })
  223. local Command = class({
  224. _aliases = {},
  225. _public_aliases = {}
  226. }, {
  227. args = 3,
  228. multiname,
  229. typechecked("description", "string"),
  230. typechecked("epilog", "string"),
  231. multiname_hidden,
  232. typechecked("summary", "string"),
  233. typechecked("target", "string"),
  234. typechecked("usage", "string"),
  235. typechecked("help", "string"),
  236. typechecked("require_command", "boolean"),
  237. typechecked("handle_options", "boolean"),
  238. typechecked("action", "function"),
  239. typechecked("command_target", "string"),
  240. typechecked("help_vertical_space", "number"),
  241. typechecked("usage_margin", "number"),
  242. typechecked("usage_max_width", "number"),
  243. typechecked("help_usage_margin", "number"),
  244. typechecked("help_description_margin", "number"),
  245. typechecked("help_max_width", "number"),
  246. typechecked("hidden", "boolean"),
  247. add_help
  248. }, Parser)
  249. local Argument = class({
  250. _minargs = 1,
  251. _maxargs = 1,
  252. _mincount = 1,
  253. _maxcount = 1,
  254. _defmode = "unused",
  255. _show_default = true
  256. }, {
  257. args = 5,
  258. typechecked("name", "string"),
  259. typechecked("description", "string"),
  260. option_default,
  261. typechecked("convert", "function", "table"),
  262. boundaries("args"),
  263. typechecked("target", "string"),
  264. typechecked("defmode", "string"),
  265. typechecked("show_default", "boolean"),
  266. typechecked("argname", "string", "table"),
  267. typechecked("choices", "table"),
  268. typechecked("hidden", "boolean"),
  269. option_action,
  270. option_init
  271. })
  272. local Option = class({
  273. _aliases = {},
  274. _public_aliases = {},
  275. _mincount = 0,
  276. _overwrite = true
  277. }, {
  278. args = 6,
  279. multiname,
  280. typechecked("description", "string"),
  281. option_default,
  282. typechecked("convert", "function", "table"),
  283. boundaries("args"),
  284. boundaries("count"),
  285. multiname_hidden,
  286. typechecked("target", "string"),
  287. typechecked("defmode", "string"),
  288. typechecked("show_default", "boolean"),
  289. typechecked("overwrite", "boolean"),
  290. typechecked("argname", "string", "table"),
  291. typechecked("choices", "table"),
  292. typechecked("hidden", "boolean"),
  293. option_action,
  294. option_init
  295. }, Argument)
  296. function Parser:_inherit_property(name, default)
  297. local element = self
  298. while true do
  299. local value = element["_" .. name]
  300. if value ~= nil then
  301. return value
  302. end
  303. if not element._parent then
  304. return default
  305. end
  306. element = element._parent
  307. end
  308. end
  309. function Argument:_get_argument_list()
  310. local buf = {}
  311. local i = 1
  312. while i <= math.min(self._minargs, 3) do
  313. local argname = self:_get_argname(i)
  314. if self._default and self._defmode:find "a" then
  315. argname = "[" .. argname .. "]"
  316. end
  317. table.insert(buf, argname)
  318. i = i+1
  319. end
  320. while i <= math.min(self._maxargs, 3) do
  321. table.insert(buf, "[" .. self:_get_argname(i) .. "]")
  322. i = i+1
  323. if self._maxargs == math.huge then
  324. break
  325. end
  326. end
  327. if i < self._maxargs then
  328. table.insert(buf, "...")
  329. end
  330. return buf
  331. end
  332. function Argument:_get_usage()
  333. local usage = table.concat(self:_get_argument_list(), " ")
  334. if self._default and self._defmode:find "u" then
  335. if self._maxargs > 1 or (self._minargs == 1 and not self._defmode:find "a") then
  336. usage = "[" .. usage .. "]"
  337. end
  338. end
  339. return usage
  340. end
  341. function actions.store_true(result, target)
  342. result[target] = true
  343. end
  344. function actions.store_false(result, target)
  345. result[target] = false
  346. end
  347. function actions.store(result, target, argument)
  348. result[target] = argument
  349. end
  350. function actions.count(result, target, _, overwrite)
  351. if not overwrite then
  352. result[target] = result[target] + 1
  353. end
  354. end
  355. function actions.append(result, target, argument, overwrite)
  356. result[target] = result[target] or {}
  357. table.insert(result[target], argument)
  358. if overwrite then
  359. table.remove(result[target], 1)
  360. end
  361. end
  362. function actions.concat(result, target, arguments, overwrite)
  363. if overwrite then
  364. error("'concat' action can't handle too many invocations")
  365. end
  366. result[target] = result[target] or {}
  367. for _, argument in ipairs(arguments) do
  368. table.insert(result[target], argument)
  369. end
  370. end
  371. function Argument:_get_action()
  372. local action, init
  373. if self._maxcount == 1 then
  374. if self._maxargs == 0 then
  375. action, init = "store_true", nil
  376. else
  377. action, init = "store", nil
  378. end
  379. else
  380. if self._maxargs == 0 then
  381. action, init = "count", 0
  382. else
  383. action, init = "append", {}
  384. end
  385. end
  386. if self._action then
  387. action = self._action
  388. end
  389. if self._has_init then
  390. init = self._init
  391. end
  392. if type(action) == "string" then
  393. action = actions[action]
  394. end
  395. return action, init
  396. end
  397. -- Returns placeholder for `narg`-th argument.
  398. function Argument:_get_argname(narg)
  399. local argname = self._argname or self:_get_default_argname()
  400. if type(argname) == "table" then
  401. return argname[narg]
  402. else
  403. return argname
  404. end
  405. end
  406. function Argument:_get_choices_list()
  407. return "{" .. table.concat(self._choices, ",") .. "}"
  408. end
  409. function Argument:_get_default_argname()
  410. if self._choices then
  411. return self:_get_choices_list()
  412. else
  413. return "<" .. self._name .. ">"
  414. end
  415. end
  416. function Option:_get_default_argname()
  417. if self._choices then
  418. return self:_get_choices_list()
  419. else
  420. return "<" .. self:_get_default_target() .. ">"
  421. end
  422. end
  423. -- Returns labels to be shown in the help message.
  424. function Argument:_get_label_lines()
  425. if self._choices then
  426. return {self:_get_choices_list()}
  427. else
  428. return {self._name}
  429. end
  430. end
  431. function Option:_get_label_lines()
  432. local argument_list = self:_get_argument_list()
  433. if #argument_list == 0 then
  434. -- Don't put aliases for simple flags like `-h` on different lines.
  435. return {table.concat(self._public_aliases, ", ")}
  436. end
  437. local longest_alias_length = -1
  438. for _, alias in ipairs(self._public_aliases) do
  439. longest_alias_length = math.max(longest_alias_length, #alias)
  440. end
  441. local argument_list_repr = table.concat(argument_list, " ")
  442. local lines = {}
  443. for i, alias in ipairs(self._public_aliases) do
  444. local line = (" "):rep(longest_alias_length - #alias) .. alias .. " " .. argument_list_repr
  445. if i ~= #self._public_aliases then
  446. line = line .. ","
  447. end
  448. table.insert(lines, line)
  449. end
  450. return lines
  451. end
  452. function Command:_get_label_lines()
  453. return {table.concat(self._public_aliases, ", ")}
  454. end
  455. function Argument:_get_description()
  456. if self._default and self._show_default then
  457. if self._description then
  458. return ("%s (default: %s)"):format(self._description, self._default)
  459. else
  460. return ("default: %s"):format(self._default)
  461. end
  462. else
  463. return self._description or ""
  464. end
  465. end
  466. function Command:_get_description()
  467. return self._summary or self._description or ""
  468. end
  469. function Option:_get_usage()
  470. local usage = self:_get_argument_list()
  471. table.insert(usage, 1, self._name)
  472. usage = table.concat(usage, " ")
  473. if self._mincount == 0 or self._default then
  474. usage = "[" .. usage .. "]"
  475. end
  476. return usage
  477. end
  478. function Argument:_get_default_target()
  479. return self._name
  480. end
  481. function Option:_get_default_target()
  482. local res
  483. for _, alias in ipairs(self._public_aliases) do
  484. if alias:sub(1, 1) == alias:sub(2, 2) then
  485. res = alias:sub(3)
  486. break
  487. end
  488. end
  489. res = res or self._name:sub(2)
  490. return (res:gsub("-", "_"))
  491. end
  492. function Option:_is_vararg()
  493. return self._maxargs ~= self._minargs
  494. end
  495. function Parser:_get_fullname(exclude_root)
  496. local parent = self._parent
  497. if exclude_root and not parent then
  498. return ""
  499. end
  500. local buf = {self._name}
  501. while parent do
  502. if not exclude_root or parent._parent then
  503. table.insert(buf, 1, parent._name)
  504. end
  505. parent = parent._parent
  506. end
  507. return table.concat(buf, " ")
  508. end
  509. function Parser:_update_charset(charset)
  510. charset = charset or {}
  511. for _, command in ipairs(self._commands) do
  512. command:_update_charset(charset)
  513. end
  514. for _, option in ipairs(self._options) do
  515. for _, alias in ipairs(option._aliases) do
  516. charset[alias:sub(1, 1)] = true
  517. end
  518. end
  519. return charset
  520. end
  521. function Parser:argument(...)
  522. local argument = Argument(...)
  523. table.insert(self._arguments, argument)
  524. return argument
  525. end
  526. function Parser:option(...)
  527. local option = Option(...)
  528. table.insert(self._options, option)
  529. return option
  530. end
  531. function Parser:flag(...)
  532. return self:option():args(0)(...)
  533. end
  534. function Parser:command(...)
  535. local command = Command():add_help(true)(...)
  536. command._parent = self
  537. table.insert(self._commands, command)
  538. return command
  539. end
  540. function Parser:mutex(...)
  541. local elements = {...}
  542. for i, element in ipairs(elements) do
  543. local mt = getmetatable(element)
  544. assert(mt == Option or mt == Argument, ("bad argument #%d to 'mutex' (Option or Argument expected)"):format(i))
  545. end
  546. table.insert(self._mutexes, elements)
  547. return self
  548. end
  549. function Parser:group(name, ...)
  550. assert(type(name) == "string", ("bad argument #1 to 'group' (string expected, got %s)"):format(type(name)))
  551. local group = {name = name, ...}
  552. for i, element in ipairs(group) do
  553. local mt = getmetatable(element)
  554. assert(mt == Option or mt == Argument or mt == Command,
  555. ("bad argument #%d to 'group' (Option or Argument or Command expected)"):format(i + 1))
  556. end
  557. table.insert(self._groups, group)
  558. return self
  559. end
  560. local usage_welcome = "Usage: "
  561. function Parser:get_usage()
  562. if self._usage then
  563. return self._usage
  564. end
  565. local usage_margin = self:_inherit_property("usage_margin", #usage_welcome)
  566. local max_usage_width = self:_inherit_property("usage_max_width", 70)
  567. local lines = {usage_welcome .. self:_get_fullname()}
  568. local function add(s)
  569. if #lines[#lines]+1+#s <= max_usage_width then
  570. lines[#lines] = lines[#lines] .. " " .. s
  571. else
  572. lines[#lines+1] = (" "):rep(usage_margin) .. s
  573. end
  574. end
  575. -- Normally options are before positional arguments in usage messages.
  576. -- However, vararg options should be after, because they can't be reliable used
  577. -- before a positional argument.
  578. -- Mutexes come into play, too, and are shown as soon as possible.
  579. -- Overall, output usages in the following order:
  580. -- 1. Mutexes that don't have positional arguments or vararg options.
  581. -- 2. Options that are not in any mutexes and are not vararg.
  582. -- 3. Positional arguments - on their own or as a part of a mutex.
  583. -- 4. Remaining mutexes.
  584. -- 5. Remaining options.
  585. local elements_in_mutexes = {}
  586. local added_elements = {}
  587. local added_mutexes = {}
  588. local argument_to_mutexes = {}
  589. local function add_mutex(mutex, main_argument)
  590. if added_mutexes[mutex] then
  591. return
  592. end
  593. added_mutexes[mutex] = true
  594. local buf = {}
  595. for _, element in ipairs(mutex) do
  596. if not element._hidden and not added_elements[element] then
  597. if getmetatable(element) == Option or element == main_argument then
  598. table.insert(buf, element:_get_usage())
  599. added_elements[element] = true
  600. end
  601. end
  602. end
  603. if #buf == 1 then
  604. add(buf[1])
  605. elseif #buf > 1 then
  606. add("(" .. table.concat(buf, " | ") .. ")")
  607. end
  608. end
  609. local function add_element(element)
  610. if not element._hidden and not added_elements[element] then
  611. add(element:_get_usage())
  612. added_elements[element] = true
  613. end
  614. end
  615. for _, mutex in ipairs(self._mutexes) do
  616. local is_vararg = false
  617. local has_argument = false
  618. for _, element in ipairs(mutex) do
  619. if getmetatable(element) == Option then
  620. if element:_is_vararg() then
  621. is_vararg = true
  622. end
  623. else
  624. has_argument = true
  625. argument_to_mutexes[element] = argument_to_mutexes[element] or {}
  626. table.insert(argument_to_mutexes[element], mutex)
  627. end
  628. elements_in_mutexes[element] = true
  629. end
  630. if not is_vararg and not has_argument then
  631. add_mutex(mutex)
  632. end
  633. end
  634. for _, option in ipairs(self._options) do
  635. if not elements_in_mutexes[option] and not option:_is_vararg() then
  636. add_element(option)
  637. end
  638. end
  639. -- Add usages for positional arguments, together with one mutex containing them, if they are in a mutex.
  640. for _, argument in ipairs(self._arguments) do
  641. -- Pick a mutex as a part of which to show this argument, take the first one that's still available.
  642. local mutex
  643. if elements_in_mutexes[argument] then
  644. for _, argument_mutex in ipairs(argument_to_mutexes[argument]) do
  645. if not added_mutexes[argument_mutex] then
  646. mutex = argument_mutex
  647. end
  648. end
  649. end
  650. if mutex then
  651. add_mutex(mutex, argument)
  652. else
  653. add_element(argument)
  654. end
  655. end
  656. for _, mutex in ipairs(self._mutexes) do
  657. add_mutex(mutex)
  658. end
  659. for _, option in ipairs(self._options) do
  660. add_element(option)
  661. end
  662. if #self._commands > 0 then
  663. if self._require_command then
  664. add("<command>")
  665. else
  666. add("[<command>]")
  667. end
  668. add("...")
  669. end
  670. return table.concat(lines, "\n")
  671. end
  672. local function split_lines(s)
  673. if s == "" then
  674. return {}
  675. end
  676. local lines = {}
  677. if s:sub(-1) ~= "\n" then
  678. s = s .. "\n"
  679. end
  680. for line in s:gmatch("([^\n]*)\n") do
  681. table.insert(lines, line)
  682. end
  683. return lines
  684. end
  685. local function autowrap_line(line, max_length)
  686. -- Algorithm for splitting lines is simple and greedy.
  687. local result_lines = {}
  688. -- Preserve original indentation of the line, put this at the beginning of each result line.
  689. -- If the first word looks like a list marker ('*', '+', or '-'), add spaces so that starts
  690. -- of the second and the following lines vertically align with the start of the second word.
  691. local indentation = line:match("^ *")
  692. if line:find("^ *[%*%+%-]") then
  693. indentation = indentation .. " " .. line:match("^ *[%*%+%-]( *)")
  694. end
  695. -- Parts of the last line being assembled.
  696. local line_parts = {}
  697. -- Length of the current line.
  698. local line_length = 0
  699. -- Index of the next character to consider.
  700. local index = 1
  701. while true do
  702. local word_start, word_finish, word = line:find("([^ ]+)", index)
  703. if not word_start then
  704. -- Ignore trailing spaces, if any.
  705. break
  706. end
  707. local preceding_spaces = line:sub(index, word_start - 1)
  708. index = word_finish + 1
  709. if (#line_parts == 0) or (line_length + #preceding_spaces + #word <= max_length) then
  710. -- Either this is the very first word or it fits as an addition to the current line, add it.
  711. table.insert(line_parts, preceding_spaces) -- For the very first word this adds the indentation.
  712. table.insert(line_parts, word)
  713. line_length = line_length + #preceding_spaces + #word
  714. else
  715. -- Does not fit, finish current line and put the word into a new one.
  716. table.insert(result_lines, table.concat(line_parts))
  717. line_parts = {indentation, word}
  718. line_length = #indentation + #word
  719. end
  720. end
  721. if #line_parts > 0 then
  722. table.insert(result_lines, table.concat(line_parts))
  723. end
  724. if #result_lines == 0 then
  725. -- Preserve empty lines.
  726. result_lines[1] = ""
  727. end
  728. return result_lines
  729. end
  730. -- Automatically wraps lines within given array,
  731. -- attempting to limit line length to `max_length`.
  732. -- Existing line splits are preserved.
  733. local function autowrap(lines, max_length)
  734. local result_lines = {}
  735. for _, line in ipairs(lines) do
  736. local autowrapped_lines = autowrap_line(line, max_length)
  737. for _, autowrapped_line in ipairs(autowrapped_lines) do
  738. table.insert(result_lines, autowrapped_line)
  739. end
  740. end
  741. return result_lines
  742. end
  743. function Parser:_get_element_help(element)
  744. local label_lines = element:_get_label_lines()
  745. local description_lines = split_lines(element:_get_description())
  746. local result_lines = {}
  747. -- All label lines should have the same length (except the last one, it has no comma).
  748. -- If too long, start description after all the label lines.
  749. -- Otherwise, combine label and description lines.
  750. local usage_margin_len = self:_inherit_property("help_usage_margin", 3)
  751. local usage_margin = (" "):rep(usage_margin_len)
  752. local description_margin_len = self:_inherit_property("help_description_margin", 25)
  753. local description_margin = (" "):rep(description_margin_len)
  754. local help_max_width = self:_inherit_property("help_max_width")
  755. if help_max_width then
  756. local description_max_width = math.max(help_max_width - description_margin_len, 10)
  757. description_lines = autowrap(description_lines, description_max_width)
  758. end
  759. if #label_lines[1] >= (description_margin_len - usage_margin_len) then
  760. for _, label_line in ipairs(label_lines) do
  761. table.insert(result_lines, usage_margin .. label_line)
  762. end
  763. for _, description_line in ipairs(description_lines) do
  764. table.insert(result_lines, description_margin .. description_line)
  765. end
  766. else
  767. for i = 1, math.max(#label_lines, #description_lines) do
  768. local label_line = label_lines[i]
  769. local description_line = description_lines[i]
  770. local line = ""
  771. if label_line then
  772. line = usage_margin .. label_line
  773. end
  774. if description_line and description_line ~= "" then
  775. line = line .. (" "):rep(description_margin_len - #line) .. description_line
  776. end
  777. table.insert(result_lines, line)
  778. end
  779. end
  780. return table.concat(result_lines, "\n")
  781. end
  782. local function get_group_types(group)
  783. local types = {}
  784. for _, element in ipairs(group) do
  785. types[getmetatable(element)] = true
  786. end
  787. return types
  788. end
  789. function Parser:_add_group_help(blocks, added_elements, label, elements)
  790. local buf = {label}
  791. for _, element in ipairs(elements) do
  792. if not element._hidden and not added_elements[element] then
  793. added_elements[element] = true
  794. table.insert(buf, self:_get_element_help(element))
  795. end
  796. end
  797. if #buf > 1 then
  798. table.insert(blocks, table.concat(buf, ("\n"):rep(self:_inherit_property("help_vertical_space", 0) + 1)))
  799. end
  800. end
  801. function Parser:get_help()
  802. if self._help then
  803. return self._help
  804. end
  805. local blocks = {self:get_usage()}
  806. local help_max_width = self:_inherit_property("help_max_width")
  807. if self._description then
  808. local description = self._description
  809. if help_max_width then
  810. description = table.concat(autowrap(split_lines(description), help_max_width), "\n")
  811. end
  812. table.insert(blocks, description)
  813. end
  814. -- 1. Put groups containing arguments first, then other arguments.
  815. -- 2. Put remaining groups containing options, then other options.
  816. -- 3. Put remaining groups containing commands, then other commands.
  817. -- Assume that an element can't be in several groups.
  818. local groups_by_type = {
  819. [Argument] = {},
  820. [Option] = {},
  821. [Command] = {}
  822. }
  823. for _, group in ipairs(self._groups) do
  824. local group_types = get_group_types(group)
  825. for _, mt in ipairs({Argument, Option, Command}) do
  826. if group_types[mt] then
  827. table.insert(groups_by_type[mt], group)
  828. break
  829. end
  830. end
  831. end
  832. local default_groups = {
  833. {name = "Arguments", type = Argument, elements = self._arguments},
  834. {name = "Options", type = Option, elements = self._options},
  835. {name = "Commands", type = Command, elements = self._commands}
  836. }
  837. local added_elements = {}
  838. for _, default_group in ipairs(default_groups) do
  839. local type_groups = groups_by_type[default_group.type]
  840. for _, group in ipairs(type_groups) do
  841. self:_add_group_help(blocks, added_elements, group.name .. ":", group)
  842. end
  843. local default_label = default_group.name .. ":"
  844. if #type_groups > 0 then
  845. default_label = "Other " .. default_label:gsub("^.", string.lower)
  846. end
  847. self:_add_group_help(blocks, added_elements, default_label, default_group.elements)
  848. end
  849. if self._epilog then
  850. local epilog = self._epilog
  851. if help_max_width then
  852. epilog = table.concat(autowrap(split_lines(epilog), help_max_width), "\n")
  853. end
  854. table.insert(blocks, epilog)
  855. end
  856. return table.concat(blocks, "\n\n")
  857. end
  858. function Parser:add_help_command(value)
  859. if value then
  860. assert(type(value) == "string" or type(value) == "table",
  861. ("bad argument #1 to 'add_help_command' (string or table expected, got %s)"):format(type(value)))
  862. end
  863. local help = self:command()
  864. :description "Show help for commands."
  865. help:argument "command"
  866. :description "The command to show help for."
  867. :args "?"
  868. :action(function(_, _, cmd)
  869. if not cmd then
  870. print(self:get_help())
  871. os.exit(0)
  872. else
  873. for _, command in ipairs(self._commands) do
  874. for _, alias in ipairs(command._aliases) do
  875. if alias == cmd then
  876. print(command:get_help())
  877. os.exit(0)
  878. end
  879. end
  880. end
  881. end
  882. help:error(("unknown command '%s'"):format(cmd))
  883. end)
  884. if value then
  885. help = help(value)
  886. end
  887. if not help._name then
  888. help "help"
  889. end
  890. help._is_help_command = true
  891. return self
  892. end
  893. function Parser:_is_shell_safe()
  894. if self._basename then
  895. if self._basename:find("[^%w_%-%+%.]") then
  896. return false
  897. end
  898. else
  899. for _, alias in ipairs(self._aliases) do
  900. if alias:find("[^%w_%-%+%.]") then
  901. return false
  902. end
  903. end
  904. end
  905. for _, option in ipairs(self._options) do
  906. for _, alias in ipairs(option._aliases) do
  907. if alias:find("[^%w_%-%+%.]") then
  908. return false
  909. end
  910. end
  911. if option._choices then
  912. for _, choice in ipairs(option._choices) do
  913. if choice:find("[%s'\"]") then
  914. return false
  915. end
  916. end
  917. end
  918. end
  919. for _, argument in ipairs(self._arguments) do
  920. if argument._choices then
  921. for _, choice in ipairs(argument._choices) do
  922. if choice:find("[%s'\"]") then
  923. return false
  924. end
  925. end
  926. end
  927. end
  928. for _, command in ipairs(self._commands) do
  929. if not command:_is_shell_safe() then
  930. return false
  931. end
  932. end
  933. return true
  934. end
  935. function Parser:add_complete(value)
  936. if value then
  937. assert(type(value) == "string" or type(value) == "table",
  938. ("bad argument #1 to 'add_complete' (string or table expected, got %s)"):format(type(value)))
  939. end
  940. local complete = self:option()
  941. :description "Output a shell completion script for the specified shell."
  942. :args(1)
  943. :choices {"bash", "zsh", "fish"}
  944. :action(function(_, _, shell)
  945. io.write(self["get_" .. shell .. "_complete"](self))
  946. os.exit(0)
  947. end)
  948. if value then
  949. complete = complete(value)
  950. end
  951. if not complete._name then
  952. complete "--completion"
  953. end
  954. return self
  955. end
  956. function Parser:add_complete_command(value)
  957. if value then
  958. assert(type(value) == "string" or type(value) == "table",
  959. ("bad argument #1 to 'add_complete_command' (string or table expected, got %s)"):format(type(value)))
  960. end
  961. local complete = self:command()
  962. :description "Output a shell completion script."
  963. complete:argument "shell"
  964. :description "The shell to output a completion script for."
  965. :choices {"bash", "zsh", "fish"}
  966. :action(function(_, _, shell)
  967. io.write(self["get_" .. shell .. "_complete"](self))
  968. os.exit(0)
  969. end)
  970. if value then
  971. complete = complete(value)
  972. end
  973. if not complete._name then
  974. complete "completion"
  975. end
  976. return self
  977. end
  978. local function base_name(pathname)
  979. return pathname:gsub("[/\\]*$", ""):match(".*[/\\]([^/\\]*)") or pathname
  980. end
  981. local function get_short_description(element)
  982. local short = element:_get_description():match("^(.-)%.%s")
  983. return short or element:_get_description():match("^(.-)%.?$")
  984. end
  985. function Parser:_get_options()
  986. local options = {}
  987. for _, option in ipairs(self._options) do
  988. for _, alias in ipairs(option._aliases) do
  989. table.insert(options, alias)
  990. end
  991. end
  992. return table.concat(options, " ")
  993. end
  994. function Parser:_get_commands()
  995. local commands = {}
  996. for _, command in ipairs(self._commands) do
  997. for _, alias in ipairs(command._aliases) do
  998. table.insert(commands, alias)
  999. end
  1000. end
  1001. return table.concat(commands, " ")
  1002. end
  1003. function Parser:_bash_option_args(buf, indent)
  1004. local opts = {}
  1005. for _, option in ipairs(self._options) do
  1006. if option._choices or option._minargs > 0 then
  1007. local compreply
  1008. if option._choices then
  1009. compreply = 'COMPREPLY=($(compgen -W "' .. table.concat(option._choices, " ") .. '" -- "$cur"))'
  1010. else
  1011. compreply = 'COMPREPLY=($(compgen -f -- "$cur"))'
  1012. end
  1013. table.insert(opts, (" "):rep(indent + 4) .. table.concat(option._aliases, "|") .. ")")
  1014. table.insert(opts, (" "):rep(indent + 8) .. compreply)
  1015. table.insert(opts, (" "):rep(indent + 8) .. "return 0")
  1016. table.insert(opts, (" "):rep(indent + 8) .. ";;")
  1017. end
  1018. end
  1019. if #opts > 0 then
  1020. table.insert(buf, (" "):rep(indent) .. 'case "$prev" in')
  1021. table.insert(buf, table.concat(opts, "\n"))
  1022. table.insert(buf, (" "):rep(indent) .. "esac\n")
  1023. end
  1024. end
  1025. function Parser:_bash_get_cmd(buf, indent)
  1026. if #self._commands == 0 then
  1027. return
  1028. end
  1029. table.insert(buf, (" "):rep(indent) .. 'args=("${args[@]:1}")')
  1030. table.insert(buf, (" "):rep(indent) .. 'for arg in "${args[@]}"; do')
  1031. table.insert(buf, (" "):rep(indent + 4) .. 'case "$arg" in')
  1032. for _, command in ipairs(self._commands) do
  1033. table.insert(buf, (" "):rep(indent + 8) .. table.concat(command._aliases, "|") .. ")")
  1034. if self._parent then
  1035. table.insert(buf, (" "):rep(indent + 12) .. 'cmd="$cmd ' .. command._name .. '"')
  1036. else
  1037. table.insert(buf, (" "):rep(indent + 12) .. 'cmd="' .. command._name .. '"')
  1038. end
  1039. table.insert(buf, (" "):rep(indent + 12) .. 'opts="$opts ' .. command:_get_options() .. '"')
  1040. command:_bash_get_cmd(buf, indent + 12)
  1041. table.insert(buf, (" "):rep(indent + 12) .. "break")
  1042. table.insert(buf, (" "):rep(indent + 12) .. ";;")
  1043. end
  1044. table.insert(buf, (" "):rep(indent + 4) .. "esac")
  1045. table.insert(buf, (" "):rep(indent) .. "done")
  1046. end
  1047. function Parser:_bash_cmd_completions(buf)
  1048. local cmd_buf = {}
  1049. if self._parent then
  1050. self:_bash_option_args(cmd_buf, 12)
  1051. end
  1052. if #self._commands > 0 then
  1053. table.insert(cmd_buf, (" "):rep(12) .. 'COMPREPLY=($(compgen -W "' .. self:_get_commands() .. '" -- "$cur"))')
  1054. elseif self._is_help_command then
  1055. table.insert(cmd_buf, (" "):rep(12)
  1056. .. 'COMPREPLY=($(compgen -W "'
  1057. .. self._parent:_get_commands()
  1058. .. '" -- "$cur"))')
  1059. end
  1060. if #cmd_buf > 0 then
  1061. table.insert(buf, (" "):rep(8) .. "'" .. self:_get_fullname(true) .. "')")
  1062. table.insert(buf, table.concat(cmd_buf, "\n"))
  1063. table.insert(buf, (" "):rep(12) .. ";;")
  1064. end
  1065. for _, command in ipairs(self._commands) do
  1066. command:_bash_cmd_completions(buf)
  1067. end
  1068. end
  1069. function Parser:get_bash_complete()
  1070. self._basename = base_name(self._name)
  1071. assert(self:_is_shell_safe())
  1072. local buf = {([[
  1073. _%s() {
  1074. local IFS=$' \t\n'
  1075. local args cur prev cmd opts arg
  1076. args=("${COMP_WORDS[@]}")
  1077. cur="${COMP_WORDS[COMP_CWORD]}"
  1078. prev="${COMP_WORDS[COMP_CWORD-1]}"
  1079. opts="%s"
  1080. ]]):format(self._basename, self:_get_options())}
  1081. self:_bash_option_args(buf, 4)
  1082. self:_bash_get_cmd(buf, 4)
  1083. if #self._commands > 0 then
  1084. table.insert(buf, "")
  1085. table.insert(buf, (" "):rep(4) .. 'case "$cmd" in')
  1086. self:_bash_cmd_completions(buf)
  1087. table.insert(buf, (" "):rep(4) .. "esac\n")
  1088. end
  1089. table.insert(buf, ([=[
  1090. if [[ "$cur" = -* ]]; then
  1091. COMPREPLY=($(compgen -W "$opts" -- "$cur"))
  1092. fi
  1093. }
  1094. complete -F _%s -o bashdefault -o default %s
  1095. ]=]):format(self._basename, self._basename))
  1096. return table.concat(buf, "\n")
  1097. end
  1098. function Parser:_zsh_arguments(buf, cmd_name, indent)
  1099. if self._parent then
  1100. table.insert(buf, (" "):rep(indent) .. "options=(")
  1101. table.insert(buf, (" "):rep(indent + 2) .. "$options")
  1102. else
  1103. table.insert(buf, (" "):rep(indent) .. "local -a options=(")
  1104. end
  1105. for _, option in ipairs(self._options) do
  1106. local line = {}
  1107. if #option._aliases > 1 then
  1108. if option._maxcount > 1 then
  1109. table.insert(line, '"*"')
  1110. end
  1111. table.insert(line, "{" .. table.concat(option._aliases, ",") .. '}"')
  1112. else
  1113. table.insert(line, '"')
  1114. if option._maxcount > 1 then
  1115. table.insert(line, "*")
  1116. end
  1117. table.insert(line, option._name)
  1118. end
  1119. if option._description then
  1120. local description = get_short_description(option):gsub('["%]:`$]', "\\%0")
  1121. table.insert(line, "[" .. description .. "]")
  1122. end
  1123. if option._maxargs == math.huge then
  1124. table.insert(line, ":*")
  1125. end
  1126. if option._choices then
  1127. table.insert(line, ": :(" .. table.concat(option._choices, " ") .. ")")
  1128. elseif option._maxargs > 0 then
  1129. table.insert(line, ": :_files")
  1130. end
  1131. table.insert(line, '"')
  1132. table.insert(buf, (" "):rep(indent + 2) .. table.concat(line))
  1133. end
  1134. table.insert(buf, (" "):rep(indent) .. ")")
  1135. table.insert(buf, (" "):rep(indent) .. "_arguments -s -S \\")
  1136. table.insert(buf, (" "):rep(indent + 2) .. "$options \\")
  1137. if self._is_help_command then
  1138. table.insert(buf, (" "):rep(indent + 2) .. '": :(' .. self._parent:_get_commands() .. ')" \\')
  1139. else
  1140. for _, argument in ipairs(self._arguments) do
  1141. local spec
  1142. if argument._choices then
  1143. spec = ": :(" .. table.concat(argument._choices, " ") .. ")"
  1144. else
  1145. spec = ": :_files"
  1146. end
  1147. if argument._maxargs == math.huge then
  1148. table.insert(buf, (" "):rep(indent + 2) .. '"*' .. spec .. '" \\')
  1149. break
  1150. end
  1151. for _ = 1, argument._maxargs do
  1152. table.insert(buf, (" "):rep(indent + 2) .. '"' .. spec .. '" \\')
  1153. end
  1154. end
  1155. if #self._commands > 0 then
  1156. table.insert(buf, (" "):rep(indent + 2) .. '": :_' .. cmd_name .. '_cmds" \\')
  1157. table.insert(buf, (" "):rep(indent + 2) .. '"*:: :->args" \\')
  1158. end
  1159. end
  1160. table.insert(buf, (" "):rep(indent + 2) .. "&& return 0")
  1161. end
  1162. function Parser:_zsh_cmds(buf, cmd_name)
  1163. table.insert(buf, "\n_" .. cmd_name .. "_cmds() {")
  1164. table.insert(buf, " local -a commands=(")
  1165. for _, command in ipairs(self._commands) do
  1166. local line = {}
  1167. if #command._aliases > 1 then
  1168. table.insert(line, "{" .. table.concat(command._aliases, ",") .. '}"')
  1169. else
  1170. table.insert(line, '"' .. command._name)
  1171. end
  1172. if command._description then
  1173. table.insert(line, ":" .. get_short_description(command):gsub('["`$]', "\\%0"))
  1174. end
  1175. table.insert(buf, " " .. table.concat(line) .. '"')
  1176. end
  1177. table.insert(buf, ' )\n _describe "command" commands\n}')
  1178. end
  1179. function Parser:_zsh_complete_help(buf, cmds_buf, cmd_name, indent)
  1180. if #self._commands == 0 then
  1181. return
  1182. end
  1183. self:_zsh_cmds(cmds_buf, cmd_name)
  1184. table.insert(buf, "\n" .. (" "):rep(indent) .. "case $words[1] in")
  1185. for _, command in ipairs(self._commands) do
  1186. local name = cmd_name .. "_" .. command._name
  1187. table.insert(buf, (" "):rep(indent + 2) .. table.concat(command._aliases, "|") .. ")")
  1188. command:_zsh_arguments(buf, name, indent + 4)
  1189. command:_zsh_complete_help(buf, cmds_buf, name, indent + 4)
  1190. table.insert(buf, (" "):rep(indent + 4) .. ";;\n")
  1191. end
  1192. table.insert(buf, (" "):rep(indent) .. "esac")
  1193. end
  1194. function Parser:get_zsh_complete()
  1195. self._basename = base_name(self._name)
  1196. assert(self:_is_shell_safe())
  1197. local buf = {("#compdef %s\n"):format(self._basename)}
  1198. local cmds_buf = {}
  1199. table.insert(buf, "_" .. self._basename .. "() {")
  1200. if #self._commands > 0 then
  1201. table.insert(buf, " local context state state_descr line")
  1202. table.insert(buf, " typeset -A opt_args\n")
  1203. end
  1204. self:_zsh_arguments(buf, self._basename, 2)
  1205. self:_zsh_complete_help(buf, cmds_buf, self._basename, 2)
  1206. table.insert(buf, "\n return 1")
  1207. table.insert(buf, "}")
  1208. local result = table.concat(buf, "\n")
  1209. if #cmds_buf > 0 then
  1210. result = result .. "\n" .. table.concat(cmds_buf, "\n")
  1211. end
  1212. return result .. "\n\n_" .. self._basename .. "\n"
  1213. end
  1214. local function fish_escape(string)
  1215. return string:gsub("[\\']", "\\%0")
  1216. end
  1217. function Parser:_fish_get_cmd(buf, indent)
  1218. if #self._commands == 0 then
  1219. return
  1220. end
  1221. table.insert(buf, (" "):rep(indent) .. "set -e cmdline[1]")
  1222. table.insert(buf, (" "):rep(indent) .. "for arg in $cmdline")
  1223. table.insert(buf, (" "):rep(indent + 4) .. "switch $arg")
  1224. for _, command in ipairs(self._commands) do
  1225. table.insert(buf, (" "):rep(indent + 8) .. "case " .. table.concat(command._aliases, " "))
  1226. table.insert(buf, (" "):rep(indent + 12) .. "set cmd $cmd " .. command._name)
  1227. command:_fish_get_cmd(buf, indent + 12)
  1228. table.insert(buf, (" "):rep(indent + 12) .. "break")
  1229. end
  1230. table.insert(buf, (" "):rep(indent + 4) .. "end")
  1231. table.insert(buf, (" "):rep(indent) .. "end")
  1232. end
  1233. function Parser:_fish_complete_help(buf, basename)
  1234. local prefix = "complete -c " .. basename
  1235. table.insert(buf, "")
  1236. for _, command in ipairs(self._commands) do
  1237. local aliases = table.concat(command._aliases, " ")
  1238. local line
  1239. if self._parent then
  1240. line = ("%s -n '__fish_%s_using_command %s' -xa '%s'")
  1241. :format(prefix, basename, self:_get_fullname(true), aliases)
  1242. else
  1243. line = ("%s -n '__fish_%s_using_command' -xa '%s'"):format(prefix, basename, aliases)
  1244. end
  1245. if command._description then
  1246. line = ("%s -d '%s'"):format(line, fish_escape(get_short_description(command)))
  1247. end
  1248. table.insert(buf, line)
  1249. end
  1250. if self._is_help_command then
  1251. local line = ("%s -n '__fish_%s_using_command %s' -xa '%s'")
  1252. :format(prefix, basename, self:_get_fullname(true), self._parent:_get_commands())
  1253. table.insert(buf, line)
  1254. end
  1255. for _, option in ipairs(self._options) do
  1256. local parts = {prefix}
  1257. if self._parent then
  1258. table.insert(parts, "-n '__fish_" .. basename .. "_seen_command " .. self:_get_fullname(true) .. "'")
  1259. end
  1260. for _, alias in ipairs(option._aliases) do
  1261. if alias:match("^%-.$") then
  1262. table.insert(parts, "-s " .. alias:sub(2))
  1263. elseif alias:match("^%-%-.+") then
  1264. table.insert(parts, "-l " .. alias:sub(3))
  1265. end
  1266. end
  1267. if option._choices then
  1268. table.insert(parts, "-xa '" .. table.concat(option._choices, " ") .. "'")
  1269. elseif option._minargs > 0 then
  1270. table.insert(parts, "-r")
  1271. end
  1272. if option._description then
  1273. table.insert(parts, "-d '" .. fish_escape(get_short_description(option)) .. "'")
  1274. end
  1275. table.insert(buf, table.concat(parts, " "))
  1276. end
  1277. for _, command in ipairs(self._commands) do
  1278. command:_fish_complete_help(buf, basename)
  1279. end
  1280. end
  1281. function Parser:get_fish_complete()
  1282. self._basename = base_name(self._name)
  1283. assert(self:_is_shell_safe())
  1284. local buf = {}
  1285. if #self._commands > 0 then
  1286. table.insert(buf, ([[
  1287. function __fish_%s_print_command
  1288. set -l cmdline (commandline -poc)
  1289. set -l cmd]]):format(self._basename))
  1290. self:_fish_get_cmd(buf, 4)
  1291. table.insert(buf, ([[
  1292. echo "$cmd"
  1293. end
  1294. function __fish_%s_using_command
  1295. test (__fish_%s_print_command) = "$argv"
  1296. and return 0
  1297. or return 1
  1298. end
  1299. function __fish_%s_seen_command
  1300. string match -q "$argv*" (__fish_%s_print_command)
  1301. and return 0
  1302. or return 1
  1303. end]]):format(self._basename, self._basename, self._basename, self._basename))
  1304. end
  1305. self:_fish_complete_help(buf, self._basename)
  1306. return table.concat(buf, "\n") .. "\n"
  1307. end
  1308. local function get_tip(context, wrong_name)
  1309. local context_pool = {}
  1310. local possible_name
  1311. local possible_names = {}
  1312. for name in pairs(context) do
  1313. if type(name) == "string" then
  1314. for i = 1, #name do
  1315. possible_name = name:sub(1, i - 1) .. name:sub(i + 1)
  1316. if not context_pool[possible_name] then
  1317. context_pool[possible_name] = {}
  1318. end
  1319. table.insert(context_pool[possible_name], name)
  1320. end
  1321. end
  1322. end
  1323. for i = 1, #wrong_name + 1 do
  1324. possible_name = wrong_name:sub(1, i - 1) .. wrong_name:sub(i + 1)
  1325. if context[possible_name] then
  1326. possible_names[possible_name] = true
  1327. elseif context_pool[possible_name] then
  1328. for _, name in ipairs(context_pool[possible_name]) do
  1329. possible_names[name] = true
  1330. end
  1331. end
  1332. end
  1333. local first = next(possible_names)
  1334. if first then
  1335. if next(possible_names, first) then
  1336. local possible_names_arr = {}
  1337. for name in pairs(possible_names) do
  1338. table.insert(possible_names_arr, "'" .. name .. "'")
  1339. end
  1340. table.sort(possible_names_arr)
  1341. return "\nDid you mean one of these: " .. table.concat(possible_names_arr, " ") .. "?"
  1342. else
  1343. return "\nDid you mean '" .. first .. "'?"
  1344. end
  1345. else
  1346. return ""
  1347. end
  1348. end
  1349. local ElementState = class({
  1350. invocations = 0
  1351. })
  1352. function ElementState:__call(state, element)
  1353. self.state = state
  1354. self.result = state.result
  1355. self.element = element
  1356. self.target = element._target or element:_get_default_target()
  1357. self.action, self.result[self.target] = element:_get_action()
  1358. return self
  1359. end
  1360. function ElementState:error(fmt, ...)
  1361. self.state:error(fmt, ...)
  1362. end
  1363. function ElementState:convert(argument, index)
  1364. local converter = self.element._convert
  1365. if converter then
  1366. local ok, err
  1367. if type(converter) == "function" then
  1368. ok, err = converter(argument)
  1369. elseif type(converter[index]) == "function" then
  1370. ok, err = converter[index](argument)
  1371. else
  1372. ok = converter[argument]
  1373. end
  1374. if ok == nil then
  1375. self:error(err and "%s" or "malformed argument '%s'", err or argument)
  1376. end
  1377. argument = ok
  1378. end
  1379. return argument
  1380. end
  1381. function ElementState:default(mode)
  1382. return self.element._defmode:find(mode) and self.element._default
  1383. end
  1384. local function bound(noun, min, max, is_max)
  1385. local res = ""
  1386. if min ~= max then
  1387. res = "at " .. (is_max and "most" or "least") .. " "
  1388. end
  1389. local number = is_max and max or min
  1390. return res .. tostring(number) .. " " .. noun .. (number == 1 and "" or "s")
  1391. end
  1392. function ElementState:set_name(alias)
  1393. self.name = ("%s '%s'"):format(alias and "option" or "argument", alias or self.element._name)
  1394. end
  1395. function ElementState:invoke()
  1396. self.open = true
  1397. self.overwrite = false
  1398. if self.invocations >= self.element._maxcount then
  1399. if self.element._overwrite then
  1400. self.overwrite = true
  1401. else
  1402. local num_times_repr = bound("time", self.element._mincount, self.element._maxcount, true)
  1403. self:error("%s must be used %s", self.name, num_times_repr)
  1404. end
  1405. else
  1406. self.invocations = self.invocations + 1
  1407. end
  1408. self.args = {}
  1409. if self.element._maxargs <= 0 then
  1410. self:close()
  1411. end
  1412. return self.open
  1413. end
  1414. function ElementState:check_choices(argument)
  1415. if self.element._choices then
  1416. for _, choice in ipairs(self.element._choices) do
  1417. if argument == choice then
  1418. return
  1419. end
  1420. end
  1421. local choices_list = "'" .. table.concat(self.element._choices, "', '") .. "'"
  1422. local is_option = getmetatable(self.element) == Option
  1423. self:error("%s%s must be one of %s", is_option and "argument for " or "", self.name, choices_list)
  1424. end
  1425. end
  1426. function ElementState:pass(argument)
  1427. self:check_choices(argument)
  1428. argument = self:convert(argument, #self.args + 1)
  1429. table.insert(self.args, argument)
  1430. if #self.args >= self.element._maxargs then
  1431. self:close()
  1432. end
  1433. return self.open
  1434. end
  1435. function ElementState:complete_invocation()
  1436. while #self.args < self.element._minargs do
  1437. self:pass(self.element._default)
  1438. end
  1439. end
  1440. function ElementState:close()
  1441. if self.open then
  1442. self.open = false
  1443. if #self.args < self.element._minargs then
  1444. if self:default("a") then
  1445. self:complete_invocation()
  1446. else
  1447. if #self.args == 0 then
  1448. if getmetatable(self.element) == Argument then
  1449. self:error("missing %s", self.name)
  1450. elseif self.element._maxargs == 1 then
  1451. self:error("%s requires an argument", self.name)
  1452. end
  1453. end
  1454. self:error("%s requires %s", self.name, bound("argument", self.element._minargs, self.element._maxargs))
  1455. end
  1456. end
  1457. local args
  1458. if self.element._maxargs == 0 then
  1459. args = self.args[1]
  1460. elseif self.element._maxargs == 1 then
  1461. if self.element._minargs == 0 and self.element._mincount ~= self.element._maxcount then
  1462. args = self.args
  1463. else
  1464. args = self.args[1]
  1465. end
  1466. else
  1467. args = self.args
  1468. end
  1469. self.action(self.result, self.target, args, self.overwrite)
  1470. end
  1471. end
  1472. local ParseState = class({
  1473. result = {},
  1474. options = {},
  1475. arguments = {},
  1476. argument_i = 1,
  1477. element_to_mutexes = {},
  1478. mutex_to_element_state = {},
  1479. command_actions = {}
  1480. })
  1481. function ParseState:__call(parser, error_handler)
  1482. self.parser = parser
  1483. self.error_handler = error_handler
  1484. self.charset = parser:_update_charset()
  1485. self:switch(parser)
  1486. return self
  1487. end
  1488. function ParseState:error(fmt, ...)
  1489. self.error_handler(self.parser, fmt:format(...))
  1490. end
  1491. function ParseState:switch(parser)
  1492. self.parser = parser
  1493. if parser._action then
  1494. table.insert(self.command_actions, {action = parser._action, name = parser._name})
  1495. end
  1496. for _, option in ipairs(parser._options) do
  1497. option = ElementState(self, option)
  1498. table.insert(self.options, option)
  1499. for _, alias in ipairs(option.element._aliases) do
  1500. self.options[alias] = option
  1501. end
  1502. end
  1503. for _, mutex in ipairs(parser._mutexes) do
  1504. for _, element in ipairs(mutex) do
  1505. if not self.element_to_mutexes[element] then
  1506. self.element_to_mutexes[element] = {}
  1507. end
  1508. table.insert(self.element_to_mutexes[element], mutex)
  1509. end
  1510. end
  1511. for _, argument in ipairs(parser._arguments) do
  1512. argument = ElementState(self, argument)
  1513. table.insert(self.arguments, argument)
  1514. argument:set_name()
  1515. argument:invoke()
  1516. end
  1517. self.handle_options = parser._handle_options
  1518. self.argument = self.arguments[self.argument_i]
  1519. self.commands = parser._commands
  1520. for _, command in ipairs(self.commands) do
  1521. for _, alias in ipairs(command._aliases) do
  1522. self.commands[alias] = command
  1523. end
  1524. end
  1525. end
  1526. function ParseState:get_option(name)
  1527. local option = self.options[name]
  1528. if not option then
  1529. self:error("unknown option '%s'%s", name, get_tip(self.options, name))
  1530. else
  1531. return option
  1532. end
  1533. end
  1534. function ParseState:get_command(name)
  1535. local command = self.commands[name]
  1536. if not command then
  1537. if #self.commands > 0 then
  1538. self:error("unknown command '%s'%s", name, get_tip(self.commands, name))
  1539. else
  1540. self:error("too many arguments")
  1541. end
  1542. else
  1543. return command
  1544. end
  1545. end
  1546. function ParseState:check_mutexes(element_state)
  1547. if self.element_to_mutexes[element_state.element] then
  1548. for _, mutex in ipairs(self.element_to_mutexes[element_state.element]) do
  1549. local used_element_state = self.mutex_to_element_state[mutex]
  1550. if used_element_state and used_element_state ~= element_state then
  1551. self:error("%s can not be used together with %s", element_state.name, used_element_state.name)
  1552. else
  1553. self.mutex_to_element_state[mutex] = element_state
  1554. end
  1555. end
  1556. end
  1557. end
  1558. function ParseState:invoke(option, name)
  1559. self:close()
  1560. option:set_name(name)
  1561. self:check_mutexes(option, name)
  1562. if option:invoke() then
  1563. self.option = option
  1564. end
  1565. end
  1566. function ParseState:pass(arg)
  1567. if self.option then
  1568. if not self.option:pass(arg) then
  1569. self.option = nil
  1570. end
  1571. elseif self.argument then
  1572. self:check_mutexes(self.argument)
  1573. if not self.argument:pass(arg) then
  1574. self.argument_i = self.argument_i + 1
  1575. self.argument = self.arguments[self.argument_i]
  1576. end
  1577. else
  1578. local command = self:get_command(arg)
  1579. self.result[command._target or command._name] = true
  1580. if self.parser._command_target then
  1581. self.result[self.parser._command_target] = command._name
  1582. end
  1583. self:switch(command)
  1584. end
  1585. end
  1586. function ParseState:close()
  1587. if self.option then
  1588. self.option:close()
  1589. self.option = nil
  1590. end
  1591. end
  1592. function ParseState:finalize()
  1593. self:close()
  1594. for i = self.argument_i, #self.arguments do
  1595. local argument = self.arguments[i]
  1596. if #argument.args == 0 and argument:default("u") then
  1597. argument:complete_invocation()
  1598. else
  1599. argument:close()
  1600. end
  1601. end
  1602. if self.parser._require_command and #self.commands > 0 then
  1603. self:error("a command is required")
  1604. end
  1605. for _, option in ipairs(self.options) do
  1606. option.name = option.name or ("option '%s'"):format(option.element._name)
  1607. if option.invocations == 0 then
  1608. if option:default("u") then
  1609. option:invoke()
  1610. option:complete_invocation()
  1611. option:close()
  1612. end
  1613. end
  1614. local mincount = option.element._mincount
  1615. if option.invocations < mincount then
  1616. if option:default("a") then
  1617. while option.invocations < mincount do
  1618. option:invoke()
  1619. option:close()
  1620. end
  1621. elseif option.invocations == 0 then
  1622. self:error("missing %s", option.name)
  1623. else
  1624. self:error("%s must be used %s", option.name, bound("time", mincount, option.element._maxcount))
  1625. end
  1626. end
  1627. end
  1628. for i = #self.command_actions, 1, -1 do
  1629. self.command_actions[i].action(self.result, self.command_actions[i].name)
  1630. end
  1631. end
  1632. function ParseState:parse(args)
  1633. for _, arg in ipairs(args) do
  1634. local plain = true
  1635. if self.handle_options then
  1636. local first = arg:sub(1, 1)
  1637. if self.charset[first] then
  1638. if #arg > 1 then
  1639. plain = false
  1640. if arg:sub(2, 2) == first then
  1641. if #arg == 2 then
  1642. if self.options[arg] then
  1643. local option = self:get_option(arg)
  1644. self:invoke(option, arg)
  1645. else
  1646. self:close()
  1647. end
  1648. self.handle_options = false
  1649. else
  1650. local equals = arg:find "="
  1651. if equals then
  1652. local name = arg:sub(1, equals - 1)
  1653. local option = self:get_option(name)
  1654. if option.element._maxargs <= 0 then
  1655. self:error("option '%s' does not take arguments", name)
  1656. end
  1657. self:invoke(option, name)
  1658. self:pass(arg:sub(equals + 1))
  1659. else
  1660. local option = self:get_option(arg)
  1661. self:invoke(option, arg)
  1662. end
  1663. end
  1664. else
  1665. for i = 2, #arg do
  1666. local name = first .. arg:sub(i, i)
  1667. local option = self:get_option(name)
  1668. self:invoke(option, name)
  1669. if i ~= #arg and option.element._maxargs > 0 then
  1670. self:pass(arg:sub(i + 1))
  1671. break
  1672. end
  1673. end
  1674. end
  1675. end
  1676. end
  1677. end
  1678. if plain then
  1679. self:pass(arg)
  1680. end
  1681. end
  1682. self:finalize()
  1683. return self.result
  1684. end
  1685. function Parser:error(msg)
  1686. io.stderr:write(("%s\n\nError: %s\n"):format(self:get_usage(), msg))
  1687. os.exit(1)
  1688. end
  1689. -- Compatibility with strict.lua and other checkers:
  1690. local default_cmdline = rawget(_G, "arg") or {}
  1691. function Parser:_parse(args, error_handler)
  1692. return ParseState(self, error_handler):parse(args or default_cmdline)
  1693. end
  1694. function Parser:parse(args)
  1695. return self:_parse(args, self.error)
  1696. end
  1697. local function xpcall_error_handler(err)
  1698. return tostring(err) .. "\noriginal " .. debug.traceback("", 2):sub(2)
  1699. end
  1700. function Parser:pparse(args)
  1701. local parse_error
  1702. local ok, result = xpcall(function()
  1703. return self:_parse(args, function(_, err)
  1704. parse_error = err
  1705. error(err, 0)
  1706. end)
  1707. end, xpcall_error_handler)
  1708. if ok then
  1709. return true, result
  1710. elseif not parse_error then
  1711. error(result, 0)
  1712. else
  1713. return false, parse_error
  1714. end
  1715. end
  1716. local argparse = {}
  1717. argparse.version = "0.7.1"
  1718. setmetatable(argparse, {__call = function(_, ...)
  1719. return Parser(default_cmdline[0]):add_help(true)(...)
  1720. end})
  1721. return argparse