clink.lua 106 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420
  1. --
  2. -- Copyright (c) 2012 Martin Ridgers
  3. --
  4. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  5. -- of this software and associated documentation files (the "Software"), to deal
  6. -- in the Software without restriction, including without limitation the rights
  7. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. -- copies of the Software, and to permit persons to whom the Software is
  9. -- furnished to do so, subject to the following conditions:
  10. --
  11. -- The above copyright notice and this permission notice shall be included in
  12. -- all copies or substantial portions of the Software.
  13. --
  14. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. -- SOFTWARE.
  21. --
  22. --------------------------------------------------------------------------------
  23. clink.matches = {}
  24. clink.generators = {}
  25. clink.prompt = {}
  26. clink.prompt.filters = {}
  27. --------------------------------------------------------------------------------
  28. function clink.compute_lcd(text, list)
  29. local list_n = #list
  30. if list_n < 2 then
  31. return
  32. end
  33. -- Find min and max limits
  34. local max = 100000
  35. for i = 1, #list, 1 do
  36. local j = #(list[i])
  37. if max > j then
  38. max = j
  39. end
  40. end
  41. -- For each character in the search range...
  42. local mid = #text
  43. local lcd = ""
  44. for i = 1, max, 1 do
  45. local same = true
  46. local l = list[1]:sub(i, i)
  47. local m = l:lower()
  48. -- Compare character at the index with each other character in the
  49. -- other matches.
  50. for j = 2, list_n, 1 do
  51. local n = list[j]:sub(i, i):lower()
  52. if m ~= n then
  53. same = false
  54. break
  55. end
  56. end
  57. -- If all characters match then use first match's character.
  58. if same then
  59. lcd = lcd..l
  60. else
  61. -- Otherwise use what the user's typed or if we're past that then
  62. -- bail out.
  63. if i <= mid then
  64. lcd = lcd..text:sub(i, i)
  65. else
  66. break
  67. end
  68. end
  69. end
  70. return lcd
  71. end
  72. --------------------------------------------------------------------------------
  73. function clink.is_single_match(matches)
  74. if #matches <= 1 then
  75. return true
  76. end
  77. local first = matches[1]:lower()
  78. for i = 2, #matches, 1 do
  79. if first ~= matches[i]:lower() then
  80. return false
  81. end
  82. end
  83. return true
  84. end
  85. --------------------------------------------------------------------------------
  86. function clink.is_point_in_quote(str, i)
  87. if i > #str then
  88. i = #str
  89. end
  90. local c = 1
  91. local q = string.byte("\"")
  92. for j = 1, i do
  93. if string.byte(str, j) == q then
  94. c = c * -1
  95. end
  96. end
  97. if c < 0 then
  98. return true
  99. end
  100. return false
  101. end
  102. --------------------------------------------------------------------------------
  103. function clink.adjust_for_separator(buffer, point, first, last)
  104. local seps = nil
  105. if clink.get_host_process() == "cmd.exe" then
  106. seps = "|&"
  107. end
  108. if seps then
  109. -- Find any valid command separators and if found, manipulate the
  110. -- completion state a little bit.
  111. local leading = buffer:sub(1, first - 1)
  112. -- regex is: <sep> <not_seps> <eol>
  113. local regex = "["..seps.."]([^"..seps.."]*)$"
  114. local sep_found, _, post_sep = leading:find(regex)
  115. if sep_found and not clink.is_point_in_quote(leading, sep_found) then
  116. local delta = #leading - #post_sep
  117. buffer = buffer:sub(delta + 1)
  118. first = first - delta
  119. last = last - delta
  120. point = point - delta
  121. if first < 1 then
  122. first = 1
  123. end
  124. end
  125. end
  126. return buffer, point, first, last
  127. end
  128. --------------------------------------------------------------------------------
  129. function clink.generate_matches(text, first, last)
  130. local line_buffer
  131. local point
  132. line_buffer, point, first, last = clink.adjust_for_separator(
  133. rl_state.line_buffer,
  134. rl_state.point,
  135. first,
  136. last
  137. )
  138. rl_state.line_buffer = line_buffer
  139. rl_state.point = point
  140. clink.matches = {}
  141. clink.match_display_filter = nil
  142. for _, generator in ipairs(clink.generators) do
  143. if generator.f(text, first, last) == true then
  144. if #clink.matches > 1 then
  145. -- Catch instances where there's many entries of a single match
  146. if clink.is_single_match(clink.matches) then
  147. clink.matches = { clink.matches[1] }
  148. return true;
  149. end
  150. -- First entry in the match list should be the user's input,
  151. -- modified here to be the lowest common denominator.
  152. local lcd = clink.compute_lcd(text, clink.matches)
  153. table.insert(clink.matches, 1, lcd)
  154. end
  155. return true
  156. end
  157. end
  158. return false
  159. end
  160. --------------------------------------------------------------------------------
  161. function clink.add_match(match)
  162. if type(match) == "table" then
  163. for _, i in ipairs(match) do
  164. table.insert(clink.matches, i)
  165. end
  166. return
  167. end
  168. table.insert(clink.matches, match)
  169. end
  170. --------------------------------------------------------------------------------
  171. function clink.register_match_generator(func, priority)
  172. if priority == nil then
  173. priority = 999
  174. end
  175. table.insert(clink.generators, {f=func, p=priority})
  176. table.sort(clink.generators, function(a, b) return a["p"] < b["p"] end)
  177. end
  178. --------------------------------------------------------------------------------
  179. function clink.is_match(needle, candidate)
  180. if needle == nil then
  181. error("Nil needle value when calling clink.is_match()", 2)
  182. end
  183. if clink.lower(candidate:sub(1, #needle)) == clink.lower(needle) then
  184. return true
  185. end
  186. return false
  187. end
  188. --------------------------------------------------------------------------------
  189. function clink.match_count()
  190. return #clink.matches
  191. end
  192. --------------------------------------------------------------------------------
  193. function clink.set_match(i, value)
  194. clink.matches[i] = value
  195. end
  196. --------------------------------------------------------------------------------
  197. function clink.get_match(i)
  198. return clink.matches[i]
  199. end
  200. --------------------------------------------------------------------------------
  201. function clink.match_words(text, words)
  202. local count = clink.match_count()
  203. for _, i in ipairs(words) do
  204. if clink.is_match(text, i) then
  205. clink.add_match(i)
  206. end
  207. end
  208. return clink.match_count() - count
  209. end
  210. --------------------------------------------------------------------------------
  211. function clink.match_files(pattern, full_path, find_func)
  212. -- Fill out default values
  213. if type(find_func) ~= "function" then
  214. find_func = clink.find_files
  215. end
  216. if full_path == nil then
  217. full_path = true
  218. end
  219. if pattern == nil then
  220. pattern = "*"
  221. end
  222. -- Glob files.
  223. pattern = pattern:gsub("/", "\\")
  224. local glob = find_func(pattern, true)
  225. -- Get glob's base.
  226. local base = ""
  227. local i = pattern:find("[\\:][^\\:]*$")
  228. if i and full_path then
  229. base = pattern:sub(1, i)
  230. end
  231. -- Match them.
  232. local count = clink.match_count()
  233. for _, i in ipairs(glob) do
  234. local full = base..i
  235. clink.add_match(full)
  236. end
  237. return clink.match_count() - count
  238. end
  239. --------------------------------------------------------------------------------
  240. function clink.split(str, sep)
  241. local i = 1
  242. local ret = {}
  243. for _, j in function() return str:find(sep, i, true) end do
  244. table.insert(ret, str:sub(i, j - 1))
  245. i = j + 1
  246. end
  247. table.insert(ret, str:sub(i, j))
  248. return ret
  249. end
  250. --------------------------------------------------------------------------------
  251. function clink.quote_split(str, ql, qr)
  252. if not qr then
  253. qr = ql
  254. end
  255. -- First parse in "pre[ql]quote_string[qr]" chunks
  256. local insert = table.insert
  257. local i = 1
  258. local needle = "%b"..ql..qr
  259. local parts = {}
  260. for l, r, quote in function() return str:find(needle, i) end do
  261. -- "pre"
  262. if l > 1 then
  263. insert(parts, str:sub(i, l - 1))
  264. end
  265. -- "quote_string"
  266. insert(parts, str:sub(l, r))
  267. i = r + 1
  268. end
  269. -- Second parse what remains as "pre[ql]being_quoted"
  270. local l = str:find(ql, i, true)
  271. if l then
  272. -- "pre"
  273. if l > 1 then
  274. insert(parts, str:sub(i, l - 1))
  275. end
  276. -- "being_quoted"
  277. insert(parts, str:sub(l))
  278. elseif i <= #str then
  279. -- Finally add whatever remains...
  280. insert(parts, str:sub(i))
  281. end
  282. return parts
  283. end
  284. --------------------------------------------------------------------------------
  285. function clink.prompt.register_filter(filter, priority)
  286. if priority == nil then
  287. priority = 999
  288. end
  289. table.insert(clink.prompt.filters, {f=filter, p=priority})
  290. table.sort(clink.prompt.filters, function(a, b) return a["p"] < b["p"] end)
  291. end
  292. --------------------------------------------------------------------------------
  293. function clink.filter_prompt(prompt)
  294. local function add_ansi_codes(p)
  295. local c = tonumber(clink.get_setting_int("prompt_colour"))
  296. if c < 0 then
  297. return p
  298. end
  299. c = c % 16
  300. --[[
  301. <4 >=4 %2
  302. 0 0 0 Black 4 1 -3 Blue 0
  303. 1 4 3 Red 5 5 0 Magenta 1
  304. 2 2 0 Green 6 3 -3 Cyan 0
  305. 3 6 3 Yellow 7 7 0 Gray 1
  306. --]]
  307. -- Convert from cmd.exe colour indices to ANSI ones.
  308. local colour_id = c % 8
  309. if (colour_id % 2) == 1 then
  310. if colour_id < 4 then
  311. c = c + 3
  312. end
  313. elseif colour_id >= 4 then
  314. c = c - 3
  315. end
  316. -- Clamp
  317. if c > 15 then
  318. c = 15
  319. end
  320. -- Build ANSI code
  321. local code = "\x1b[0;"
  322. if c > 7 then
  323. c = c - 8
  324. code = code.."1;"
  325. end
  326. code = code..(c + 30).."m"
  327. return code..p.."\x1b[0m"
  328. end
  329. clink.prompt.value = prompt
  330. for _, filter in ipairs(clink.prompt.filters) do
  331. if filter.f() == true then
  332. return add_ansi_codes(clink.prompt.value)
  333. end
  334. end
  335. return add_ansi_codes(clink.prompt.value)
  336. end
  337. -- vim: expandtab
  338. --
  339. -- Copyright (c) 2012 Martin Ridgers
  340. --
  341. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  342. -- of this software and associated documentation files (the "Software"), to deal
  343. -- in the Software without restriction, including without limitation the rights
  344. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  345. -- copies of the Software, and to permit persons to whom the Software is
  346. -- furnished to do so, subject to the following conditions:
  347. --
  348. -- The above copyright notice and this permission notice shall be included in
  349. -- all copies or substantial portions of the Software.
  350. --
  351. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  352. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  353. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  354. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  355. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  356. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  357. -- SOFTWARE.
  358. --
  359. --------------------------------------------------------------------------------
  360. clink.arg = {}
  361. --------------------------------------------------------------------------------
  362. local parsers = {}
  363. local is_parser
  364. local is_sub_parser
  365. local new_sub_parser
  366. local parser_go_impl
  367. local merge_parsers
  368. local parser_meta_table = {}
  369. local sub_parser_meta_table = {}
  370. --------------------------------------------------------------------------------
  371. function parser_meta_table.__concat(lhs, rhs)
  372. if not is_parser(rhs) then
  373. error("Right-handside must be parser.", 2)
  374. end
  375. local t = type(lhs)
  376. if t == "table" then
  377. local ret = {}
  378. for _, i in ipairs(lhs) do
  379. table.insert(ret, i .. rhs)
  380. end
  381. return ret
  382. elseif t ~= "string" then
  383. error("Left-handside must be a string or a table.", 2)
  384. end
  385. return new_sub_parser(lhs, rhs)
  386. end
  387. --------------------------------------------------------------------------------
  388. local function unfold_table(source, target)
  389. for _, i in ipairs(source) do
  390. if type(i) == "table" and getmetatable(i) == nil then
  391. unfold_table(i, target)
  392. else
  393. table.insert(target, i)
  394. end
  395. end
  396. end
  397. --------------------------------------------------------------------------------
  398. local function parser_is_flag(parser, part)
  399. if part == nil then
  400. return false
  401. end
  402. local prefix = part:sub(1, 1)
  403. return prefix == "-" or prefix == "/"
  404. end
  405. --------------------------------------------------------------------------------
  406. local function parser_add_arguments(parser, ...)
  407. for _, i in ipairs({...}) do
  408. -- Check all arguments are tables.
  409. if type(i) ~= "table" then
  410. error("All arguments to add_arguments() must be tables.", 2)
  411. end
  412. -- Only parsers are allowed to be specified without being wrapped in a
  413. -- containing table.
  414. if getmetatable(i) ~= nil then
  415. if is_parser(i) then
  416. table.insert(parser.arguments, i)
  417. else
  418. error("Tables can't have meta-tables.", 2)
  419. end
  420. else
  421. -- Expand out nested tables and insert into object's arguments table.
  422. local arguments = {}
  423. unfold_table(i, arguments)
  424. table.insert(parser.arguments, arguments)
  425. end
  426. end
  427. return parser
  428. end
  429. --------------------------------------------------------------------------------
  430. local function parser_set_arguments(parser, ...)
  431. parser.arguments = {}
  432. return parser:add_arguments(...)
  433. end
  434. --------------------------------------------------------------------------------
  435. local function parser_add_flags(parser, ...)
  436. local flags = {}
  437. unfold_table({...}, flags)
  438. -- Validate the specified flags.
  439. for _, i in ipairs(flags) do
  440. if is_sub_parser(i) then
  441. i = i.key
  442. end
  443. -- Check all flags are strings.
  444. if type(i) ~= "string" then
  445. error("All parser flags must be strings. Found "..type(i), 2)
  446. end
  447. -- Check all flags start with a - or a /
  448. if not parser:is_flag(i) then
  449. error("Flags must begin with a '-' or a '/'", 2)
  450. end
  451. end
  452. -- Append flags to parser's existing table of flags.
  453. for _, i in ipairs(flags) do
  454. table.insert(parser.flags, i)
  455. end
  456. return parser
  457. end
  458. --------------------------------------------------------------------------------
  459. local function parser_set_flags(parser, ...)
  460. parser.flags = {}
  461. return parser:add_flags(...)
  462. end
  463. --------------------------------------------------------------------------------
  464. local function parser_flatten_argument(parser, index, func_thunk)
  465. -- Sanity check the 'index' param to make sure it's valid.
  466. if type(index) == "number" then
  467. if index <= 0 or index > #parser.arguments then
  468. return parser.use_file_matching
  469. end
  470. end
  471. -- index == nil is a special case that returns the parser's flags
  472. local opts = {}
  473. local arg_opts
  474. if index == nil then
  475. arg_opts = parser.flags
  476. else
  477. arg_opts = parser.arguments[index]
  478. end
  479. -- Convert each argument option into a string and collect them in a table.
  480. for _, i in ipairs(arg_opts) do
  481. if is_sub_parser(i) then
  482. table.insert(opts, i.key)
  483. else
  484. local t = type(i)
  485. if t == "function" then
  486. local results = func_thunk(i)
  487. local t = type(results)
  488. if not results then
  489. return parser.use_file_matching
  490. elseif t == "boolean" then
  491. return (results and parser.use_file_matching)
  492. elseif t == "table" then
  493. for _, j in ipairs(results) do
  494. table.insert(opts, j)
  495. end
  496. end
  497. elseif t == "string" or t == "number" then
  498. table.insert(opts, tostring(i))
  499. end
  500. end
  501. end
  502. return opts
  503. end
  504. --------------------------------------------------------------------------------
  505. local function parser_go_args(parser, state)
  506. local exhausted_args = false
  507. local exhausted_parts = false
  508. local part = state.parts[state.part_index]
  509. local arg_index = state.arg_index
  510. local arg_opts = parser.arguments[arg_index]
  511. local arg_count = #parser.arguments
  512. -- Is the next argument a parser? Parse control directly on to it.
  513. if is_parser(arg_opts) then
  514. state.arg_index = 1
  515. return parser_go_impl(arg_opts, state)
  516. end
  517. -- Advance parts state.
  518. state.part_index = state.part_index + 1
  519. if state.part_index > #state.parts then
  520. exhausted_parts = true
  521. end
  522. -- Advance argument state.
  523. state.arg_index = arg_index + 1
  524. if arg_index > arg_count then
  525. exhausted_args = true
  526. end
  527. -- We've exhausted all available arguments. We either loop or we're done.
  528. if parser.loop_point > 0 and state.arg_index > arg_count then
  529. state.arg_index = parser.loop_point
  530. if state.arg_index > arg_count then
  531. state.arg_index = arg_count
  532. end
  533. end
  534. -- Is there some state to process?
  535. if not exhausted_parts and not exhausted_args then
  536. local exact = false
  537. for _, arg_opt in ipairs(arg_opts) do
  538. -- Is the argument a key to a sub-parser? If so then hand control
  539. -- off to it.
  540. if is_sub_parser(arg_opt) then
  541. if arg_opt.key == part then
  542. state.arg_index = 1
  543. return parser_go_impl(arg_opt.parser, state)
  544. end
  545. end
  546. -- Check so see if the part has an exact match in the argument. Note
  547. -- that only string-type options are considered.
  548. if type(arg_opt) == "string" then
  549. exact = exact or arg_opt == part
  550. else
  551. exact = true
  552. end
  553. end
  554. -- If the parser's required to be precise then check here.
  555. if parser.precise and not exact then
  556. exhausted_args = true
  557. else
  558. return nil
  559. end
  560. end
  561. -- If we've no more arguments to traverse but there's still parts remaining
  562. -- then we start skipping arguments but keep going so that flags still get
  563. -- parsed (as flags have no position).
  564. if exhausted_args then
  565. state.part_index = state.part_index - 1
  566. if not exhausted_parts then
  567. if state.depth <= 1 then
  568. state.skip_args = true
  569. return
  570. end
  571. return parser.use_file_matching
  572. end
  573. end
  574. -- Now we've an index into the parser's arguments that matches the line
  575. -- state. Flatten it.
  576. local func_thunk = function(func)
  577. return func(part)
  578. end
  579. return parser:flatten_argument(arg_index, func_thunk)
  580. end
  581. --------------------------------------------------------------------------------
  582. local function parser_go_flags(parser, state)
  583. local part = state.parts[state.part_index]
  584. -- Advance parts state.
  585. state.part_index = state.part_index + 1
  586. if state.part_index > #state.parts then
  587. return parser:flatten_argument()
  588. end
  589. for _, arg_opt in ipairs(parser.flags) do
  590. if is_sub_parser(arg_opt) then
  591. if arg_opt.key == part then
  592. local arg_index_cache = state.arg_index
  593. local skip_args_cache = state.skip_args
  594. state.arg_index = 1
  595. state.skip_args = false
  596. state.depth = state.depth + 1
  597. local ret = parser_go_impl(arg_opt.parser, state)
  598. if type(ret) == "table" then
  599. return ret
  600. end
  601. state.depth = state.depth - 1
  602. state.skip_args = skip_args_cache
  603. state.arg_index = arg_index_cache
  604. end
  605. end
  606. end
  607. end
  608. --------------------------------------------------------------------------------
  609. function parser_go_impl(parser, state)
  610. local has_flags = #parser.flags > 0
  611. while state.part_index <= #state.parts do
  612. local part = state.parts[state.part_index]
  613. local dispatch_func
  614. if has_flags and parser:is_flag(part) then
  615. dispatch_func = parser_go_flags
  616. elseif not state.skip_args then
  617. dispatch_func = parser_go_args
  618. end
  619. if dispatch_func ~= nil then
  620. local ret = dispatch_func(parser, state)
  621. if ret ~= nil then
  622. return ret
  623. end
  624. else
  625. state.part_index = state.part_index + 1
  626. end
  627. end
  628. return parser.use_file_matching
  629. end
  630. --------------------------------------------------------------------------------
  631. local function parser_go(parser, parts)
  632. -- Validate 'parts'.
  633. if type(parts) ~= "table" then
  634. error("'Parts' param must be a table of strings ("..type(parts)..").", 2)
  635. else
  636. if #parts == 0 then
  637. part = { "" }
  638. end
  639. for i, j in ipairs(parts) do
  640. local t = type(parts[i])
  641. if t ~= "string" then
  642. error("'Parts' table can only contain strings; "..j.."="..t, 2)
  643. end
  644. end
  645. end
  646. local state = {
  647. arg_index = 1,
  648. part_index = 1,
  649. parts = parts,
  650. skip_args = false,
  651. depth = 1,
  652. }
  653. return parser_go_impl(parser, state)
  654. end
  655. --------------------------------------------------------------------------------
  656. local function parser_dump(parser, depth)
  657. if depth == nil then
  658. depth = 0
  659. end
  660. function prt(depth, index, text)
  661. local indent = string.sub(" ", 1, depth)
  662. text = tostring(text)
  663. print(indent..depth.."."..index.." - "..text)
  664. end
  665. -- Print arguments
  666. local i = 0
  667. for _, arg_opts in ipairs(parser.arguments) do
  668. for _, arg_opt in ipairs(arg_opts) do
  669. if is_sub_parser(arg_opt) then
  670. prt(depth, i, arg_opt.key)
  671. arg_opt.parser:dump(depth + 1)
  672. else
  673. prt(depth, i, arg_opt)
  674. end
  675. end
  676. i = i + 1
  677. end
  678. -- Print flags
  679. for _, flag in ipairs(parser.flags) do
  680. prt(depth, "F", flag)
  681. end
  682. end
  683. --------------------------------------------------------------------------------
  684. function parser_be_precise(parser)
  685. parser.precise = true
  686. return parser
  687. end
  688. --------------------------------------------------------------------------------
  689. function is_parser(p)
  690. return type(p) == "table" and getmetatable(p) == parser_meta_table
  691. end
  692. --------------------------------------------------------------------------------
  693. function is_sub_parser(sp)
  694. return type(sp) == "table" and getmetatable(sp) == sub_parser_meta_table
  695. end
  696. --------------------------------------------------------------------------------
  697. local function get_sub_parser(argument, str)
  698. for _, arg in ipairs(argument) do
  699. if is_sub_parser(arg) then
  700. if arg.key == str then
  701. return arg.parser
  702. end
  703. end
  704. end
  705. end
  706. --------------------------------------------------------------------------------
  707. function new_sub_parser(key, parser)
  708. local sub_parser = {}
  709. sub_parser.key = key
  710. sub_parser.parser = parser
  711. setmetatable(sub_parser, sub_parser_meta_table)
  712. return sub_parser
  713. end
  714. --------------------------------------------------------------------------------
  715. local function parser_disable_file_matching(parser)
  716. parser.use_file_matching = false
  717. return parser
  718. end
  719. --------------------------------------------------------------------------------
  720. local function parser_loop(parser, loop_point)
  721. if loop_point == nil or type(loop_point) ~= "number" or loop_point < 1 then
  722. loop_point = 1
  723. end
  724. parser.loop_point = loop_point
  725. return parser
  726. end
  727. --------------------------------------------------------------------------------
  728. local function parser_initialise(parser, ...)
  729. for _, word in ipairs({...}) do
  730. local t = type(word)
  731. if t == "string" then
  732. parser:add_flags(word)
  733. elseif t == "table" then
  734. if is_sub_parser(word) and parser_is_flag(nil, word.key) then
  735. parser:add_flags(word)
  736. else
  737. parser:add_arguments(word)
  738. end
  739. else
  740. error("Additional arguments to new_parser() must be tables or strings", 2)
  741. end
  742. end
  743. end
  744. --------------------------------------------------------------------------------
  745. function clink.arg.new_parser(...)
  746. local parser = {}
  747. -- Methods
  748. parser.set_flags = parser_set_flags
  749. parser.add_flags = parser_add_flags
  750. parser.set_arguments = parser_set_arguments
  751. parser.add_arguments = parser_add_arguments
  752. parser.dump = parser_dump
  753. parser.go = parser_go
  754. parser.flatten_argument = parser_flatten_argument
  755. parser.be_precise = parser_be_precise
  756. parser.disable_file_matching = parser_disable_file_matching
  757. parser.loop = parser_loop
  758. parser.is_flag = parser_is_flag
  759. -- Members.
  760. parser.flags = {}
  761. parser.arguments = {}
  762. parser.precise = false
  763. parser.use_file_matching = true
  764. parser.loop_point = 0
  765. setmetatable(parser, parser_meta_table)
  766. -- If any arguments are provided treat them as parser's arguments or flags
  767. if ... then
  768. success, msg = pcall(parser_initialise, parser, ...)
  769. if not success then
  770. error(msg, 2)
  771. end
  772. end
  773. return parser
  774. end
  775. --------------------------------------------------------------------------------
  776. function merge_parsers(lhs, rhs)
  777. -- Merging parsers is not a trivial matter and this implementation is far
  778. -- from correct. It is however sufficient for the majority of cases.
  779. -- Merge flags.
  780. for _, rflag in ipairs(rhs.flags) do
  781. table.insert(lhs.flags, rflag)
  782. end
  783. -- Remove (and save value of) the first argument in RHS.
  784. local rhs_arg_1 = table.remove(rhs.arguments, 1)
  785. if rhs_arg_1 == nil then
  786. return
  787. end
  788. -- Get reference to the LHS's first argument table (creating it if needed).
  789. local lhs_arg_1 = lhs.arguments[1]
  790. if lhs_arg_1 == nil then
  791. lhs_arg_1 = {}
  792. table.insert(lhs.arguments, lhs_arg_1)
  793. end
  794. -- Link RHS to LHS through sub-parsers.
  795. for _, rarg in ipairs(rhs_arg_1) do
  796. local child
  797. -- Split sub parser
  798. if is_sub_parser(rarg) then
  799. child = rarg.parser
  800. rarg = rarg.key
  801. else
  802. child = rhs
  803. end
  804. -- If LHS's first argument has rarg in it which links to a sub-parser
  805. -- then we need to recursively merge them.
  806. local lhs_sub_parser = get_sub_parser(lhs_arg_1, rarg)
  807. if lhs_sub_parser then
  808. merge_parsers(lhs_sub_parser, child)
  809. else
  810. local to_add = rarg
  811. if type(rarg) ~= "function" then
  812. to_add = rarg .. child
  813. end
  814. table.insert(lhs_arg_1, to_add)
  815. end
  816. end
  817. end
  818. --------------------------------------------------------------------------------
  819. function clink.arg.register_parser(cmd, parser)
  820. if not is_parser(parser) then
  821. local p = clink.arg.new_parser()
  822. p:set_arguments({ parser })
  823. parser = p
  824. end
  825. cmd = cmd:lower()
  826. local prev = parsers[cmd]
  827. if prev ~= nil then
  828. merge_parsers(prev, parser)
  829. else
  830. parsers[cmd] = parser
  831. end
  832. end
  833. --------------------------------------------------------------------------------
  834. local function argument_match_generator(text, first, last)
  835. local leading = rl_state.line_buffer:sub(1, first - 1):lower()
  836. -- Extract the command.
  837. local cmd_l, cmd_r
  838. if leading:find("^%s*\"") then
  839. -- Command appears to be surround by quotes.
  840. cmd_l, cmd_r = leading:find("%b\"\"")
  841. if cmd_l and cmd_r then
  842. cmd_l = cmd_l + 1
  843. cmd_r = cmd_r - 1
  844. end
  845. else
  846. -- No quotes so the first, longest, non-whitespace word is extracted.
  847. cmd_l, cmd_r = leading:find("[^%s]+")
  848. end
  849. if not cmd_l or not cmd_r then
  850. return false
  851. end
  852. local regex = "[\\/:]*([^\\/:.]+)(%.*[%l]*)%s*$"
  853. local _, _, cmd, ext = leading:sub(cmd_l, cmd_r):lower():find(regex)
  854. -- Check to make sure the extension extracted is in pathext.
  855. if ext and ext ~= "" then
  856. if not clink.get_env("pathext"):lower():match(ext.."[;$]", 1, true) then
  857. return false
  858. end
  859. end
  860. -- Find a registered parser.
  861. local parser = parsers[cmd]
  862. if parser == nil then
  863. return false
  864. end
  865. -- Split the command line into parts.
  866. local str = rl_state.line_buffer:sub(cmd_r + 2, last)
  867. local parts = {}
  868. for _, sub_str in ipairs(clink.quote_split(str, "\"")) do
  869. -- Quoted strings still have their quotes. Look for those type of
  870. -- strings, strip the quotes and add it completely.
  871. if sub_str:sub(1, 1) == "\"" then
  872. local l, r = sub_str:find("\"[^\"]+")
  873. if l then
  874. local part = sub_str:sub(l + 1, r)
  875. table.insert(parts, part)
  876. end
  877. else
  878. -- Extract non-whitespace parts.
  879. for _, r, part in function () return sub_str:find("^%s*([^%s]+)") end do
  880. table.insert(parts, part)
  881. sub_str = sub_str:sub(r + 1)
  882. end
  883. end
  884. end
  885. -- If 'text' is empty then add it as a part as it would have been skipped
  886. -- by the split loop above.
  887. if text == "" then
  888. table.insert(parts, text)
  889. end
  890. -- Extend rl_state with match generation state; text, first, and last.
  891. rl_state.text = text
  892. rl_state.first = first
  893. rl_state.last = last
  894. -- Call the parser.
  895. local needle = parts[#parts]
  896. local ret = parser:go(parts)
  897. if type(ret) ~= "table" then
  898. return not ret
  899. end
  900. -- Iterate through the matches the parser returned and collect matches.
  901. for _, match in ipairs(ret) do
  902. if clink.is_match(needle, match) then
  903. clink.add_match(match)
  904. end
  905. end
  906. return true
  907. end
  908. --------------------------------------------------------------------------------
  909. clink.register_match_generator(argument_match_generator, 25)
  910. -- vim: expandtab
  911. --{{{ history
  912. --15/03/06 DCN Created based on RemDebug
  913. --28/04/06 DCN Update for Lua 5.1
  914. --01/06/06 DCN Fix command argument parsing
  915. -- Add step/over N facility
  916. -- Add trace lines facility
  917. --05/06/06 DCN Add trace call/return facility
  918. --06/06/06 DCN Make it behave when stepping through the creation of a coroutine
  919. --06/06/06 DCN Integrate the simple debugger into the main one
  920. --07/06/06 DCN Provide facility to step into coroutines
  921. --13/06/06 DCN Fix bug that caused the function environment to get corrupted with the global one
  922. --14/06/06 DCN Allow 'sloppy' file names when setting breakpoints
  923. --04/08/06 DCN Allow for no space after command name
  924. --11/08/06 DCN Use io.write not print
  925. --30/08/06 DCN Allow access to array elements in 'dump'
  926. --10/10/06 DCN Default to breakfile for all commands that require a filename and give '-'
  927. --06/12/06 DCN Allow for punctuation characters in DUMP variable names
  928. --03/01/07 DCN Add pause on/off facility
  929. --19/06/07 DCN Allow for duff commands being typed in the debugger (thanks to [email protected])
  930. -- Allow for case sensitive file systems (thanks to [email protected])
  931. --04/08/09 DCN Add optional line count param to pause
  932. --05/08/09 DCN Reset the debug hook in Pause() even if we think we're started
  933. --30/09/09 DCN Re-jig to not use co-routines (makes debugging co-routines awkward)
  934. --01/10/09 DCN Add ability to break on reaching any line in a file
  935. --24/07/13 TWW Added code for emulating setfenv/getfenv in Lua 5.2 as per
  936. -- http://lua-users.org/lists/lua-l/2010-06/msg00313.html
  937. --25/07/13 TWW Copied Alex Parrill's fix for errors when tracing back across a C frame
  938. -- (https://github.com/ColonelThirtyTwo/clidebugger, 26/01/12)
  939. --25/07/13 DCN Allow for windows and unix file name conventions in has_breakpoint
  940. --26/07/13 DCN Allow for \ being interpreted as an escape inside a [] pattern in 5.2
  941. --}}}
  942. --{{{ description
  943. --A simple command line debug system for Lua written by Dave Nichols of
  944. --Match-IT Limited. Its public domain software. Do with it as you wish.
  945. --This debugger was inspired by:
  946. -- RemDebug 1.0 Beta
  947. -- Copyright Kepler Project 2005 (http://www.keplerproject.org/remdebug)
  948. --Usage:
  949. -- require('debugger') --load the debug library
  950. -- pause(message) --start/resume a debug session
  951. --An assert() failure will also invoke the debugger.
  952. --}}}
  953. local IsWindows = string.find(string.lower(os.getenv('OS') or ''),'^windows')
  954. local coro_debugger
  955. local events = { BREAK = 1, WATCH = 2, STEP = 3, SET = 4 }
  956. local breakpoints = {}
  957. local watches = {}
  958. local step_into = false
  959. local step_over = false
  960. local step_lines = 0
  961. local step_level = {main=0}
  962. local stack_level = {main=0}
  963. local trace_level = {main=0}
  964. local trace_calls = false
  965. local trace_returns = false
  966. local trace_lines = false
  967. local ret_file, ret_line, ret_name
  968. local current_thread = 'main'
  969. local started = false
  970. local pause_off = false
  971. local _g = _G
  972. local cocreate, cowrap = coroutine.create, coroutine.wrap
  973. local pausemsg = 'pause'
  974. local aliases = {
  975. p = "over",
  976. t = "step",
  977. q = "exit",
  978. g = "run",
  979. dv = "dump",
  980. dt = "locs",
  981. k = "trace",
  982. bp = "setb",
  983. bc = "delb",
  984. bl = "listb",
  985. pt = "out",
  986. }
  987. --{{{ make Lua 5.2 compatible
  988. if not setfenv then -- Lua 5.2
  989. --[[
  990. As far as I can see, the only missing detail of these functions (except
  991. for occasional bugs) to achieve 100% compatibility is the case of
  992. 'getfenv' over a function that does not have an _ENV variable (that is,
  993. it uses no globals).
  994. We could use a weak table to keep the environments of these functions
  995. when set by setfenv, but that still misses the case of a function
  996. without _ENV that was not subjected to setfenv.
  997. -- Roberto
  998. ]]--
  999. setfenv = setfenv or function(f, t)
  1000. f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func)
  1001. local name
  1002. local up = 0
  1003. repeat
  1004. up = up + 1
  1005. name = debug.getupvalue(f, up)
  1006. until name == '_ENV' or name == nil
  1007. if name then
  1008. debug.upvaluejoin(f, up, function() return name end, 1) -- use unique upvalue
  1009. debug.setupvalue(f, up, t)
  1010. end
  1011. end
  1012. getfenv = getfenv or function(f)
  1013. f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func)
  1014. local name, val
  1015. local up = 0
  1016. repeat
  1017. up = up + 1
  1018. name, val = debug.getupvalue(f, up)
  1019. until name == '_ENV' or name == nil
  1020. return val
  1021. end
  1022. unpack = table.unpack
  1023. end
  1024. --}}}
  1025. --{{{ local hints -- command help
  1026. --The format in here is name=summary|description
  1027. local hints = {
  1028. pause = [[
  1029. pause(msg[,lines][,force]) -- start/resume a debugger session|
  1030. This can only be used in your code or from the console as a means to
  1031. start/resume a debug session.
  1032. If msg is given that is shown when the session starts/resumes. Useful to
  1033. give a context if you've instrumented your code with pause() statements.
  1034. If lines is given, the script pauses after that many lines, else it pauses
  1035. immediately.
  1036. If force is true, the pause function is honoured even if poff has been used.
  1037. This is useful when in an interactive console session to regain debugger
  1038. control.
  1039. ]],
  1040. poff = [[
  1041. poff -- turn off pause() command|
  1042. This causes all pause() commands to be ignored. This is useful if you have
  1043. instrumented your code in a busy loop and want to continue normal execution
  1044. with no further interruption.
  1045. ]],
  1046. pon = [[
  1047. pon -- turn on pause() command|
  1048. This re-instates honouring the pause() commands you may have instrumented
  1049. your code with.
  1050. ]],
  1051. setb = [[
  1052. setb [line file] -- set a breakpoint to line/file|, line 0 means 'any'
  1053. If file is omitted or is "-" the breakpoint is set at the file for the
  1054. currently set level (see "set"). Execution pauses when this line is about
  1055. to be executed and the debugger session is re-activated.
  1056. The file can be given as the fully qualified name, partially qualified or
  1057. just the file name. E.g. if file is set as "myfile.lua", then whenever
  1058. execution reaches any file that ends with "myfile.lua" it will pause. If
  1059. no extension is given, any extension will do.
  1060. If the line is given as 0, then reaching any line in the file will do.
  1061. ]],
  1062. delb = [[
  1063. delb [line file] -- removes a breakpoint|
  1064. If file is omitted or is "-" the breakpoint is removed for the file of the
  1065. currently set level (see "set").
  1066. ]],
  1067. delallb = [[
  1068. delallb -- removes all breakpoints|
  1069. ]],
  1070. setw = [[
  1071. setw <exp> -- adds a new watch expression|
  1072. The expression is evaluated before each line is executed. If the expression
  1073. yields true then execution is paused and the debugger session re-activated.
  1074. The expression is executed in the context of the line about to be executed.
  1075. ]],
  1076. delw = [[
  1077. delw <index> -- removes the watch expression at index|
  1078. The index is that returned when the watch expression was set by setw.
  1079. ]],
  1080. delallw = [[
  1081. delallw -- removes all watch expressions|
  1082. ]],
  1083. run = [[
  1084. run -- run until next breakpoint or watch expression|
  1085. ]],
  1086. step = [[
  1087. step [N] -- run next N lines, stepping into function calls|
  1088. If N is omitted, use 1.
  1089. ]],
  1090. over = [[
  1091. over [N] -- run next N lines, stepping over function calls|
  1092. If N is omitted, use 1.
  1093. ]],
  1094. out = [[
  1095. out [N] -- run lines until stepped out of N functions|
  1096. If N is omitted, use 1.
  1097. If you are inside a function, using "out 1" will run until you return
  1098. from that function to the caller.
  1099. ]],
  1100. gotoo = [[
  1101. gotoo [line file] -- step to line in file|
  1102. This is equivalent to 'setb line file', followed by 'run', followed
  1103. by 'delb line file'.
  1104. ]],
  1105. listb = [[
  1106. listb -- lists breakpoints|
  1107. ]],
  1108. listw = [[
  1109. listw -- lists watch expressions|
  1110. ]],
  1111. set = [[
  1112. set [level] -- set context to stack level, omitted=show|
  1113. If level is omitted it just prints the current level set.
  1114. This sets the current context to the level given. This affects the
  1115. context used for several other functions (e.g. vars). The possible
  1116. levels are those shown by trace.
  1117. ]],
  1118. vars = [[
  1119. vars [depth] -- list context locals to depth, omitted=1|
  1120. If depth is omitted then uses 1.
  1121. Use a depth of 0 for the maximum.
  1122. Lists all non-nil local variables and all non-nil upvalues in the
  1123. currently set context. For variables that are tables, lists all fields
  1124. to the given depth.
  1125. ]],
  1126. fenv = [[
  1127. fenv [depth] -- list context function env to depth, omitted=1|
  1128. If depth is omitted then uses 1.
  1129. Use a depth of 0 for the maximum.
  1130. Lists all function environment variables in the currently set context.
  1131. For variables that are tables, lists all fields to the given depth.
  1132. ]],
  1133. glob = [[
  1134. glob [depth] -- list globals to depth, omitted=1|
  1135. If depth is omitted then uses 1.
  1136. Use a depth of 0 for the maximum.
  1137. Lists all global variables.
  1138. For variables that are tables, lists all fields to the given depth.
  1139. ]],
  1140. ups = [[
  1141. ups -- list all the upvalue names|
  1142. These names will also be in the "vars" list unless their value is nil.
  1143. This provides a means to identify which vars are upvalues and which are
  1144. locals. If a name is both an upvalue and a local, the local value takes
  1145. precedance.
  1146. ]],
  1147. locs = [[
  1148. locs -- list all the locals names|
  1149. These names will also be in the "vars" list unless their value is nil.
  1150. This provides a means to identify which vars are upvalues and which are
  1151. locals. If a name is both an upvalue and a local, the local value takes
  1152. precedance.
  1153. ]],
  1154. dump = [[
  1155. dump <var> [depth] -- dump all fields of variable to depth|
  1156. If depth is omitted then uses 1.
  1157. Use a depth of 0 for the maximum.
  1158. Prints the value of <var> in the currently set context level. If <var>
  1159. is a table, lists all fields to the given depth. <var> can be just a
  1160. name, or name.field or name.# to any depth, e.g. t.1.f accesses field
  1161. 'f' in array element 1 in table 't'.
  1162. Can also be called from a script as dump(var,depth).
  1163. ]],
  1164. tron = [[
  1165. tron [crl] -- turn trace on for (c)alls, (r)etuns, (l)lines|
  1166. If no parameter is given then tracing is turned off.
  1167. When tracing is turned on a line is printed to the console for each
  1168. debug 'event' selected. c=function calls, r=function returns, l=lines.
  1169. ]],
  1170. trace = [[
  1171. trace -- dumps a stack trace|
  1172. Format is [level] = file,line,name
  1173. The level is a candidate for use by the 'set' command.
  1174. ]],
  1175. info = [[
  1176. info -- dumps the complete debug info captured|
  1177. Only useful as a diagnostic aid for the debugger itself. This information
  1178. can be HUGE as it dumps all variables to the maximum depth, so be careful.
  1179. ]],
  1180. show = [[
  1181. show line file X Y -- show X lines before and Y after line in file|
  1182. If line is omitted or is '-' then the current set context line is used.
  1183. If file is omitted or is '-' then the current set context file is used.
  1184. If file is not fully qualified and cannot be opened as specified, then
  1185. a search for the file in the package[path] is performed using the usual
  1186. "require" searching rules. If no file extension is given, .lua is used.
  1187. Prints the lines from the source file around the given line.
  1188. ]],
  1189. exit = [[
  1190. exit -- exits debugger, re-start it using pause()|
  1191. ]],
  1192. help = [[
  1193. help [command] -- show this list or help for command|
  1194. ]],
  1195. ["<statement>"] = [[
  1196. <statement> -- execute a statement in the current context|
  1197. The statement can be anything that is legal in the context, including
  1198. assignments. Such assignments affect the context and will be in force
  1199. immediately. Any results returned are printed. Use '=' as a short-hand
  1200. for 'return', e.g. "=func(arg)" will call 'func' with 'arg' and print
  1201. the results, and "=var" will just print the value of 'var'.
  1202. ]],
  1203. what = [[
  1204. what <func> -- show where <func> is defined (if known)|
  1205. ]],
  1206. }
  1207. --}}}
  1208. --{{{ local function getinfo(level,field)
  1209. --like debug.getinfo but copes with no activation record at the given level
  1210. --and knows how to get 'field'. 'field' can be the name of any of the
  1211. --activation record fields or any of the 'what' names or nil for everything.
  1212. --only valid when using the stack level to get info, not a function name.
  1213. local function getinfo(level,field)
  1214. level = level + 1 --to get to the same relative level as the caller
  1215. if not field then return debug.getinfo(level) end
  1216. local what
  1217. if field == 'name' or field == 'namewhat' then
  1218. what = 'n'
  1219. elseif field == 'what' or field == 'source' or field == 'linedefined' or field == 'lastlinedefined' or field == 'short_src' then
  1220. what = 'S'
  1221. elseif field == 'currentline' then
  1222. what = 'l'
  1223. elseif field == 'nups' then
  1224. what = 'u'
  1225. elseif field == 'func' then
  1226. what = 'f'
  1227. else
  1228. return debug.getinfo(level,field)
  1229. end
  1230. local ar = debug.getinfo(level,what)
  1231. if ar then return ar[field] else return nil end
  1232. end
  1233. --}}}
  1234. --{{{ local function indented( level, ... )
  1235. local function indented( level, ... )
  1236. io.write( string.rep(' ',level), table.concat({...}), '\n' )
  1237. end
  1238. --}}}
  1239. --{{{ local function dumpval( level, name, value, limit )
  1240. local dumpvisited
  1241. local function dumpval( level, name, value, limit )
  1242. local index
  1243. if type(name) == 'number' then
  1244. index = string.format('[%d] = ',name)
  1245. elseif type(name) == 'string'
  1246. and (name == '__VARSLEVEL__' or name == '__ENVIRONMENT__' or name == '__GLOBALS__' or name == '__UPVALUES__' or name == '__LOCALS__') then
  1247. --ignore these, they are debugger generated
  1248. return
  1249. elseif type(name) == 'string' and string.find(name,'^[_%a][_.%w]*$') then
  1250. index = name ..' = '
  1251. else
  1252. index = string.format('[%q] = ',tostring(name))
  1253. end
  1254. if type(value) == 'table' then
  1255. if dumpvisited[value] then
  1256. indented( level, index, string.format('ref%q;',dumpvisited[value]) )
  1257. else
  1258. dumpvisited[value] = tostring(value)
  1259. if (limit or 0) > 0 and level+1 >= limit then
  1260. indented( level, index, dumpvisited[value] )
  1261. else
  1262. indented( level, index, '{ -- ', dumpvisited[value] )
  1263. for n,v in pairs(value) do
  1264. dumpval( level+1, n, v, limit )
  1265. end
  1266. indented( level, '};' )
  1267. end
  1268. end
  1269. else
  1270. if type(value) == 'string' then
  1271. if string.len(value) > 40 then
  1272. indented( level, index, '[[', value, ']];' )
  1273. else
  1274. indented( level, index, string.format('%q',value), ';' )
  1275. end
  1276. else
  1277. indented( level, index, tostring(value), ';' )
  1278. end
  1279. end
  1280. end
  1281. --}}}
  1282. --{{{ local function dumpvar( value, limit, name )
  1283. local function dumpvar( value, limit, name )
  1284. dumpvisited = {}
  1285. dumpval( 0, name or tostring(value), value, limit )
  1286. end
  1287. --}}}
  1288. --{{{ local function show(file,line,before,after)
  1289. --show +/-N lines of a file around line M
  1290. local function show(file,line,before,after)
  1291. line = tonumber(line or 1)
  1292. before = tonumber(before or 10)
  1293. after = tonumber(after or before)
  1294. if not string.find(file,'%.') then file = file..'.lua' end
  1295. local f = io.open(file,'r')
  1296. if not f then
  1297. --{{{ try to find the file in the path
  1298. --
  1299. -- looks for a file in the package path
  1300. --
  1301. local path = package.path or LUA_PATH or ''
  1302. for c in string.gmatch (path, "[^;]+") do
  1303. local c = string.gsub (c, "%?%.lua", file)
  1304. f = io.open (c,'r')
  1305. if f then
  1306. break
  1307. end
  1308. end
  1309. --}}}
  1310. if not f then
  1311. io.write('Cannot find '..file..'\n')
  1312. return
  1313. end
  1314. end
  1315. local i = 0
  1316. for l in f:lines() do
  1317. i = i + 1
  1318. if i >= (line-before) then
  1319. if i > (line+after) then break end
  1320. if i == line then
  1321. io.write(i..'***\t'..l..'\n')
  1322. else
  1323. io.write(i..'\t'..l..'\n')
  1324. end
  1325. end
  1326. end
  1327. f:close()
  1328. end
  1329. --}}}
  1330. --{{{ local function tracestack(l)
  1331. local function gi( i )
  1332. return function() i=i+1 return debug.getinfo(i),i end
  1333. end
  1334. local function gl( level, j )
  1335. return function() j=j+1 return debug.getlocal( level, j ) end
  1336. end
  1337. local function gu( func, k )
  1338. return function() k=k+1 return debug.getupvalue( func, k ) end
  1339. end
  1340. local traceinfo
  1341. local function tracestack(l)
  1342. local l = l + 1 --NB: +1 to get level relative to caller
  1343. traceinfo = {}
  1344. traceinfo.pausemsg = pausemsg
  1345. for ar,i in gi(l) do
  1346. table.insert( traceinfo, ar )
  1347. if ar.what ~= 'C' then
  1348. local names = {}
  1349. local values = {}
  1350. for n,v in gl(i,0) do
  1351. if string.sub(n,1,1) ~= '(' then --ignore internal control variables
  1352. table.insert( names, n )
  1353. table.insert( values, v )
  1354. end
  1355. end
  1356. if #names > 0 then
  1357. ar.lnames = names
  1358. ar.lvalues = values
  1359. end
  1360. end
  1361. if ar.func then
  1362. local names = {}
  1363. local values = {}
  1364. for n,v in gu(ar.func,0) do
  1365. if string.sub(n,1,1) ~= '(' then --ignore internal control variables
  1366. table.insert( names, n )
  1367. table.insert( values, v )
  1368. end
  1369. end
  1370. if #names > 0 then
  1371. ar.unames = names
  1372. ar.uvalues = values
  1373. end
  1374. end
  1375. end
  1376. end
  1377. --}}}
  1378. --{{{ local function trace()
  1379. local function trace(set)
  1380. local mark
  1381. for level,ar in ipairs(traceinfo) do
  1382. if level == set then
  1383. mark = '***'
  1384. else
  1385. mark = ''
  1386. end
  1387. io.write('['..level..']'..mark..'\t'..(ar.name or ar.what)..' in '..ar.short_src..':'..ar.currentline..'\n')
  1388. end
  1389. end
  1390. --}}}
  1391. --{{{ local function info()
  1392. local function info() dumpvar( traceinfo, 0, 'traceinfo' ) end
  1393. --}}}
  1394. --{{{ local function set_breakpoint(file, line, once)
  1395. local function set_breakpoint(file, line, once)
  1396. if not breakpoints[line] then
  1397. breakpoints[line] = {}
  1398. end
  1399. if once then
  1400. breakpoints[line][file] = 1
  1401. else
  1402. breakpoints[line][file] = true
  1403. end
  1404. end
  1405. --}}}
  1406. --{{{ local function remove_breakpoint(file, line)
  1407. local function remove_breakpoint(file, line)
  1408. if breakpoints[line] then
  1409. breakpoints[line][file] = nil
  1410. end
  1411. end
  1412. --}}}
  1413. --{{{ local function has_breakpoint(file, line)
  1414. --allow for 'sloppy' file names
  1415. --search for file and all variations walking up its directory hierachy
  1416. --ditto for the file with no extension
  1417. --a breakpoint can be permenant or once only, if once only its removed
  1418. --after detection here, these are used for temporary breakpoints in the
  1419. --debugger loop when executing the 'gotoo' command
  1420. --a breakpoint on line 0 of a file means any line in that file
  1421. local function has_breakpoint(file, line)
  1422. local isLine = breakpoints[line]
  1423. local isZero = breakpoints[0]
  1424. if not isLine and not isZero then return false end
  1425. local noext = string.gsub(file,"(%..-)$",'',1)
  1426. if noext == file then noext = nil end
  1427. while file do
  1428. if isLine and isLine[file] then
  1429. if isLine[file] == 1 then isLine[file] = nil end
  1430. return true
  1431. end
  1432. if isZero and isZero[file] then
  1433. if isZero[file] == 1 then isZero[file] = nil end
  1434. return true
  1435. end
  1436. if IsWindows then
  1437. file = string.match(file,"[:/\\](.+)$")
  1438. else
  1439. file = string.match(file,"[:/](.+)$")
  1440. end
  1441. end
  1442. while noext do
  1443. if isLine and isLine[noext] then
  1444. if isLine[noext] == 1 then isLine[noext] = nil end
  1445. return true
  1446. end
  1447. if isZero and isZero[noext] then
  1448. if isZero[noext] == 1 then isZero[noext] = nil end
  1449. return true
  1450. end
  1451. if IsWindows then
  1452. noext = string.match(noext,"[:/\\](.+)$")
  1453. else
  1454. noext = string.match(noext,"[:/](.+)$")
  1455. end
  1456. end
  1457. return false
  1458. end
  1459. --}}}
  1460. --{{{ local function capture_vars(ref,level,line)
  1461. local function capture_vars(ref,level,line)
  1462. --get vars, file and line for the given level relative to debug_hook offset by ref
  1463. local lvl = ref + level --NB: This includes an offset of +1 for the call to here
  1464. --{{{ capture variables
  1465. local ar = debug.getinfo(lvl, "f")
  1466. if not ar then return {},'?',0 end
  1467. local vars = {__UPVALUES__={}, __LOCALS__={}}
  1468. local i
  1469. local func = ar.func
  1470. if func then
  1471. i = 1
  1472. while true do
  1473. local name, value = debug.getupvalue(func, i)
  1474. if not name then break end
  1475. if string.sub(name,1,1) ~= '(' then --NB: ignoring internal control variables
  1476. vars[name] = value
  1477. vars.__UPVALUES__[i] = name
  1478. end
  1479. i = i + 1
  1480. end
  1481. vars.__ENVIRONMENT__ = getfenv(func)
  1482. end
  1483. vars.__GLOBALS__ = getfenv(0)
  1484. i = 1
  1485. while true do
  1486. local name, value = debug.getlocal(lvl, i)
  1487. if not name then break end
  1488. if string.sub(name,1,1) ~= '(' then --NB: ignoring internal control variables
  1489. vars[name] = value
  1490. vars.__LOCALS__[i] = name
  1491. end
  1492. i = i + 1
  1493. end
  1494. vars.__VARSLEVEL__ = level
  1495. if func then
  1496. --NB: Do not do this until finished filling the vars table
  1497. setmetatable(vars, { __index = getfenv(func), __newindex = getfenv(func) })
  1498. end
  1499. --NB: Do not read or write the vars table anymore else the metatable functions will get invoked!
  1500. --}}}
  1501. local file = getinfo(lvl, "source")
  1502. if string.find(file, "@") == 1 then
  1503. file = string.sub(file, 2)
  1504. end
  1505. if IsWindows then file = string.lower(file) end
  1506. if not line then
  1507. line = getinfo(lvl, "currentline")
  1508. end
  1509. return vars,file,line
  1510. end
  1511. --}}}
  1512. --{{{ local function restore_vars(ref,vars)
  1513. local function restore_vars(ref,vars)
  1514. if type(vars) ~= 'table' then return end
  1515. local level = vars.__VARSLEVEL__ --NB: This level is relative to debug_hook offset by ref
  1516. if not level then return end
  1517. level = level + ref --NB: This includes an offset of +1 for the call to here
  1518. local i
  1519. local written_vars = {}
  1520. i = 1
  1521. while true do
  1522. local name, value = debug.getlocal(level, i)
  1523. if not name then break end
  1524. if vars[name] and string.sub(name,1,1) ~= '(' then --NB: ignoring internal control variables
  1525. debug.setlocal(level, i, vars[name])
  1526. written_vars[name] = true
  1527. end
  1528. i = i + 1
  1529. end
  1530. local ar = debug.getinfo(level, "f")
  1531. if not ar then return end
  1532. local func = ar.func
  1533. if func then
  1534. i = 1
  1535. while true do
  1536. local name, value = debug.getupvalue(func, i)
  1537. if not name then break end
  1538. if vars[name] and string.sub(name,1,1) ~= '(' then --NB: ignoring internal control variables
  1539. if not written_vars[name] then
  1540. debug.setupvalue(func, i, vars[name])
  1541. end
  1542. written_vars[name] = true
  1543. end
  1544. i = i + 1
  1545. end
  1546. end
  1547. end
  1548. --}}}
  1549. --{{{ local function trace_event(event, line, level)
  1550. local function print_trace(level,depth,event,file,line,name)
  1551. --NB: level here is relative to the caller of trace_event, so offset by 2 to get to there
  1552. level = level + 2
  1553. local file = file or getinfo(level,'short_src')
  1554. local line = line or getinfo(level,'currentline')
  1555. local name = name or getinfo(level,'name')
  1556. local prefix = ''
  1557. if current_thread ~= 'main' then prefix = '['..tostring(current_thread)..'] ' end
  1558. io.write(prefix..
  1559. string.format('%08.2f:%02i.',os.clock(),depth)..
  1560. string.rep('.',depth%32)..
  1561. (file or '')..' ('..(line or '')..') '..
  1562. (name or '')..
  1563. ' ('..event..')\n')
  1564. end
  1565. local function trace_event(event, line, level)
  1566. if event == 'return' and trace_returns then
  1567. --note the line info for later
  1568. ret_file = getinfo(level+1,'short_src')
  1569. ret_line = getinfo(level+1,'currentline')
  1570. ret_name = getinfo(level+1,'name')
  1571. end
  1572. if event ~= 'line' then return end
  1573. local slevel = stack_level[current_thread]
  1574. local tlevel = trace_level[current_thread]
  1575. if trace_calls and slevel > tlevel then
  1576. --we are now in the function called, so look back 1 level further to find the calling file and line
  1577. print_trace(level+1,slevel-1,'c',nil,nil,getinfo(level+1,'name'))
  1578. end
  1579. if trace_returns and slevel < tlevel then
  1580. print_trace(level,slevel,'r',ret_file,ret_line,ret_name)
  1581. end
  1582. if trace_lines then
  1583. print_trace(level,slevel,'l')
  1584. end
  1585. trace_level[current_thread] = stack_level[current_thread]
  1586. end
  1587. --}}}
  1588. --{{{ local function report(ev, vars, file, line, idx_watch)
  1589. local function report(ev, vars, file, line, idx_watch)
  1590. function show_source()
  1591. show(traceinfo[1].short_src, traceinfo[1].currentline, 2, 2)
  1592. end
  1593. local vars = vars or {}
  1594. local file = file or '?'
  1595. local line = line or 0
  1596. local prefix = ''
  1597. if current_thread ~= 'main' then prefix = '['..tostring(current_thread)..'] ' end
  1598. if ev == events.STEP then
  1599. io.write(prefix.."Paused at file "..file.." line "..line..' ('..stack_level[current_thread]..')\n')
  1600. show_source()
  1601. elseif ev == events.BREAK then
  1602. io.write(prefix.."Paused at file "..file.." line "..line..' ('..stack_level[current_thread]..') (breakpoint)\n')
  1603. show_source()
  1604. elseif ev == events.WATCH then
  1605. io.write(prefix.."Paused at file "..file.." line "..line..' ('..stack_level[current_thread]..')'.." (watch expression "..idx_watch.. ": ["..watches[idx_watch].exp.."])\n")
  1606. show_source()
  1607. elseif ev == events.SET then
  1608. --do nothing
  1609. else
  1610. io.write(prefix.."Error in application: "..file.." line "..line.."\n")
  1611. end
  1612. if ev ~= events.SET then
  1613. if pausemsg and pausemsg ~= '' then io.write('Message: '..pausemsg..'\n') end
  1614. pausemsg = ''
  1615. end
  1616. return vars, file, line
  1617. end
  1618. --}}}
  1619. --{{{ local function debugger_loop(ev, vars, file, line, idx_watch)
  1620. local last_line = ""
  1621. local function debugger_loop(ev, vars, file, line, idx_watch)
  1622. local eval_env = vars or {}
  1623. local breakfile = file or '?'
  1624. local breakline = line or 0
  1625. local command, args
  1626. --{{{ local function getargs(spec)
  1627. --get command arguments according to the given spec from the args string
  1628. --the spec has a single character for each argument, arguments are separated
  1629. --by white space, the spec characters can be one of:
  1630. -- F for a filename (defaults to breakfile if - given in args)
  1631. -- L for a line number (defaults to breakline if - given in args)
  1632. -- N for a number
  1633. -- V for a variable name
  1634. -- S for a string
  1635. local function getargs(spec)
  1636. local res={}
  1637. local char,arg
  1638. local ptr=1
  1639. for i=1,string.len(spec) do
  1640. char = string.sub(spec,i,i)
  1641. if char == 'F' then
  1642. _,ptr,arg = string.find(args..' ',"%s*([%w%p]*)%s*",ptr)
  1643. if not arg or arg == '' then arg = '-' end
  1644. if arg == '-' then arg = breakfile end
  1645. elseif char == 'L' then
  1646. _,ptr,arg = string.find(args..' ',"%s*([%w%p]*)%s*",ptr)
  1647. if not arg or arg == '' then arg = '-' end
  1648. if arg == '-' then arg = breakline end
  1649. arg = tonumber(arg) or 0
  1650. elseif char == 'N' then
  1651. _,ptr,arg = string.find(args..' ',"%s*([%w%p]*)%s*",ptr)
  1652. if not arg or arg == '' then arg = '0' end
  1653. arg = tonumber(arg) or 0
  1654. elseif char == 'V' then
  1655. _,ptr,arg = string.find(args..' ',"%s*([%w%p]*)%s*",ptr)
  1656. if not arg or arg == '' then arg = '' end
  1657. elseif char == 'S' then
  1658. _,ptr,arg = string.find(args..' ',"%s*([%w%p]*)%s*",ptr)
  1659. if not arg or arg == '' then arg = '' end
  1660. else
  1661. arg = ''
  1662. end
  1663. table.insert(res,arg or '')
  1664. end
  1665. return unpack(res)
  1666. end
  1667. --}}}
  1668. while true do
  1669. io.write("[DEBUG]> ")
  1670. local line = io.read("*line")
  1671. if line == nil then io.write('\n'); line = 'exit' end
  1672. if line == "" then
  1673. line = last_line
  1674. else
  1675. last_line = line
  1676. end
  1677. io.write("'" .. last_line .. "'\n")
  1678. if string.find(line, "^[a-z]+") then
  1679. command = string.sub(line, string.find(line, "^[a-z]+"))
  1680. args = string.gsub(line,"^[a-z]+%s*",'',1) --strip command off line
  1681. else
  1682. command = ''
  1683. end
  1684. command = aliases[command] or command
  1685. if command == "setb" then
  1686. --{{{ set breakpoint
  1687. local line, filename = getargs('LF')
  1688. if filename ~= '' and line ~= '' then
  1689. set_breakpoint(filename,line)
  1690. io.write("Breakpoint set in file "..filename..' line '..line..'\n')
  1691. else
  1692. io.write("Bad request\n")
  1693. end
  1694. --}}}
  1695. elseif command == "delb" then
  1696. --{{{ delete breakpoint
  1697. local line, filename = getargs('LF')
  1698. if filename ~= '' and line ~= '' then
  1699. remove_breakpoint(filename, line)
  1700. io.write("Breakpoint deleted from file "..filename..' line '..line.."\n")
  1701. else
  1702. io.write("Bad request\n")
  1703. end
  1704. --}}}
  1705. elseif command == "delallb" then
  1706. --{{{ delete all breakpoints
  1707. breakpoints = {}
  1708. io.write('All breakpoints deleted\n')
  1709. --}}}
  1710. elseif command == "listb" then
  1711. --{{{ list breakpoints
  1712. for i, v in pairs(breakpoints) do
  1713. for ii, vv in pairs(v) do
  1714. io.write("Break at: "..i..' in '..ii..'\n')
  1715. end
  1716. end
  1717. --}}}
  1718. elseif command == "setw" then
  1719. --{{{ set watch expression
  1720. if args and args ~= '' then
  1721. local func = loadstring("return(" .. args .. ")")
  1722. local newidx = #watches + 1
  1723. watches[newidx] = {func = func, exp = args}
  1724. io.write("Set watch exp no. " .. newidx..'\n')
  1725. else
  1726. io.write("Bad request\n")
  1727. end
  1728. --}}}
  1729. elseif command == "delw" then
  1730. --{{{ delete watch expression
  1731. local index = tonumber(args)
  1732. if index then
  1733. watches[index] = nil
  1734. io.write("Watch expression deleted\n")
  1735. else
  1736. io.write("Bad request\n")
  1737. end
  1738. --}}}
  1739. elseif command == "delallw" then
  1740. --{{{ delete all watch expressions
  1741. watches = {}
  1742. io.write('All watch expressions deleted\n')
  1743. --}}}
  1744. elseif command == "listw" then
  1745. --{{{ list watch expressions
  1746. for i, v in pairs(watches) do
  1747. io.write("Watch exp. " .. i .. ": " .. v.exp..'\n')
  1748. end
  1749. --}}}
  1750. elseif command == "run" then
  1751. --{{{ run until breakpoint
  1752. step_into = false
  1753. step_over = false
  1754. return 'cont'
  1755. --}}}
  1756. elseif command == "step" then
  1757. --{{{ step N lines (into functions)
  1758. local N = tonumber(args) or 1
  1759. step_over = false
  1760. step_into = true
  1761. step_lines = tonumber(N or 1)
  1762. return 'cont'
  1763. --}}}
  1764. elseif command == "over" then
  1765. --{{{ step N lines (over functions)
  1766. local N = tonumber(args) or 1
  1767. step_into = false
  1768. step_over = true
  1769. step_lines = tonumber(N or 1)
  1770. step_level[current_thread] = stack_level[current_thread]
  1771. return 'cont'
  1772. --}}}
  1773. elseif command == "out" then
  1774. --{{{ step N lines (out of functions)
  1775. local N = tonumber(args) or 1
  1776. step_into = false
  1777. step_over = true
  1778. step_lines = 1
  1779. step_level[current_thread] = stack_level[current_thread] - tonumber(N or 1)
  1780. return 'cont'
  1781. --}}}
  1782. elseif command == "gotoo" then
  1783. --{{{ step until reach line
  1784. local line, filename = getargs('LF')
  1785. if line ~= '' then
  1786. step_over = false
  1787. step_into = false
  1788. if has_breakpoint(filename,line) then
  1789. return 'cont'
  1790. else
  1791. set_breakpoint(filename,line,true)
  1792. return 'cont'
  1793. end
  1794. else
  1795. io.write("Bad request\n")
  1796. end
  1797. --}}}
  1798. elseif command == "set" then
  1799. --{{{ set/show context level
  1800. local level = args
  1801. if level and level == '' then level = nil end
  1802. if level then return level end
  1803. --}}}
  1804. elseif command == "vars" then
  1805. --{{{ list context variables
  1806. local depth = args
  1807. if depth and depth == '' then depth = nil end
  1808. depth = tonumber(depth) or 1
  1809. dumpvar(eval_env, depth+1, 'variables')
  1810. --}}}
  1811. elseif command == "glob" then
  1812. --{{{ list global variables
  1813. local depth = args
  1814. if depth and depth == '' then depth = nil end
  1815. depth = tonumber(depth) or 1
  1816. dumpvar(eval_env.__GLOBALS__,depth+1,'globals')
  1817. --}}}
  1818. elseif command == "fenv" then
  1819. --{{{ list function environment variables
  1820. local depth = args
  1821. if depth and depth == '' then depth = nil end
  1822. depth = tonumber(depth) or 1
  1823. dumpvar(eval_env.__ENVIRONMENT__,depth+1,'environment')
  1824. --}}}
  1825. elseif command == "ups" then
  1826. --{{{ list upvalue names
  1827. dumpvar(eval_env.__UPVALUES__,2,'upvalues')
  1828. --}}}
  1829. elseif command == "locs" then
  1830. --{{{ list locals names
  1831. dumpvar(eval_env.__LOCALS__,2,'upvalues')
  1832. --}}}
  1833. elseif command == "what" then
  1834. --{{{ show where a function is defined
  1835. if args and args ~= '' then
  1836. local v = eval_env
  1837. local n = nil
  1838. for w in string.gmatch(args,"[%w_]+") do
  1839. v = v[w]
  1840. if n then n = n..'.'..w else n = w end
  1841. if not v then break end
  1842. end
  1843. if type(v) == 'function' then
  1844. local def = debug.getinfo(v,'S')
  1845. if def then
  1846. io.write(def.what..' in '..def.short_src..' '..def.linedefined..'..'..def.lastlinedefined..'\n')
  1847. else
  1848. io.write('Cannot get info for '..v..'\n')
  1849. end
  1850. else
  1851. io.write(v..' is not a function\n')
  1852. end
  1853. else
  1854. io.write("Bad request\n")
  1855. end
  1856. --}}}
  1857. elseif command == "dump" then
  1858. --{{{ dump a variable
  1859. local name, depth = getargs('VN')
  1860. if name ~= '' then
  1861. if depth == '' or depth == 0 then depth = nil end
  1862. depth = tonumber(depth or 1)
  1863. local v = eval_env
  1864. local n = nil
  1865. for w in string.gmatch(name,"[^%.]+") do --get everything between dots
  1866. if tonumber(w) then
  1867. v = v[tonumber(w)]
  1868. else
  1869. v = v[w]
  1870. end
  1871. if n then n = n..'.'..w else n = w end
  1872. if not v then break end
  1873. end
  1874. dumpvar(v,depth+1,n)
  1875. else
  1876. io.write("Bad request\n")
  1877. end
  1878. --}}}
  1879. elseif command == "show" then
  1880. --{{{ show file around a line or the current breakpoint
  1881. local line, file, before, after = getargs('LFNN')
  1882. if before == 0 then before = 10 end
  1883. if after == 0 then after = before end
  1884. if file ~= '' and file ~= "=stdin" then
  1885. show(file,line,before,after)
  1886. else
  1887. io.write('Nothing to show\n')
  1888. end
  1889. --}}}
  1890. elseif command == "poff" then
  1891. --{{{ turn pause command off
  1892. pause_off = true
  1893. --}}}
  1894. elseif command == "pon" then
  1895. --{{{ turn pause command on
  1896. pause_off = false
  1897. --}}}
  1898. elseif command == "tron" then
  1899. --{{{ turn tracing on/off
  1900. local option = getargs('S')
  1901. trace_calls = false
  1902. trace_returns = false
  1903. trace_lines = false
  1904. if string.find(option,'c') then trace_calls = true end
  1905. if string.find(option,'r') then trace_returns = true end
  1906. if string.find(option,'l') then trace_lines = true end
  1907. --}}}
  1908. elseif command == "trace" then
  1909. --{{{ dump a stack trace
  1910. trace(eval_env.__VARSLEVEL__)
  1911. --}}}
  1912. elseif command == "info" then
  1913. --{{{ dump all debug info captured
  1914. info()
  1915. --}}}
  1916. elseif command == "pause" then
  1917. --{{{ not allowed in here
  1918. io.write('pause() should only be used in the script you are debugging\n')
  1919. --}}}
  1920. elseif command == "help" then
  1921. --{{{ help
  1922. local command = getargs('S')
  1923. if command ~= '' and hints[command] then
  1924. io.write(hints[command]..'\n')
  1925. else
  1926. for _,v in pairs(hints) do
  1927. local _,_,h = string.find(v,"(.+)|")
  1928. io.write(h..'\n')
  1929. end
  1930. end
  1931. --}}}
  1932. elseif command == "exit" then
  1933. --{{{ exit debugger
  1934. return 'stop'
  1935. --}}}
  1936. elseif line ~= '' then
  1937. --{{{ just execute whatever it is in the current context
  1938. --map line starting with "=..." to "return ..."
  1939. if string.sub(line,1,1) == '=' then line = string.gsub(line,'=','return ',1) end
  1940. local ok, func = pcall(loadstring,line)
  1941. if func == nil then [email protected]
  1942. io.write("Compile error: "..line..'\n')
  1943. elseif not ok then
  1944. io.write("Compile error: "..func..'\n')
  1945. else
  1946. setfenv(func, eval_env)
  1947. local res = {pcall(func)}
  1948. if res[1] then
  1949. if res[2] then
  1950. table.remove(res,1)
  1951. for _,v in ipairs(res) do
  1952. io.write(tostring(v))
  1953. io.write('\t')
  1954. end
  1955. io.write('\n')
  1956. end
  1957. --update in the context
  1958. return 0
  1959. else
  1960. io.write("Run error: "..res[2]..'\n')
  1961. end
  1962. end
  1963. --}}}
  1964. end
  1965. end
  1966. end
  1967. --}}}
  1968. --{{{ local function debug_hook(event, line, level, thread)
  1969. local function debug_hook(event, line, level, thread)
  1970. if not started then debug.sethook(); coro_debugger = nil; return end
  1971. current_thread = thread or 'main'
  1972. local level = level or 2
  1973. trace_event(event,line,level)
  1974. if event == "call" then
  1975. stack_level[current_thread] = stack_level[current_thread] + 1
  1976. elseif event == "return" then
  1977. stack_level[current_thread] = stack_level[current_thread] - 1
  1978. if stack_level[current_thread] < 0 then stack_level[current_thread] = 0 end
  1979. else
  1980. local vars,file,line = capture_vars(level,1,line)
  1981. local stop, ev, idx = false, events.STEP, 0
  1982. while true do
  1983. for index, value in pairs(watches) do
  1984. setfenv(value.func, vars)
  1985. local status, res = pcall(value.func)
  1986. if status and res then
  1987. ev, idx = events.WATCH, index
  1988. stop = true
  1989. break
  1990. end
  1991. end
  1992. if stop then break end
  1993. if (step_into)
  1994. or (step_over and (stack_level[current_thread] <= step_level[current_thread] or stack_level[current_thread] == 0)) then
  1995. step_lines = step_lines - 1
  1996. if step_lines < 1 then
  1997. ev, idx = events.STEP, 0
  1998. break
  1999. end
  2000. end
  2001. if has_breakpoint(file, line) then
  2002. ev, idx = events.BREAK, 0
  2003. break
  2004. end
  2005. return
  2006. end
  2007. tracestack(level)
  2008. if not coro_debugger then
  2009. io.write("\nLua Debugger\n")
  2010. vars, file, line = report(ev, vars, file, line, idx)
  2011. io.write("Type 'help' for commands\n")
  2012. coro_debugger = true
  2013. else
  2014. vars, file, line = report(ev, vars, file, line, idx)
  2015. end
  2016. local last_next = 1
  2017. local next = 'ask'
  2018. local silent = false
  2019. while true do
  2020. if next == 'ask' then
  2021. next = debugger_loop(ev, vars, file, line, idx)
  2022. elseif next == 'cont' then
  2023. return
  2024. elseif next == 'stop' then
  2025. started = false
  2026. debug.sethook()
  2027. coro_debugger = nil
  2028. return
  2029. elseif tonumber(next) then --get vars for given level or last level
  2030. next = tonumber(next)
  2031. if next == 0 then silent = true; next = last_next else silent = false end
  2032. last_next = next
  2033. restore_vars(level,vars)
  2034. vars, file, line = capture_vars(level,next)
  2035. if not silent then
  2036. if vars and vars.__VARSLEVEL__ then
  2037. io.write('Level: '..vars.__VARSLEVEL__..'\n')
  2038. else
  2039. io.write('No level set\n')
  2040. end
  2041. end
  2042. ev = events.SET
  2043. next = 'ask'
  2044. else
  2045. io.write('Unknown command from debugger_loop: '..tostring(next)..'\n')
  2046. io.write('Stopping debugger\n')
  2047. next = 'stop'
  2048. end
  2049. end
  2050. end
  2051. end
  2052. --}}}
  2053. --{{{ coroutine.create
  2054. --This function overrides the built-in for the purposes of propagating
  2055. --the debug hook settings from the creator into the created coroutine.
  2056. _G.coroutine.create = function(f)
  2057. local thread
  2058. local hook, mask, count = debug.gethook()
  2059. if hook then
  2060. local function thread_hook(event,line)
  2061. hook(event,line,3,thread)
  2062. end
  2063. thread = cocreate(function(...)
  2064. stack_level[thread] = 0
  2065. trace_level[thread] = 0
  2066. step_level [thread] = 0
  2067. debug.sethook(thread_hook,mask,count)
  2068. return f(...)
  2069. end)
  2070. return thread
  2071. else
  2072. return cocreate(f)
  2073. end
  2074. end
  2075. --}}}
  2076. --{{{ coroutine.wrap
  2077. --This function overrides the built-in for the purposes of propagating
  2078. --the debug hook settings from the creator into the created coroutine.
  2079. _G.coroutine.wrap = function(f)
  2080. local thread
  2081. local hook, mask, count = debug.gethook()
  2082. if hook then
  2083. local function thread_hook(event,line)
  2084. hook(event,line,3,thread)
  2085. end
  2086. thread = cowrap(function(...)
  2087. stack_level[thread] = 0
  2088. trace_level[thread] = 0
  2089. step_level [thread] = 0
  2090. debug.sethook(thread_hook,mask,count)
  2091. return f(...)
  2092. end)
  2093. return thread
  2094. else
  2095. return cowrap(f)
  2096. end
  2097. end
  2098. --}}}
  2099. --{{{ function pause(x,l,f)
  2100. --
  2101. -- Starts/resumes a debug session
  2102. --
  2103. function pause(x,l,f)
  2104. if not f and pause_off then return end --being told to ignore pauses
  2105. pausemsg = x or 'pause'
  2106. local lines
  2107. local src = getinfo(2,'short_src')
  2108. if l then
  2109. lines = l --being told when to stop
  2110. elseif src == "stdin" then
  2111. lines = 1 --if in a console session, stop now
  2112. else
  2113. lines = 2 --if in a script, stop when get out of pause()
  2114. end
  2115. if started then
  2116. --we'll stop now 'cos the existing debug hook will grab us
  2117. step_lines = lines
  2118. step_into = true
  2119. debug.sethook(debug_hook, "crl") --reset it in case some external agent fiddled with it
  2120. else
  2121. --set to stop when get out of pause()
  2122. trace_level[current_thread] = 0
  2123. step_level [current_thread] = 0
  2124. stack_level[current_thread] = 1
  2125. step_lines = lines
  2126. step_into = true
  2127. started = true
  2128. debug.sethook(debug_hook, "crl") --NB: this will cause an immediate entry to the debugger_loop
  2129. end
  2130. end
  2131. --}}}
  2132. --{{{ function dump(v,depth)
  2133. --shows the value of the given variable, only really useful
  2134. --when the variable is a table
  2135. --see dump debug command hints for full semantics
  2136. function dump(v,depth)
  2137. dumpvar(v,(depth or 1)+1,tostring(v))
  2138. end
  2139. --}}}
  2140. --{{{ function debug.traceback(x)
  2141. local _traceback = debug.traceback --note original function
  2142. --override standard function
  2143. debug.traceback = function(x)
  2144. local assertmsg = _traceback(x) --do original function
  2145. pause(x) --let user have a look at stuff
  2146. return assertmsg --carry on
  2147. end
  2148. _TRACEBACK = debug.traceback --Lua 5.0 function
  2149. --}}}
  2150. --------------------------------------------------------------------------------
  2151. -- dir.lua
  2152. --
  2153. --
  2154. -- Copyright (c) 2012 Martin Ridgers
  2155. --
  2156. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  2157. -- of this software and associated documentation files (the "Software"), to deal
  2158. -- in the Software without restriction, including without limitation the rights
  2159. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  2160. -- copies of the Software, and to permit persons to whom the Software is
  2161. -- furnished to do so, subject to the following conditions:
  2162. --
  2163. -- The above copyright notice and this permission notice shall be included in
  2164. -- all copies or substantial portions of the Software.
  2165. --
  2166. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2167. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2168. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2169. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2170. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  2171. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  2172. -- SOFTWARE.
  2173. --
  2174. --------------------------------------------------------------------------------
  2175. function dir_match_generator_impl(text)
  2176. -- Strip off any path components that may be on text.
  2177. local prefix = ""
  2178. local i = text:find("[\\/:][^\\/:]*$")
  2179. if i then
  2180. prefix = text:sub(1, i)
  2181. end
  2182. local include_dots = text:find("%.+$") ~= nil
  2183. local matches = {}
  2184. local mask = text.."*"
  2185. -- Find matches.
  2186. for _, dir in ipairs(clink.find_dirs(mask, true)) do
  2187. local file = prefix..dir
  2188. if include_dots or (dir ~= "." and dir ~= "..") then
  2189. if clink.is_match(text, file) then
  2190. table.insert(matches, prefix..dir)
  2191. end
  2192. end
  2193. end
  2194. return matches
  2195. end
  2196. --------------------------------------------------------------------------------
  2197. local function dir_match_generator(word)
  2198. local matches = dir_match_generator_impl(word)
  2199. -- If there was no matches but text is a dir then use it as the single match.
  2200. -- Otherwise tell readline that matches are files and it will do magic.
  2201. if #matches == 0 then
  2202. if clink.is_dir(rl_state.text) then
  2203. table.insert(matches, rl_state.text)
  2204. end
  2205. else
  2206. clink.matches_are_files()
  2207. end
  2208. return matches
  2209. end
  2210. --------------------------------------------------------------------------------
  2211. clink.arg.register_parser("cd", dir_match_generator)
  2212. clink.arg.register_parser("chdir", dir_match_generator)
  2213. clink.arg.register_parser("pushd", dir_match_generator)
  2214. clink.arg.register_parser("rd", dir_match_generator)
  2215. clink.arg.register_parser("rmdir", dir_match_generator)
  2216. clink.arg.register_parser("md", dir_match_generator)
  2217. clink.arg.register_parser("mkdir", dir_match_generator)
  2218. -- vim: expandtab
  2219. --------------------------------------------------------------------------------
  2220. -- env.lua
  2221. --
  2222. --
  2223. -- Copyright (c) 2012 Martin Ridgers
  2224. --
  2225. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  2226. -- of this software and associated documentation files (the "Software"), to deal
  2227. -- in the Software without restriction, including without limitation the rights
  2228. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  2229. -- copies of the Software, and to permit persons to whom the Software is
  2230. -- furnished to do so, subject to the following conditions:
  2231. --
  2232. -- The above copyright notice and this permission notice shall be included in
  2233. -- all copies or substantial portions of the Software.
  2234. --
  2235. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2236. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2237. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2238. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2239. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  2240. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  2241. -- SOFTWARE.
  2242. --
  2243. --------------------------------------------------------------------------------
  2244. local special_env_vars = {
  2245. "cd", "date", "time", "random", "errorlevel",
  2246. "cmdextversion", "cmdcmdline", "highestnumanodenumber"
  2247. }
  2248. --------------------------------------------------------------------------------
  2249. local function env_vars_display_filter(matches)
  2250. local to_display = {}
  2251. for _, m in ipairs(matches) do
  2252. local _, _, out = m:find("(%%[^%%]+%%)$")
  2253. table.insert(to_display, out)
  2254. end
  2255. return to_display
  2256. end
  2257. --------------------------------------------------------------------------------
  2258. local function env_vars_find_matches(candidates, prefix, part)
  2259. local part_len = #part
  2260. for _, name in ipairs(candidates) do
  2261. if clink.lower(name:sub(1, part_len)) == part then
  2262. clink.add_match(prefix..'%'..name:lower()..'%')
  2263. end
  2264. end
  2265. end
  2266. --------------------------------------------------------------------------------
  2267. local function env_vars_match_generator(text, first, last)
  2268. local all = rl_state.line_buffer:sub(1, last)
  2269. -- Skip pairs of %s
  2270. local i = 1
  2271. for _, r in function () return all:find("%b%%", i) end do
  2272. i = r + 2
  2273. end
  2274. -- Find a solitary %
  2275. local i = all:find("%%", i)
  2276. if not i then
  2277. return false
  2278. end
  2279. if i < first then
  2280. return false
  2281. end
  2282. local part = clink.lower(all:sub(i + 1))
  2283. local part_len = #part
  2284. i = i - first
  2285. local prefix = text:sub(1, i)
  2286. env_vars_find_matches(clink.get_env_var_names(), prefix, part)
  2287. env_vars_find_matches(special_env_vars, prefix, part)
  2288. if clink.match_count() >= 1 then
  2289. clink.match_display_filter = env_vars_display_filter
  2290. clink.suppress_char_append()
  2291. clink.suppress_quoting()
  2292. return true
  2293. end
  2294. return false
  2295. end
  2296. --------------------------------------------------------------------------------
  2297. if clink.get_host_process() == "cmd.exe" then
  2298. clink.register_match_generator(env_vars_match_generator, 10)
  2299. end
  2300. -- vim: expandtab
  2301. --------------------------------------------------------------------------------
  2302. -- exec.lua
  2303. --
  2304. --
  2305. -- Copyright (c) 2012 Martin Ridgers
  2306. --
  2307. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  2308. -- of this software and associated documentation files (the "Software"), to deal
  2309. -- in the Software without restriction, including without limitation the rights
  2310. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  2311. -- copies of the Software, and to permit persons to whom the Software is
  2312. -- furnished to do so, subject to the following conditions:
  2313. --
  2314. -- The above copyright notice and this permission notice shall be included in
  2315. -- all copies or substantial portions of the Software.
  2316. --
  2317. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2318. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2319. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2320. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2321. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  2322. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  2323. -- SOFTWARE.
  2324. --
  2325. --------------------------------------------------------------------------------
  2326. local dos_commands = {
  2327. "assoc", "break", "call", "cd", "chcp", "chdir", "cls", "color", "copy",
  2328. "date", "del", "dir", "diskcomp", "diskcopy", "echo", "endlocal", "erase",
  2329. "exit", "for", "format", "ftype", "goto", "graftabl", "if", "md", "mkdir",
  2330. "mklink", "more", "move", "path", "pause", "popd", "prompt", "pushd", "rd",
  2331. "rem", "ren", "rename", "rmdir", "set", "setlocal", "shift", "start",
  2332. "time", "title", "tree", "type", "ver", "verify", "vol"
  2333. }
  2334. --------------------------------------------------------------------------------
  2335. local function get_environment_paths()
  2336. local paths = clink.split(clink.get_env("PATH"), ";")
  2337. -- We're expecting absolute paths and as ';' is a valid path character
  2338. -- there maybe unneccessary splits. Here we resolve them.
  2339. local paths_merged = { paths[1] }
  2340. for i = 2, #paths, 1 do
  2341. if not paths[i]:find("^[a-zA-Z]:") then
  2342. local t = paths_merged[#paths_merged];
  2343. paths_merged[#paths_merged] = t..paths[i]
  2344. else
  2345. table.insert(paths_merged, paths[i])
  2346. end
  2347. end
  2348. -- Append slashes.
  2349. for i = 1, #paths_merged, 1 do
  2350. paths_merged[i] = paths_merged[i].."/"
  2351. end
  2352. return paths_merged
  2353. end
  2354. --------------------------------------------------------------------------------
  2355. local function exec_find_dirs(pattern, case_map)
  2356. local ret = {}
  2357. for _, dir in ipairs(clink.find_dirs(pattern, case_map)) do
  2358. if dir ~= "." and dir ~= ".." then
  2359. table.insert(ret, dir)
  2360. end
  2361. end
  2362. return ret
  2363. end
  2364. --------------------------------------------------------------------------------
  2365. local function exec_match_generator(text, first, last)
  2366. -- If match style setting is < 0 then consider executable matching disabled.
  2367. local match_style = clink.get_setting_int("exec_match_style")
  2368. if match_style < 0 then
  2369. return false
  2370. end
  2371. -- We're only interested in exec completion if this is the first word of the
  2372. -- line, or the first word after a command separator.
  2373. if clink.get_setting_int("space_prefix_match_files") > 0 then
  2374. if first > 1 then
  2375. return false
  2376. end
  2377. else
  2378. local leading = rl_state.line_buffer:sub(1, first - 1)
  2379. local is_first = leading:find("^%s*\"*$")
  2380. if not is_first then
  2381. return false
  2382. end
  2383. end
  2384. -- Split text into directory and name
  2385. local text_dir = ""
  2386. local text_name = text
  2387. local i = text:find("[\\/:][^\\/:]*$")
  2388. if i then
  2389. text_dir = text:sub(1, i)
  2390. text_name = text:sub(i + 1)
  2391. end
  2392. local paths
  2393. if not text:find("[\\/:]") then
  2394. -- If the terminal is cmd.exe check it's commands for matches.
  2395. if clink.get_host_process() == "cmd.exe" then
  2396. clink.match_words(text, dos_commands)
  2397. end
  2398. -- Add console aliases as matches.
  2399. local aliases = clink.get_console_aliases()
  2400. clink.match_words(text, aliases)
  2401. paths = get_environment_paths();
  2402. else
  2403. paths = {}
  2404. -- 'text' is an absolute or relative path. If we're doing Bash-style
  2405. -- matching should now consider directories.
  2406. if match_style < 1 then
  2407. match_style = 2
  2408. else
  2409. match_style = 1
  2410. end
  2411. end
  2412. -- Should we also consider the path referenced by 'text'?
  2413. if match_style >= 1 then
  2414. table.insert(paths, text_dir)
  2415. end
  2416. -- Search 'paths' for files ending in 'suffices' and look for matches
  2417. local suffices = clink.split(clink.get_env("pathext"), ";")
  2418. for _, suffix in ipairs(suffices) do
  2419. for _, path in ipairs(paths) do
  2420. local files = clink.find_files(path.."*"..suffix, false)
  2421. for _, file in ipairs(files) do
  2422. if clink.is_match(text_name, file) then
  2423. clink.add_match(text_dir..file)
  2424. end
  2425. end
  2426. end
  2427. end
  2428. -- Lastly we may wish to consider directories too.
  2429. if clink.match_count() == 0 or match_style >= 2 then
  2430. clink.match_files(text.."*", true, exec_find_dirs)
  2431. end
  2432. clink.matches_are_files()
  2433. return true
  2434. end
  2435. --------------------------------------------------------------------------------
  2436. clink.register_match_generator(exec_match_generator, 50)
  2437. -- vim: expandtab
  2438. --------------------------------------------------------------------------------
  2439. -- git.lua
  2440. --
  2441. --
  2442. -- Copyright (c) 2012 Martin Ridgers
  2443. --
  2444. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  2445. -- of this software and associated documentation files (the "Software"), to deal
  2446. -- in the Software without restriction, including without limitation the rights
  2447. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  2448. -- copies of the Software, and to permit persons to whom the Software is
  2449. -- furnished to do so, subject to the following conditions:
  2450. --
  2451. -- The above copyright notice and this permission notice shall be included in
  2452. -- all copies or substantial portions of the Software.
  2453. --
  2454. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2455. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2456. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2457. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2458. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  2459. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  2460. -- SOFTWARE.
  2461. --
  2462. --------------------------------------------------------------------------------
  2463. local git_argument_tree = {
  2464. -- Porcelain and ancillary commands from git's man page.
  2465. "add", "am", "archive", "bisect", "branch", "bundle", "checkout",
  2466. "cherry-pick", "citool", "clean", "clone", "commit", "describe", "diff",
  2467. "fetch", "format-patch", "gc", "grep", "gui", "init", "log", "merge", "mv",
  2468. "notes", "pull", "push", "rebase", "reset", "revert", "rm", "shortlog",
  2469. "show", "stash", "status", "submodule", "tag", "config", "fast-export",
  2470. "fast-import", "filter-branch", "lost-found", "mergetool", "pack-refs",
  2471. "prune", "reflog", "relink", "remote", "repack", "replace", "repo-config",
  2472. "annotate", "blame", "cherry", "count-objects", "difftool", "fsck",
  2473. "get-tar-commit-id", "help", "instaweb", "merge-tree", "rerere",
  2474. "rev-parse", "show-branch", "verify-tag", "whatchanged"
  2475. }
  2476. clink.arg.register_parser("git", git_argument_tree)
  2477. -- vim: expandtab
  2478. --------------------------------------------------------------------------------
  2479. -- go.lua
  2480. --
  2481. --
  2482. -- Copyright (c) 2013 Dobroslaw Zybort
  2483. --
  2484. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  2485. -- of this software and associated documentation files (the "Software"), to deal
  2486. -- in the Software without restriction, including without limitation the rights
  2487. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  2488. -- copies of the Software, and to permit persons to whom the Software is
  2489. -- furnished to do so, subject to the following conditions:
  2490. --
  2491. -- The above copyright notice and this permission notice shall be included in
  2492. -- all copies or substantial portions of the Software.
  2493. --
  2494. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2495. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2496. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2497. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2498. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  2499. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  2500. -- SOFTWARE.
  2501. --
  2502. --------------------------------------------------------------------------------
  2503. local function flags(...)
  2504. local p = clink.arg.new_parser()
  2505. p:set_flags(...)
  2506. return p
  2507. end
  2508. --------------------------------------------------------------------------------
  2509. local go_tool_parser = clink.arg.new_parser()
  2510. go_tool_parser:set_flags("-n")
  2511. go_tool_parser:set_arguments({
  2512. "8a", "8c", "8g", "8l", "addr2line", "cgo", "dist", "nm", "objdump",
  2513. "pack",
  2514. "cover" .. flags("-func", "-html", "-mode", "-o", "-var"),
  2515. "fix" .. flags("-diff", "-force", "-r"),
  2516. "prof" .. flags("-p", "-t", "-d", "-P", "-h", "-f", "-l", "-r", "-s",
  2517. "-hs"),
  2518. "pprof" .. flags(-- Options:
  2519. "--cum", "--base", "--interactive", "--seconds",
  2520. "--add_lib", "--lib_prefix",
  2521. -- Reporting Granularity:
  2522. "--addresses", "--lines", "--functions", "--files",
  2523. -- Output type:
  2524. "--text", "--callgrind", "--gv", "--web", "--list",
  2525. "--disasm", "--symbols", "--dot", "--ps", "--pdf",
  2526. "--svg", "--gif", "--raw",
  2527. -- Heap-Profile Options:
  2528. "--inuse_space", "--inuse_objects", "--alloc_space",
  2529. "--alloc_objects", "--show_bytes", "--drop_negative",
  2530. -- Contention-profile options:
  2531. "--total_delay", "--contentions", "--mean_delay",
  2532. -- Call-graph Options:
  2533. "--nodecount", "--nodefraction", "--edgefraction",
  2534. "--focus", "--ignore", "--scale", "--heapcheck",
  2535. -- Miscellaneous:
  2536. "--tools", "--test", "--help", "--version"),
  2537. "vet" .. flags("-all", "-asmdecl", "-assign", "-atomic", "-buildtags",
  2538. "-composites", "-compositewhitelist", "-copylocks",
  2539. "-methods", "-nilfunc", "-printf", "-printfuncs",
  2540. "-rangeloops", "-shadow", "-shadowstrict", "-structtags",
  2541. "-test", "-unreachable", "-v"),
  2542. "yacc" .. flags("-l", "-o", "-p", "-v"),
  2543. })
  2544. --------------------------------------------------------------------------------
  2545. local go_parser = clink.arg.new_parser()
  2546. go_parser:set_arguments({
  2547. "env",
  2548. "fix",
  2549. "version",
  2550. "build" .. flags("-o", "-a", "-n", "-p", "-installsuffix", "-v", "-x",
  2551. "-work", "-gcflags", "-ccflags", "-ldflags",
  2552. "-gccgoflags", "-tags", "-compiler", "-race"),
  2553. "clean" .. flags("-i", "-n", "-r", "-x"),
  2554. "fmt" .. flags("-n", "-x"),
  2555. "get" .. flags("-d", "-fix", "-t", "-u",
  2556. -- Build flags
  2557. "-a", "-n", "-p", "-installsuffix", "-v", "-x",
  2558. "-work", "-gcflags", "-ccflags", "-ldflags",
  2559. "-gccgoflags", "-tags", "-compiler", "-race"),
  2560. "install" .. flags(-- All `go build` flags
  2561. "-o", "-a", "-n", "-p", "-installsuffix", "-v", "-x",
  2562. "-work", "-gcflags", "-ccflags", "-ldflags",
  2563. "-gccgoflags", "-tags", "-compiler", "-race"),
  2564. "list" .. flags("-e", "-race", "-f", "-json", "-tags"),
  2565. "run" .. flags("-exec",
  2566. -- Build flags
  2567. "-a", "-n", "-p", "-installsuffix", "-v", "-x",
  2568. "-work", "-gcflags", "-ccflags", "-ldflags",
  2569. "-gccgoflags", "-tags", "-compiler", "-race"),
  2570. "test" .. flags(-- Local.
  2571. "-c", "-file", "-i", "-cover", "-coverpkg",
  2572. -- Build flags
  2573. "-a", "-n", "-p", "-x", "-work", "-ccflags",
  2574. "-gcflags", "-exec", "-ldflags", "-gccgoflags",
  2575. "-tags", "-compiler", "-race", "-installsuffix",
  2576. -- Passed to 6.out
  2577. "-bench", "-benchmem", "-benchtime", "-covermode",
  2578. "-coverprofile", "-cpu", "-cpuprofile", "-memprofile",
  2579. "-memprofilerate", "-blockprofile",
  2580. "-blockprofilerate", "-outputdir", "-parallel", "-run",
  2581. "-short", "-timeout", "-v"),
  2582. "tool" .. go_tool_parser,
  2583. "vet" .. flags("-n", "-x"),
  2584. })
  2585. --------------------------------------------------------------------------------
  2586. local go_help_parser = clink.arg.new_parser()
  2587. go_help_parser:set_arguments({
  2588. "help" .. clink.arg.new_parser():set_arguments({
  2589. go_parser:flatten_argument(1)
  2590. })
  2591. })
  2592. --------------------------------------------------------------------------------
  2593. local godoc_parser = clink.arg.new_parser()
  2594. godoc_parser:set_flags(
  2595. "-zip", "-write_index", "-analysis", "-http", "-server", "-html","-src",
  2596. "-url", "-q", "-v", "-goroot", "-tabwidth", "-timestamps", "-templates",
  2597. "-play", "-ex", "-links", "-index", "-index_files", "-maxresults",
  2598. "-index_throttle", "-notes", "-httptest.serve"
  2599. )
  2600. --------------------------------------------------------------------------------
  2601. local gofmt_parser = clink.arg.new_parser()
  2602. gofmt_parser:set_flags(
  2603. "-cpuprofile", "-d", "-e", "-l", "-r", "-s", "-w"
  2604. )
  2605. --------------------------------------------------------------------------------
  2606. clink.arg.register_parser("go", go_parser)
  2607. clink.arg.register_parser("go", go_help_parser)
  2608. clink.arg.register_parser("godoc", godoc_parser)
  2609. clink.arg.register_parser("gofmt", gofmt_parser)
  2610. --------------------------------------------------------------------------------
  2611. -- hg.lua
  2612. --
  2613. --
  2614. -- Copyright (c) 2012 Martin Ridgers
  2615. --
  2616. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  2617. -- of this software and associated documentation files (the "Software"), to deal
  2618. -- in the Software without restriction, including without limitation the rights
  2619. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  2620. -- copies of the Software, and to permit persons to whom the Software is
  2621. -- furnished to do so, subject to the following conditions:
  2622. --
  2623. -- The above copyright notice and this permission notice shall be included in
  2624. -- all copies or substantial portions of the Software.
  2625. --
  2626. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2627. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2628. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2629. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2630. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  2631. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  2632. -- SOFTWARE.
  2633. --
  2634. --------------------------------------------------------------------------------
  2635. local hg_tree = {
  2636. "add", "addremove", "annotate", "archive", "backout", "bisect", "bookmarks",
  2637. "branch", "branches", "bundle", "cat", "clone", "commit", "copy", "diff",
  2638. "export", "forget", "grep", "heads", "help", "identify", "import",
  2639. "incoming", "init", "locate", "log", "manifest", "merge", "outgoing",
  2640. "parents", "paths", "pull", "push", "recover", "remove", "rename", "resolve",
  2641. "revert", "rollback", "root", "serve", "showconfig", "status", "summary",
  2642. "tag", "tags", "tip", "unbundle", "update", "verify", "version", "graft",
  2643. "phases"
  2644. }
  2645. clink.arg.register_parser("hg", hg_tree)
  2646. -- vim: expandtab
  2647. --------------------------------------------------------------------------------
  2648. -- p4.lua
  2649. --
  2650. --
  2651. -- Copyright (c) 2012 Martin Ridgers
  2652. --
  2653. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  2654. -- of this software and associated documentation files (the "Software"), to deal
  2655. -- in the Software without restriction, including without limitation the rights
  2656. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  2657. -- copies of the Software, and to permit persons to whom the Software is
  2658. -- furnished to do so, subject to the following conditions:
  2659. --
  2660. -- The above copyright notice and this permission notice shall be included in
  2661. -- all copies or substantial portions of the Software.
  2662. --
  2663. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2664. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2665. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2666. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2667. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  2668. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  2669. -- SOFTWARE.
  2670. --
  2671. --------------------------------------------------------------------------------
  2672. local p4_tree = {
  2673. "add", "annotate", "attribute", "branch", "branches", "browse", "change",
  2674. "changes", "changelist", "changelists", "client", "clients", "copy",
  2675. "counter", "counters", "cstat", "delete", "depot", "depots", "describe",
  2676. "diff", "diff2", "dirs", "edit", "filelog", "files", "fix", "fixes",
  2677. "flush", "fstat", "grep", "group", "groups", "have", "help", "info",
  2678. "integrate", "integrated", "interchanges", "istat", "job", "jobs", "label",
  2679. "labels", "labelsync", "legal", "list", "lock", "logger", "login",
  2680. "logout", "merge", "move", "opened", "passwd", "populate", "print",
  2681. "protect", "protects", "reconcile", "rename", "reopen", "resolve",
  2682. "resolved", "revert", "review", "reviews", "set", "shelve", "status",
  2683. "sizes", "stream", "streams", "submit", "sync", "tag", "tickets", "unlock",
  2684. "unshelve", "update", "user", "users", "where", "workspace", "workspaces"
  2685. }
  2686. clink.arg.register_parser("p4", p4_tree)
  2687. --------------------------------------------------------------------------------
  2688. local p4vc_tree = {
  2689. "help", "branchmappings", "branches", "diff", "groups", "branch", "change",
  2690. "client", "workspace", "depot", "group", "job", "label", "user", "jobs",
  2691. "labels", "pendingchanges", "resolve", "revisiongraph", "revgraph",
  2692. "streamgraph", "streams", "submit", "submittedchanges", "timelapse",
  2693. "timelapseview", "tlv", "users", "workspaces", "clients", "shutdown"
  2694. }
  2695. clink.arg.register_parser("p4vc", p4vc_tree)
  2696. -- vim: expandtab
  2697. --------------------------------------------------------------------------------
  2698. -- powershell.lua
  2699. --
  2700. --
  2701. -- Copyright (c) 2013 Martin Ridgers
  2702. --
  2703. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  2704. -- of this software and associated documentation files (the "Software"), to deal
  2705. -- in the Software without restriction, including without limitation the rights
  2706. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  2707. -- copies of the Software, and to permit persons to whom the Software is
  2708. -- furnished to do so, subject to the following conditions:
  2709. --
  2710. -- The above copyright notice and this permission notice shall be included in
  2711. -- all copies or substantial portions of the Software.
  2712. --
  2713. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2714. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2715. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2716. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2717. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  2718. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  2719. -- SOFTWARE.
  2720. --
  2721. --------------------------------------------------------------------------------
  2722. local function powershell_prompt_filter()
  2723. local l, r, path = clink.prompt.value:find("([a-zA-Z]:\\.*)> $")
  2724. if path ~= nil then
  2725. clink.chdir(path)
  2726. end
  2727. end
  2728. --------------------------------------------------------------------------------
  2729. if clink.get_host_process() == "powershell.exe" then
  2730. clink.prompt.register_filter(powershell_prompt_filter, -493)
  2731. end
  2732. --------------------------------------------------------------------------------
  2733. -- self.lua
  2734. --
  2735. --
  2736. -- Copyright (c) 2012 Martin Ridgers
  2737. --
  2738. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  2739. -- of this software and associated documentation files (the "Software"), to deal
  2740. -- in the Software without restriction, including without limitation the rights
  2741. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  2742. -- copies of the Software, and to permit persons to whom the Software is
  2743. -- furnished to do so, subject to the following conditions:
  2744. --
  2745. -- The above copyright notice and this permission notice shall be included in
  2746. -- all copies or substantial portions of the Software.
  2747. --
  2748. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2749. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2750. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2751. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2752. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  2753. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  2754. -- SOFTWARE.
  2755. --
  2756. --------------------------------------------------------------------------------
  2757. local null_parser = clink.arg.new_parser()
  2758. null_parser:disable_file_matching()
  2759. local inject_parser = clink.arg.new_parser()
  2760. inject_parser:set_flags(
  2761. "--help",
  2762. "--nohostcheck",
  2763. "--pid",
  2764. "--profile",
  2765. "--quiet",
  2766. "--scripts"
  2767. )
  2768. local autorun_dashdash_parser = clink.arg.new_parser()
  2769. autorun_dashdash_parser:set_arguments({ "--" .. inject_parser })
  2770. local autorun_parser = clink.arg.new_parser()
  2771. autorun_parser:set_flags("--allusers", "--help")
  2772. autorun_parser:set_arguments(
  2773. {
  2774. "install" .. autorun_dashdash_parser,
  2775. "uninstall" .. null_parser,
  2776. "show" .. null_parser,
  2777. "set"
  2778. }
  2779. )
  2780. local set_parser = clink.arg.new_parser()
  2781. set_parser:disable_file_matching()
  2782. set_parser:set_flags("--help")
  2783. set_parser:set_arguments(
  2784. {
  2785. "ansi_code_support",
  2786. "ctrld_exits",
  2787. "esc_clears_line",
  2788. "exec_match_style",
  2789. "history_dupe_mode",
  2790. "history_expand_mode",
  2791. "history_file_lines",
  2792. "history_ignore_space",
  2793. "history_io",
  2794. "match_colour",
  2795. "prompt_colour",
  2796. "space_prefix_match_files",
  2797. "strip_crlf_on_paste",
  2798. "terminate_autoanswer",
  2799. "use_altgr_substitute",
  2800. }
  2801. )
  2802. local self_parser = clink.arg.new_parser()
  2803. self_parser:set_arguments(
  2804. {
  2805. "inject" .. inject_parser,
  2806. "autorun" .. autorun_parser,
  2807. "set" .. set_parser,
  2808. }
  2809. )
  2810. clink.arg.register_parser("clink", self_parser)
  2811. clink.arg.register_parser("clink_x86", self_parser)
  2812. clink.arg.register_parser("clink_x64", self_parser)
  2813. -- vim: expandtab
  2814. --------------------------------------------------------------------------------
  2815. -- set.lua
  2816. --
  2817. --
  2818. -- Copyright (c) 2012 Martin Ridgers
  2819. --
  2820. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  2821. -- of this software and associated documentation files (the "Software"), to deal
  2822. -- in the Software without restriction, including without limitation the rights
  2823. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  2824. -- copies of the Software, and to permit persons to whom the Software is
  2825. -- furnished to do so, subject to the following conditions:
  2826. --
  2827. -- The above copyright notice and this permission notice shall be included in
  2828. -- all copies or substantial portions of the Software.
  2829. --
  2830. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2831. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2832. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2833. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2834. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  2835. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  2836. -- SOFTWARE.
  2837. --
  2838. --------------------------------------------------------------------------------
  2839. local function set_match_generator(word)
  2840. -- Skip this generator if first is in the rvalue.
  2841. local leading = rl_state.line_buffer:sub(1, rl_state.first - 1)
  2842. if leading:find("=") then
  2843. return false
  2844. end
  2845. -- Enumerate environment variables and check for potential matches.
  2846. local matches = {}
  2847. for _, name in ipairs(clink.get_env_var_names()) do
  2848. if clink.is_match(word, name) then
  2849. table.insert(matches, name:lower())
  2850. end
  2851. end
  2852. clink.suppress_char_append()
  2853. return matches
  2854. end
  2855. --------------------------------------------------------------------------------
  2856. clink.arg.register_parser("set", set_match_generator)
  2857. -- vim: expandtab
  2858. --------------------------------------------------------------------------------
  2859. -- svn.lua
  2860. --
  2861. --
  2862. -- Copyright (c) 2012 Martin Ridgers
  2863. --
  2864. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  2865. -- of this software and associated documentation files (the "Software"), to deal
  2866. -- in the Software without restriction, including without limitation the rights
  2867. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  2868. -- copies of the Software, and to permit persons to whom the Software is
  2869. -- furnished to do so, subject to the following conditions:
  2870. --
  2871. -- The above copyright notice and this permission notice shall be included in
  2872. -- all copies or substantial portions of the Software.
  2873. --
  2874. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2875. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2876. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2877. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2878. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  2879. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  2880. -- SOFTWARE.
  2881. --
  2882. --------------------------------------------------------------------------------
  2883. local svn_tree = {
  2884. "add", "blame", "praise", "annotate", "ann", "cat", "changelist", "cl",
  2885. "checkout", "co", "cleanup", "commit", "ci", "copy", "cp", "delete", "del",
  2886. "remove", "rm", "diff", "di", "export", "help", "h", "import", "info",
  2887. "list", "ls", "lock", "log", "merge", "mergeinfo", "mkdir", "move", "mv",
  2888. "rename", "ren", "propdel", "pdel", "pd", "propedit", "pedit", "pe",
  2889. "propget", "pget", "pg", "proplist", "plist", "pl", "propset", "pset", "ps",
  2890. "resolve", "resolved", "revert", "status", "stat", "st", "switch", "sw",
  2891. "unlock", "update", "up"
  2892. }
  2893. clink.arg.register_parser("svn", svn_tree)
  2894. -- vim: expandtab