AST.cpp 113 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "AST.h"
  7. #include "Shell.h"
  8. #include <AK/MemoryStream.h>
  9. #include <AK/ScopeGuard.h>
  10. #include <AK/ScopedValueRollback.h>
  11. #include <AK/String.h>
  12. #include <AK/StringBuilder.h>
  13. #include <AK/URL.h>
  14. #include <LibCore/EventLoop.h>
  15. #include <LibCore/File.h>
  16. #include <errno.h>
  17. #include <fcntl.h>
  18. #include <signal.h>
  19. #include <unistd.h>
  20. ErrorOr<void> AK::Formatter<Shell::AST::Command>::format(FormatBuilder& builder, Shell::AST::Command const& value)
  21. {
  22. if (m_sign_mode != FormatBuilder::SignMode::Default)
  23. VERIFY_NOT_REACHED();
  24. if (m_alternative_form)
  25. VERIFY_NOT_REACHED();
  26. if (m_zero_pad)
  27. VERIFY_NOT_REACHED();
  28. if (m_mode != Mode::Default && m_mode != Mode::String)
  29. VERIFY_NOT_REACHED();
  30. if (m_width.has_value())
  31. VERIFY_NOT_REACHED();
  32. if (m_precision.has_value())
  33. VERIFY_NOT_REACHED();
  34. if (value.argv.is_empty()) {
  35. TRY(builder.put_literal("(ShellInternal)"));
  36. } else {
  37. bool first = true;
  38. for (auto& arg : value.argv) {
  39. if (!first)
  40. TRY(builder.put_literal(" "));
  41. first = false;
  42. TRY(builder.put_literal(arg));
  43. }
  44. }
  45. for (auto& redir : value.redirections) {
  46. TRY(builder.put_padding(' ', 1));
  47. if (redir.is_path_redirection()) {
  48. auto path_redir = (const Shell::AST::PathRedirection*)&redir;
  49. TRY(builder.put_i64(path_redir->fd));
  50. switch (path_redir->direction) {
  51. case Shell::AST::PathRedirection::Read:
  52. TRY(builder.put_literal("<"));
  53. break;
  54. case Shell::AST::PathRedirection::Write:
  55. TRY(builder.put_literal(">"));
  56. break;
  57. case Shell::AST::PathRedirection::WriteAppend:
  58. TRY(builder.put_literal(">>"));
  59. break;
  60. case Shell::AST::PathRedirection::ReadWrite:
  61. TRY(builder.put_literal("<>"));
  62. break;
  63. }
  64. TRY(builder.put_literal(path_redir->path));
  65. } else if (redir.is_fd_redirection()) {
  66. auto* fdredir = (const Shell::AST::FdRedirection*)&redir;
  67. TRY(builder.put_i64(fdredir->new_fd));
  68. TRY(builder.put_literal(">"));
  69. TRY(builder.put_i64(fdredir->old_fd));
  70. } else if (redir.is_close_redirection()) {
  71. auto close_redir = (const Shell::AST::CloseRedirection*)&redir;
  72. TRY(builder.put_i64(close_redir->fd));
  73. TRY(builder.put_literal(">&-"));
  74. } else {
  75. VERIFY_NOT_REACHED();
  76. }
  77. }
  78. if (!value.next_chain.is_empty()) {
  79. for (auto& command : value.next_chain) {
  80. switch (command.action) {
  81. case Shell::AST::NodeWithAction::And:
  82. TRY(builder.put_literal(" && "));
  83. break;
  84. case Shell::AST::NodeWithAction::Or:
  85. TRY(builder.put_literal(" || "));
  86. break;
  87. case Shell::AST::NodeWithAction::Sequence:
  88. TRY(builder.put_literal("; "));
  89. break;
  90. }
  91. TRY(builder.put_literal("("));
  92. TRY(builder.put_literal(command.node->class_name()));
  93. TRY(builder.put_literal("...)"));
  94. }
  95. }
  96. if (!value.should_wait)
  97. TRY(builder.put_literal("&"));
  98. return {};
  99. }
  100. namespace Shell::AST {
  101. static inline void print_indented(const String& str, int indent)
  102. {
  103. dbgln("{}{}", String::repeated(' ', indent * 2), str);
  104. }
  105. static inline Optional<Position> merge_positions(const Optional<Position>& left, const Optional<Position>& right)
  106. {
  107. if (!left.has_value())
  108. return right;
  109. if (!right.has_value())
  110. return left;
  111. return Position {
  112. .start_offset = left->start_offset,
  113. .end_offset = right->end_offset,
  114. .start_line = left->start_line,
  115. .end_line = right->end_line,
  116. };
  117. }
  118. static inline Vector<Command> join_commands(Vector<Command> left, Vector<Command> right)
  119. {
  120. Command command;
  121. auto last_in_left = left.take_last();
  122. auto first_in_right = right.take_first();
  123. command.argv.extend(last_in_left.argv);
  124. command.argv.extend(first_in_right.argv);
  125. command.redirections.extend(last_in_left.redirections);
  126. command.redirections.extend(first_in_right.redirections);
  127. command.should_wait = first_in_right.should_wait && last_in_left.should_wait;
  128. command.is_pipe_source = first_in_right.is_pipe_source;
  129. command.should_notify_if_in_background = first_in_right.should_notify_if_in_background || last_in_left.should_notify_if_in_background;
  130. command.position = merge_positions(last_in_left.position, first_in_right.position);
  131. Vector<Command> commands;
  132. commands.extend(left);
  133. commands.append(command);
  134. commands.extend(right);
  135. return commands;
  136. }
  137. static String resolve_slices(RefPtr<Shell> shell, String&& input_value, NonnullRefPtrVector<Slice> slices)
  138. {
  139. if (slices.is_empty())
  140. return move(input_value);
  141. for (auto& slice : slices) {
  142. auto value = slice.run(shell);
  143. if (shell && shell->has_any_error())
  144. break;
  145. if (!value) {
  146. shell->raise_error(Shell::ShellError::InvalidSliceContentsError, "Invalid slice contents", slice.position());
  147. return move(input_value);
  148. }
  149. auto index_values = value->resolve_as_list(shell);
  150. Vector<size_t> indices;
  151. indices.ensure_capacity(index_values.size());
  152. size_t i = 0;
  153. for (auto& value : index_values) {
  154. auto maybe_index = value.to_int();
  155. if (!maybe_index.has_value()) {
  156. shell->raise_error(Shell::ShellError::InvalidSliceContentsError, String::formatted("Invalid value in slice index {}: {} (expected a number)", i, value), slice.position());
  157. return move(input_value);
  158. }
  159. ++i;
  160. auto index = maybe_index.value();
  161. auto original_index = index;
  162. if (index < 0)
  163. index += input_value.length();
  164. if (index < 0 || (size_t)index >= input_value.length()) {
  165. shell->raise_error(Shell::ShellError::InvalidSliceContentsError, String::formatted("Slice index {} (evaluated as {}) out of value bounds [0-{})", index, original_index, input_value.length()), slice.position());
  166. return move(input_value);
  167. }
  168. indices.unchecked_append(index);
  169. }
  170. StringBuilder builder { indices.size() };
  171. for (auto& index : indices)
  172. builder.append(input_value[index]);
  173. input_value = builder.build();
  174. }
  175. return move(input_value);
  176. }
  177. static Vector<String> resolve_slices(RefPtr<Shell> shell, Vector<String>&& values, NonnullRefPtrVector<Slice> slices)
  178. {
  179. if (slices.is_empty())
  180. return move(values);
  181. for (auto& slice : slices) {
  182. auto value = slice.run(shell);
  183. if (shell && shell->has_any_error())
  184. break;
  185. if (!value) {
  186. shell->raise_error(Shell::ShellError::InvalidSliceContentsError, "Invalid slice contents", slice.position());
  187. return move(values);
  188. }
  189. auto index_values = value->resolve_as_list(shell);
  190. Vector<size_t> indices;
  191. indices.ensure_capacity(index_values.size());
  192. size_t i = 0;
  193. for (auto& value : index_values) {
  194. auto maybe_index = value.to_int();
  195. if (!maybe_index.has_value()) {
  196. shell->raise_error(Shell::ShellError::InvalidSliceContentsError, String::formatted("Invalid value in slice index {}: {} (expected a number)", i, value), slice.position());
  197. return move(values);
  198. }
  199. ++i;
  200. auto index = maybe_index.value();
  201. auto original_index = index;
  202. if (index < 0)
  203. index += values.size();
  204. if (index < 0 || (size_t)index >= values.size()) {
  205. shell->raise_error(Shell::ShellError::InvalidSliceContentsError, String::formatted("Slice index {} (evaluated as {}) out of value bounds [0-{})", index, original_index, values.size()), slice.position());
  206. return move(values);
  207. }
  208. indices.unchecked_append(index);
  209. }
  210. Vector<String> result;
  211. result.ensure_capacity(indices.size());
  212. for (auto& index : indices)
  213. result.unchecked_append(values[index]);
  214. values = move(result);
  215. }
  216. return move(values);
  217. }
  218. void Node::clear_syntax_error()
  219. {
  220. m_syntax_error_node->clear_syntax_error();
  221. }
  222. void Node::set_is_syntax_error(const SyntaxError& error_node)
  223. {
  224. if (!m_syntax_error_node) {
  225. m_syntax_error_node = error_node;
  226. } else {
  227. m_syntax_error_node->set_is_syntax_error(error_node);
  228. }
  229. }
  230. bool Node::is_syntax_error() const
  231. {
  232. return m_syntax_error_node && m_syntax_error_node->is_syntax_error();
  233. }
  234. void Node::for_each_entry(RefPtr<Shell> shell, Function<IterationDecision(NonnullRefPtr<Value>)> callback)
  235. {
  236. auto value = run(shell)->resolve_without_cast(shell);
  237. if (shell && shell->has_any_error())
  238. return;
  239. if (value->is_job()) {
  240. callback(value);
  241. return;
  242. }
  243. if (value->is_list_without_resolution()) {
  244. auto list = value->resolve_without_cast(shell);
  245. for (auto& element : static_cast<ListValue*>(list.ptr())->values()) {
  246. if (callback(element) == IterationDecision::Break)
  247. break;
  248. }
  249. return;
  250. }
  251. auto list = value->resolve_as_list(shell);
  252. for (auto& element : list) {
  253. if (callback(make_ref_counted<StringValue>(move(element))) == IterationDecision::Break)
  254. break;
  255. }
  256. }
  257. Vector<Command> Node::to_lazy_evaluated_commands(RefPtr<Shell> shell)
  258. {
  259. if (would_execute()) {
  260. // Wrap the node in a "should immediately execute next" command.
  261. return {
  262. Command { {}, {}, true, false, true, true, {}, { NodeWithAction(*this, NodeWithAction::Sequence) }, position() }
  263. };
  264. }
  265. return run(shell)->resolve_as_commands(shell);
  266. }
  267. void Node::dump(int level) const
  268. {
  269. print_indented(String::formatted("{} at {}:{} (from {}.{} to {}.{})",
  270. class_name().characters(),
  271. m_position.start_offset,
  272. m_position.end_offset,
  273. m_position.start_line.line_number,
  274. m_position.start_line.line_column,
  275. m_position.end_line.line_number,
  276. m_position.end_line.line_column),
  277. level);
  278. }
  279. Node::Node(Position position)
  280. : m_position(position)
  281. {
  282. }
  283. Vector<Line::CompletionSuggestion> Node::complete_for_editor(Shell& shell, size_t offset, const HitTestResult& hit_test_result)
  284. {
  285. auto matching_node = hit_test_result.matching_node;
  286. if (matching_node) {
  287. if (matching_node->is_bareword()) {
  288. auto* node = static_cast<BarewordLiteral*>(matching_node.ptr());
  289. auto corrected_offset = find_offset_into_node(node->text(), offset - matching_node->position().start_offset);
  290. if (corrected_offset > node->text().length())
  291. return {};
  292. auto& text = node->text();
  293. // If the literal isn't an option, treat it as a path.
  294. if (!(text.starts_with("-") || text == "--" || text == "-"))
  295. return shell.complete_path("", text, corrected_offset, Shell::ExecutableOnly::No);
  296. // If the literal is an option, we have to know the program name
  297. // should we have no way to get that, bail early.
  298. if (!hit_test_result.closest_command_node)
  299. return {};
  300. auto program_name_node = hit_test_result.closest_command_node->leftmost_trivial_literal();
  301. if (!program_name_node)
  302. return {};
  303. String program_name;
  304. if (program_name_node->is_bareword())
  305. program_name = static_cast<BarewordLiteral*>(program_name_node.ptr())->text();
  306. else
  307. program_name = static_cast<StringLiteral*>(program_name_node.ptr())->text();
  308. return shell.complete_option(program_name, text, corrected_offset);
  309. }
  310. return {};
  311. }
  312. auto result = hit_test_position(offset);
  313. if (!result.matching_node)
  314. return {};
  315. auto node = result.matching_node;
  316. if (node->is_bareword() || node != result.closest_node_with_semantic_meaning)
  317. node = result.closest_node_with_semantic_meaning;
  318. if (!node)
  319. return {};
  320. return node->complete_for_editor(shell, offset, result);
  321. }
  322. Vector<Line::CompletionSuggestion> Node::complete_for_editor(Shell& shell, size_t offset)
  323. {
  324. return Node::complete_for_editor(shell, offset, { nullptr, nullptr, nullptr });
  325. }
  326. Node::~Node()
  327. {
  328. }
  329. void And::dump(int level) const
  330. {
  331. Node::dump(level);
  332. m_left->dump(level + 1);
  333. m_right->dump(level + 1);
  334. }
  335. RefPtr<Value> And::run(RefPtr<Shell> shell)
  336. {
  337. auto commands = m_left->to_lazy_evaluated_commands(shell);
  338. if (shell && shell->has_any_error())
  339. return make_ref_counted<ListValue>({});
  340. commands.last().next_chain.append(NodeWithAction { *m_right, NodeWithAction::And });
  341. return make_ref_counted<CommandSequenceValue>(move(commands));
  342. }
  343. void And::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  344. {
  345. metadata.is_first_in_list = true;
  346. m_left->highlight_in_editor(editor, shell, metadata);
  347. m_right->highlight_in_editor(editor, shell, metadata);
  348. }
  349. HitTestResult And::hit_test_position(size_t offset) const
  350. {
  351. auto result = m_left->hit_test_position(offset);
  352. if (result.matching_node) {
  353. if (!result.closest_command_node)
  354. result.closest_command_node = m_right;
  355. return result;
  356. }
  357. result = m_right->hit_test_position(offset);
  358. if (!result.closest_command_node)
  359. result.closest_command_node = m_right;
  360. return result;
  361. }
  362. And::And(Position position, NonnullRefPtr<Node> left, NonnullRefPtr<Node> right, Position and_position)
  363. : Node(move(position))
  364. , m_left(move(left))
  365. , m_right(move(right))
  366. , m_and_position(and_position)
  367. {
  368. if (m_left->is_syntax_error())
  369. set_is_syntax_error(m_left->syntax_error_node());
  370. else if (m_right->is_syntax_error())
  371. set_is_syntax_error(m_right->syntax_error_node());
  372. }
  373. And::~And()
  374. {
  375. }
  376. void ListConcatenate::dump(int level) const
  377. {
  378. Node::dump(level);
  379. for (auto& element : m_list)
  380. element->dump(level + 1);
  381. }
  382. RefPtr<Value> ListConcatenate::run(RefPtr<Shell> shell)
  383. {
  384. RefPtr<Value> result = nullptr;
  385. for (auto& element : m_list) {
  386. if (shell && shell->has_any_error())
  387. break;
  388. if (!result) {
  389. result = make_ref_counted<ListValue>({ element->run(shell)->resolve_without_cast(shell) });
  390. continue;
  391. }
  392. auto element_value = element->run(shell)->resolve_without_cast(shell);
  393. if (shell && shell->has_any_error())
  394. break;
  395. if (result->is_command() || element_value->is_command()) {
  396. auto joined_commands = join_commands(result->resolve_as_commands(shell), element_value->resolve_as_commands(shell));
  397. if (joined_commands.size() == 1) {
  398. auto& command = joined_commands[0];
  399. command.position = position();
  400. result = make_ref_counted<CommandValue>(command);
  401. } else {
  402. result = make_ref_counted<CommandSequenceValue>(move(joined_commands));
  403. }
  404. } else {
  405. NonnullRefPtrVector<Value> values;
  406. if (result->is_list_without_resolution()) {
  407. values.extend(static_cast<ListValue*>(result.ptr())->values());
  408. } else {
  409. for (auto& result : result->resolve_as_list(shell))
  410. values.append(make_ref_counted<StringValue>(result));
  411. }
  412. values.append(element_value);
  413. result = make_ref_counted<ListValue>(move(values));
  414. }
  415. }
  416. if (!result)
  417. return make_ref_counted<ListValue>({});
  418. return result;
  419. }
  420. void ListConcatenate::for_each_entry(RefPtr<Shell> shell, Function<IterationDecision(NonnullRefPtr<Value>)> callback)
  421. {
  422. for (auto& entry : m_list) {
  423. auto value = entry->run(shell);
  424. if (shell && shell->has_any_error())
  425. break;
  426. if (!value)
  427. continue;
  428. if (callback(value.release_nonnull()) == IterationDecision::Break)
  429. break;
  430. }
  431. }
  432. void ListConcatenate::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  433. {
  434. auto first = metadata.is_first_in_list;
  435. metadata.is_first_in_list = false;
  436. metadata.is_first_in_list = first;
  437. for (auto& element : m_list) {
  438. element->highlight_in_editor(editor, shell, metadata);
  439. metadata.is_first_in_list = false;
  440. }
  441. }
  442. HitTestResult ListConcatenate::hit_test_position(size_t offset) const
  443. {
  444. bool first = true;
  445. for (auto& element : m_list) {
  446. auto result = element->hit_test_position(offset);
  447. if (!result.closest_node_with_semantic_meaning && !first)
  448. result.closest_node_with_semantic_meaning = this;
  449. if (result.matching_node)
  450. return result;
  451. first = false;
  452. }
  453. return {};
  454. }
  455. RefPtr<Node> ListConcatenate::leftmost_trivial_literal() const
  456. {
  457. if (m_list.is_empty())
  458. return nullptr;
  459. return m_list.first()->leftmost_trivial_literal();
  460. }
  461. ListConcatenate::ListConcatenate(Position position, Vector<NonnullRefPtr<Node>> list)
  462. : Node(move(position))
  463. , m_list(move(list))
  464. {
  465. for (auto& element : m_list) {
  466. if (element->is_syntax_error()) {
  467. set_is_syntax_error(element->syntax_error_node());
  468. break;
  469. }
  470. }
  471. }
  472. ListConcatenate::~ListConcatenate()
  473. {
  474. }
  475. void Background::dump(int level) const
  476. {
  477. Node::dump(level);
  478. m_command->dump(level + 1);
  479. }
  480. RefPtr<Value> Background::run(RefPtr<Shell> shell)
  481. {
  482. auto commands = m_command->to_lazy_evaluated_commands(shell);
  483. for (auto& command : commands)
  484. command.should_wait = false;
  485. return make_ref_counted<CommandSequenceValue>(move(commands));
  486. }
  487. void Background::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  488. {
  489. m_command->highlight_in_editor(editor, shell, metadata);
  490. }
  491. HitTestResult Background::hit_test_position(size_t offset) const
  492. {
  493. return m_command->hit_test_position(offset);
  494. }
  495. Background::Background(Position position, NonnullRefPtr<Node> command)
  496. : Node(move(position))
  497. , m_command(move(command))
  498. {
  499. if (m_command->is_syntax_error())
  500. set_is_syntax_error(m_command->syntax_error_node());
  501. }
  502. Background::~Background()
  503. {
  504. }
  505. void BarewordLiteral::dump(int level) const
  506. {
  507. Node::dump(level);
  508. print_indented(m_text, level + 1);
  509. }
  510. RefPtr<Value> BarewordLiteral::run(RefPtr<Shell>)
  511. {
  512. return make_ref_counted<StringValue>(m_text);
  513. }
  514. void BarewordLiteral::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  515. {
  516. if (metadata.is_first_in_list) {
  517. if (shell.is_runnable(m_text)) {
  518. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Bold });
  519. } else {
  520. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Red) });
  521. }
  522. return;
  523. }
  524. if (m_text.starts_with('-')) {
  525. if (m_text == "--") {
  526. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Green) });
  527. return;
  528. }
  529. if (m_text == "-")
  530. return;
  531. if (m_text.starts_with("--")) {
  532. auto index = m_text.find('=').value_or(m_text.length() - 1) + 1;
  533. editor.stylize({ m_position.start_offset, m_position.start_offset + index }, { Line::Style::Foreground(Line::Style::XtermColor::Cyan) });
  534. } else {
  535. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Cyan) });
  536. }
  537. }
  538. if (Core::File::exists(m_text)) {
  539. auto realpath = shell.resolve_path(m_text);
  540. auto url = URL::create_with_file_protocol(realpath);
  541. url.set_host(shell.hostname);
  542. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Hyperlink(url.to_string()) });
  543. }
  544. }
  545. BarewordLiteral::BarewordLiteral(Position position, String text)
  546. : Node(move(position))
  547. , m_text(move(text))
  548. {
  549. }
  550. BarewordLiteral::~BarewordLiteral()
  551. {
  552. }
  553. void BraceExpansion::dump(int level) const
  554. {
  555. Node::dump(level);
  556. for (auto& entry : m_entries)
  557. entry.dump(level + 1);
  558. }
  559. RefPtr<Value> BraceExpansion::run(RefPtr<Shell> shell)
  560. {
  561. NonnullRefPtrVector<Value> values;
  562. for (auto& entry : m_entries) {
  563. if (shell && shell->has_any_error())
  564. break;
  565. auto value = entry.run(shell);
  566. if (value)
  567. values.append(value.release_nonnull());
  568. }
  569. return make_ref_counted<ListValue>(move(values));
  570. }
  571. HitTestResult BraceExpansion::hit_test_position(size_t offset) const
  572. {
  573. for (auto& entry : m_entries) {
  574. auto result = entry.hit_test_position(offset);
  575. if (result.matching_node) {
  576. if (!result.closest_command_node)
  577. result.closest_command_node = &entry;
  578. return result;
  579. }
  580. }
  581. return {};
  582. }
  583. void BraceExpansion::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  584. {
  585. for (auto& entry : m_entries) {
  586. entry.highlight_in_editor(editor, shell, metadata);
  587. metadata.is_first_in_list = false;
  588. }
  589. }
  590. BraceExpansion::BraceExpansion(Position position, NonnullRefPtrVector<Node> entries)
  591. : Node(move(position))
  592. , m_entries(move(entries))
  593. {
  594. for (auto& entry : m_entries) {
  595. if (entry.is_syntax_error()) {
  596. set_is_syntax_error(entry.syntax_error_node());
  597. break;
  598. }
  599. }
  600. }
  601. BraceExpansion::~BraceExpansion()
  602. {
  603. }
  604. void CastToCommand::dump(int level) const
  605. {
  606. Node::dump(level);
  607. m_inner->dump(level + 1);
  608. }
  609. RefPtr<Value> CastToCommand::run(RefPtr<Shell> shell)
  610. {
  611. if (m_inner->is_command())
  612. return m_inner->run(shell);
  613. auto value = m_inner->run(shell)->resolve_without_cast(shell);
  614. if (shell && shell->has_any_error())
  615. return make_ref_counted<ListValue>({});
  616. if (value->is_command())
  617. return value;
  618. auto argv = value->resolve_as_list(shell);
  619. return make_ref_counted<CommandValue>(move(argv), position());
  620. }
  621. void CastToCommand::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  622. {
  623. m_inner->highlight_in_editor(editor, shell, metadata);
  624. }
  625. HitTestResult CastToCommand::hit_test_position(size_t offset) const
  626. {
  627. auto result = m_inner->hit_test_position(offset);
  628. if (!result.closest_node_with_semantic_meaning)
  629. result.closest_node_with_semantic_meaning = this;
  630. return result;
  631. }
  632. Vector<Line::CompletionSuggestion> CastToCommand::complete_for_editor(Shell& shell, size_t offset, const HitTestResult& hit_test_result)
  633. {
  634. auto matching_node = hit_test_result.matching_node;
  635. if (!matching_node || !matching_node->is_bareword())
  636. return {};
  637. auto corrected_offset = offset - matching_node->position().start_offset;
  638. auto* node = static_cast<BarewordLiteral*>(matching_node.ptr());
  639. if (corrected_offset > node->text().length())
  640. return {};
  641. return shell.complete_program_name(node->text(), corrected_offset);
  642. }
  643. RefPtr<Node> CastToCommand::leftmost_trivial_literal() const
  644. {
  645. return m_inner->leftmost_trivial_literal();
  646. }
  647. CastToCommand::CastToCommand(Position position, NonnullRefPtr<Node> inner)
  648. : Node(move(position))
  649. , m_inner(move(inner))
  650. {
  651. if (m_inner->is_syntax_error())
  652. set_is_syntax_error(m_inner->syntax_error_node());
  653. }
  654. CastToCommand::~CastToCommand()
  655. {
  656. }
  657. void CastToList::dump(int level) const
  658. {
  659. Node::dump(level);
  660. if (m_inner)
  661. m_inner->dump(level + 1);
  662. else
  663. print_indented("(empty)", level + 1);
  664. }
  665. RefPtr<Value> CastToList::run(RefPtr<Shell> shell)
  666. {
  667. if (!m_inner)
  668. return make_ref_counted<ListValue>({});
  669. auto inner_value = m_inner->run(shell)->resolve_without_cast(shell);
  670. if (shell && shell->has_any_error())
  671. return make_ref_counted<ListValue>({});
  672. if (inner_value->is_command() || inner_value->is_list())
  673. return inner_value;
  674. auto values = inner_value->resolve_as_list(shell);
  675. NonnullRefPtrVector<Value> cast_values;
  676. for (auto& value : values)
  677. cast_values.append(make_ref_counted<StringValue>(value));
  678. return make_ref_counted<ListValue>(cast_values);
  679. }
  680. void CastToList::for_each_entry(RefPtr<Shell> shell, Function<IterationDecision(NonnullRefPtr<Value>)> callback)
  681. {
  682. if (m_inner)
  683. m_inner->for_each_entry(shell, move(callback));
  684. }
  685. void CastToList::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  686. {
  687. if (m_inner)
  688. m_inner->highlight_in_editor(editor, shell, metadata);
  689. }
  690. HitTestResult CastToList::hit_test_position(size_t offset) const
  691. {
  692. if (!m_inner)
  693. return {};
  694. return m_inner->hit_test_position(offset);
  695. }
  696. RefPtr<Node> CastToList::leftmost_trivial_literal() const
  697. {
  698. return m_inner->leftmost_trivial_literal();
  699. }
  700. CastToList::CastToList(Position position, RefPtr<Node> inner)
  701. : Node(move(position))
  702. , m_inner(move(inner))
  703. {
  704. if (m_inner && m_inner->is_syntax_error())
  705. set_is_syntax_error(m_inner->syntax_error_node());
  706. }
  707. CastToList::~CastToList()
  708. {
  709. }
  710. void CloseFdRedirection::dump(int level) const
  711. {
  712. Node::dump(level);
  713. print_indented(String::formatted("{} -> Close", m_fd), level);
  714. }
  715. RefPtr<Value> CloseFdRedirection::run(RefPtr<Shell>)
  716. {
  717. Command command;
  718. command.position = position();
  719. command.redirections.append(adopt_ref(*new CloseRedirection(m_fd)));
  720. return make_ref_counted<CommandValue>(move(command));
  721. }
  722. void CloseFdRedirection::highlight_in_editor(Line::Editor& editor, Shell&, HighlightMetadata)
  723. {
  724. editor.stylize({ m_position.start_offset, m_position.end_offset - 1 }, { Line::Style::Foreground(0x87, 0x9b, 0xcd) }); // 25% Darkened Periwinkle
  725. editor.stylize({ m_position.end_offset - 1, m_position.end_offset }, { Line::Style::Foreground(0xff, 0x7e, 0x00) }); // Amber
  726. }
  727. CloseFdRedirection::CloseFdRedirection(Position position, int fd)
  728. : Node(move(position))
  729. , m_fd(fd)
  730. {
  731. }
  732. CloseFdRedirection::~CloseFdRedirection()
  733. {
  734. }
  735. void CommandLiteral::dump(int level) const
  736. {
  737. Node::dump(level);
  738. print_indented(String::formatted("(Generated command literal: {})", m_command), level + 1);
  739. }
  740. RefPtr<Value> CommandLiteral::run(RefPtr<Shell>)
  741. {
  742. return make_ref_counted<CommandValue>(m_command);
  743. }
  744. CommandLiteral::CommandLiteral(Position position, Command command)
  745. : Node(move(position))
  746. , m_command(move(command))
  747. {
  748. }
  749. CommandLiteral::~CommandLiteral()
  750. {
  751. }
  752. void Comment::dump(int level) const
  753. {
  754. Node::dump(level);
  755. print_indented(m_text, level + 1);
  756. }
  757. RefPtr<Value> Comment::run(RefPtr<Shell>)
  758. {
  759. return make_ref_counted<ListValue>({});
  760. }
  761. void Comment::highlight_in_editor(Line::Editor& editor, Shell&, HighlightMetadata)
  762. {
  763. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(150, 150, 150) }); // Light gray
  764. }
  765. Comment::Comment(Position position, String text)
  766. : Node(move(position))
  767. , m_text(move(text))
  768. {
  769. }
  770. Comment::~Comment()
  771. {
  772. }
  773. void ContinuationControl::dump(int level) const
  774. {
  775. Node::dump(level);
  776. print_indented(m_kind == Continue ? "(Continue)" : "(Break)", level + 1);
  777. }
  778. RefPtr<Value> ContinuationControl::run(RefPtr<Shell> shell)
  779. {
  780. if (m_kind == Break)
  781. shell->raise_error(Shell::ShellError::InternalControlFlowBreak, {}, position());
  782. else if (m_kind == Continue)
  783. shell->raise_error(Shell::ShellError::InternalControlFlowContinue, {}, position());
  784. else
  785. VERIFY_NOT_REACHED();
  786. return make_ref_counted<ListValue>({});
  787. }
  788. void ContinuationControl::highlight_in_editor(Line::Editor& editor, Shell&, HighlightMetadata)
  789. {
  790. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
  791. }
  792. void DoubleQuotedString::dump(int level) const
  793. {
  794. Node::dump(level);
  795. m_inner->dump(level + 1);
  796. }
  797. RefPtr<Value> DoubleQuotedString::run(RefPtr<Shell> shell)
  798. {
  799. StringBuilder builder;
  800. auto values = m_inner->run(shell)->resolve_as_list(shell);
  801. builder.join("", values);
  802. return make_ref_counted<StringValue>(builder.to_string());
  803. }
  804. void DoubleQuotedString::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  805. {
  806. Line::Style style { Line::Style::Foreground(Line::Style::XtermColor::Yellow) };
  807. if (metadata.is_first_in_list)
  808. style.unify_with({ Line::Style::Bold });
  809. editor.stylize({ m_position.start_offset, m_position.end_offset }, style);
  810. metadata.is_first_in_list = false;
  811. m_inner->highlight_in_editor(editor, shell, metadata);
  812. }
  813. HitTestResult DoubleQuotedString::hit_test_position(size_t offset) const
  814. {
  815. return m_inner->hit_test_position(offset);
  816. }
  817. DoubleQuotedString::DoubleQuotedString(Position position, RefPtr<Node> inner)
  818. : Node(move(position))
  819. , m_inner(move(inner))
  820. {
  821. if (m_inner->is_syntax_error())
  822. set_is_syntax_error(m_inner->syntax_error_node());
  823. }
  824. DoubleQuotedString::~DoubleQuotedString()
  825. {
  826. }
  827. void DynamicEvaluate::dump(int level) const
  828. {
  829. Node::dump(level);
  830. m_inner->dump(level + 1);
  831. }
  832. RefPtr<Value> DynamicEvaluate::run(RefPtr<Shell> shell)
  833. {
  834. auto result = m_inner->run(shell)->resolve_without_cast(shell);
  835. if (shell && shell->has_any_error())
  836. return make_ref_counted<ListValue>({});
  837. // Dynamic Evaluation behaves differently between strings and lists.
  838. // Strings are treated as variables, and Lists are treated as commands.
  839. if (result->is_string()) {
  840. auto name_part = result->resolve_as_list(shell);
  841. VERIFY(name_part.size() == 1);
  842. return make_ref_counted<SimpleVariableValue>(name_part[0]);
  843. }
  844. // If it's anything else, we're just gonna cast it to a list.
  845. auto list = result->resolve_as_list(shell);
  846. return make_ref_counted<CommandValue>(move(list), position());
  847. }
  848. void DynamicEvaluate::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  849. {
  850. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
  851. m_inner->highlight_in_editor(editor, shell, metadata);
  852. }
  853. HitTestResult DynamicEvaluate::hit_test_position(size_t offset) const
  854. {
  855. return m_inner->hit_test_position(offset);
  856. }
  857. DynamicEvaluate::DynamicEvaluate(Position position, NonnullRefPtr<Node> inner)
  858. : Node(move(position))
  859. , m_inner(move(inner))
  860. {
  861. if (m_inner->is_syntax_error())
  862. set_is_syntax_error(m_inner->syntax_error_node());
  863. }
  864. DynamicEvaluate::~DynamicEvaluate()
  865. {
  866. }
  867. void Fd2FdRedirection::dump(int level) const
  868. {
  869. Node::dump(level);
  870. print_indented(String::formatted("{} -> {}", m_old_fd, m_new_fd), level);
  871. }
  872. RefPtr<Value> Fd2FdRedirection::run(RefPtr<Shell>)
  873. {
  874. Command command;
  875. command.position = position();
  876. command.redirections.append(FdRedirection::create(m_new_fd, m_old_fd, Rewiring::Close::None));
  877. return make_ref_counted<CommandValue>(move(command));
  878. }
  879. void Fd2FdRedirection::highlight_in_editor(Line::Editor& editor, Shell&, HighlightMetadata)
  880. {
  881. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(0x87, 0x9b, 0xcd) }); // 25% Darkened Periwinkle
  882. }
  883. Fd2FdRedirection::Fd2FdRedirection(Position position, int src, int dst)
  884. : Node(move(position))
  885. , m_old_fd(src)
  886. , m_new_fd(dst)
  887. {
  888. }
  889. Fd2FdRedirection::~Fd2FdRedirection()
  890. {
  891. }
  892. void FunctionDeclaration::dump(int level) const
  893. {
  894. Node::dump(level);
  895. print_indented(String::formatted("(name: {})\n", m_name.name), level + 1);
  896. print_indented("(argument names)", level + 1);
  897. for (auto& arg : m_arguments)
  898. print_indented(String::formatted("(name: {})\n", arg.name), level + 2);
  899. print_indented("(body)", level + 1);
  900. if (m_block)
  901. m_block->dump(level + 2);
  902. else
  903. print_indented("(null)", level + 2);
  904. }
  905. RefPtr<Value> FunctionDeclaration::run(RefPtr<Shell> shell)
  906. {
  907. Vector<String> args;
  908. for (auto& arg : m_arguments)
  909. args.append(arg.name);
  910. shell->define_function(m_name.name, move(args), m_block);
  911. return make_ref_counted<ListValue>({});
  912. }
  913. void FunctionDeclaration::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  914. {
  915. editor.stylize({ m_name.position.start_offset, m_name.position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Blue) });
  916. for (auto& arg : m_arguments)
  917. editor.stylize({ arg.position.start_offset, arg.position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Blue), Line::Style::Italic });
  918. metadata.is_first_in_list = true;
  919. if (m_block)
  920. m_block->highlight_in_editor(editor, shell, metadata);
  921. }
  922. HitTestResult FunctionDeclaration::hit_test_position(size_t offset) const
  923. {
  924. if (!m_block)
  925. return {};
  926. auto result = m_block->hit_test_position(offset);
  927. if (result.matching_node && result.matching_node->is_simple_variable())
  928. result.closest_node_with_semantic_meaning = this;
  929. return result;
  930. }
  931. Vector<Line::CompletionSuggestion> FunctionDeclaration::complete_for_editor(Shell& shell, size_t offset, const HitTestResult& hit_test_result)
  932. {
  933. auto matching_node = hit_test_result.matching_node;
  934. if (!matching_node)
  935. return {};
  936. if (!matching_node->is_simple_variable())
  937. return matching_node->complete_for_editor(shell, offset, hit_test_result);
  938. auto corrected_offset = offset - matching_node->position().start_offset - 1; // Skip the first '$'
  939. auto* node = static_cast<SimpleVariable*>(matching_node.ptr());
  940. auto name = node->name().substring_view(0, corrected_offset);
  941. Vector<Line::CompletionSuggestion> results;
  942. for (auto& arg : m_arguments) {
  943. if (arg.name.starts_with(name))
  944. results.append(arg.name);
  945. }
  946. results.extend(matching_node->complete_for_editor(shell, offset, hit_test_result));
  947. return results;
  948. }
  949. FunctionDeclaration::FunctionDeclaration(Position position, NameWithPosition name, Vector<NameWithPosition> arguments, RefPtr<AST::Node> body)
  950. : Node(move(position))
  951. , m_name(move(name))
  952. , m_arguments(arguments)
  953. , m_block(move(body))
  954. {
  955. if (m_block && m_block->is_syntax_error())
  956. set_is_syntax_error(m_block->syntax_error_node());
  957. }
  958. FunctionDeclaration::~FunctionDeclaration()
  959. {
  960. }
  961. void ForLoop::dump(int level) const
  962. {
  963. Node::dump(level);
  964. if (m_variable.has_value())
  965. print_indented(String::formatted("iterating with {} in", m_variable->name), level + 1);
  966. if (m_index_variable.has_value())
  967. print_indented(String::formatted("with index name {} in", m_index_variable->name), level + 1);
  968. if (m_iterated_expression)
  969. m_iterated_expression->dump(level + 2);
  970. else
  971. print_indented("(ever)", level + 2);
  972. print_indented("Running", level + 1);
  973. if (m_block)
  974. m_block->dump(level + 2);
  975. else
  976. print_indented("(null)", level + 2);
  977. }
  978. RefPtr<Value> ForLoop::run(RefPtr<Shell> shell)
  979. {
  980. if (!m_block)
  981. return make_ref_counted<ListValue>({});
  982. size_t consecutive_interruptions = 0;
  983. auto run = [&](auto& block_value) {
  984. if (shell->has_error(Shell::ShellError::InternalControlFlowBreak)) {
  985. shell->take_error();
  986. return IterationDecision::Break;
  987. }
  988. if (shell->has_error(Shell::ShellError::InternalControlFlowContinue)) {
  989. shell->take_error();
  990. return IterationDecision::Continue;
  991. }
  992. if (!shell->has_error(Shell::ShellError::None))
  993. return IterationDecision::Break;
  994. if (block_value->is_job()) {
  995. auto job = static_cast<JobValue*>(block_value.ptr())->job();
  996. if (!job || job->is_running_in_background())
  997. return IterationDecision::Continue;
  998. shell->block_on_job(job);
  999. if (job->signaled()) {
  1000. if (job->termination_signal() == SIGINT)
  1001. ++consecutive_interruptions;
  1002. else
  1003. return IterationDecision::Break;
  1004. } else {
  1005. consecutive_interruptions = 0;
  1006. }
  1007. }
  1008. return IterationDecision::Continue;
  1009. };
  1010. if (m_iterated_expression) {
  1011. auto variable_name = m_variable.has_value() ? m_variable->name : "it";
  1012. Optional<StringView> index_name = m_index_variable.has_value() ? Optional<StringView>(m_index_variable->name) : Optional<StringView>();
  1013. size_t i = 0;
  1014. m_iterated_expression->for_each_entry(shell, [&](auto value) {
  1015. if (consecutive_interruptions == 2)
  1016. return IterationDecision::Break;
  1017. if (shell && shell->has_any_error())
  1018. return IterationDecision::Break;
  1019. RefPtr<Value> block_value;
  1020. {
  1021. auto frame = shell->push_frame(String::formatted("for ({})", this));
  1022. shell->set_local_variable(variable_name, value, true);
  1023. if (index_name.has_value())
  1024. shell->set_local_variable(index_name.value(), make_ref_counted<AST::StringValue>(String::number(i)), true);
  1025. ++i;
  1026. block_value = m_block->run(shell);
  1027. }
  1028. return run(block_value);
  1029. });
  1030. } else {
  1031. for (;;) {
  1032. if (shell && shell->has_any_error())
  1033. break;
  1034. if (consecutive_interruptions == 2)
  1035. break;
  1036. RefPtr<Value> block_value = m_block->run(shell);
  1037. if (run(block_value) == IterationDecision::Break)
  1038. break;
  1039. }
  1040. }
  1041. return make_ref_counted<ListValue>({});
  1042. }
  1043. void ForLoop::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  1044. {
  1045. auto is_loop = m_iterated_expression.is_null();
  1046. editor.stylize({ m_position.start_offset, m_position.start_offset + (is_loop ? 4 : 3) }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
  1047. if (!is_loop) {
  1048. if (m_in_kw_position.has_value())
  1049. editor.stylize({ m_in_kw_position.value().start_offset, m_in_kw_position.value().end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
  1050. if (m_index_kw_position.has_value())
  1051. editor.stylize({ m_index_kw_position.value().start_offset, m_index_kw_position.value().end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
  1052. metadata.is_first_in_list = false;
  1053. m_iterated_expression->highlight_in_editor(editor, shell, metadata);
  1054. }
  1055. if (m_index_variable.has_value())
  1056. editor.stylize({ m_index_variable->position.start_offset, m_index_variable->position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Blue), Line::Style::Italic });
  1057. if (m_variable.has_value())
  1058. editor.stylize({ m_variable->position.start_offset, m_variable->position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Blue), Line::Style::Italic });
  1059. metadata.is_first_in_list = true;
  1060. if (m_block)
  1061. m_block->highlight_in_editor(editor, shell, metadata);
  1062. }
  1063. HitTestResult ForLoop::hit_test_position(size_t offset) const
  1064. {
  1065. if (m_iterated_expression) {
  1066. if (auto result = m_iterated_expression->hit_test_position(offset); result.matching_node)
  1067. return result;
  1068. }
  1069. if (!m_block)
  1070. return {};
  1071. return m_block->hit_test_position(offset);
  1072. }
  1073. ForLoop::ForLoop(Position position, Optional<NameWithPosition> variable, Optional<NameWithPosition> index_variable, RefPtr<AST::Node> iterated_expr, RefPtr<AST::Node> block, Optional<Position> in_kw_position, Optional<Position> index_kw_position)
  1074. : Node(move(position))
  1075. , m_variable(move(variable))
  1076. , m_index_variable(move(index_variable))
  1077. , m_iterated_expression(move(iterated_expr))
  1078. , m_block(move(block))
  1079. , m_in_kw_position(move(in_kw_position))
  1080. , m_index_kw_position(move(index_kw_position))
  1081. {
  1082. if (m_iterated_expression && m_iterated_expression->is_syntax_error())
  1083. set_is_syntax_error(m_iterated_expression->syntax_error_node());
  1084. else if (m_block && m_block->is_syntax_error())
  1085. set_is_syntax_error(m_block->syntax_error_node());
  1086. }
  1087. ForLoop::~ForLoop()
  1088. {
  1089. }
  1090. void Glob::dump(int level) const
  1091. {
  1092. Node::dump(level);
  1093. print_indented(m_text, level + 1);
  1094. }
  1095. RefPtr<Value> Glob::run(RefPtr<Shell>)
  1096. {
  1097. return make_ref_counted<GlobValue>(m_text, position());
  1098. }
  1099. void Glob::highlight_in_editor(Line::Editor& editor, Shell&, HighlightMetadata metadata)
  1100. {
  1101. Line::Style style { Line::Style::Foreground(Line::Style::XtermColor::Cyan) };
  1102. if (metadata.is_first_in_list)
  1103. style.unify_with({ Line::Style::Bold });
  1104. editor.stylize({ m_position.start_offset, m_position.end_offset }, move(style));
  1105. }
  1106. Glob::Glob(Position position, String text)
  1107. : Node(move(position))
  1108. , m_text(move(text))
  1109. {
  1110. }
  1111. Glob::~Glob()
  1112. {
  1113. }
  1114. void Heredoc::dump(int level) const
  1115. {
  1116. Node::dump(level);
  1117. print_indented("(End Key)", level + 1);
  1118. print_indented(m_end, level + 2);
  1119. print_indented("(Allows Interpolation)", level + 1);
  1120. print_indented(String::formatted("{}", m_allows_interpolation), level + 2);
  1121. print_indented("(Contents)", level + 1);
  1122. if (m_contents)
  1123. m_contents->dump(level + 2);
  1124. else
  1125. print_indented("(null)", level + 2);
  1126. }
  1127. RefPtr<Value> Heredoc::run(RefPtr<Shell> shell)
  1128. {
  1129. if (!m_deindent)
  1130. return m_contents->run(shell);
  1131. // To deindent, first split to lines...
  1132. auto value = m_contents->run(shell);
  1133. if (shell && shell->has_any_error())
  1134. return make_ref_counted<ListValue>({});
  1135. if (!value)
  1136. return value;
  1137. auto list = value->resolve_as_list(shell);
  1138. // The list better have one entry, otherwise we've put the wrong kind of node inside this heredoc
  1139. VERIFY(list.size() == 1);
  1140. auto lines = list.first().split_view('\n');
  1141. // Now just trim each line and put them back in a string
  1142. StringBuilder builder { list.first().length() };
  1143. for (auto& line : lines) {
  1144. builder.append(line.trim_whitespace(TrimMode::Left));
  1145. builder.append('\n');
  1146. }
  1147. return make_ref_counted<StringValue>(builder.to_string());
  1148. }
  1149. void Heredoc::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  1150. {
  1151. Line::Style content_style { Line::Style::Foreground(Line::Style::XtermColor::Yellow) };
  1152. if (metadata.is_first_in_list)
  1153. content_style.unify_with({ Line::Style::Bold });
  1154. if (!m_contents)
  1155. content_style.unify_with({ Line::Style::Foreground(Line::Style::XtermColor::Red) }, true);
  1156. editor.stylize({ m_position.start_offset, m_position.end_offset }, content_style);
  1157. if (m_contents)
  1158. m_contents->highlight_in_editor(editor, shell, metadata);
  1159. }
  1160. HitTestResult Heredoc::hit_test_position(size_t offset) const
  1161. {
  1162. if (!m_contents)
  1163. return {};
  1164. return m_contents->hit_test_position(offset);
  1165. }
  1166. Heredoc::Heredoc(Position position, String end, bool allow_interpolation, bool deindent)
  1167. : Node(move(position))
  1168. , m_end(move(end))
  1169. , m_allows_interpolation(allow_interpolation)
  1170. , m_deindent(deindent)
  1171. {
  1172. }
  1173. Heredoc::~Heredoc()
  1174. {
  1175. }
  1176. void HistoryEvent::dump(int level) const
  1177. {
  1178. Node::dump(level);
  1179. print_indented("Event Selector", level + 1);
  1180. switch (m_selector.event.kind) {
  1181. case HistorySelector::EventKind::IndexFromStart:
  1182. print_indented("IndexFromStart", level + 2);
  1183. break;
  1184. case HistorySelector::EventKind::IndexFromEnd:
  1185. print_indented("IndexFromEnd", level + 2);
  1186. break;
  1187. case HistorySelector::EventKind::ContainingStringLookup:
  1188. print_indented("ContainingStringLookup", level + 2);
  1189. break;
  1190. case HistorySelector::EventKind::StartingStringLookup:
  1191. print_indented("StartingStringLookup", level + 2);
  1192. break;
  1193. }
  1194. print_indented(String::formatted("{}({})", m_selector.event.index, m_selector.event.text), level + 3);
  1195. print_indented("Word Selector", level + 1);
  1196. auto print_word_selector = [&](const HistorySelector::WordSelector& selector) {
  1197. switch (selector.kind) {
  1198. case HistorySelector::WordSelectorKind::Index:
  1199. print_indented(String::formatted("Index {}", selector.selector), level + 3);
  1200. break;
  1201. case HistorySelector::WordSelectorKind::Last:
  1202. print_indented(String::formatted("Last"), level + 3);
  1203. break;
  1204. }
  1205. };
  1206. if (m_selector.word_selector_range.end.has_value()) {
  1207. print_indented("Range Start", level + 2);
  1208. print_word_selector(m_selector.word_selector_range.start);
  1209. print_indented("Range End", level + 2);
  1210. print_word_selector(m_selector.word_selector_range.end.value());
  1211. } else {
  1212. print_indented("Direct Address", level + 2);
  1213. print_word_selector(m_selector.word_selector_range.start);
  1214. }
  1215. }
  1216. RefPtr<Value> HistoryEvent::run(RefPtr<Shell> shell)
  1217. {
  1218. if (!shell)
  1219. return make_ref_counted<AST::ListValue>({});
  1220. auto editor = shell->editor();
  1221. if (!editor) {
  1222. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, "No history available!", position());
  1223. return make_ref_counted<AST::ListValue>({});
  1224. }
  1225. auto& history = editor->history();
  1226. // FIXME: Implement reverse iterators and find()?
  1227. auto find_reverse = [](auto it_start, auto it_end, auto finder) {
  1228. auto it = it_end;
  1229. while (it != it_start) {
  1230. --it;
  1231. if (finder(*it))
  1232. return it;
  1233. }
  1234. return it_end;
  1235. };
  1236. // First, resolve the event itself.
  1237. String resolved_history;
  1238. switch (m_selector.event.kind) {
  1239. case HistorySelector::EventKind::IndexFromStart:
  1240. if (m_selector.event.index >= history.size()) {
  1241. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, "History event index out of bounds", m_selector.event.text_position);
  1242. return make_ref_counted<AST::ListValue>({});
  1243. }
  1244. resolved_history = history[m_selector.event.index].entry;
  1245. break;
  1246. case HistorySelector::EventKind::IndexFromEnd:
  1247. if (m_selector.event.index >= history.size()) {
  1248. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, "History event index out of bounds", m_selector.event.text_position);
  1249. return make_ref_counted<AST::ListValue>({});
  1250. }
  1251. resolved_history = history[history.size() - m_selector.event.index - 1].entry;
  1252. break;
  1253. case HistorySelector::EventKind::ContainingStringLookup: {
  1254. auto it = find_reverse(history.begin(), history.end(), [&](auto& entry) { return entry.entry.contains(m_selector.event.text); });
  1255. if (it.is_end()) {
  1256. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, "History event did not match any entry", m_selector.event.text_position);
  1257. return make_ref_counted<AST::ListValue>({});
  1258. }
  1259. resolved_history = it->entry;
  1260. break;
  1261. }
  1262. case HistorySelector::EventKind::StartingStringLookup: {
  1263. auto it = find_reverse(history.begin(), history.end(), [&](auto& entry) { return entry.entry.starts_with(m_selector.event.text); });
  1264. if (it.is_end()) {
  1265. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, "History event did not match any entry", m_selector.event.text_position);
  1266. return make_ref_counted<AST::ListValue>({});
  1267. }
  1268. resolved_history = it->entry;
  1269. break;
  1270. }
  1271. }
  1272. // Then, split it up to "words".
  1273. auto nodes = Parser { resolved_history }.parse_as_multiple_expressions();
  1274. // Now take the "words" as described by the word selectors.
  1275. bool is_range = m_selector.word_selector_range.end.has_value();
  1276. if (is_range) {
  1277. auto start_index = m_selector.word_selector_range.start.resolve(nodes.size());
  1278. auto end_index = m_selector.word_selector_range.end->resolve(nodes.size());
  1279. if (start_index >= nodes.size()) {
  1280. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, "History word index out of bounds", m_selector.word_selector_range.start.position);
  1281. return make_ref_counted<AST::ListValue>({});
  1282. }
  1283. if (end_index >= nodes.size()) {
  1284. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, "History word index out of bounds", m_selector.word_selector_range.end->position);
  1285. return make_ref_counted<AST::ListValue>({});
  1286. }
  1287. decltype(nodes) resolved_nodes;
  1288. resolved_nodes.append(nodes.data() + start_index, end_index - start_index + 1);
  1289. NonnullRefPtr<AST::Node> list = make_ref_counted<AST::ListConcatenate>(position(), move(resolved_nodes));
  1290. return list->run(shell);
  1291. }
  1292. auto index = m_selector.word_selector_range.start.resolve(nodes.size());
  1293. if (index >= nodes.size()) {
  1294. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, "History word index out of bounds", m_selector.word_selector_range.start.position);
  1295. return make_ref_counted<AST::ListValue>({});
  1296. }
  1297. return nodes[index].run(shell);
  1298. }
  1299. void HistoryEvent::highlight_in_editor(Line::Editor& editor, Shell&, HighlightMetadata metadata)
  1300. {
  1301. Line::Style style { Line::Style::Foreground(Line::Style::XtermColor::Green) };
  1302. if (metadata.is_first_in_list)
  1303. style.unify_with({ Line::Style::Bold });
  1304. editor.stylize({ m_position.start_offset, m_position.end_offset }, move(style));
  1305. }
  1306. HistoryEvent::HistoryEvent(Position position, HistorySelector selector)
  1307. : Node(move(position))
  1308. , m_selector(move(selector))
  1309. {
  1310. if (m_selector.word_selector_range.start.syntax_error_node)
  1311. set_is_syntax_error(*m_selector.word_selector_range.start.syntax_error_node);
  1312. else if (m_selector.word_selector_range.end.has_value() && m_selector.word_selector_range.end->syntax_error_node)
  1313. set_is_syntax_error(*m_selector.word_selector_range.end->syntax_error_node);
  1314. }
  1315. HistoryEvent::~HistoryEvent()
  1316. {
  1317. }
  1318. void Execute::dump(int level) const
  1319. {
  1320. Node::dump(level);
  1321. if (m_capture_stdout)
  1322. print_indented("(Capturing stdout)", level + 1);
  1323. m_command->dump(level + 1);
  1324. }
  1325. void Execute::for_each_entry(RefPtr<Shell> shell, Function<IterationDecision(NonnullRefPtr<Value>)> callback)
  1326. {
  1327. if (m_command->would_execute())
  1328. return m_command->for_each_entry(shell, move(callback));
  1329. auto unexpanded_commands = m_command->run(shell)->resolve_as_commands(shell);
  1330. if (shell && shell->has_any_error())
  1331. return;
  1332. auto commands = shell->expand_aliases(move(unexpanded_commands));
  1333. if (m_capture_stdout) {
  1334. // Make sure that we're going to be running _something_.
  1335. auto has_one_command = false;
  1336. for (auto& command : commands) {
  1337. if (command.argv.is_empty() && !command.pipeline && command.next_chain.is_empty())
  1338. continue;
  1339. has_one_command = true;
  1340. break;
  1341. }
  1342. if (!has_one_command) {
  1343. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, "Cannot capture standard output when no command is being executed", m_position);
  1344. return;
  1345. }
  1346. int pipefd[2];
  1347. int rc = pipe(pipefd);
  1348. if (rc < 0) {
  1349. dbgln("Error: cannot pipe(): {}", strerror(errno));
  1350. return;
  1351. }
  1352. auto& last_in_commands = commands.last();
  1353. last_in_commands.redirections.prepend(FdRedirection::create(pipefd[1], STDOUT_FILENO, Rewiring::Close::Old));
  1354. last_in_commands.should_wait = false;
  1355. last_in_commands.should_notify_if_in_background = false;
  1356. last_in_commands.is_pipe_source = false;
  1357. Core::EventLoop loop;
  1358. auto notifier = Core::Notifier::construct(pipefd[0], Core::Notifier::Read);
  1359. DuplexMemoryStream stream;
  1360. enum {
  1361. Continue,
  1362. Break,
  1363. NothingLeft,
  1364. };
  1365. auto check_and_call = [&] {
  1366. auto ifs = shell->local_variable_or("IFS", "\n");
  1367. if (auto offset = stream.offset_of(ifs.bytes()); offset.has_value()) {
  1368. auto line_end = offset.value();
  1369. if (line_end == 0) {
  1370. auto rc = stream.discard_or_error(ifs.length());
  1371. VERIFY(rc);
  1372. if (shell->options.inline_exec_keep_empty_segments)
  1373. if (callback(make_ref_counted<StringValue>("")) == IterationDecision::Break) {
  1374. loop.quit(Break);
  1375. notifier->set_enabled(false);
  1376. return Break;
  1377. }
  1378. } else {
  1379. auto entry_result = ByteBuffer::create_uninitialized(line_end + ifs.length());
  1380. if (!entry_result.has_value()) {
  1381. loop.quit(Break);
  1382. notifier->set_enabled(false);
  1383. return Break;
  1384. }
  1385. auto entry = entry_result.release_value();
  1386. auto rc = stream.read_or_error(entry);
  1387. VERIFY(rc);
  1388. auto str = StringView(entry.data(), entry.size() - ifs.length());
  1389. if (callback(make_ref_counted<StringValue>(str)) == IterationDecision::Break) {
  1390. loop.quit(Break);
  1391. notifier->set_enabled(false);
  1392. return Break;
  1393. }
  1394. }
  1395. return Continue;
  1396. }
  1397. return NothingLeft;
  1398. };
  1399. notifier->on_ready_to_read = [&] {
  1400. constexpr static auto buffer_size = 16;
  1401. u8 buffer[buffer_size];
  1402. size_t remaining_size = buffer_size;
  1403. for (;;) {
  1404. notifier->set_event_mask(Core::Notifier::None);
  1405. bool should_enable_notifier = false;
  1406. ScopeGuard notifier_enabler { [&] {
  1407. if (should_enable_notifier)
  1408. notifier->set_event_mask(Core::Notifier::Read);
  1409. } };
  1410. if (check_and_call() == Break) {
  1411. loop.quit(Break);
  1412. return;
  1413. }
  1414. auto read_size = read(pipefd[0], buffer, remaining_size);
  1415. if (read_size < 0) {
  1416. int saved_errno = errno;
  1417. if (saved_errno == EINTR) {
  1418. should_enable_notifier = true;
  1419. continue;
  1420. }
  1421. if (saved_errno == 0)
  1422. continue;
  1423. dbgln("read() failed: {}", strerror(saved_errno));
  1424. break;
  1425. }
  1426. if (read_size == 0)
  1427. break;
  1428. should_enable_notifier = true;
  1429. stream.write({ buffer, (size_t)read_size });
  1430. }
  1431. loop.quit(NothingLeft);
  1432. };
  1433. auto jobs = shell->run_commands(commands);
  1434. ScopeGuard kill_jobs_if_around { [&] {
  1435. for (auto& job : jobs) {
  1436. if (job.is_running_in_background() && !job.exited() && !job.signaled()) {
  1437. job.set_should_announce_signal(false); // We're explicitly killing it here.
  1438. shell->kill_job(&job, SIGTERM);
  1439. }
  1440. }
  1441. } };
  1442. auto exit_reason = loop.exec();
  1443. notifier->on_ready_to_read = nullptr;
  1444. if (close(pipefd[0]) < 0) {
  1445. dbgln("close() failed: {}", strerror(errno));
  1446. }
  1447. if (exit_reason != Break && !stream.eof()) {
  1448. auto action = Continue;
  1449. do {
  1450. action = check_and_call();
  1451. if (action == Break)
  1452. return;
  1453. } while (action == Continue);
  1454. if (!stream.eof()) {
  1455. auto entry_result = ByteBuffer::create_uninitialized(stream.size());
  1456. if (!entry_result.has_value()) {
  1457. shell->raise_error(Shell::ShellError::OutOfMemory, {}, position());
  1458. return;
  1459. }
  1460. auto entry = entry_result.release_value();
  1461. auto rc = stream.read_or_error(entry);
  1462. VERIFY(rc);
  1463. callback(make_ref_counted<StringValue>(String::copy(entry)));
  1464. }
  1465. }
  1466. return;
  1467. }
  1468. auto jobs = shell->run_commands(commands);
  1469. if (!jobs.is_empty())
  1470. callback(make_ref_counted<JobValue>(&jobs.last()));
  1471. }
  1472. RefPtr<Value> Execute::run(RefPtr<Shell> shell)
  1473. {
  1474. if (shell && shell->has_any_error())
  1475. return make_ref_counted<ListValue>({});
  1476. if (m_command->would_execute())
  1477. return m_command->run(shell);
  1478. NonnullRefPtrVector<Value> values;
  1479. for_each_entry(shell, [&](auto value) {
  1480. values.append(*value);
  1481. return IterationDecision::Continue;
  1482. });
  1483. if (values.size() == 1 && values.first().is_job())
  1484. return values.first();
  1485. return make_ref_counted<ListValue>(move(values));
  1486. }
  1487. void Execute::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  1488. {
  1489. if (m_capture_stdout)
  1490. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Green) });
  1491. metadata.is_first_in_list = true;
  1492. m_command->highlight_in_editor(editor, shell, metadata);
  1493. }
  1494. HitTestResult Execute::hit_test_position(size_t offset) const
  1495. {
  1496. auto result = m_command->hit_test_position(offset);
  1497. if (!result.closest_node_with_semantic_meaning)
  1498. result.closest_node_with_semantic_meaning = this;
  1499. if (!result.closest_command_node)
  1500. result.closest_command_node = m_command;
  1501. return result;
  1502. }
  1503. Vector<Line::CompletionSuggestion> Execute::complete_for_editor(Shell& shell, size_t offset, const HitTestResult& hit_test_result)
  1504. {
  1505. auto matching_node = hit_test_result.matching_node;
  1506. if (!matching_node || !matching_node->is_bareword())
  1507. return {};
  1508. auto corrected_offset = offset - matching_node->position().start_offset;
  1509. auto* node = static_cast<BarewordLiteral*>(matching_node.ptr());
  1510. if (corrected_offset > node->text().length())
  1511. return {};
  1512. return shell.complete_program_name(node->text(), corrected_offset);
  1513. }
  1514. Execute::Execute(Position position, NonnullRefPtr<Node> command, bool capture_stdout)
  1515. : Node(move(position))
  1516. , m_command(move(command))
  1517. , m_capture_stdout(capture_stdout)
  1518. {
  1519. if (m_command->is_syntax_error())
  1520. set_is_syntax_error(m_command->syntax_error_node());
  1521. }
  1522. Execute::~Execute()
  1523. {
  1524. }
  1525. void IfCond::dump(int level) const
  1526. {
  1527. Node::dump(level);
  1528. print_indented("Condition", ++level);
  1529. m_condition->dump(level + 1);
  1530. print_indented("True Branch", level);
  1531. if (m_true_branch)
  1532. m_true_branch->dump(level + 1);
  1533. else
  1534. print_indented("(empty)", level + 1);
  1535. print_indented("False Branch", level);
  1536. if (m_false_branch)
  1537. m_false_branch->dump(level + 1);
  1538. else
  1539. print_indented("(empty)", level + 1);
  1540. }
  1541. RefPtr<Value> IfCond::run(RefPtr<Shell> shell)
  1542. {
  1543. auto cond = m_condition->run(shell)->resolve_without_cast(shell);
  1544. if (shell && shell->has_any_error())
  1545. return make_ref_counted<ListValue>({});
  1546. // The condition could be a builtin, in which case it has already run and exited.
  1547. if (cond->is_job()) {
  1548. auto cond_job_value = static_cast<const JobValue*>(cond.ptr());
  1549. auto cond_job = cond_job_value->job();
  1550. shell->block_on_job(cond_job);
  1551. }
  1552. if (shell->last_return_code == 0) {
  1553. if (m_true_branch)
  1554. return m_true_branch->run(shell);
  1555. } else {
  1556. if (m_false_branch)
  1557. return m_false_branch->run(shell);
  1558. }
  1559. return make_ref_counted<ListValue>({});
  1560. }
  1561. void IfCond::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  1562. {
  1563. metadata.is_first_in_list = true;
  1564. editor.stylize({ m_position.start_offset, m_position.start_offset + 2 }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
  1565. if (m_else_position.has_value())
  1566. editor.stylize({ m_else_position.value().start_offset, m_else_position.value().start_offset + 4 }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
  1567. m_condition->highlight_in_editor(editor, shell, metadata);
  1568. if (m_true_branch)
  1569. m_true_branch->highlight_in_editor(editor, shell, metadata);
  1570. if (m_false_branch)
  1571. m_false_branch->highlight_in_editor(editor, shell, metadata);
  1572. }
  1573. HitTestResult IfCond::hit_test_position(size_t offset) const
  1574. {
  1575. if (auto result = m_condition->hit_test_position(offset); result.matching_node)
  1576. return result;
  1577. if (m_true_branch) {
  1578. if (auto result = m_true_branch->hit_test_position(offset); result.matching_node)
  1579. return result;
  1580. }
  1581. if (m_false_branch) {
  1582. if (auto result = m_false_branch->hit_test_position(offset); result.matching_node)
  1583. return result;
  1584. }
  1585. return {};
  1586. }
  1587. IfCond::IfCond(Position position, Optional<Position> else_position, NonnullRefPtr<Node> condition, RefPtr<Node> true_branch, RefPtr<Node> false_branch)
  1588. : Node(move(position))
  1589. , m_condition(move(condition))
  1590. , m_true_branch(move(true_branch))
  1591. , m_false_branch(move(false_branch))
  1592. , m_else_position(move(else_position))
  1593. {
  1594. if (m_condition->is_syntax_error())
  1595. set_is_syntax_error(m_condition->syntax_error_node());
  1596. else if (m_true_branch && m_true_branch->is_syntax_error())
  1597. set_is_syntax_error(m_true_branch->syntax_error_node());
  1598. else if (m_false_branch && m_false_branch->is_syntax_error())
  1599. set_is_syntax_error(m_false_branch->syntax_error_node());
  1600. m_condition = make_ref_counted<AST::Execute>(m_condition->position(), m_condition);
  1601. if (m_true_branch) {
  1602. auto true_branch = m_true_branch.release_nonnull();
  1603. if (true_branch->is_execute())
  1604. m_true_branch = static_ptr_cast<AST::Execute>(true_branch)->command();
  1605. else
  1606. m_true_branch = move(true_branch);
  1607. }
  1608. if (m_false_branch) {
  1609. auto false_branch = m_false_branch.release_nonnull();
  1610. if (false_branch->is_execute())
  1611. m_false_branch = static_ptr_cast<AST::Execute>(false_branch)->command();
  1612. else
  1613. m_false_branch = move(false_branch);
  1614. }
  1615. }
  1616. IfCond::~IfCond()
  1617. {
  1618. }
  1619. void ImmediateExpression::dump(int level) const
  1620. {
  1621. Node::dump(level);
  1622. print_indented("(function)", level + 1);
  1623. print_indented(m_function.name, level + 2);
  1624. print_indented("(arguments)", level + 1);
  1625. for (auto& argument : arguments())
  1626. argument.dump(level + 2);
  1627. }
  1628. RefPtr<Value> ImmediateExpression::run(RefPtr<Shell> shell)
  1629. {
  1630. auto node = shell->run_immediate_function(m_function.name, *this, arguments());
  1631. if (node)
  1632. return node->run(shell);
  1633. return make_ref_counted<ListValue>({});
  1634. }
  1635. void ImmediateExpression::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  1636. {
  1637. // '${' - FIXME: This could also be '$\\\n{'
  1638. editor.stylize({ m_position.start_offset, m_position.start_offset + 2 }, { Line::Style::Foreground(Line::Style::XtermColor::Green) });
  1639. // Function name
  1640. Line::Style function_style { Line::Style::Foreground(Line::Style::XtermColor::Red) };
  1641. if (shell.has_immediate_function(function_name()))
  1642. function_style = { Line::Style::Foreground(Line::Style::XtermColor::Green) };
  1643. editor.stylize({ m_function.position.start_offset, m_function.position.end_offset }, move(function_style));
  1644. // Arguments
  1645. for (auto& argument : m_arguments) {
  1646. metadata.is_first_in_list = false;
  1647. argument.highlight_in_editor(editor, shell, metadata);
  1648. }
  1649. // Closing brace
  1650. if (m_closing_brace_position.has_value())
  1651. editor.stylize({ m_closing_brace_position->start_offset, m_closing_brace_position->end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Green) });
  1652. }
  1653. Vector<Line::CompletionSuggestion> ImmediateExpression::complete_for_editor(Shell& shell, size_t offset, const HitTestResult& hit_test_result)
  1654. {
  1655. auto matching_node = hit_test_result.matching_node;
  1656. if (!matching_node || matching_node != this)
  1657. return {};
  1658. auto corrected_offset = offset - m_function.position.start_offset;
  1659. if (corrected_offset > m_function.name.length())
  1660. return {};
  1661. return shell.complete_immediate_function_name(m_function.name, corrected_offset);
  1662. }
  1663. HitTestResult ImmediateExpression::hit_test_position(size_t offset) const
  1664. {
  1665. if (m_function.position.contains(offset))
  1666. return { this, this, this };
  1667. for (auto& argument : m_arguments) {
  1668. if (auto result = argument.hit_test_position(offset); result.matching_node)
  1669. return result;
  1670. }
  1671. return {};
  1672. }
  1673. ImmediateExpression::ImmediateExpression(Position position, NameWithPosition function, NonnullRefPtrVector<AST::Node> arguments, Optional<Position> closing_brace_position)
  1674. : Node(move(position))
  1675. , m_arguments(move(arguments))
  1676. , m_function(move(function))
  1677. , m_closing_brace_position(move(closing_brace_position))
  1678. {
  1679. if (is_syntax_error())
  1680. return;
  1681. for (auto& argument : m_arguments) {
  1682. if (argument.is_syntax_error()) {
  1683. set_is_syntax_error(argument.syntax_error_node());
  1684. return;
  1685. }
  1686. }
  1687. }
  1688. ImmediateExpression::~ImmediateExpression()
  1689. {
  1690. }
  1691. void Join::dump(int level) const
  1692. {
  1693. Node::dump(level);
  1694. m_left->dump(level + 1);
  1695. m_right->dump(level + 1);
  1696. }
  1697. RefPtr<Value> Join::run(RefPtr<Shell> shell)
  1698. {
  1699. auto left = m_left->to_lazy_evaluated_commands(shell);
  1700. if (shell && shell->has_any_error())
  1701. return make_ref_counted<ListValue>({});
  1702. if (left.last().should_wait && !left.last().next_chain.is_empty()) {
  1703. // Join (C0s*; C1) X -> (C0s*; Join C1 X)
  1704. auto& lhs_node = left.last().next_chain.last().node;
  1705. lhs_node = make_ref_counted<Join>(m_position, lhs_node, m_right);
  1706. return make_ref_counted<CommandSequenceValue>(move(left));
  1707. }
  1708. auto right = m_right->to_lazy_evaluated_commands(shell);
  1709. if (shell && shell->has_any_error())
  1710. return make_ref_counted<ListValue>({});
  1711. return make_ref_counted<CommandSequenceValue>(join_commands(move(left), move(right)));
  1712. }
  1713. void Join::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  1714. {
  1715. m_left->highlight_in_editor(editor, shell, metadata);
  1716. if (m_left->is_list() || m_left->is_command())
  1717. metadata.is_first_in_list = false;
  1718. m_right->highlight_in_editor(editor, shell, metadata);
  1719. }
  1720. HitTestResult Join::hit_test_position(size_t offset) const
  1721. {
  1722. auto result = m_left->hit_test_position(offset);
  1723. if (result.matching_node)
  1724. return result;
  1725. return m_right->hit_test_position(offset);
  1726. }
  1727. RefPtr<Node> Join::leftmost_trivial_literal() const
  1728. {
  1729. if (auto value = m_left->leftmost_trivial_literal())
  1730. return value;
  1731. return m_right->leftmost_trivial_literal();
  1732. }
  1733. Join::Join(Position position, NonnullRefPtr<Node> left, NonnullRefPtr<Node> right)
  1734. : Node(move(position))
  1735. , m_left(move(left))
  1736. , m_right(move(right))
  1737. {
  1738. if (m_left->is_syntax_error())
  1739. set_is_syntax_error(m_left->syntax_error_node());
  1740. else if (m_right->is_syntax_error())
  1741. set_is_syntax_error(m_right->syntax_error_node());
  1742. }
  1743. Join::~Join()
  1744. {
  1745. }
  1746. void MatchExpr::dump(int level) const
  1747. {
  1748. Node::dump(level);
  1749. print_indented(String::formatted("(expression: {})", m_expr_name.characters()), level + 1);
  1750. m_matched_expr->dump(level + 2);
  1751. print_indented(String::formatted("(named: {})", m_expr_name.characters()), level + 1);
  1752. print_indented("(entries)", level + 1);
  1753. for (auto& entry : m_entries) {
  1754. StringBuilder builder;
  1755. builder.append("(match");
  1756. if (entry.match_names.has_value()) {
  1757. builder.append(" to names (");
  1758. bool first = true;
  1759. for (auto& name : entry.match_names.value()) {
  1760. if (!first)
  1761. builder.append(' ');
  1762. first = false;
  1763. builder.append(name);
  1764. }
  1765. builder.append("))");
  1766. } else {
  1767. builder.append(')');
  1768. }
  1769. print_indented(builder.string_view(), level + 2);
  1770. for (auto& node : entry.options)
  1771. node.dump(level + 3);
  1772. print_indented("(execute)", level + 2);
  1773. if (entry.body)
  1774. entry.body->dump(level + 3);
  1775. else
  1776. print_indented("(nothing)", level + 3);
  1777. }
  1778. }
  1779. RefPtr<Value> MatchExpr::run(RefPtr<Shell> shell)
  1780. {
  1781. auto value = m_matched_expr->run(shell)->resolve_without_cast(shell);
  1782. if (shell && shell->has_any_error())
  1783. return make_ref_counted<ListValue>({});
  1784. auto list = value->resolve_as_list(shell);
  1785. auto list_matches = [&](auto&& pattern, auto& spans) {
  1786. if (pattern.size() != list.size())
  1787. return false;
  1788. for (size_t i = 0; i < pattern.size(); ++i) {
  1789. Vector<AK::MaskSpan> mask_spans;
  1790. if (!list[i].matches(pattern[i], mask_spans))
  1791. return false;
  1792. for (auto& span : mask_spans)
  1793. spans.append(list[i].substring(span.start, span.length));
  1794. }
  1795. return true;
  1796. };
  1797. auto resolve_pattern = [&](auto& option) {
  1798. Vector<String> pattern;
  1799. if (option.is_glob()) {
  1800. pattern.append(static_cast<const Glob*>(&option)->text());
  1801. } else if (option.is_bareword()) {
  1802. pattern.append(static_cast<const BarewordLiteral*>(&option)->text());
  1803. } else {
  1804. auto list = option.run(shell);
  1805. if (shell && shell->has_any_error())
  1806. return pattern;
  1807. option.for_each_entry(shell, [&](auto&& value) {
  1808. pattern.extend(value->resolve_as_list(nullptr)); // Note: 'nullptr' incurs special behavior,
  1809. // asking the node for a 'raw' value.
  1810. return IterationDecision::Continue;
  1811. });
  1812. }
  1813. return pattern;
  1814. };
  1815. auto frame = shell->push_frame(String::formatted("match ({})", this));
  1816. if (!m_expr_name.is_empty())
  1817. shell->set_local_variable(m_expr_name, value, true);
  1818. for (auto& entry : m_entries) {
  1819. for (auto& option : entry.options) {
  1820. Vector<String> spans;
  1821. if (list_matches(resolve_pattern(option), spans)) {
  1822. if (entry.body) {
  1823. if (entry.match_names.has_value()) {
  1824. size_t i = 0;
  1825. for (auto& name : entry.match_names.value()) {
  1826. if (spans.size() > i)
  1827. shell->set_local_variable(name, make_ref_counted<AST::StringValue>(spans[i]), true);
  1828. ++i;
  1829. }
  1830. }
  1831. return entry.body->run(shell);
  1832. } else {
  1833. return make_ref_counted<AST::ListValue>({});
  1834. }
  1835. }
  1836. }
  1837. }
  1838. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, "Non-exhaustive match rules!", position());
  1839. return make_ref_counted<AST::ListValue>({});
  1840. }
  1841. void MatchExpr::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  1842. {
  1843. editor.stylize({ m_position.start_offset, m_position.start_offset + 5 }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
  1844. if (m_as_position.has_value())
  1845. editor.stylize({ m_as_position.value().start_offset, m_as_position.value().end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
  1846. metadata.is_first_in_list = false;
  1847. m_matched_expr->highlight_in_editor(editor, shell, metadata);
  1848. for (auto& entry : m_entries) {
  1849. metadata.is_first_in_list = false;
  1850. for (auto& option : entry.options)
  1851. option.highlight_in_editor(editor, shell, metadata);
  1852. metadata.is_first_in_list = true;
  1853. if (entry.body)
  1854. entry.body->highlight_in_editor(editor, shell, metadata);
  1855. for (auto& position : entry.pipe_positions)
  1856. editor.stylize({ position.start_offset, position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
  1857. if (entry.match_as_position.has_value())
  1858. editor.stylize({ entry.match_as_position.value().start_offset, entry.match_as_position.value().end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
  1859. }
  1860. }
  1861. HitTestResult MatchExpr::hit_test_position(size_t offset) const
  1862. {
  1863. auto result = m_matched_expr->hit_test_position(offset);
  1864. if (result.matching_node)
  1865. return result;
  1866. for (auto& entry : m_entries) {
  1867. if (!entry.body)
  1868. continue;
  1869. auto result = entry.body->hit_test_position(offset);
  1870. if (result.matching_node)
  1871. return result;
  1872. }
  1873. return {};
  1874. }
  1875. MatchExpr::MatchExpr(Position position, NonnullRefPtr<Node> expr, String name, Optional<Position> as_position, Vector<MatchEntry> entries)
  1876. : Node(move(position))
  1877. , m_matched_expr(move(expr))
  1878. , m_expr_name(move(name))
  1879. , m_as_position(move(as_position))
  1880. , m_entries(move(entries))
  1881. {
  1882. if (m_matched_expr->is_syntax_error()) {
  1883. set_is_syntax_error(m_matched_expr->syntax_error_node());
  1884. } else {
  1885. for (auto& entry : m_entries) {
  1886. if (!entry.body)
  1887. continue;
  1888. if (entry.body->is_syntax_error()) {
  1889. set_is_syntax_error(entry.body->syntax_error_node());
  1890. break;
  1891. }
  1892. }
  1893. }
  1894. }
  1895. MatchExpr::~MatchExpr()
  1896. {
  1897. }
  1898. void Or::dump(int level) const
  1899. {
  1900. Node::dump(level);
  1901. m_left->dump(level + 1);
  1902. m_right->dump(level + 1);
  1903. }
  1904. RefPtr<Value> Or::run(RefPtr<Shell> shell)
  1905. {
  1906. auto commands = m_left->to_lazy_evaluated_commands(shell);
  1907. if (shell && shell->has_any_error())
  1908. return make_ref_counted<ListValue>({});
  1909. commands.last().next_chain.empend(*m_right, NodeWithAction::Or);
  1910. return make_ref_counted<CommandSequenceValue>(move(commands));
  1911. }
  1912. void Or::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  1913. {
  1914. m_left->highlight_in_editor(editor, shell, metadata);
  1915. m_right->highlight_in_editor(editor, shell, metadata);
  1916. }
  1917. HitTestResult Or::hit_test_position(size_t offset) const
  1918. {
  1919. auto result = m_left->hit_test_position(offset);
  1920. if (result.matching_node) {
  1921. if (!result.closest_command_node)
  1922. result.closest_command_node = m_right;
  1923. return result;
  1924. }
  1925. result = m_right->hit_test_position(offset);
  1926. if (!result.closest_command_node)
  1927. result.closest_command_node = m_right;
  1928. return result;
  1929. }
  1930. Or::Or(Position position, NonnullRefPtr<Node> left, NonnullRefPtr<Node> right, Position or_position)
  1931. : Node(move(position))
  1932. , m_left(move(left))
  1933. , m_right(move(right))
  1934. , m_or_position(or_position)
  1935. {
  1936. if (m_left->is_syntax_error())
  1937. set_is_syntax_error(m_left->syntax_error_node());
  1938. else if (m_right->is_syntax_error())
  1939. set_is_syntax_error(m_right->syntax_error_node());
  1940. }
  1941. Or::~Or()
  1942. {
  1943. }
  1944. void Pipe::dump(int level) const
  1945. {
  1946. Node::dump(level);
  1947. m_left->dump(level + 1);
  1948. m_right->dump(level + 1);
  1949. }
  1950. RefPtr<Value> Pipe::run(RefPtr<Shell> shell)
  1951. {
  1952. auto left = m_left->to_lazy_evaluated_commands(shell);
  1953. if (shell && shell->has_any_error())
  1954. return make_ref_counted<ListValue>({});
  1955. auto right = m_right->to_lazy_evaluated_commands(shell);
  1956. if (shell && shell->has_any_error())
  1957. return make_ref_counted<ListValue>({});
  1958. auto last_in_left = left.take_last();
  1959. auto first_in_right = right.take_first();
  1960. auto pipe_read_end = FdRedirection::create(-1, STDIN_FILENO, Rewiring::Close::Old);
  1961. auto pipe_write_end = FdRedirection::create(-1, STDOUT_FILENO, pipe_read_end, Rewiring::Close::RefreshOld);
  1962. auto insert_at_start_or_after_last_pipe = [&](auto& pipe, auto& command) {
  1963. size_t insert_index = 0;
  1964. auto& redirections = command.redirections;
  1965. for (ssize_t i = redirections.size() - 1; i >= 0; --i) {
  1966. auto& redirection = redirections[i];
  1967. if (!redirection.is_fd_redirection())
  1968. continue;
  1969. auto& fd_redirection = static_cast<FdRedirection&>(redirection);
  1970. if (fd_redirection.old_fd == -1) {
  1971. insert_index = i;
  1972. break;
  1973. }
  1974. }
  1975. redirections.insert(insert_index, pipe);
  1976. };
  1977. insert_at_start_or_after_last_pipe(pipe_read_end, first_in_right);
  1978. insert_at_start_or_after_last_pipe(pipe_write_end, last_in_left);
  1979. last_in_left.should_wait = false;
  1980. last_in_left.is_pipe_source = true;
  1981. if (first_in_right.pipeline) {
  1982. last_in_left.pipeline = first_in_right.pipeline;
  1983. } else {
  1984. auto pipeline = make_ref_counted<Pipeline>();
  1985. last_in_left.pipeline = pipeline;
  1986. first_in_right.pipeline = pipeline;
  1987. }
  1988. Vector<Command> commands;
  1989. commands.extend(left);
  1990. commands.append(last_in_left);
  1991. commands.append(first_in_right);
  1992. commands.extend(right);
  1993. return make_ref_counted<CommandSequenceValue>(move(commands));
  1994. }
  1995. void Pipe::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  1996. {
  1997. m_left->highlight_in_editor(editor, shell, metadata);
  1998. m_right->highlight_in_editor(editor, shell, metadata);
  1999. }
  2000. HitTestResult Pipe::hit_test_position(size_t offset) const
  2001. {
  2002. auto result = m_left->hit_test_position(offset);
  2003. if (result.matching_node) {
  2004. if (!result.closest_command_node)
  2005. result.closest_command_node = m_right;
  2006. return result;
  2007. }
  2008. result = m_right->hit_test_position(offset);
  2009. if (!result.closest_command_node)
  2010. result.closest_command_node = m_right;
  2011. return result;
  2012. }
  2013. Pipe::Pipe(Position position, NonnullRefPtr<Node> left, NonnullRefPtr<Node> right)
  2014. : Node(move(position))
  2015. , m_left(move(left))
  2016. , m_right(move(right))
  2017. {
  2018. if (m_left->is_syntax_error())
  2019. set_is_syntax_error(m_left->syntax_error_node());
  2020. else if (m_right->is_syntax_error())
  2021. set_is_syntax_error(m_right->syntax_error_node());
  2022. }
  2023. Pipe::~Pipe()
  2024. {
  2025. }
  2026. PathRedirectionNode::PathRedirectionNode(Position position, int fd, NonnullRefPtr<Node> path)
  2027. : Node(move(position))
  2028. , m_fd(fd)
  2029. , m_path(move(path))
  2030. {
  2031. }
  2032. void PathRedirectionNode::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  2033. {
  2034. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(0x87, 0x9b, 0xcd) }); // 25% Darkened Periwinkle
  2035. metadata.is_first_in_list = false;
  2036. m_path->highlight_in_editor(editor, shell, metadata);
  2037. if (m_path->is_bareword()) {
  2038. auto path_text = m_path->run(nullptr)->resolve_as_list(nullptr);
  2039. VERIFY(path_text.size() == 1);
  2040. // Apply a URL to the path.
  2041. auto& position = m_path->position();
  2042. auto& path = path_text[0];
  2043. if (!path.starts_with('/'))
  2044. path = String::formatted("{}/{}", shell.cwd, path);
  2045. auto url = URL::create_with_file_protocol(path);
  2046. url.set_host(shell.hostname);
  2047. editor.stylize({ position.start_offset, position.end_offset }, { Line::Style::Hyperlink(url.to_string()) });
  2048. }
  2049. }
  2050. HitTestResult PathRedirectionNode::hit_test_position(size_t offset) const
  2051. {
  2052. auto result = m_path->hit_test_position(offset);
  2053. if (!result.closest_node_with_semantic_meaning)
  2054. result.closest_node_with_semantic_meaning = this;
  2055. return result;
  2056. }
  2057. Vector<Line::CompletionSuggestion> PathRedirectionNode::complete_for_editor(Shell& shell, size_t offset, const HitTestResult& hit_test_result)
  2058. {
  2059. auto matching_node = hit_test_result.matching_node;
  2060. if (!matching_node || !matching_node->is_bareword())
  2061. return {};
  2062. auto corrected_offset = offset - matching_node->position().start_offset;
  2063. auto* node = static_cast<BarewordLiteral*>(matching_node.ptr());
  2064. if (corrected_offset > node->text().length())
  2065. return {};
  2066. return shell.complete_path("", node->text(), corrected_offset, Shell::ExecutableOnly::No);
  2067. }
  2068. PathRedirectionNode::~PathRedirectionNode()
  2069. {
  2070. }
  2071. void Range::dump(int level) const
  2072. {
  2073. Node::dump(level);
  2074. print_indented("(From)", level + 1);
  2075. m_start->dump(level + 2);
  2076. print_indented("(To)", level + 1);
  2077. m_end->dump(level + 2);
  2078. }
  2079. RefPtr<Value> Range::run(RefPtr<Shell> shell)
  2080. {
  2081. auto interpolate = [position = position()](RefPtr<Value> start, RefPtr<Value> end, RefPtr<Shell> shell) -> NonnullRefPtrVector<Value> {
  2082. NonnullRefPtrVector<Value> values;
  2083. if (start->is_string() && end->is_string()) {
  2084. auto start_str = start->resolve_as_list(shell)[0];
  2085. auto end_str = end->resolve_as_list(shell)[0];
  2086. Utf8View start_view { start_str }, end_view { end_str };
  2087. if (start_view.validate() && end_view.validate()) {
  2088. if (start_view.length() == 1 && end_view.length() == 1) {
  2089. // Interpolate between two code points.
  2090. auto start_code_point = *start_view.begin();
  2091. auto end_code_point = *end_view.begin();
  2092. auto step = start_code_point > end_code_point ? -1 : 1;
  2093. StringBuilder builder;
  2094. for (u32 code_point = start_code_point; code_point != end_code_point; code_point += step) {
  2095. builder.clear();
  2096. builder.append_code_point(code_point);
  2097. values.append(make_ref_counted<StringValue>(builder.to_string()));
  2098. }
  2099. // Append the ending code point too, most shells treat this as inclusive.
  2100. builder.clear();
  2101. builder.append_code_point(end_code_point);
  2102. values.append(make_ref_counted<StringValue>(builder.to_string()));
  2103. } else {
  2104. // Could be two numbers?
  2105. auto start_int = start_str.to_int();
  2106. auto end_int = end_str.to_int();
  2107. if (start_int.has_value() && end_int.has_value()) {
  2108. auto start = start_int.value();
  2109. auto end = end_int.value();
  2110. auto step = start > end ? -1 : 1;
  2111. for (int value = start; value != end; value += step)
  2112. values.append(make_ref_counted<StringValue>(String::number(value)));
  2113. // Append the range end too, most shells treat this as inclusive.
  2114. values.append(make_ref_counted<StringValue>(String::number(end)));
  2115. } else {
  2116. goto yield_start_end;
  2117. }
  2118. }
  2119. } else {
  2120. yield_start_end:;
  2121. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, String::formatted("Cannot interpolate between '{}' and '{}'!", start_str, end_str), position);
  2122. // We can't really interpolate between the two, so just yield both.
  2123. values.append(make_ref_counted<StringValue>(move(start_str)));
  2124. values.append(make_ref_counted<StringValue>(move(end_str)));
  2125. }
  2126. return values;
  2127. }
  2128. warnln("Shell: Cannot apply the requested interpolation");
  2129. return values;
  2130. };
  2131. auto start_value = m_start->run(shell);
  2132. if (shell && shell->has_any_error())
  2133. return make_ref_counted<ListValue>({});
  2134. auto end_value = m_end->run(shell);
  2135. if (shell && shell->has_any_error())
  2136. return make_ref_counted<ListValue>({});
  2137. if (!start_value || !end_value)
  2138. return make_ref_counted<ListValue>({});
  2139. return make_ref_counted<ListValue>(interpolate(*start_value, *end_value, shell));
  2140. }
  2141. void Range::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  2142. {
  2143. m_start->highlight_in_editor(editor, shell, metadata);
  2144. // Highlight the '..'
  2145. editor.stylize({ m_start->position().end_offset, m_end->position().start_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
  2146. metadata.is_first_in_list = false;
  2147. m_end->highlight_in_editor(editor, shell, metadata);
  2148. }
  2149. HitTestResult Range::hit_test_position(size_t offset) const
  2150. {
  2151. auto result = m_start->hit_test_position(offset);
  2152. if (result.matching_node) {
  2153. if (!result.closest_command_node)
  2154. result.closest_command_node = m_start;
  2155. return result;
  2156. }
  2157. result = m_end->hit_test_position(offset);
  2158. if (!result.closest_command_node)
  2159. result.closest_command_node = m_end;
  2160. return result;
  2161. }
  2162. Range::Range(Position position, NonnullRefPtr<Node> start, NonnullRefPtr<Node> end)
  2163. : Node(move(position))
  2164. , m_start(move(start))
  2165. , m_end(move(end))
  2166. {
  2167. if (m_start->is_syntax_error())
  2168. set_is_syntax_error(m_start->syntax_error_node());
  2169. else if (m_end->is_syntax_error())
  2170. set_is_syntax_error(m_end->syntax_error_node());
  2171. }
  2172. Range::~Range()
  2173. {
  2174. }
  2175. void ReadRedirection::dump(int level) const
  2176. {
  2177. Node::dump(level);
  2178. m_path->dump(level + 1);
  2179. print_indented(String::formatted("To {}", m_fd), level + 1);
  2180. }
  2181. RefPtr<Value> ReadRedirection::run(RefPtr<Shell> shell)
  2182. {
  2183. Command command;
  2184. auto path_segments = m_path->run(shell)->resolve_as_list(shell);
  2185. if (shell && shell->has_any_error())
  2186. return make_ref_counted<ListValue>({});
  2187. StringBuilder builder;
  2188. builder.join(" ", path_segments);
  2189. command.redirections.append(PathRedirection::create(builder.to_string(), m_fd, PathRedirection::Read));
  2190. return make_ref_counted<CommandValue>(move(command));
  2191. }
  2192. ReadRedirection::ReadRedirection(Position position, int fd, NonnullRefPtr<Node> path)
  2193. : PathRedirectionNode(move(position), fd, move(path))
  2194. {
  2195. }
  2196. ReadRedirection::~ReadRedirection()
  2197. {
  2198. }
  2199. void ReadWriteRedirection::dump(int level) const
  2200. {
  2201. Node::dump(level);
  2202. m_path->dump(level + 1);
  2203. print_indented(String::formatted("To/From {}", m_fd), level + 1);
  2204. }
  2205. RefPtr<Value> ReadWriteRedirection::run(RefPtr<Shell> shell)
  2206. {
  2207. Command command;
  2208. auto path_segments = m_path->run(shell)->resolve_as_list(shell);
  2209. if (shell && shell->has_any_error())
  2210. return make_ref_counted<ListValue>({});
  2211. StringBuilder builder;
  2212. builder.join(" ", path_segments);
  2213. command.redirections.append(PathRedirection::create(builder.to_string(), m_fd, PathRedirection::ReadWrite));
  2214. return make_ref_counted<CommandValue>(move(command));
  2215. }
  2216. ReadWriteRedirection::ReadWriteRedirection(Position position, int fd, NonnullRefPtr<Node> path)
  2217. : PathRedirectionNode(move(position), fd, move(path))
  2218. {
  2219. }
  2220. ReadWriteRedirection::~ReadWriteRedirection()
  2221. {
  2222. }
  2223. void Sequence::dump(int level) const
  2224. {
  2225. Node::dump(level);
  2226. for (auto& entry : m_entries)
  2227. entry.dump(level + 1);
  2228. }
  2229. RefPtr<Value> Sequence::run(RefPtr<Shell> shell)
  2230. {
  2231. Vector<Command> all_commands;
  2232. Command* last_command_in_sequence = nullptr;
  2233. for (auto& entry : m_entries) {
  2234. if (shell && shell->has_any_error())
  2235. break;
  2236. if (!last_command_in_sequence) {
  2237. auto commands = entry.to_lazy_evaluated_commands(shell);
  2238. all_commands.extend(move(commands));
  2239. last_command_in_sequence = &all_commands.last();
  2240. continue;
  2241. }
  2242. if (last_command_in_sequence->should_wait) {
  2243. last_command_in_sequence->next_chain.append(NodeWithAction { entry, NodeWithAction::Sequence });
  2244. } else {
  2245. all_commands.extend(entry.to_lazy_evaluated_commands(shell));
  2246. last_command_in_sequence = &all_commands.last();
  2247. }
  2248. }
  2249. return make_ref_counted<CommandSequenceValue>(move(all_commands));
  2250. }
  2251. void Sequence::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  2252. {
  2253. for (auto& entry : m_entries)
  2254. entry.highlight_in_editor(editor, shell, metadata);
  2255. }
  2256. HitTestResult Sequence::hit_test_position(size_t offset) const
  2257. {
  2258. for (auto& entry : m_entries) {
  2259. auto result = entry.hit_test_position(offset);
  2260. if (result.matching_node) {
  2261. if (!result.closest_command_node)
  2262. result.closest_command_node = entry;
  2263. return result;
  2264. }
  2265. }
  2266. return {};
  2267. }
  2268. Sequence::Sequence(Position position, NonnullRefPtrVector<Node> entries, Vector<Position> separator_positions)
  2269. : Node(move(position))
  2270. , m_entries(move(entries))
  2271. , m_separator_positions(separator_positions)
  2272. {
  2273. for (auto& entry : m_entries) {
  2274. if (entry.is_syntax_error()) {
  2275. set_is_syntax_error(entry.syntax_error_node());
  2276. break;
  2277. }
  2278. }
  2279. }
  2280. Sequence::~Sequence()
  2281. {
  2282. }
  2283. void Subshell::dump(int level) const
  2284. {
  2285. Node::dump(level);
  2286. if (m_block)
  2287. m_block->dump(level + 1);
  2288. }
  2289. RefPtr<Value> Subshell::run(RefPtr<Shell> shell)
  2290. {
  2291. if (!m_block)
  2292. return make_ref_counted<ListValue>({});
  2293. return make_ref_counted<AST::CommandSequenceValue>(m_block->to_lazy_evaluated_commands(shell));
  2294. }
  2295. void Subshell::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  2296. {
  2297. metadata.is_first_in_list = true;
  2298. if (m_block)
  2299. m_block->highlight_in_editor(editor, shell, metadata);
  2300. }
  2301. HitTestResult Subshell::hit_test_position(size_t offset) const
  2302. {
  2303. if (m_block)
  2304. return m_block->hit_test_position(offset);
  2305. return {};
  2306. }
  2307. Subshell::Subshell(Position position, RefPtr<Node> block)
  2308. : Node(move(position))
  2309. , m_block(block)
  2310. {
  2311. if (m_block && m_block->is_syntax_error())
  2312. set_is_syntax_error(m_block->syntax_error_node());
  2313. }
  2314. Subshell::~Subshell()
  2315. {
  2316. }
  2317. void Slice::dump(int level) const
  2318. {
  2319. Node::dump(level);
  2320. m_selector->dump(level + 1);
  2321. }
  2322. RefPtr<Value> Slice::run(RefPtr<Shell> shell)
  2323. {
  2324. return m_selector->run(shell);
  2325. }
  2326. void Slice::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  2327. {
  2328. m_selector->highlight_in_editor(editor, shell, metadata);
  2329. }
  2330. HitTestResult Slice::hit_test_position(size_t offset) const
  2331. {
  2332. return m_selector->hit_test_position(offset);
  2333. }
  2334. Vector<Line::CompletionSuggestion> Slice::complete_for_editor(Shell& shell, size_t offset, const HitTestResult& hit_test_result)
  2335. {
  2336. // TODO: Maybe intercept this, and suggest values in range?
  2337. return m_selector->complete_for_editor(shell, offset, hit_test_result);
  2338. }
  2339. Slice::Slice(Position position, NonnullRefPtr<AST::Node> selector)
  2340. : Node(move(position))
  2341. , m_selector(move(selector))
  2342. {
  2343. if (m_selector->is_syntax_error())
  2344. set_is_syntax_error(m_selector->syntax_error_node());
  2345. }
  2346. Slice::~Slice()
  2347. {
  2348. }
  2349. void SimpleVariable::dump(int level) const
  2350. {
  2351. Node::dump(level);
  2352. print_indented("(Name)", level + 1);
  2353. print_indented(m_name, level + 2);
  2354. print_indented("(Slice)", level + 1);
  2355. if (m_slice)
  2356. m_slice->dump(level + 2);
  2357. else
  2358. print_indented("(None)", level + 2);
  2359. }
  2360. RefPtr<Value> SimpleVariable::run(RefPtr<Shell>)
  2361. {
  2362. NonnullRefPtr<Value> value = make_ref_counted<SimpleVariableValue>(m_name);
  2363. if (m_slice)
  2364. value = value->with_slices(*m_slice);
  2365. return value;
  2366. }
  2367. void SimpleVariable::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  2368. {
  2369. Line::Style style { Line::Style::Foreground(214, 112, 214) };
  2370. if (metadata.is_first_in_list)
  2371. style.unify_with({ Line::Style::Bold });
  2372. editor.stylize({ m_position.start_offset, m_position.end_offset }, move(style));
  2373. if (m_slice)
  2374. m_slice->highlight_in_editor(editor, shell, metadata);
  2375. }
  2376. HitTestResult SimpleVariable::hit_test_position(size_t offset) const
  2377. {
  2378. if (m_slice && m_slice->position().contains(offset))
  2379. return m_slice->hit_test_position(offset);
  2380. return { this, this, nullptr };
  2381. }
  2382. Vector<Line::CompletionSuggestion> SimpleVariable::complete_for_editor(Shell& shell, size_t offset, const HitTestResult& hit_test_result)
  2383. {
  2384. auto matching_node = hit_test_result.matching_node;
  2385. if (!matching_node)
  2386. return {};
  2387. if (matching_node != this)
  2388. return {};
  2389. auto corrected_offset = offset - matching_node->position().start_offset - 1;
  2390. if (corrected_offset > m_name.length() + 1)
  2391. return {};
  2392. return shell.complete_variable(m_name, corrected_offset);
  2393. }
  2394. SimpleVariable::SimpleVariable(Position position, String name)
  2395. : VariableNode(move(position))
  2396. , m_name(move(name))
  2397. {
  2398. }
  2399. SimpleVariable::~SimpleVariable()
  2400. {
  2401. }
  2402. void SpecialVariable::dump(int level) const
  2403. {
  2404. Node::dump(level);
  2405. print_indented("(Name)", level + 1);
  2406. print_indented(String { &m_name, 1 }, level + 1);
  2407. print_indented("(Slice)", level + 1);
  2408. if (m_slice)
  2409. m_slice->dump(level + 2);
  2410. else
  2411. print_indented("(None)", level + 2);
  2412. }
  2413. RefPtr<Value> SpecialVariable::run(RefPtr<Shell>)
  2414. {
  2415. NonnullRefPtr<Value> value = make_ref_counted<SpecialVariableValue>(m_name);
  2416. if (m_slice)
  2417. value = value->with_slices(*m_slice);
  2418. return value;
  2419. }
  2420. void SpecialVariable::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  2421. {
  2422. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(214, 112, 214) });
  2423. if (m_slice)
  2424. m_slice->highlight_in_editor(editor, shell, metadata);
  2425. }
  2426. Vector<Line::CompletionSuggestion> SpecialVariable::complete_for_editor(Shell&, size_t, const HitTestResult&)
  2427. {
  2428. return {};
  2429. }
  2430. HitTestResult SpecialVariable::hit_test_position(size_t offset) const
  2431. {
  2432. if (m_slice && m_slice->position().contains(offset))
  2433. return m_slice->hit_test_position(offset);
  2434. return { this, this, nullptr };
  2435. }
  2436. SpecialVariable::SpecialVariable(Position position, char name)
  2437. : VariableNode(move(position))
  2438. , m_name(name)
  2439. {
  2440. }
  2441. SpecialVariable::~SpecialVariable()
  2442. {
  2443. }
  2444. void Juxtaposition::dump(int level) const
  2445. {
  2446. Node::dump(level);
  2447. m_left->dump(level + 1);
  2448. m_right->dump(level + 1);
  2449. }
  2450. RefPtr<Value> Juxtaposition::run(RefPtr<Shell> shell)
  2451. {
  2452. auto left_value = m_left->run(shell)->resolve_without_cast(shell);
  2453. if (shell && shell->has_any_error())
  2454. return make_ref_counted<ListValue>({});
  2455. auto right_value = m_right->run(shell)->resolve_without_cast(shell);
  2456. if (shell && shell->has_any_error())
  2457. return make_ref_counted<ListValue>({});
  2458. auto left = left_value->resolve_as_list(shell);
  2459. auto right = right_value->resolve_as_list(shell);
  2460. if (left_value->is_string() && right_value->is_string()) {
  2461. VERIFY(left.size() == 1);
  2462. VERIFY(right.size() == 1);
  2463. StringBuilder builder;
  2464. builder.append(left[0]);
  2465. builder.append(right[0]);
  2466. return make_ref_counted<StringValue>(builder.to_string());
  2467. }
  2468. // Otherwise, treat them as lists and create a list product.
  2469. if (left.is_empty() || right.is_empty())
  2470. return make_ref_counted<ListValue>({});
  2471. Vector<String> result;
  2472. result.ensure_capacity(left.size() * right.size());
  2473. StringBuilder builder;
  2474. for (auto& left_element : left) {
  2475. for (auto& right_element : right) {
  2476. builder.append(left_element);
  2477. builder.append(right_element);
  2478. result.append(builder.to_string());
  2479. builder.clear();
  2480. }
  2481. }
  2482. return make_ref_counted<ListValue>(move(result));
  2483. }
  2484. void Juxtaposition::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  2485. {
  2486. m_left->highlight_in_editor(editor, shell, metadata);
  2487. // '~/foo/bar' is special, we have to actually resolve the tilde
  2488. // since that resolution is a pure operation, we can just go ahead
  2489. // and do it to get the value :)
  2490. if (m_right->is_bareword() && m_left->is_tilde()) {
  2491. auto tilde_value = m_left->run(shell)->resolve_as_list(shell)[0];
  2492. auto bareword_value = m_right->run(shell)->resolve_as_list(shell)[0];
  2493. StringBuilder path_builder;
  2494. path_builder.append(tilde_value);
  2495. path_builder.append("/");
  2496. path_builder.append(bareword_value);
  2497. auto path = path_builder.to_string();
  2498. if (Core::File::exists(path)) {
  2499. auto realpath = shell.resolve_path(path);
  2500. auto url = URL::create_with_file_protocol(realpath);
  2501. url.set_host(shell.hostname);
  2502. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Hyperlink(url.to_string()) });
  2503. }
  2504. } else {
  2505. m_right->highlight_in_editor(editor, shell, metadata);
  2506. }
  2507. }
  2508. Vector<Line::CompletionSuggestion> Juxtaposition::complete_for_editor(Shell& shell, size_t offset, const HitTestResult& hit_test_result)
  2509. {
  2510. auto matching_node = hit_test_result.matching_node;
  2511. // '~/foo/bar' is special, we have to actually resolve the tilde
  2512. // then complete the bareword with that path prefix.
  2513. if (m_right->is_bareword() && m_left->is_tilde()) {
  2514. auto tilde_value = m_left->run(shell)->resolve_as_list(shell)[0];
  2515. auto corrected_offset = offset - matching_node->position().start_offset;
  2516. auto* node = static_cast<BarewordLiteral*>(matching_node.ptr());
  2517. if (corrected_offset > node->text().length())
  2518. return {};
  2519. auto text = node->text().substring(1, node->text().length() - 1);
  2520. return shell.complete_path(tilde_value, text, corrected_offset - 1, Shell::ExecutableOnly::No);
  2521. }
  2522. return Node::complete_for_editor(shell, offset, hit_test_result);
  2523. }
  2524. HitTestResult Juxtaposition::hit_test_position(size_t offset) const
  2525. {
  2526. auto result = m_left->hit_test_position(offset);
  2527. if (!result.closest_node_with_semantic_meaning)
  2528. result.closest_node_with_semantic_meaning = this;
  2529. if (result.matching_node)
  2530. return result;
  2531. result = m_right->hit_test_position(offset);
  2532. if (!result.closest_node_with_semantic_meaning)
  2533. result.closest_node_with_semantic_meaning = this;
  2534. return result;
  2535. }
  2536. Juxtaposition::Juxtaposition(Position position, NonnullRefPtr<Node> left, NonnullRefPtr<Node> right)
  2537. : Node(move(position))
  2538. , m_left(move(left))
  2539. , m_right(move(right))
  2540. {
  2541. if (m_left->is_syntax_error())
  2542. set_is_syntax_error(m_left->syntax_error_node());
  2543. else if (m_right->is_syntax_error())
  2544. set_is_syntax_error(m_right->syntax_error_node());
  2545. }
  2546. Juxtaposition::~Juxtaposition()
  2547. {
  2548. }
  2549. void StringLiteral::dump(int level) const
  2550. {
  2551. Node::dump(level);
  2552. print_indented(m_text, level + 1);
  2553. }
  2554. RefPtr<Value> StringLiteral::run(RefPtr<Shell>)
  2555. {
  2556. return make_ref_counted<StringValue>(m_text);
  2557. }
  2558. void StringLiteral::highlight_in_editor(Line::Editor& editor, Shell&, HighlightMetadata metadata)
  2559. {
  2560. if (m_text.is_empty())
  2561. return;
  2562. Line::Style style { Line::Style::Foreground(Line::Style::XtermColor::Yellow) };
  2563. if (metadata.is_first_in_list)
  2564. style.unify_with({ Line::Style::Bold });
  2565. editor.stylize({ m_position.start_offset, m_position.end_offset }, move(style));
  2566. }
  2567. StringLiteral::StringLiteral(Position position, String text)
  2568. : Node(move(position))
  2569. , m_text(move(text))
  2570. {
  2571. }
  2572. StringLiteral::~StringLiteral()
  2573. {
  2574. }
  2575. void StringPartCompose::dump(int level) const
  2576. {
  2577. Node::dump(level);
  2578. m_left->dump(level + 1);
  2579. m_right->dump(level + 1);
  2580. }
  2581. RefPtr<Value> StringPartCompose::run(RefPtr<Shell> shell)
  2582. {
  2583. auto left = m_left->run(shell)->resolve_as_list(shell);
  2584. if (shell && shell->has_any_error())
  2585. return make_ref_counted<ListValue>({});
  2586. auto right = m_right->run(shell)->resolve_as_list(shell);
  2587. if (shell && shell->has_any_error())
  2588. return make_ref_counted<ListValue>({});
  2589. StringBuilder builder;
  2590. builder.join(" ", left);
  2591. builder.join(" ", right);
  2592. return make_ref_counted<StringValue>(builder.to_string());
  2593. }
  2594. void StringPartCompose::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  2595. {
  2596. m_left->highlight_in_editor(editor, shell, metadata);
  2597. m_right->highlight_in_editor(editor, shell, metadata);
  2598. }
  2599. HitTestResult StringPartCompose::hit_test_position(size_t offset) const
  2600. {
  2601. auto result = m_left->hit_test_position(offset);
  2602. if (result.matching_node)
  2603. return result;
  2604. return m_right->hit_test_position(offset);
  2605. }
  2606. StringPartCompose::StringPartCompose(Position position, NonnullRefPtr<Node> left, NonnullRefPtr<Node> right)
  2607. : Node(move(position))
  2608. , m_left(move(left))
  2609. , m_right(move(right))
  2610. {
  2611. if (m_left->is_syntax_error())
  2612. set_is_syntax_error(m_left->syntax_error_node());
  2613. else if (m_right->is_syntax_error())
  2614. set_is_syntax_error(m_right->syntax_error_node());
  2615. }
  2616. StringPartCompose::~StringPartCompose()
  2617. {
  2618. }
  2619. void SyntaxError::dump(int level) const
  2620. {
  2621. Node::dump(level);
  2622. print_indented("(Error text)", level + 1);
  2623. print_indented(m_syntax_error_text, level + 2);
  2624. print_indented("(Can be recovered from)", level + 1);
  2625. print_indented(String::formatted("{}", m_is_continuable), level + 2);
  2626. }
  2627. RefPtr<Value> SyntaxError::run(RefPtr<Shell> shell)
  2628. {
  2629. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, m_syntax_error_text, position());
  2630. return make_ref_counted<StringValue>("");
  2631. }
  2632. void SyntaxError::highlight_in_editor(Line::Editor& editor, Shell&, HighlightMetadata)
  2633. {
  2634. editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Red), Line::Style::Bold });
  2635. }
  2636. SyntaxError::SyntaxError(Position position, String error, bool is_continuable)
  2637. : Node(move(position))
  2638. , m_syntax_error_text(move(error))
  2639. , m_is_continuable(is_continuable)
  2640. {
  2641. }
  2642. const SyntaxError& SyntaxError::syntax_error_node() const
  2643. {
  2644. return *this;
  2645. }
  2646. SyntaxError::~SyntaxError()
  2647. {
  2648. }
  2649. void SyntheticNode::dump(int level) const
  2650. {
  2651. Node::dump(level);
  2652. }
  2653. RefPtr<Value> SyntheticNode::run(RefPtr<Shell>)
  2654. {
  2655. return m_value;
  2656. }
  2657. void SyntheticNode::highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata)
  2658. {
  2659. }
  2660. SyntheticNode::SyntheticNode(Position position, NonnullRefPtr<Value> value)
  2661. : Node(move(position))
  2662. , m_value(move(value))
  2663. {
  2664. }
  2665. void Tilde::dump(int level) const
  2666. {
  2667. Node::dump(level);
  2668. print_indented(m_username, level + 1);
  2669. }
  2670. RefPtr<Value> Tilde::run(RefPtr<Shell>)
  2671. {
  2672. return make_ref_counted<TildeValue>(m_username);
  2673. }
  2674. void Tilde::highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata)
  2675. {
  2676. }
  2677. HitTestResult Tilde::hit_test_position(size_t offset) const
  2678. {
  2679. if (!position().contains(offset))
  2680. return {};
  2681. return { this, this, nullptr };
  2682. }
  2683. Vector<Line::CompletionSuggestion> Tilde::complete_for_editor(Shell& shell, size_t offset, const HitTestResult& hit_test_result)
  2684. {
  2685. auto matching_node = hit_test_result.matching_node;
  2686. if (!matching_node)
  2687. return {};
  2688. if (matching_node != this)
  2689. return {};
  2690. auto corrected_offset = offset - matching_node->position().start_offset - 1;
  2691. if (corrected_offset > m_username.length() + 1)
  2692. return {};
  2693. return shell.complete_user(m_username, corrected_offset);
  2694. }
  2695. String Tilde::text() const
  2696. {
  2697. StringBuilder builder;
  2698. builder.append('~');
  2699. builder.append(m_username);
  2700. return builder.to_string();
  2701. }
  2702. Tilde::Tilde(Position position, String username)
  2703. : Node(move(position))
  2704. , m_username(move(username))
  2705. {
  2706. }
  2707. Tilde::~Tilde()
  2708. {
  2709. }
  2710. void WriteAppendRedirection::dump(int level) const
  2711. {
  2712. Node::dump(level);
  2713. m_path->dump(level + 1);
  2714. print_indented(String::formatted("From {}", m_fd), level + 1);
  2715. }
  2716. RefPtr<Value> WriteAppendRedirection::run(RefPtr<Shell> shell)
  2717. {
  2718. Command command;
  2719. auto path_segments = m_path->run(shell)->resolve_as_list(shell);
  2720. if (shell && shell->has_any_error())
  2721. return make_ref_counted<ListValue>({});
  2722. StringBuilder builder;
  2723. builder.join(" ", path_segments);
  2724. command.redirections.append(PathRedirection::create(builder.to_string(), m_fd, PathRedirection::WriteAppend));
  2725. return make_ref_counted<CommandValue>(move(command));
  2726. }
  2727. WriteAppendRedirection::WriteAppendRedirection(Position position, int fd, NonnullRefPtr<Node> path)
  2728. : PathRedirectionNode(move(position), fd, move(path))
  2729. {
  2730. }
  2731. WriteAppendRedirection::~WriteAppendRedirection()
  2732. {
  2733. }
  2734. void WriteRedirection::dump(int level) const
  2735. {
  2736. Node::dump(level);
  2737. m_path->dump(level + 1);
  2738. print_indented(String::formatted("From {}", m_fd), level + 1);
  2739. }
  2740. RefPtr<Value> WriteRedirection::run(RefPtr<Shell> shell)
  2741. {
  2742. Command command;
  2743. auto path_segments = m_path->run(shell)->resolve_as_list(shell);
  2744. if (shell && shell->has_any_error())
  2745. return make_ref_counted<ListValue>({});
  2746. StringBuilder builder;
  2747. builder.join(" ", path_segments);
  2748. command.redirections.append(PathRedirection::create(builder.to_string(), m_fd, PathRedirection::Write));
  2749. return make_ref_counted<CommandValue>(move(command));
  2750. }
  2751. WriteRedirection::WriteRedirection(Position position, int fd, NonnullRefPtr<Node> path)
  2752. : PathRedirectionNode(move(position), fd, move(path))
  2753. {
  2754. }
  2755. WriteRedirection::~WriteRedirection()
  2756. {
  2757. }
  2758. void VariableDeclarations::dump(int level) const
  2759. {
  2760. Node::dump(level);
  2761. for (auto& var : m_variables) {
  2762. print_indented("Set", level + 1);
  2763. var.name->dump(level + 2);
  2764. var.value->dump(level + 2);
  2765. }
  2766. }
  2767. RefPtr<Value> VariableDeclarations::run(RefPtr<Shell> shell)
  2768. {
  2769. for (auto& var : m_variables) {
  2770. auto name_value = var.name->run(shell)->resolve_as_list(shell);
  2771. if (shell && shell->has_any_error())
  2772. break;
  2773. VERIFY(name_value.size() == 1);
  2774. auto name = name_value[0];
  2775. auto value = var.value->run(shell);
  2776. if (shell && shell->has_any_error())
  2777. break;
  2778. shell->set_local_variable(name, value.release_nonnull());
  2779. }
  2780. return make_ref_counted<ListValue>({});
  2781. }
  2782. void VariableDeclarations::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
  2783. {
  2784. metadata.is_first_in_list = false;
  2785. for (auto& var : m_variables) {
  2786. var.name->highlight_in_editor(editor, shell, metadata);
  2787. // Highlight the '='.
  2788. editor.stylize({ var.name->position().end_offset - 1, var.name->position().end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Blue) });
  2789. var.value->highlight_in_editor(editor, shell, metadata);
  2790. }
  2791. }
  2792. HitTestResult VariableDeclarations::hit_test_position(size_t offset) const
  2793. {
  2794. for (auto decl : m_variables) {
  2795. auto result = decl.value->hit_test_position(offset);
  2796. if (result.matching_node)
  2797. return result;
  2798. }
  2799. return { nullptr, nullptr, nullptr };
  2800. }
  2801. VariableDeclarations::VariableDeclarations(Position position, Vector<Variable> variables)
  2802. : Node(move(position))
  2803. , m_variables(move(variables))
  2804. {
  2805. for (auto& decl : m_variables) {
  2806. if (decl.name->is_syntax_error()) {
  2807. set_is_syntax_error(decl.name->syntax_error_node());
  2808. break;
  2809. }
  2810. if (decl.value->is_syntax_error()) {
  2811. set_is_syntax_error(decl.value->syntax_error_node());
  2812. break;
  2813. }
  2814. }
  2815. }
  2816. VariableDeclarations::~VariableDeclarations()
  2817. {
  2818. }
  2819. Value::~Value()
  2820. {
  2821. }
  2822. Vector<AST::Command> Value::resolve_as_commands(RefPtr<Shell> shell)
  2823. {
  2824. Command command;
  2825. command.argv = resolve_as_list(shell);
  2826. return { command };
  2827. }
  2828. ListValue::ListValue(Vector<String> values)
  2829. {
  2830. if (values.is_empty())
  2831. return;
  2832. m_contained_values.ensure_capacity(values.size());
  2833. for (auto& str : values)
  2834. m_contained_values.append(adopt_ref(*new StringValue(move(str))));
  2835. }
  2836. NonnullRefPtr<Value> Value::with_slices(NonnullRefPtr<Slice> slice) const&
  2837. {
  2838. auto value = clone();
  2839. value->m_slices.append(move(slice));
  2840. return value;
  2841. }
  2842. NonnullRefPtr<Value> Value::with_slices(NonnullRefPtrVector<Slice> slices) const&
  2843. {
  2844. auto value = clone();
  2845. value->m_slices.extend(move(slices));
  2846. return value;
  2847. }
  2848. ListValue::~ListValue()
  2849. {
  2850. }
  2851. Vector<String> ListValue::resolve_as_list(RefPtr<Shell> shell)
  2852. {
  2853. Vector<String> values;
  2854. for (auto& value : m_contained_values)
  2855. values.extend(value.resolve_as_list(shell));
  2856. return resolve_slices(shell, move(values), m_slices);
  2857. }
  2858. NonnullRefPtr<Value> ListValue::resolve_without_cast(RefPtr<Shell> shell)
  2859. {
  2860. NonnullRefPtrVector<Value> values;
  2861. for (auto& value : m_contained_values)
  2862. values.append(value.resolve_without_cast(shell));
  2863. NonnullRefPtr<Value> value = make_ref_counted<ListValue>(move(values));
  2864. if (!m_slices.is_empty())
  2865. value = value->with_slices(m_slices);
  2866. return value;
  2867. }
  2868. CommandValue::~CommandValue()
  2869. {
  2870. }
  2871. CommandSequenceValue::~CommandSequenceValue()
  2872. {
  2873. }
  2874. Vector<String> CommandSequenceValue::resolve_as_list(RefPtr<Shell> shell)
  2875. {
  2876. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, "Unexpected cast of a command sequence to a list");
  2877. return {};
  2878. }
  2879. Vector<Command> CommandSequenceValue::resolve_as_commands(RefPtr<Shell>)
  2880. {
  2881. return m_contained_values;
  2882. }
  2883. Vector<String> CommandValue::resolve_as_list(RefPtr<Shell> shell)
  2884. {
  2885. shell->raise_error(Shell::ShellError::EvaluatedSyntaxError, "Unexpected cast of a command to a list");
  2886. return {};
  2887. }
  2888. Vector<Command> CommandValue::resolve_as_commands(RefPtr<Shell>)
  2889. {
  2890. return { m_command };
  2891. }
  2892. JobValue::~JobValue()
  2893. {
  2894. }
  2895. StringValue::~StringValue()
  2896. {
  2897. }
  2898. Vector<String> StringValue::resolve_as_list(RefPtr<Shell> shell)
  2899. {
  2900. if (is_list()) {
  2901. auto parts = StringView(m_string).split_view(m_split, m_keep_empty);
  2902. Vector<String> result;
  2903. result.ensure_capacity(parts.size());
  2904. for (auto& part : parts)
  2905. result.append(part);
  2906. return resolve_slices(shell, move(result), m_slices);
  2907. }
  2908. return { resolve_slices(shell, String { m_string }, m_slices) };
  2909. }
  2910. NonnullRefPtr<Value> StringValue::resolve_without_cast(RefPtr<Shell> shell)
  2911. {
  2912. if (is_list())
  2913. return make_ref_counted<AST::ListValue>(resolve_as_list(shell)); // No need to reapply the slices.
  2914. return *this;
  2915. }
  2916. GlobValue::~GlobValue()
  2917. {
  2918. }
  2919. Vector<String> GlobValue::resolve_as_list(RefPtr<Shell> shell)
  2920. {
  2921. if (!shell)
  2922. return { resolve_slices(shell, String { m_glob }, m_slices) };
  2923. auto results = shell->expand_globs(m_glob, shell->cwd);
  2924. if (results.is_empty())
  2925. shell->raise_error(Shell::ShellError::InvalidGlobError, "Glob did not match anything!", m_generation_position);
  2926. return resolve_slices(shell, move(results), m_slices);
  2927. }
  2928. SimpleVariableValue::~SimpleVariableValue()
  2929. {
  2930. }
  2931. Vector<String> SimpleVariableValue::resolve_as_list(RefPtr<Shell> shell)
  2932. {
  2933. if (!shell)
  2934. return resolve_slices(shell, Vector<String> {}, m_slices);
  2935. if (auto value = resolve_without_cast(shell); value != this)
  2936. return value->resolve_as_list(shell);
  2937. char* env_value = getenv(m_name.characters());
  2938. if (env_value == nullptr)
  2939. return { resolve_slices(shell, "", m_slices) };
  2940. return { resolve_slices(shell, String { env_value }, m_slices) };
  2941. }
  2942. NonnullRefPtr<Value> SimpleVariableValue::resolve_without_cast(RefPtr<Shell> shell)
  2943. {
  2944. VERIFY(shell);
  2945. if (auto value = shell->lookup_local_variable(m_name)) {
  2946. auto result = value.release_nonnull();
  2947. // If a slice is applied, add it.
  2948. if (!m_slices.is_empty())
  2949. result = result->with_slices(m_slices);
  2950. return result;
  2951. }
  2952. return *this;
  2953. }
  2954. SpecialVariableValue::~SpecialVariableValue()
  2955. {
  2956. }
  2957. Vector<String> SpecialVariableValue::resolve_as_list(RefPtr<Shell> shell)
  2958. {
  2959. if (!shell)
  2960. return {};
  2961. switch (m_name) {
  2962. case '?':
  2963. return { resolve_slices(shell, String::number(shell->last_return_code), m_slices) };
  2964. case '$':
  2965. return { resolve_slices(shell, String::number(getpid()), m_slices) };
  2966. case '*':
  2967. if (auto argv = shell->lookup_local_variable("ARGV"))
  2968. return resolve_slices(shell, argv->resolve_as_list(shell), m_slices);
  2969. return resolve_slices(shell, Vector<String> {}, m_slices);
  2970. case '#':
  2971. if (auto argv = shell->lookup_local_variable("ARGV")) {
  2972. if (argv->is_list()) {
  2973. auto list_argv = static_cast<AST::ListValue*>(argv.ptr());
  2974. return { resolve_slices(shell, String::number(list_argv->values().size()), m_slices) };
  2975. }
  2976. return { resolve_slices(shell, "1", m_slices) };
  2977. }
  2978. return { resolve_slices(shell, "0", m_slices) };
  2979. default:
  2980. return { resolve_slices(shell, "", m_slices) };
  2981. }
  2982. }
  2983. TildeValue::~TildeValue()
  2984. {
  2985. }
  2986. Vector<String> TildeValue::resolve_as_list(RefPtr<Shell> shell)
  2987. {
  2988. StringBuilder builder;
  2989. builder.append("~");
  2990. builder.append(m_username);
  2991. if (!shell)
  2992. return { resolve_slices(shell, builder.to_string(), m_slices) };
  2993. return { resolve_slices(shell, shell->expand_tilde(builder.to_string()), m_slices) };
  2994. }
  2995. ErrorOr<NonnullRefPtr<Rewiring>> CloseRedirection::apply() const
  2996. {
  2997. return adopt_nonnull_ref_or_enomem(new (nothrow) Rewiring(fd, fd, Rewiring::Close::ImmediatelyCloseNew));
  2998. }
  2999. CloseRedirection::~CloseRedirection()
  3000. {
  3001. }
  3002. ErrorOr<NonnullRefPtr<Rewiring>> PathRedirection::apply() const
  3003. {
  3004. auto check_fd_and_return = [my_fd = this->fd](int fd, String const& path) -> ErrorOr<NonnullRefPtr<Rewiring>> {
  3005. if (fd < 0) {
  3006. auto error = Error::from_errno(errno);
  3007. dbgln("open() failed for '{}' with {}", path, error);
  3008. return error;
  3009. }
  3010. return adopt_nonnull_ref_or_enomem(new (nothrow) Rewiring(fd, my_fd, Rewiring::Close::Old));
  3011. };
  3012. switch (direction) {
  3013. case AST::PathRedirection::WriteAppend:
  3014. return check_fd_and_return(open(path.characters(), O_WRONLY | O_CREAT | O_APPEND, 0666), path);
  3015. case AST::PathRedirection::Write:
  3016. return check_fd_and_return(open(path.characters(), O_WRONLY | O_CREAT | O_TRUNC, 0666), path);
  3017. case AST::PathRedirection::Read:
  3018. return check_fd_and_return(open(path.characters(), O_RDONLY), path);
  3019. case AST::PathRedirection::ReadWrite:
  3020. return check_fd_and_return(open(path.characters(), O_RDWR | O_CREAT, 0666), path);
  3021. }
  3022. VERIFY_NOT_REACHED();
  3023. }
  3024. PathRedirection::~PathRedirection()
  3025. {
  3026. }
  3027. FdRedirection::~FdRedirection()
  3028. {
  3029. }
  3030. Redirection::~Redirection()
  3031. {
  3032. }
  3033. }