sh-script.el 157 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475
  1. ;;; sh-script.el --- shell-script editing commands for Emacs -*- lexical-binding:t -*-
  2. ;; Copyright (C) 1993-1997, 1999, 2001-2015 Free Software Foundation, Inc.
  3. ;; Author: Daniel Pfeiffer <occitan@esperanto.org>
  4. ;; Version: 2.0f
  5. ;; Maintainer: emacs-devel@gnu.org
  6. ;; Keywords: languages, unix
  7. ;; This file is part of GNU Emacs.
  8. ;; GNU Emacs is free software: you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; GNU Emacs is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;; Major mode for editing shell scripts. Bourne, C and rc shells as well
  20. ;; as various derivatives are supported and easily derived from. Structured
  21. ;; statements can be inserted with one command or abbrev. Completion is
  22. ;; available for filenames, variables known from the script, the shell and
  23. ;; the environment as well as commands.
  24. ;;; Known Bugs:
  25. ;; - In Bourne the keyword `in' is not anchored to case, for, select ...
  26. ;; - Variables in `"' strings aren't fontified because there's no way of
  27. ;; syntactically distinguishing those from `'' strings.
  28. ;; Indentation
  29. ;; ===========
  30. ;; Indentation for rc and es modes is very limited, but for Bourne shells
  31. ;; and its derivatives it is quite customizable.
  32. ;;
  33. ;; The following description applies to sh and derived shells (bash,
  34. ;; zsh, ...).
  35. ;;
  36. ;; There are various customization variables which allow tailoring to
  37. ;; a wide variety of styles. Most of these variables are named
  38. ;; sh-indent-for-XXX and sh-indent-after-XXX. For example.
  39. ;; sh-indent-after-if controls the indenting of a line following
  40. ;; an if statement, and sh-indent-for-fi controls the indentation
  41. ;; of the line containing the fi.
  42. ;;
  43. ;; You can set each to a numeric value, but it is often more convenient
  44. ;; to a symbol such as `+' which uses the value of variable `sh-basic-offset'.
  45. ;; By changing this one variable you can increase or decrease how much
  46. ;; indentation there is. Valid symbols:
  47. ;;
  48. ;; + Indent right by sh-basic-offset
  49. ;; - Indent left by sh-basic-offset
  50. ;; ++ Indent right twice sh-basic-offset
  51. ;; -- Indent left twice sh-basic-offset
  52. ;; * Indent right half sh-basic-offset
  53. ;; / Indent left half sh-basic-offset.
  54. ;;
  55. ;; There are 4 commands to help set the indentation variables:
  56. ;;
  57. ;; `sh-show-indent'
  58. ;; This shows what variable controls the indentation of the current
  59. ;; line and its value.
  60. ;;
  61. ;; `sh-set-indent'
  62. ;; This allows you to set the value of the variable controlling the
  63. ;; current line's indentation. You can enter a number or one of a
  64. ;; number of special symbols to denote the value of sh-basic-offset,
  65. ;; or its negative, or half it, or twice it, etc. If you've used
  66. ;; cc-mode this should be familiar. If you forget which symbols are
  67. ;; valid simply press C-h at the prompt.
  68. ;;
  69. ;; `sh-learn-line-indent'
  70. ;; Simply make the line look the way you want it, then invoke this
  71. ;; command. It will set the variable to the value that makes the line
  72. ;; indent like that. If called with a prefix argument then it will set
  73. ;; the value to one of the symbols if applicable.
  74. ;;
  75. ;; `sh-learn-buffer-indent'
  76. ;; This is the deluxe function! It "learns" the whole buffer (use
  77. ;; narrowing if you want it to process only part). It outputs to a
  78. ;; buffer *indent* any conflicts it finds, and all the variables it has
  79. ;; learned. This buffer is a sort of Occur mode buffer, allowing you to
  80. ;; easily find where something was set. It is popped to automatically
  81. ;; if there are any conflicts found or if `sh-popup-occur-buffer' is
  82. ;; non-nil.
  83. ;; `sh-indent-comment' will be set if all comments follow the same
  84. ;; pattern; if they don't it will be set to nil.
  85. ;; Whether `sh-basic-offset' is set is determined by variable
  86. ;; `sh-learn-basic-offset'.
  87. ;;
  88. ;; Unfortunately, `sh-learn-buffer-indent' can take a long time to run
  89. ;; (e.g. if there are large case statements). Perhaps it does not make
  90. ;; sense to run it on large buffers: if lots of lines have different
  91. ;; indentation styles it will produce a lot of diagnostics in the
  92. ;; *indent* buffer; if there is a consistent style then running
  93. ;; `sh-learn-buffer-indent' on a small region of the buffer should
  94. ;; suffice.
  95. ;;
  96. ;; Saving indentation values
  97. ;; -------------------------
  98. ;; After you've learned the values in a buffer, how to you remember
  99. ;; them? Originally I had hoped that `sh-learn-buffer-indent'
  100. ;; would make this unnecessary; simply learn the values when you visit
  101. ;; the buffer.
  102. ;; You can do this automatically like this:
  103. ;; (add-hook 'sh-set-shell-hook 'sh-learn-buffer-indent)
  104. ;;
  105. ;; However... `sh-learn-buffer-indent' is extremely slow,
  106. ;; especially on large-ish buffer. Also, if there are conflicts the
  107. ;; "last one wins" which may not produce the desired setting.
  108. ;;
  109. ;; So...There is a minimal way of being able to save indentation values and
  110. ;; to reload them in another buffer or at another point in time.
  111. ;;
  112. ;; Use `sh-name-style' to give a name to the indentation settings of
  113. ;; the current buffer.
  114. ;; Use `sh-load-style' to load indentation settings for the current
  115. ;; buffer from a specific style.
  116. ;; Use `sh-save-styles-to-buffer' to write all the styles to a buffer
  117. ;; in lisp code. You can then store it in a file and later use
  118. ;; `load-file' to load it.
  119. ;;
  120. ;; Indentation variables - buffer local or global?
  121. ;; ----------------------------------------------
  122. ;; I think that often having them buffer-local makes sense,
  123. ;; especially if one is using `sh-learn-buffer-indent'. However, if
  124. ;; a user sets values using customization, these changes won't appear
  125. ;; to work if the variables are already local!
  126. ;;
  127. ;; To get round this, there is a variable `sh-make-vars-local' and 2
  128. ;; functions: `sh-make-vars-local' and `sh-reset-indent-vars-to-global-values'.
  129. ;;
  130. ;; If `sh-make-vars-local' is non-nil, then these variables become
  131. ;; buffer local when the mode is established.
  132. ;; If this is nil, then the variables are global. At any time you
  133. ;; can make them local with the command `sh-make-vars-local'.
  134. ;; Conversely, to update with the global values you can use the
  135. ;; command `sh-reset-indent-vars-to-global-values'.
  136. ;;
  137. ;; This may be awkward, but the intent is to cover all cases.
  138. ;;
  139. ;; Awkward things, pitfalls
  140. ;; ------------------------
  141. ;; Indentation for a sh script is complicated for a number of reasons:
  142. ;;
  143. ;; 1. You can't format by simply looking at symbols, you need to look
  144. ;; at keywords. [This is not the case for rc and es shells.]
  145. ;; 2. The character ")" is used both as a matched pair "(" ... ")" and
  146. ;; as a stand-alone symbol (in a case alternative). This makes
  147. ;; things quite tricky!
  148. ;; 3. Here-documents in a script should be treated "as is", and when
  149. ;; they terminate we want to revert to the indentation of the line
  150. ;; containing the "<<" symbol.
  151. ;; 4. A line may be continued using the "\".
  152. ;; 5. The character "#" (outside a string) normally starts a comment,
  153. ;; but it doesn't in the sequence "$#"!
  154. ;;
  155. ;; To try and address points 2 3 and 5 I used a feature that cperl mode
  156. ;; uses, that of a text's syntax property. This, however, has 2
  157. ;; disadvantages:
  158. ;; 1. We need to scan the buffer to find which ")" symbols belong to a
  159. ;; case alternative, to find any here documents, and handle "$#".
  160. ;;
  161. ;; Bugs
  162. ;; ----
  163. ;; - Indenting many lines is slow. It currently does each line
  164. ;; independently, rather than saving state information.
  165. ;;
  166. ;; - `sh-learn-buffer-indent' is extremely slow.
  167. ;;
  168. ;; - "case $x in y) echo ;; esac)" the last ) is mis-identified as being
  169. ;; part of a case-pattern. You need to add a semi-colon after "esac" to
  170. ;; coerce sh-script into doing the right thing.
  171. ;;
  172. ;; - "echo $z in ps | head)" the last ) is mis-identified as being part of
  173. ;; a case-pattern. You need to put the "in" between quotes to coerce
  174. ;; sh-script into doing the right thing.
  175. ;;
  176. ;; - A line starting with "}>foo" is not indented like "} >foo".
  177. ;;
  178. ;; Richard Sharman <rsharman@pobox.com> June 1999.
  179. ;;; Code:
  180. ;; page 1: variables and settings
  181. ;; page 2: indentation stuff
  182. ;; page 3: mode-command and utility functions
  183. ;; page 4: statement syntax-commands for various shells
  184. ;; page 5: various other commands
  185. (eval-when-compile
  186. (require 'skeleton)
  187. (require 'cl-lib)
  188. (require 'comint))
  189. (require 'executable)
  190. (autoload 'comint-completion-at-point "comint")
  191. (autoload 'comint-filename-completion "comint")
  192. (autoload 'shell-command-completion "shell")
  193. (autoload 'shell-environment-variable-completion "shell")
  194. (defvar font-lock-comment-face)
  195. (defvar font-lock-set-defaults)
  196. (defvar font-lock-string-face)
  197. (defgroup sh nil
  198. "Shell programming utilities."
  199. :group 'languages)
  200. (defgroup sh-script nil
  201. "Shell script mode."
  202. :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
  203. :group 'sh
  204. :prefix "sh-")
  205. (defcustom sh-ancestor-alist
  206. '((ash . sh)
  207. (bash . jsh)
  208. (bash2 . jsh)
  209. (dash . ash)
  210. (dtksh . ksh)
  211. (es . rc)
  212. (itcsh . tcsh)
  213. (jcsh . csh)
  214. (jsh . sh)
  215. (ksh . ksh88)
  216. (ksh88 . jsh)
  217. (oash . sh)
  218. (pdksh . ksh88)
  219. (mksh . pdksh)
  220. (posix . sh)
  221. (tcsh . csh)
  222. (wksh . ksh88)
  223. (wsh . sh)
  224. (zsh . ksh88)
  225. (rpm . sh))
  226. "Alist showing the direct ancestor of various shells.
  227. This is the basis for `sh-feature'. See also `sh-alias-alist'.
  228. By default we have the following three hierarchies:
  229. csh C Shell
  230. jcsh C Shell with Job Control
  231. tcsh TENEX C Shell
  232. itcsh Ian's TENEX C Shell
  233. rc Plan 9 Shell
  234. es Extensible Shell
  235. sh Bourne Shell
  236. ash Almquist Shell
  237. dash Debian Almquist Shell
  238. jsh Bourne Shell with Job Control
  239. bash GNU Bourne Again Shell
  240. ksh88 Korn Shell '88
  241. ksh Korn Shell '93
  242. dtksh CDE Desktop Korn Shell
  243. pdksh Public Domain Korn Shell
  244. mksh MirOS BSD Korn Shell
  245. wksh Window Korn Shell
  246. zsh Z Shell
  247. oash SCO OA (curses) Shell
  248. posix IEEE 1003.2 Shell Standard
  249. wsh ? Shell"
  250. :type '(repeat (cons symbol symbol))
  251. :version "24.4" ; added dash
  252. :group 'sh-script)
  253. (defcustom sh-alias-alist
  254. (append (if (eq system-type 'gnu/linux)
  255. '((csh . tcsh)
  256. (ksh . pdksh)))
  257. ;; for the time being
  258. '((ksh . ksh88)
  259. (bash2 . bash)
  260. (sh5 . sh)
  261. ;; Android's system shell
  262. ("^/system/bin/sh$" . mksh)))
  263. "Alist for transforming shell names to what they really are.
  264. Use this where the name of the executable doesn't correspond to
  265. the type of shell it really is. Keys are regular expressions
  266. matched against the full path of the interpreter. (For backward
  267. compatibility, keys may also be symbols, which are matched
  268. against the interpreter's basename. The values are symbols
  269. naming the shell."
  270. :type '(repeat (cons (radio
  271. (regexp :tag "Regular expression")
  272. (symbol :tag "Basename"))
  273. (symbol :tag "Shell")))
  274. :group 'sh-script)
  275. (defcustom sh-shell-file
  276. (or
  277. ;; On MSDOS and Windows, collapse $SHELL to lower-case and remove
  278. ;; the executable extension, so comparisons with the list of
  279. ;; known shells work.
  280. (and (memq system-type '(ms-dos windows-nt))
  281. (let* ((shell (getenv "SHELL"))
  282. (shell-base
  283. (and shell (file-name-nondirectory shell))))
  284. ;; shell-script mode doesn't support DOS/Windows shells,
  285. ;; so use the default instead.
  286. (if (or (null shell)
  287. (member (downcase shell-base)
  288. '("command.com" "cmd.exe" "4dos.com" "ndos.com"
  289. "cmdproxy.exe")))
  290. "/bin/sh"
  291. (file-name-sans-extension (downcase shell)))))
  292. (getenv "SHELL")
  293. "/bin/sh")
  294. "The executable file name for the shell being programmed."
  295. :type 'string
  296. :group 'sh-script)
  297. (defcustom sh-shell-arg
  298. ;; bash does not need any options when run in a shell script,
  299. '((bash)
  300. (csh . "-f")
  301. (pdksh)
  302. ;; Bill_Mann@praxisint.com says -p with ksh can do harm.
  303. (ksh88)
  304. ;; -p means don't initialize functions from the environment.
  305. (rc . "-p")
  306. ;; Someone proposed -motif, but we don't want to encourage
  307. ;; use of a non-free widget set.
  308. (wksh)
  309. ;; -f means don't run .zshrc.
  310. (zsh . "-f"))
  311. "Single argument string for the magic number. See `sh-feature'."
  312. :type '(repeat (cons (symbol :tag "Shell")
  313. (choice (const :tag "No Arguments" nil)
  314. (string :tag "Arguments")
  315. (sexp :format "Evaluate: %v"))))
  316. :group 'sh-script)
  317. (defcustom sh-imenu-generic-expression
  318. `((sh
  319. . ((nil
  320. ;; function FOO
  321. ;; function FOO()
  322. "^\\s-*function\\s-+\\\([[:alpha:]_][[:alnum:]_]*\\)\\s-*\\(?:()\\)?"
  323. 1)
  324. ;; FOO()
  325. (nil
  326. "^\\s-*\\([[:alpha:]_][[:alnum:]_]*\\)\\s-*()"
  327. 1)
  328. )))
  329. "Alist of regular expressions for recognizing shell function definitions.
  330. See `sh-feature' and `imenu-generic-expression'."
  331. :type '(alist :key-type (symbol :tag "Shell")
  332. :value-type (alist :key-type (choice :tag "Title"
  333. string
  334. (const :tag "None" nil))
  335. :value-type
  336. (repeat :tag "Regexp, index..." sexp)))
  337. :group 'sh-script
  338. :version "20.4")
  339. (defun sh-current-defun-name ()
  340. "Find the name of function or variable at point.
  341. For use in `add-log-current-defun-function'."
  342. (save-excursion
  343. (end-of-line)
  344. (when (re-search-backward
  345. (concat "\\(?:"
  346. ;; function FOO
  347. ;; function FOO()
  348. "^\\s-*function\\s-+\\\([[:alpha:]_][[:alnum:]_]*\\)\\s-*\\(?:()\\)?"
  349. "\\)\\|\\(?:"
  350. ;; FOO()
  351. "^\\s-*\\([[:alpha:]_][[:alnum:]_]*\\)\\s-*()"
  352. "\\)\\|\\(?:"
  353. ;; FOO=
  354. "^\\([[:alpha:]_][[:alnum:]_]*\\)="
  355. "\\)")
  356. nil t)
  357. (or (match-string-no-properties 1)
  358. (match-string-no-properties 2)
  359. (match-string-no-properties 3)))))
  360. (defvar sh-shell-variables nil
  361. "Alist of shell variable names that should be included in completion.
  362. These are used for completion in addition to all the variables named
  363. in `process-environment'. Each element looks like (VAR . VAR), where
  364. the car and cdr are the same symbol.")
  365. (defvar sh-shell-variables-initialized nil
  366. "Non-nil if `sh-shell-variables' is initialized.")
  367. (defun sh-canonicalize-shell (shell)
  368. "Convert a shell name SHELL to the one we should handle it as.
  369. SHELL is a full path to the shell interpreter; return a shell
  370. name symbol."
  371. (cl-loop
  372. with shell = (cond ((string-match "\\.exe\\'" shell)
  373. (substring shell 0 (match-beginning 0)))
  374. (t shell))
  375. with shell-base = (intern (file-name-nondirectory shell))
  376. for (key . value) in sh-alias-alist
  377. if (and (stringp key) (string-match key shell)) return value
  378. if (eq key shell-base) return value
  379. finally return shell-base))
  380. (defvar sh-shell (sh-canonicalize-shell sh-shell-file)
  381. "The shell being programmed. This is set by \\[sh-set-shell].")
  382. ;;;###autoload(put 'sh-shell 'safe-local-variable 'symbolp)
  383. (define-abbrev-table 'sh-mode-abbrev-table ())
  384. ;; I turned off this feature because it doesn't permit typing commands
  385. ;; in the usual way without help.
  386. ;;(defvar sh-abbrevs
  387. ;; '((csh sh-abbrevs shell
  388. ;; "switch" 'sh-case
  389. ;; "getopts" 'sh-while-getopts)
  390. ;; (es sh-abbrevs shell
  391. ;; "function" 'sh-function)
  392. ;; (ksh88 sh-abbrevs sh
  393. ;; "select" 'sh-select)
  394. ;; (rc sh-abbrevs shell
  395. ;; "case" 'sh-case
  396. ;; "function" 'sh-function)
  397. ;; (sh sh-abbrevs shell
  398. ;; "case" 'sh-case
  399. ;; "function" 'sh-function
  400. ;; "until" 'sh-until
  401. ;; "getopts" 'sh-while-getopts)
  402. ;; ;; The next entry is only used for defining the others
  403. ;; (shell "for" sh-for
  404. ;; "loop" sh-indexed-loop
  405. ;; "if" sh-if
  406. ;; "tmpfile" sh-tmp-file
  407. ;; "while" sh-while)
  408. ;; (zsh sh-abbrevs ksh88
  409. ;; "repeat" 'sh-repeat))
  410. ;; "Abbrev-table used in Shell-Script mode. See `sh-feature'.
  411. ;;;Due to the internal workings of abbrev tables, the shell name symbol is
  412. ;;;actually defined as the table for the like of \\[edit-abbrevs].")
  413. (defun sh-mode-syntax-table (table &rest list)
  414. "Copy TABLE and set syntax for successive CHARs according to strings S."
  415. (setq table (copy-syntax-table table))
  416. (while list
  417. (modify-syntax-entry (pop list) (pop list) table))
  418. table)
  419. (defvar sh-mode-syntax-table
  420. (sh-mode-syntax-table ()
  421. ?\# "<"
  422. ?\n ">#"
  423. ?\" "\"\""
  424. ?\' "\"'"
  425. ?\` "\"`"
  426. ;; ?$ might also have a ". p" syntax. Both "'" and ". p" seem
  427. ;; to work fine. This is needed so that dabbrev-expand
  428. ;; $VARNAME works.
  429. ?$ "'"
  430. ?! "_"
  431. ?% "_"
  432. ?: "_"
  433. ?. "_"
  434. ?^ "_"
  435. ?~ "_"
  436. ?, "_"
  437. ?= "."
  438. ?\; "."
  439. ?| "."
  440. ?& "."
  441. ?< "."
  442. ?> ".")
  443. "The syntax table to use for Shell-Script mode.
  444. This is buffer-local in every such buffer.")
  445. (defvar sh-mode-syntax-table-input
  446. '((sh . nil))
  447. "Syntax-table used in Shell-Script mode. See `sh-feature'.")
  448. (defvar sh-mode-map
  449. (let ((map (make-sparse-keymap))
  450. (menu-map (make-sparse-keymap)))
  451. (define-key map "\C-c(" 'sh-function)
  452. (define-key map "\C-c\C-w" 'sh-while)
  453. (define-key map "\C-c\C-u" 'sh-until)
  454. (define-key map "\C-c\C-t" 'sh-tmp-file)
  455. (define-key map "\C-c\C-s" 'sh-select)
  456. (define-key map "\C-c\C-r" 'sh-repeat)
  457. (define-key map "\C-c\C-o" 'sh-while-getopts)
  458. (define-key map "\C-c\C-l" 'sh-indexed-loop)
  459. (define-key map "\C-c\C-i" 'sh-if)
  460. (define-key map "\C-c\C-f" 'sh-for)
  461. (define-key map "\C-c\C-c" 'sh-case)
  462. (define-key map "\C-c?" 'sh-show-indent)
  463. (define-key map "\C-c=" 'sh-set-indent)
  464. (define-key map "\C-c<" 'sh-learn-line-indent)
  465. (define-key map "\C-c>" 'sh-learn-buffer-indent)
  466. (define-key map "\C-c\C-\\" 'sh-backslash-region)
  467. (define-key map "=" 'sh-assignment)
  468. (define-key map "\C-c+" 'sh-add)
  469. (define-key map "\C-\M-x" 'sh-execute-region)
  470. (define-key map "\C-c\C-x" 'executable-interpret)
  471. (define-key map "\C-c\C-n" 'sh-send-line-or-region-and-step)
  472. (define-key map "\C-c\C-d" 'sh-cd-here)
  473. (define-key map "\C-c\C-z" 'sh-show-shell)
  474. (define-key map [remap delete-backward-char]
  475. 'backward-delete-char-untabify)
  476. (define-key map "\C-c:" 'sh-set-shell)
  477. (define-key map [remap backward-sentence] 'sh-beginning-of-command)
  478. (define-key map [remap forward-sentence] 'sh-end-of-command)
  479. (define-key map [menu-bar sh-script] (cons "Sh-Script" menu-map))
  480. (define-key menu-map [sh-learn-buffer-indent]
  481. '(menu-item "Learn buffer indentation" sh-learn-buffer-indent
  482. :help "Learn how to indent the buffer the way it currently is."))
  483. (define-key menu-map [sh-learn-line-indent]
  484. '(menu-item "Learn line indentation" sh-learn-line-indent
  485. :help "Learn how to indent a line as it currently is indented"))
  486. (define-key menu-map [sh-show-indent]
  487. '(menu-item "Show indentation" sh-show-indent
  488. :help "Show the how the current line would be indented"))
  489. (define-key menu-map [sh-set-indent]
  490. '(menu-item "Set indentation" sh-set-indent
  491. :help "Set the indentation for the current line"))
  492. (define-key menu-map [sh-pair]
  493. '(menu-item "Insert braces and quotes in pairs"
  494. electric-pair-mode
  495. :button (:toggle . (bound-and-true-p electric-pair-mode))
  496. :help "Inserting a brace or quote automatically inserts the matching pair"))
  497. (define-key menu-map [sh-s0] '("--"))
  498. ;; Insert
  499. (define-key menu-map [sh-function]
  500. '(menu-item "Function..." sh-function
  501. :help "Insert a function definition"))
  502. (define-key menu-map [sh-add]
  503. '(menu-item "Addition..." sh-add
  504. :help "Insert an addition of VAR and prefix DELTA for Bourne (type) shell"))
  505. (define-key menu-map [sh-until]
  506. '(menu-item "Until Loop" sh-until
  507. :help "Insert an until loop"))
  508. (define-key menu-map [sh-repeat]
  509. '(menu-item "Repeat Loop" sh-repeat
  510. :help "Insert a repeat loop definition"))
  511. (define-key menu-map [sh-while]
  512. '(menu-item "While Loop" sh-while
  513. :help "Insert a while loop"))
  514. (define-key menu-map [sh-getopts]
  515. '(menu-item "Options Loop" sh-while-getopts
  516. :help "Insert a while getopts loop."))
  517. (define-key menu-map [sh-indexed-loop]
  518. '(menu-item "Indexed Loop" sh-indexed-loop
  519. :help "Insert an indexed loop from 1 to n."))
  520. (define-key menu-map [sh-select]
  521. '(menu-item "Select Statement" sh-select
  522. :help "Insert a select statement "))
  523. (define-key menu-map [sh-if]
  524. '(menu-item "If Statement" sh-if
  525. :help "Insert an if statement"))
  526. (define-key menu-map [sh-for]
  527. '(menu-item "For Loop" sh-for
  528. :help "Insert a for loop"))
  529. (define-key menu-map [sh-case]
  530. '(menu-item "Case Statement" sh-case
  531. :help "Insert a case/switch statement"))
  532. (define-key menu-map [sh-s1] '("--"))
  533. (define-key menu-map [sh-exec]
  534. '(menu-item "Execute region" sh-execute-region
  535. :help "Pass optional header and region to a subshell for noninteractive execution"))
  536. (define-key menu-map [sh-exec-interpret]
  537. '(menu-item "Execute script..." executable-interpret
  538. :help "Run script with user-specified args, and collect output in a buffer"))
  539. (define-key menu-map [sh-set-shell]
  540. '(menu-item "Set shell type..." sh-set-shell
  541. :help "Set this buffer's shell to SHELL (a string)"))
  542. (define-key menu-map [sh-backslash-region]
  543. '(menu-item "Backslash region" sh-backslash-region
  544. :help "Insert, align, or delete end-of-line backslashes on the lines in the region."))
  545. map)
  546. "Keymap used in Shell-Script mode.")
  547. (defvar sh-skeleton-pair-default-alist '((?( _ ?)) (?\))
  548. (?[ ?\s _ ?\s ?]) (?\])
  549. (?{ _ ?}) (?\}))
  550. "Value to use for `skeleton-pair-default-alist' in Shell-Script mode.")
  551. (defcustom sh-dynamic-complete-functions
  552. '(shell-environment-variable-completion
  553. shell-command-completion
  554. comint-filename-completion)
  555. "Functions for doing TAB dynamic completion."
  556. :type '(repeat function)
  557. :group 'sh-script)
  558. (defcustom sh-assignment-regexp
  559. `((csh . "\\<\\([[:alnum:]_]+\\)\\(\\[.+\\]\\)?[ \t]*[-+*/%^]?=")
  560. ;; actually spaces are only supported in let/(( ... ))
  561. (ksh88 . ,(concat "\\<\\([[:alnum:]_]+\\)\\(\\[.+\\]\\)?"
  562. "[ \t]*\\(?:[-+*/%&|~^]\\|<<\\|>>\\)?="))
  563. (bash . "\\<\\([[:alnum:]_]+\\)\\(\\[.+\\]\\)?\\+?=")
  564. (rc . "\\<\\([[:alnum:]_*]+\\)[ \t]*=")
  565. (sh . "\\<\\([[:alnum:]_]+\\)="))
  566. "Regexp for the variable name and what may follow in an assignment.
  567. First grouping matches the variable name. This is upto and including the `='
  568. sign. See `sh-feature'."
  569. :type '(repeat (cons (symbol :tag "Shell")
  570. (choice regexp
  571. (sexp :format "Evaluate: %v"))))
  572. :group 'sh-script)
  573. (defcustom sh-indentation 4
  574. "The width for further indentation in Shell-Script mode."
  575. :type 'integer
  576. :group 'sh-script)
  577. (put 'sh-indentation 'safe-local-variable 'integerp)
  578. (defcustom sh-remember-variable-min 3
  579. "Don't remember variables less than this length for completing reads."
  580. :type 'integer
  581. :group 'sh-script)
  582. (defvar sh-header-marker nil
  583. "When non-nil is the end of header for prepending by \\[sh-execute-region].
  584. That command is also used for setting this variable.")
  585. (make-variable-buffer-local 'sh-header-marker)
  586. (defcustom sh-beginning-of-command
  587. "\\([;({`|&]\\|\\`\\|[^\\]\n\\)[ \t]*\\([/~[:alnum:]:]\\)"
  588. "Regexp to determine the beginning of a shell command.
  589. The actual command starts at the beginning of the second \\(grouping\\)."
  590. :type 'regexp
  591. :group 'sh-script)
  592. (defcustom sh-end-of-command
  593. "\\([/~[:alnum:]:]\\)[ \t]*\\([;#)}`|&]\\|$\\)"
  594. "Regexp to determine the end of a shell command.
  595. The actual command ends at the end of the first \\(grouping\\)."
  596. :type 'regexp
  597. :group 'sh-script)
  598. (defcustom sh-here-document-word "EOF"
  599. "Word to delimit here documents.
  600. If the first character of this string is \"-\", this is taken as
  601. part of the redirection operator, rather than part of the
  602. word (that is, \"<<-\" instead of \"<<\"). This is a feature
  603. used by some shells (for example Bash) to indicate that leading
  604. tabs inside the here document should be ignored. In this case,
  605. Emacs indents the initial body and end of the here document with
  606. tabs, to the same level as the start (note that apart from this
  607. there is no support for indentation of here documents). This
  608. will only work correctly if `sh-basic-offset' is a multiple of
  609. `tab-width'.
  610. Any quote characters or leading whitespace in the word are
  611. removed when closing the here document."
  612. :type 'string
  613. :group 'sh-script)
  614. (defvar sh-test
  615. '((sh "[ ]" . 3)
  616. (ksh88 "[[ ]]" . 4))
  617. "Initial input in Bourne if, while and until skeletons. See `sh-feature'.")
  618. ;; customized this out of sheer bravado. not for the faint of heart.
  619. ;; but it *did* have an asterisk in the docstring!
  620. (defcustom sh-builtins
  621. '((bash sh-append posix
  622. "." "alias" "bg" "bind" "builtin" "caller" "compgen" "complete"
  623. "declare" "dirs" "disown" "enable" "fc" "fg" "help" "history"
  624. "jobs" "kill" "let" "local" "popd" "printf" "pushd" "shopt"
  625. "source" "suspend" "typeset" "unalias"
  626. ;; bash4
  627. "mapfile" "readarray" "coproc")
  628. ;; The next entry is only used for defining the others
  629. (bourne sh-append shell
  630. "eval" "export" "getopts" "newgrp" "pwd" "read" "readonly"
  631. "times" "ulimit")
  632. (csh sh-append shell
  633. "alias" "chdir" "glob" "history" "limit" "nice" "nohup" "rehash"
  634. "setenv" "source" "time" "unalias" "unhash")
  635. (dtksh sh-append wksh)
  636. (es "access" "apids" "cd" "echo" "eval" "false" "let" "limit" "local"
  637. "newpgrp" "result" "time" "umask" "var" "vars" "wait" "whatis")
  638. (jsh sh-append sh
  639. "bg" "fg" "jobs" "kill" "stop" "suspend")
  640. (jcsh sh-append csh
  641. "bg" "fg" "jobs" "kill" "notify" "stop" "suspend")
  642. (ksh88 sh-append bourne
  643. "alias" "bg" "false" "fc" "fg" "jobs" "kill" "let" "print" "time"
  644. "typeset" "unalias" "whence")
  645. (oash sh-append sh
  646. "checkwin" "dateline" "error" "form" "menu" "newwin" "oadeinit"
  647. "oaed" "oahelp" "oainit" "pp" "ppfile" "scan" "scrollok" "wattr"
  648. "wclear" "werase" "win" "wmclose" "wmmessage" "wmopen" "wmove"
  649. "wmtitle" "wrefresh")
  650. (pdksh sh-append ksh88
  651. "bind")
  652. (posix sh-append sh
  653. "command")
  654. (rc "builtin" "cd" "echo" "eval" "limit" "newpgrp" "shift" "umask" "wait"
  655. "whatis")
  656. (sh sh-append bourne
  657. "hash" "test" "type")
  658. ;; The next entry is only used for defining the others
  659. (shell "cd" "echo" "eval" "set" "shift" "umask" "unset" "wait")
  660. (wksh sh-append ksh88
  661. ;; FIXME: This looks too much like a regexp. --Stef
  662. "Xt[A-Z][A-Za-z]*")
  663. (zsh sh-append ksh88
  664. "autoload" "bindkey" "builtin" "chdir" "compctl" "declare" "dirs"
  665. "disable" "disown" "echotc" "enable" "functions" "getln" "hash"
  666. "history" "integer" "limit" "local" "log" "popd" "pushd" "r"
  667. "readonly" "rehash" "sched" "setopt" "source" "suspend" "true"
  668. "ttyctl" "type" "unfunction" "unhash" "unlimit" "unsetopt" "vared"
  669. "which"))
  670. "List of all shell builtins for completing read and fontification.
  671. Note that on some systems not all builtins are available or some are
  672. implemented as aliases. See `sh-feature'."
  673. :type '(repeat (cons (symbol :tag "Shell")
  674. (choice (repeat string)
  675. (sexp :format "Evaluate: %v"))))
  676. :version "24.4" ; bash4 additions
  677. :group 'sh-script)
  678. (defcustom sh-leading-keywords
  679. '((bash sh-append sh
  680. "time")
  681. (csh "else")
  682. (es "true" "unwind-protect" "whatis")
  683. (rc "else")
  684. (sh "!" "do" "elif" "else" "if" "then" "trap" "type" "until" "while"))
  685. "List of keywords that may be immediately followed by a builtin or keyword.
  686. Given some confusion between keywords and builtins depending on shell and
  687. system, the distinction here has been based on whether they influence the
  688. flow of control or syntax. See `sh-feature'."
  689. :type '(repeat (cons (symbol :tag "Shell")
  690. (choice (repeat string)
  691. (sexp :format "Evaluate: %v"))))
  692. :group 'sh-script)
  693. (defcustom sh-other-keywords
  694. '((bash sh-append bourne
  695. "bye" "logout" "select")
  696. ;; The next entry is only used for defining the others
  697. (bourne sh-append sh
  698. "function")
  699. (csh sh-append shell
  700. "breaksw" "default" "end" "endif" "endsw" "foreach" "goto"
  701. "if" "logout" "onintr" "repeat" "switch" "then" "while")
  702. (es "break" "catch" "exec" "exit" "fn" "for" "forever" "fork" "if"
  703. "return" "throw" "while")
  704. (ksh88 sh-append bourne
  705. "select")
  706. (rc "break" "case" "exec" "exit" "fn" "for" "if" "in" "return" "switch"
  707. "while")
  708. (sh sh-append shell
  709. "done" "esac" "fi" "for" "in" "return")
  710. ;; The next entry is only used for defining the others
  711. (shell "break" "case" "continue" "exec" "exit")
  712. (zsh sh-append bash
  713. "select" "foreach"))
  714. "List of keywords not in `sh-leading-keywords'.
  715. See `sh-feature'."
  716. :type '(repeat (cons (symbol :tag "Shell")
  717. (choice (repeat string)
  718. (sexp :format "Evaluate: %v"))))
  719. :group 'sh-script)
  720. (defvar sh-variables
  721. '((bash sh-append sh
  722. "allow_null_glob_expansion" "auto_resume" "BASH" "BASH_ENV"
  723. "BASH_VERSINFO" "BASH_VERSION" "cdable_vars" "COMP_CWORD"
  724. "COMP_LINE" "COMP_POINT" "COMP_WORDS" "COMPREPLY" "DIRSTACK"
  725. "ENV" "EUID" "FCEDIT" "FIGNORE" "FUNCNAME"
  726. "glob_dot_filenames" "GLOBIGNORE" "GROUPS" "histchars"
  727. "HISTCMD" "HISTCONTROL" "HISTFILE" "HISTFILESIZE"
  728. "HISTIGNORE" "history_control" "HISTSIZE"
  729. "hostname_completion_file" "HOSTFILE" "HOSTTYPE" "IGNOREEOF"
  730. "ignoreeof" "INPUTRC" "LINENO" "MACHTYPE" "MAIL_WARNING"
  731. "noclobber" "nolinks" "notify" "no_exit_on_failed_exec"
  732. "NO_PROMPT_VARS" "OLDPWD" "OPTERR" "OSTYPE" "PIPESTATUS"
  733. "PPID" "POSIXLY_CORRECT" "PROMPT_COMMAND" "PS3" "PS4"
  734. "pushd_silent" "PWD" "RANDOM" "REPLY" "SECONDS" "SHELLOPTS"
  735. "SHLVL" "TIMEFORMAT" "TMOUT" "UID")
  736. (csh sh-append shell
  737. "argv" "cdpath" "child" "echo" "histchars" "history" "home"
  738. "ignoreeof" "mail" "noclobber" "noglob" "nonomatch" "path" "prompt"
  739. "shell" "status" "time" "verbose")
  740. (es sh-append shell
  741. "apid" "cdpath" "CDPATH" "history" "home" "ifs" "noexport" "path"
  742. "pid" "prompt" "signals")
  743. (jcsh sh-append csh
  744. "notify")
  745. (ksh88 sh-append sh
  746. "ENV" "ERRNO" "FCEDIT" "FPATH" "HISTFILE" "HISTSIZE" "LINENO"
  747. "OLDPWD" "PPID" "PS3" "PS4" "PWD" "RANDOM" "REPLY" "SECONDS"
  748. "TMOUT")
  749. (oash sh-append sh
  750. "FIELD" "FIELD_MAX" "LAST_KEY" "OALIB" "PP_ITEM" "PP_NUM")
  751. (rc sh-append shell
  752. "apid" "apids" "cdpath" "CDPATH" "history" "home" "ifs" "path" "pid"
  753. "prompt" "status")
  754. (sh sh-append shell
  755. "CDPATH" "IFS" "OPTARG" "OPTIND" "PS1" "PS2")
  756. ;; The next entry is only used for defining the others
  757. (shell "COLUMNS" "EDITOR" "HOME" "HUSHLOGIN" "LANG" "LC_COLLATE"
  758. "LC_CTYPE" "LC_MESSAGES" "LC_MONETARY" "LC_NUMERIC" "LC_TIME"
  759. "LINES" "LOGNAME" "MAIL" "MAILCHECK" "MAILPATH" "PAGER" "PATH"
  760. "SHELL" "TERM" "TERMCAP" "TERMINFO" "VISUAL")
  761. (tcsh sh-append csh
  762. "addsuffix" "ampm" "autocorrect" "autoexpand" "autolist"
  763. "autologout" "chase_symlinks" "correct" "dextract" "edit" "el"
  764. "fignore" "gid" "histlit" "HOST" "HOSTTYPE" "HPATH"
  765. "ignore_symlinks" "listjobs" "listlinks" "listmax" "matchbeep"
  766. "nobeep" "NOREBIND" "oid" "printexitvalue" "prompt2" "prompt3"
  767. "pushdsilent" "pushdtohome" "recexact" "recognize_only_executables"
  768. "rmstar" "savehist" "SHLVL" "showdots" "sl" "SYSTYPE" "tcsh" "term"
  769. "tperiod" "tty" "uid" "version" "visiblebell" "watch" "who"
  770. "wordchars")
  771. (zsh sh-append ksh88
  772. "BAUD" "bindcmds" "cdpath" "DIRSTACKSIZE" "fignore" "FIGNORE" "fpath"
  773. "HISTCHARS" "hostcmds" "hosts" "HOSTS" "LISTMAX" "LITHISTSIZE"
  774. "LOGCHECK" "mailpath" "manpath" "NULLCMD" "optcmds" "path" "POSTEDIT"
  775. "prompt" "PROMPT" "PROMPT2" "PROMPT3" "PROMPT4" "psvar" "PSVAR"
  776. "READNULLCMD" "REPORTTIME" "RPROMPT" "RPS1" "SAVEHIST" "SPROMPT"
  777. "STTY" "TIMEFMT" "TMOUT" "TMPPREFIX" "varcmds" "watch" "WATCH"
  778. "WATCHFMT" "WORDCHARS" "ZDOTDIR"))
  779. "List of all shell variables available for completing read.
  780. See `sh-feature'.")
  781. ;; Font-Lock support
  782. (defface sh-heredoc
  783. '((((min-colors 88) (class color)
  784. (background dark))
  785. (:foreground "yellow1" :weight bold))
  786. (((class color)
  787. (background dark))
  788. (:foreground "yellow" :weight bold))
  789. (((class color)
  790. (background light))
  791. (:foreground "tan1" ))
  792. (t
  793. (:weight bold)))
  794. "Face to show a here-document."
  795. :group 'sh-indentation)
  796. ;; These colors are probably icky. It's just a placeholder though.
  797. (defface sh-quoted-exec
  798. '((((class color) (background dark))
  799. (:foreground "salmon"))
  800. (((class color) (background light))
  801. (:foreground "magenta"))
  802. (t
  803. (:weight bold)))
  804. "Face to show quoted execs like \\=`blabla\\=`."
  805. :group 'sh-indentation)
  806. (define-obsolete-face-alias 'sh-heredoc-face 'sh-heredoc "22.1")
  807. (defvar sh-heredoc-face 'sh-heredoc)
  808. (defface sh-escaped-newline '((t :inherit font-lock-string-face))
  809. "Face used for (non-escaped) backslash at end of a line in Shell-script mode."
  810. :group 'sh-script
  811. :version "22.1")
  812. (defvar sh-font-lock-keywords-var
  813. '((csh sh-append shell
  814. ("\\${?[#?]?\\([[:alpha:]_][[:alnum:]_]*\\|0\\)" 1
  815. font-lock-variable-name-face))
  816. (es sh-append executable-font-lock-keywords
  817. ("\\$#?\\([[:alpha:]_][[:alnum:]_]*\\|[0-9]+\\)" 1
  818. font-lock-variable-name-face))
  819. (rc sh-append es)
  820. (bash sh-append sh ("\\$(\\(\\sw+\\)" (1 'sh-quoted-exec t) ))
  821. (sh sh-append shell
  822. ;; Variable names.
  823. ("\\$\\({#?\\)?\\([[:alpha:]_][[:alnum:]_]*\\|[-#?@!]\\)" 2
  824. font-lock-variable-name-face)
  825. ;; Function names.
  826. ("^\\(\\sw+\\)[ \t]*(" 1 font-lock-function-name-face)
  827. ("\\<\\(function\\)\\>[ \t]*\\(\\sw+\\)?"
  828. (1 font-lock-keyword-face) (2 font-lock-function-name-face nil t))
  829. ("\\(?:^\\s *\\|[[();&|]\\s *\\|\\(?:\\s +-[ao]\\|if\\|else\\|then\\|while\\|do\\)\\s +\\)\\(!\\)"
  830. 1 font-lock-negation-char-face))
  831. ;; The next entry is only used for defining the others
  832. (shell
  833. ;; Using font-lock-string-face here confuses sh-get-indent-info.
  834. ("\\(^\\|[^\\]\\)\\(\\\\\\\\\\)*\\(\\\\\\)$" 3 'sh-escaped-newline)
  835. ("\\\\[^[:alnum:]]" 0 font-lock-string-face)
  836. ("\\${?\\([[:alpha:]_][[:alnum:]_]*\\|[0-9]+\\|[$*_]\\)" 1
  837. font-lock-variable-name-face))
  838. (rpm sh-append rpm2
  839. ("%{?\\(\\sw+\\)" 1 font-lock-keyword-face))
  840. (rpm2 sh-append shell
  841. ("^Summary:\\(.*\\)$" (1 font-lock-doc-face t))
  842. ("^\\(\\sw+\\):" 1 font-lock-variable-name-face)))
  843. "Default expressions to highlight in Shell Script modes. See `sh-feature'.")
  844. (defvar sh-font-lock-keywords-var-1
  845. '((sh "[ \t]in\\>"))
  846. "Subdued level highlighting for Shell Script modes.")
  847. (defvar sh-font-lock-keywords-var-2 ()
  848. "Gaudy level highlighting for Shell Script modes.")
  849. ;; These are used for the syntax table stuff (derived from cperl-mode).
  850. ;; Note: parse-sexp-lookup-properties must be set to t for it to work.
  851. (defconst sh-st-punc (string-to-syntax "."))
  852. (defconst sh-here-doc-syntax (string-to-syntax "|")) ;; generic string
  853. (eval-and-compile
  854. (defconst sh-escaped-line-re
  855. ;; Should match until the real end-of-continued-line, but if that is not
  856. ;; possible (because we bump into EOB or the search bound), then we should
  857. ;; match until the search bound.
  858. "\\(?:\\(?:.*[^\\\n]\\)?\\(?:\\\\\\\\\\)*\\\\\n\\)*.*")
  859. (defconst sh-here-doc-open-re
  860. (concat "[^<]<<-?\\s-*\\\\?\\(\\(?:['\"][^'\"]+['\"]\\|\\sw\\|[-/~._]\\)+\\)"
  861. sh-escaped-line-re "\\(\n\\)")))
  862. (defun sh--inside-noncommand-expression (pos)
  863. (save-excursion
  864. (let ((ppss (syntax-ppss pos)))
  865. (when (nth 1 ppss)
  866. (goto-char (nth 1 ppss))
  867. (or
  868. (pcase (char-after)
  869. ;; ((...)) or $((...)) or $[...] or ${...}. Nested
  870. ;; parenthesis can occur inside the first of these forms, so
  871. ;; parse backward recursively.
  872. (`?\( (eq ?\( (char-before)))
  873. ((or `?\{ `?\[) (eq ?\$ (char-before))))
  874. (sh--inside-noncommand-expression (1- (point))))))))
  875. (defun sh-font-lock-open-heredoc (start string eol)
  876. "Determine the syntax of the \\n after a <<EOF.
  877. START is the position of <<.
  878. STRING is the actual word used as delimiter (e.g. \"EOF\").
  879. INDENTED is non-nil if the here document's content (and the EOF mark) can
  880. be indented (i.e. a <<- was used rather than just <<).
  881. Point is at the beginning of the next line."
  882. (unless (or (memq (char-before start) '(?< ?>))
  883. (sh-in-comment-or-string start)
  884. (sh--inside-noncommand-expression start))
  885. ;; We're looking at <<STRING, so we add "^STRING$" to the syntactic
  886. ;; font-lock keywords to detect the end of this here document.
  887. (let ((str (replace-regexp-in-string "['\"]" "" string))
  888. (ppss (save-excursion (syntax-ppss eol))))
  889. (if (nth 4 ppss)
  890. ;; The \n not only starts the heredoc but also closes a comment.
  891. ;; Let's close the comment just before the \n.
  892. (put-text-property (1- eol) eol 'syntax-table '(12))) ;">"
  893. (if (or (nth 5 ppss) (> (count-lines start eol) 1))
  894. ;; If the sh-escaped-line-re part of sh-here-doc-open-re has matched
  895. ;; several lines, make sure we refontify them together.
  896. ;; Furthermore, if (nth 5 ppss) is non-nil (i.e. the \n is
  897. ;; escaped), it means the right \n is actually further down.
  898. ;; Don't bother fixing it now, but place a multiline property so
  899. ;; that when jit-lock-context-* refontifies the rest of the
  900. ;; buffer, it also refontifies the current line with it.
  901. (put-text-property start (1+ eol) 'syntax-multiline t))
  902. (put-text-property eol (1+ eol) 'sh-here-doc-marker str)
  903. (prog1 sh-here-doc-syntax
  904. (goto-char (+ 2 start))))))
  905. (defun sh-syntax-propertize-here-doc (end)
  906. (let ((ppss (syntax-ppss)))
  907. (when (eq t (nth 3 ppss))
  908. (let ((key (get-text-property (nth 8 ppss) 'sh-here-doc-marker))
  909. (case-fold-search nil))
  910. (when (re-search-forward
  911. (concat "^\\([ \t]*\\)" (regexp-quote key) "\\(\n\\)")
  912. end 'move)
  913. (let ((eol (match-beginning 2)))
  914. (put-text-property eol (1+ eol)
  915. 'syntax-table sh-here-doc-syntax)))))))
  916. (defun sh-font-lock-quoted-subshell (limit)
  917. "Search for a subshell embedded in a string.
  918. Find all the unescaped \" characters within said subshell, remembering that
  919. subshells can nest."
  920. (when (eq ?\" (nth 3 (syntax-ppss))) ; Check we matched an opening quote.
  921. ;; bingo we have a $( or a ` inside a ""
  922. (let (;; `state' can be: double-quote, backquote, code.
  923. (state (if (eq (char-before) ?`) 'backquote 'code))
  924. (startpos (point))
  925. ;; Stacked states in the context.
  926. (states '(double-quote)))
  927. (while (and state (progn (skip-chars-forward "^'\\\\\"`$()" limit)
  928. (< (point) limit)))
  929. ;; unescape " inside a $( ... ) construct.
  930. (pcase (char-after)
  931. (?\' (pcase state
  932. (`double-quote nil)
  933. (_ (forward-char 1)
  934. ;; FIXME: mark skipped double quotes as punctuation syntax.
  935. (let ((spos (point)))
  936. (skip-chars-forward "^'" limit)
  937. (save-excursion
  938. (let ((epos (point)))
  939. (goto-char spos)
  940. (while (search-forward "\"" epos t)
  941. (put-text-property (point) (1- (point))
  942. 'syntax-table '(1)))))))))
  943. (?\\ (forward-char 1))
  944. (?\" (pcase state
  945. (`double-quote (setq state (pop states)))
  946. (_ (push state states) (setq state 'double-quote)))
  947. (if state (put-text-property (point) (1+ (point))
  948. 'syntax-table '(1))))
  949. (?\` (pcase state
  950. (`backquote (setq state (pop states)))
  951. (_ (push state states) (setq state 'backquote))))
  952. (?\$ (if (not (eq (char-after (1+ (point))) ?\())
  953. nil
  954. (forward-char 1)
  955. (pcase state
  956. (_ (push state states) (setq state 'code)))))
  957. (?\( (pcase state
  958. (`double-quote nil)
  959. (_ (push state states) (setq state 'code))))
  960. (?\) (pcase state
  961. (`double-quote nil)
  962. (_ (setq state (pop states)))))
  963. (_ (error "Internal error in sh-font-lock-quoted-subshell")))
  964. (forward-char 1))
  965. (when (< startpos (line-beginning-position))
  966. (put-text-property startpos (point) 'syntax-multiline t)
  967. (add-hook 'syntax-propertize-extend-region-functions
  968. 'syntax-propertize-multiline nil t))
  969. )))
  970. (defun sh-is-quoted-p (pos)
  971. (and (eq (char-before pos) ?\\)
  972. (not (sh-is-quoted-p (1- pos)))))
  973. (defun sh-font-lock-paren (start)
  974. (unless (nth 8 (syntax-ppss))
  975. (save-excursion
  976. (let ((open nil))
  977. (goto-char start)
  978. ;; Skip through all patterns
  979. (while
  980. (progn
  981. (while
  982. (progn
  983. (forward-comment (- (point-max)))
  984. (when (and (eolp) (sh-is-quoted-p (point)))
  985. (forward-char -1)
  986. t)))
  987. ;; Skip through one pattern
  988. (while
  989. (or (/= 0 (skip-syntax-backward "w_"))
  990. (/= 0 (skip-chars-backward "-$=?[]*@/\\\\"))
  991. (and (sh-is-quoted-p (1- (point)))
  992. (goto-char (- (point) 2)))
  993. (when (memq (char-before) '(?\" ?\' ?\}))
  994. (condition-case nil (progn (backward-sexp 1) t)
  995. (error nil)))))
  996. ;; Patterns can be preceded by an open-paren (bug#1320).
  997. (when (eq (char-before (point)) ?\()
  998. (backward-char 1)
  999. (setq open (point)))
  1000. (while (progn
  1001. (forward-comment (- (point-max)))
  1002. ;; Maybe we've bumped into an escaped newline.
  1003. (sh-is-quoted-p (point)))
  1004. (backward-char 1))
  1005. (when (eq (char-before) ?|)
  1006. (backward-char 1) t)))
  1007. (and (> (point) (1+ (point-min)))
  1008. (progn (backward-char 2)
  1009. (if (> start (line-end-position))
  1010. (put-text-property (point) (1+ start)
  1011. 'syntax-multiline t))
  1012. ;; FIXME: The `in' may just be a random argument to
  1013. ;; a normal command rather than the real `in' keyword.
  1014. ;; I.e. we should look back to try and find the
  1015. ;; corresponding `case'.
  1016. (and (looking-at ";[;&]\\|\\_<in")
  1017. ;; ";; esac )" is a case that looks
  1018. ;; like a case-pattern but it's really just a close
  1019. ;; paren after a case statement. I.e. if we skipped
  1020. ;; over `esac' just now, we're not looking
  1021. ;; at a case-pattern.
  1022. (not (looking-at "..[ \t\n]+esac[^[:word:]_]"))))
  1023. (progn
  1024. (when open
  1025. (put-text-property open (1+ open) 'syntax-table sh-st-punc))
  1026. sh-st-punc))))))
  1027. (defun sh-font-lock-backslash-quote ()
  1028. (if (eq (save-excursion (nth 3 (syntax-ppss (match-beginning 0)))) ?\')
  1029. ;; In a '...' the backslash is not escaping.
  1030. sh-st-punc
  1031. nil))
  1032. (defun sh-syntax-propertize-function (start end)
  1033. (goto-char start)
  1034. (sh-syntax-propertize-here-doc end)
  1035. (funcall
  1036. (syntax-propertize-rules
  1037. (sh-here-doc-open-re
  1038. (2 (sh-font-lock-open-heredoc
  1039. (match-beginning 0) (match-string 1) (match-beginning 2))))
  1040. ("\\s|" (0 (prog1 nil (sh-syntax-propertize-here-doc end))))
  1041. ;; A `#' begins a comment when it is unquoted and at the
  1042. ;; beginning of a word. In the shell, words are separated by
  1043. ;; metacharacters. The list of special chars is taken from
  1044. ;; the single-unix spec of the shell command language (under
  1045. ;; `quoting') but with `$' removed.
  1046. ("\\(?:[^|&;<>()`\\\"' \t\n]\\|\\${\\)\\(#+\\)" (1 "_"))
  1047. ;; In a '...' the backslash is not escaping.
  1048. ("\\(\\\\\\)'" (1 (sh-font-lock-backslash-quote)))
  1049. ;; Make sure $@ and $? are correctly recognized as sexps.
  1050. ("\\$\\([?@]\\)" (1 "_"))
  1051. ;; Distinguish the special close-paren in `case'.
  1052. (")" (0 (sh-font-lock-paren (match-beginning 0))))
  1053. ;; Highlight (possibly nested) subshells inside "" quoted
  1054. ;; regions correctly.
  1055. ("\"\\(?:\\(?:[^\\\"]\\|\\\\.\\)*?\\)??\\(\\$(\\|`\\)"
  1056. (1 (ignore
  1057. (if (nth 8 (save-excursion (syntax-ppss (match-beginning 0))))
  1058. (goto-char (1+ (match-beginning 0)))
  1059. ;; Save excursion because we want to also apply other
  1060. ;; syntax-propertize rules within the affected region.
  1061. (save-excursion
  1062. (sh-font-lock-quoted-subshell end)))))))
  1063. (point) end))
  1064. (defun sh-font-lock-syntactic-face-function (state)
  1065. (let ((q (nth 3 state)))
  1066. (if q
  1067. (if (characterp q)
  1068. (if (eq q ?\`) 'sh-quoted-exec font-lock-string-face)
  1069. sh-heredoc-face)
  1070. font-lock-comment-face)))
  1071. (defgroup sh-indentation nil
  1072. "Variables controlling indentation in shell scripts.
  1073. Note: customizing these variables will not affect existing buffers if
  1074. `sh-make-vars-local' is non-nil. See the documentation for
  1075. variable `sh-make-vars-local', command `sh-make-vars-local'
  1076. and command `sh-reset-indent-vars-to-global-values'."
  1077. :group 'sh-script)
  1078. (defcustom sh-set-shell-hook nil
  1079. "Hook run by `sh-set-shell'."
  1080. :type 'hook
  1081. :group 'sh-script)
  1082. (defcustom sh-mode-hook nil
  1083. "Hook run by `sh-mode'."
  1084. :type 'hook
  1085. :group 'sh-script)
  1086. (defcustom sh-learn-basic-offset nil
  1087. "When `sh-guess-basic-offset' should learn `sh-basic-offset'.
  1088. nil mean: never.
  1089. t means: only if there seems to be an obvious value.
  1090. Anything else means: whenever we have a \"good guess\" as to the value."
  1091. :type '(choice
  1092. (const :tag "Never" nil)
  1093. (const :tag "Only if sure" t)
  1094. (const :tag "If have a good guess" usually))
  1095. :group 'sh-indentation)
  1096. (defcustom sh-popup-occur-buffer nil
  1097. "Controls when `sh-learn-buffer-indent' pops the `*indent*' buffer.
  1098. If t it is always shown. If nil, it is shown only when there
  1099. are conflicts."
  1100. :type '(choice
  1101. (const :tag "Only when there are conflicts." nil)
  1102. (const :tag "Always" t))
  1103. :group 'sh-indentation)
  1104. (defcustom sh-blink t
  1105. "If non-nil, `sh-show-indent' shows the line indentation is relative to.
  1106. The position on the line is not necessarily meaningful.
  1107. In some cases the line will be the matching keyword, but this is not
  1108. always the case."
  1109. :type 'boolean
  1110. :group 'sh-indentation)
  1111. (defcustom sh-first-lines-indent 0
  1112. "The indentation of the first non-blank non-comment line.
  1113. Usually 0 meaning first column.
  1114. Can be set to a number, or to nil which means leave it as is."
  1115. :type '(choice
  1116. (const :tag "Leave as is" nil)
  1117. (integer :tag "Column number"
  1118. :menu-tag "Indent to this col (0 means first col)" ))
  1119. :group 'sh-indentation)
  1120. (defcustom sh-basic-offset 4
  1121. "The default indentation increment.
  1122. This value is used for the `+' and `-' symbols in an indentation variable."
  1123. :type 'integer
  1124. :group 'sh-indentation)
  1125. (put 'sh-basic-offset 'safe-local-variable 'integerp)
  1126. (defcustom sh-indent-comment t
  1127. "How a comment line is to be indented.
  1128. nil means leave it as it is;
  1129. t means indent it as a normal line, aligning it to previous non-blank
  1130. non-comment line;
  1131. a number means align to that column, e.g. 0 means first column."
  1132. :type '(choice
  1133. (const :tag "Leave as is." nil)
  1134. (const :tag "Indent as a normal line." t)
  1135. (integer :menu-tag "Indent to this col (0 means first col)."
  1136. :tag "Indent to column number.") )
  1137. :version "24.3"
  1138. :group 'sh-indentation)
  1139. (defvar sh-debug nil
  1140. "Enable lots of debug messages - if function `sh-debug' is enabled.")
  1141. ;; Uncomment this defun and comment the defmacro for debugging.
  1142. ;; (defun sh-debug (&rest args)
  1143. ;; "For debugging: display message ARGS if variable SH-DEBUG is non-nil."
  1144. ;; (if sh-debug
  1145. ;; (apply 'message args)))
  1146. (defmacro sh-debug (&rest _args))
  1147. (defconst sh-symbol-list
  1148. '((const :tag "+ " :value +
  1149. :menu-tag "+ Indent right by sh-basic-offset")
  1150. (const :tag "- " :value -
  1151. :menu-tag "- Indent left by sh-basic-offset")
  1152. (const :tag "++" :value ++
  1153. :menu-tag "++ Indent right twice sh-basic-offset")
  1154. (const :tag "--" :value --
  1155. :menu-tag "-- Indent left twice sh-basic-offset")
  1156. (const :tag "* " :value *
  1157. :menu-tag "* Indent right half sh-basic-offset")
  1158. (const :tag "/ " :value /
  1159. :menu-tag "/ Indent left half sh-basic-offset")))
  1160. (defcustom sh-indent-for-else 0
  1161. "How much to indent an `else' relative to its `if'. Usually 0."
  1162. :type `(choice
  1163. (integer :menu-tag "A number (positive=>indent right)"
  1164. :tag "A number")
  1165. (const :tag "--") ;; separator!
  1166. ,@ sh-symbol-list
  1167. )
  1168. :group 'sh-indentation)
  1169. (defconst sh-number-or-symbol-list
  1170. (append '((integer :menu-tag "A number (positive=>indent right)"
  1171. :tag "A number")
  1172. (const :tag "--")) ; separator
  1173. sh-symbol-list))
  1174. (defcustom sh-indent-for-fi 0
  1175. "How much to indent a `fi' relative to its `if'. Usually 0."
  1176. :type `(choice ,@ sh-number-or-symbol-list )
  1177. :group 'sh-indentation)
  1178. (defcustom sh-indent-for-done 0
  1179. "How much to indent a `done' relative to its matching stmt. Usually 0."
  1180. :type `(choice ,@ sh-number-or-symbol-list )
  1181. :group 'sh-indentation)
  1182. (defcustom sh-indent-after-else '+
  1183. "How much to indent a statement after an `else' statement."
  1184. :type `(choice ,@ sh-number-or-symbol-list )
  1185. :group 'sh-indentation)
  1186. (defcustom sh-indent-after-if '+
  1187. "How much to indent a statement after an `if' statement.
  1188. This includes lines after `else' and `elif' statements, too, but
  1189. does not affect the `else', `elif' or `fi' statements themselves."
  1190. :type `(choice ,@ sh-number-or-symbol-list )
  1191. :group 'sh-indentation)
  1192. (defcustom sh-indent-for-then 0
  1193. "How much to indent a `then' relative to its `if'."
  1194. :type `(choice ,@ sh-number-or-symbol-list )
  1195. :group 'sh-indentation)
  1196. (defcustom sh-indent-for-do 0
  1197. "How much to indent a `do' statement.
  1198. This is relative to the statement before the `do', typically a
  1199. `while', `until', `for', `repeat' or `select' statement."
  1200. :type `(choice ,@ sh-number-or-symbol-list)
  1201. :group 'sh-indentation)
  1202. (defcustom sh-indent-after-do '+
  1203. "How much to indent a line after a `do' statement.
  1204. This is used when the `do' is the first word of the line.
  1205. This is relative to the statement before the `do', typically a
  1206. `while', `until', `for', `repeat' or `select' statement."
  1207. :type `(choice ,@ sh-number-or-symbol-list)
  1208. :group 'sh-indentation)
  1209. (defcustom sh-indent-after-loop-construct '+
  1210. "How much to indent a statement after a loop construct.
  1211. This variable is used when the keyword `do' is on the same line as the
  1212. loop statement (e.g., `until', `while' or `for').
  1213. If the `do' is on a line by itself, then `sh-indent-after-do' is used instead."
  1214. :type `(choice ,@ sh-number-or-symbol-list)
  1215. :group 'sh-indentation)
  1216. (defcustom sh-indent-after-done 0
  1217. "How much to indent a statement after a `done' keyword.
  1218. Normally this is 0, which aligns the `done' to the matching
  1219. looping construct line.
  1220. Setting it non-zero allows you to have the `do' statement on a line
  1221. by itself and align the done under to do."
  1222. :type `(choice ,@ sh-number-or-symbol-list)
  1223. :group 'sh-indentation)
  1224. (defcustom sh-indent-for-case-label '+
  1225. "How much to indent a case label statement.
  1226. This is relative to the line containing the `case' statement."
  1227. :type `(choice ,@ sh-number-or-symbol-list)
  1228. :group 'sh-indentation)
  1229. (defcustom sh-indent-for-case-alt '++
  1230. "How much to indent statements after the case label.
  1231. This is relative to the line containing the `case' statement."
  1232. :type `(choice ,@ sh-number-or-symbol-list)
  1233. :group 'sh-indentation)
  1234. (defcustom sh-indent-for-continuation '+
  1235. "How much to indent for a continuation statement."
  1236. :type `(choice ,@ sh-number-or-symbol-list)
  1237. :group 'sh-indentation)
  1238. (defcustom sh-indent-after-open '+
  1239. "How much to indent after a line with an opening parenthesis or brace.
  1240. For an open paren after a function, `sh-indent-after-function' is used."
  1241. :type `(choice ,@ sh-number-or-symbol-list)
  1242. :group 'sh-indentation)
  1243. (defcustom sh-indent-after-function '+
  1244. "How much to indent after a function line."
  1245. :type `(choice ,@ sh-number-or-symbol-list)
  1246. :group 'sh-indentation)
  1247. ;; These 2 are for the rc shell:
  1248. (defcustom sh-indent-after-switch '+
  1249. "How much to indent a `case' statement relative to the `switch' statement.
  1250. This is for the rc shell."
  1251. :type `(choice ,@ sh-number-or-symbol-list)
  1252. :group 'sh-indentation)
  1253. (defcustom sh-indent-after-case '+
  1254. "How much to indent a statement relative to the `case' statement.
  1255. This is for the rc shell."
  1256. :type `(choice ,@ sh-number-or-symbol-list)
  1257. :group 'sh-indentation)
  1258. (defcustom sh-backslash-column 48
  1259. "Column in which `sh-backslash-region' inserts backslashes."
  1260. :type 'integer
  1261. :group 'sh)
  1262. (defcustom sh-backslash-align t
  1263. "If non-nil, `sh-backslash-region' will align backslashes."
  1264. :type 'boolean
  1265. :group 'sh)
  1266. ;; Internal use - not designed to be changed by the user:
  1267. (defun sh-mkword-regexpr (word)
  1268. "Make a regexp which matches WORD as a word.
  1269. This specifically excludes an occurrence of WORD followed by
  1270. punctuation characters like '-'."
  1271. (concat word "\\([^-[:alnum:]_]\\|$\\)"))
  1272. (defconst sh-re-done (sh-mkword-regexpr "done"))
  1273. (defconst sh-kws-for-done
  1274. '((sh . ( "while" "until" "for" ) )
  1275. (bash . ( "while" "until" "for" "select" ) )
  1276. (ksh88 . ( "while" "until" "for" "select" ) )
  1277. (zsh . ( "while" "until" "for" "repeat" "select" ) ) )
  1278. "Which keywords can match the word `done' in this shell.")
  1279. (defconst sh-indent-supported
  1280. '((sh . sh)
  1281. (csh . nil)
  1282. (rc . rc))
  1283. "Indentation rule set to use for each shell type.")
  1284. (defvar sh-indent-supported-here nil
  1285. "Non-nil if we support indentation for the current buffer's shell type.")
  1286. (defconst sh-var-list
  1287. '(
  1288. sh-basic-offset sh-first-lines-indent sh-indent-after-case
  1289. sh-indent-after-do sh-indent-after-done
  1290. sh-indent-after-else
  1291. sh-indent-after-if
  1292. sh-indent-after-loop-construct
  1293. sh-indent-after-open
  1294. sh-indent-comment
  1295. sh-indent-for-case-alt
  1296. sh-indent-for-case-label
  1297. sh-indent-for-continuation
  1298. sh-indent-for-do
  1299. sh-indent-for-done
  1300. sh-indent-for-else
  1301. sh-indent-for-fi
  1302. sh-indent-for-then
  1303. )
  1304. "A list of variables used by script mode to control indentation.
  1305. This list is used when switching between buffer-local and global
  1306. values of variables, and for the commands using indentation styles.")
  1307. (defvar sh-make-vars-local t
  1308. "Controls whether indentation variables are local to the buffer.
  1309. If non-nil, indentation variables are made local initially.
  1310. If nil, you can later make the variables local by invoking
  1311. command `sh-make-vars-local'.
  1312. The default is t because I assume that in one Emacs session one is
  1313. frequently editing existing scripts with different styles.")
  1314. ;; inferior shell interaction
  1315. ;; TODO: support multiple interactive shells
  1316. (defvar-local sh-shell-process nil
  1317. "The inferior shell process for interaction.")
  1318. (defvar explicit-shell-file-name)
  1319. (defun sh-shell-process (force)
  1320. "Get a shell process for interaction.
  1321. If FORCE is non-nil and no process found, create one."
  1322. (if (process-live-p sh-shell-process)
  1323. sh-shell-process
  1324. (setq sh-shell-process
  1325. (let ((found nil) proc
  1326. (procs (process-list)))
  1327. (while (and (not found) procs
  1328. (process-live-p (setq proc (pop procs)))
  1329. (process-command proc))
  1330. (when (string-equal sh-shell (file-name-nondirectory
  1331. (car (process-command proc))))
  1332. (setq found proc)))
  1333. (or found
  1334. (and force
  1335. (get-buffer-process
  1336. (let ((explicit-shell-file-name sh-shell-file))
  1337. (shell)))))))))
  1338. (defun sh-show-shell ()
  1339. "Pop the shell interaction buffer."
  1340. (interactive)
  1341. (pop-to-buffer (process-buffer (sh-shell-process t))))
  1342. (defun sh-send-text (text)
  1343. "Send the text to the `sh-shell-process'."
  1344. (comint-send-string (sh-shell-process t) (concat text "\n")))
  1345. (defun sh-cd-here ()
  1346. "Change directory in the current interaction shell to the current one."
  1347. (interactive)
  1348. (sh-send-text (concat "cd " default-directory)))
  1349. (defun sh-send-line-or-region-and-step ()
  1350. "Send the current line to the inferior shell and step to the next line.
  1351. When the region is active, send the region instead."
  1352. (interactive)
  1353. (let (from to end)
  1354. (if (use-region-p)
  1355. (setq from (region-beginning)
  1356. to (region-end)
  1357. end to)
  1358. (setq from (line-beginning-position)
  1359. to (line-end-position)
  1360. end (1+ to)))
  1361. (sh-send-text (buffer-substring-no-properties from to))
  1362. (goto-char end)))
  1363. ;; mode-command and utility functions
  1364. (defun sh-after-hack-local-variables ()
  1365. (when (assq 'sh-shell file-local-variables-alist)
  1366. (sh-set-shell (if (symbolp sh-shell)
  1367. (symbol-name sh-shell)
  1368. sh-shell))))
  1369. ;;;###autoload
  1370. (define-derived-mode sh-mode prog-mode "Shell-script"
  1371. "Major mode for editing shell scripts.
  1372. This mode works for many shells, since they all have roughly the same syntax,
  1373. as far as commands, arguments, variables, pipes, comments etc. are concerned.
  1374. Unless the file's magic number indicates the shell, your usual shell is
  1375. assumed. Since filenames rarely give a clue, they are not further analyzed.
  1376. This mode adapts to the variations between shells (see `sh-set-shell') by
  1377. means of an inheritance based feature lookup (see `sh-feature'). This
  1378. mechanism applies to all variables (including skeletons) that pertain to
  1379. shell-specific features.
  1380. The default style of this mode is that of Rosenblatt's Korn shell book.
  1381. The syntax of the statements varies with the shell being used. The
  1382. following commands are available, based on the current shell's syntax:
  1383. \\<sh-mode-map>
  1384. \\[sh-case] case statement
  1385. \\[sh-for] for loop
  1386. \\[sh-function] function definition
  1387. \\[sh-if] if statement
  1388. \\[sh-indexed-loop] indexed loop from 1 to n
  1389. \\[sh-while-getopts] while getopts loop
  1390. \\[sh-repeat] repeat loop
  1391. \\[sh-select] select loop
  1392. \\[sh-until] until loop
  1393. \\[sh-while] while loop
  1394. For sh and rc shells indentation commands are:
  1395. \\[sh-show-indent] Show the variable controlling this line's indentation.
  1396. \\[sh-set-indent] Set then variable controlling this line's indentation.
  1397. \\[sh-learn-line-indent] Change the indentation variable so this line
  1398. would indent to the way it currently is.
  1399. \\[sh-learn-buffer-indent] Set the indentation variables so the
  1400. buffer indents as it currently is indented.
  1401. \\[backward-delete-char-untabify] Delete backward one position, even if it was a tab.
  1402. \\[sh-end-of-command] Go to end of successive commands.
  1403. \\[sh-beginning-of-command] Go to beginning of successive commands.
  1404. \\[sh-set-shell] Set this buffer's shell, and maybe its magic number.
  1405. \\[sh-execute-region] Have optional header and region be executed in a subshell.
  1406. `sh-electric-here-document-mode' controls whether insertion of two
  1407. unquoted < insert a here document.
  1408. If you generally program a shell different from your login shell you can
  1409. set `sh-shell-file' accordingly. If your shell's file name doesn't correctly
  1410. indicate what shell it is use `sh-alias-alist' to translate.
  1411. If your shell gives error messages with line numbers, you can use \\[executable-interpret]
  1412. with your script for an edit-interpret-debug cycle."
  1413. (make-local-variable 'sh-shell-file)
  1414. (make-local-variable 'sh-shell)
  1415. (setq-local skeleton-pair-default-alist
  1416. sh-skeleton-pair-default-alist)
  1417. (setq-local skeleton-end-hook
  1418. (lambda () (or (eolp) (newline) (indent-relative))))
  1419. (setq-local paragraph-start (concat page-delimiter "\\|$"))
  1420. (setq-local paragraph-separate (concat paragraph-start "\\|#!/"))
  1421. (setq-local comment-start "# ")
  1422. (setq-local comment-start-skip "#+[\t ]*")
  1423. (setq-local local-abbrev-table sh-mode-abbrev-table)
  1424. (setq-local comint-dynamic-complete-functions
  1425. sh-dynamic-complete-functions)
  1426. (add-hook 'completion-at-point-functions 'comint-completion-at-point nil t)
  1427. ;; we can't look if previous line ended with `\'
  1428. (setq-local comint-prompt-regexp "^[ \t]*")
  1429. (setq-local imenu-case-fold-search nil)
  1430. (setq font-lock-defaults
  1431. `((sh-font-lock-keywords
  1432. sh-font-lock-keywords-1 sh-font-lock-keywords-2)
  1433. nil nil
  1434. ((?/ . "w") (?~ . "w") (?. . "w") (?- . "w") (?_ . "w")) nil
  1435. (font-lock-syntactic-face-function
  1436. . sh-font-lock-syntactic-face-function)))
  1437. (setq-local syntax-propertize-function #'sh-syntax-propertize-function)
  1438. (add-hook 'syntax-propertize-extend-region-functions
  1439. #'syntax-propertize-multiline 'append 'local)
  1440. (sh-electric-here-document-mode 1)
  1441. (setq-local skeleton-pair-alist '((?` _ ?`)))
  1442. (setq-local skeleton-pair-filter-function 'sh-quoted-p)
  1443. (setq-local skeleton-further-elements
  1444. '((< '(- (min sh-indentation (current-column))))))
  1445. (setq-local skeleton-filter-function 'sh-feature)
  1446. (setq-local skeleton-newline-indent-rigidly t)
  1447. (setq-local defun-prompt-regexp
  1448. (concat "^\\(function[ \t]\\|[[:alnum:]]+[ \t]+()[ \t]+\\)"))
  1449. (setq-local add-log-current-defun-function #'sh-current-defun-name)
  1450. (add-hook 'completion-at-point-functions
  1451. #'sh-completion-at-point-function nil t)
  1452. ;; Parse or insert magic number for exec, and set all variables depending
  1453. ;; on the shell thus determined.
  1454. (sh-set-shell
  1455. (cond ((save-excursion
  1456. (goto-char (point-min))
  1457. (looking-at "#![ \t]?\\([^ \t\n]*/bin/env[ \t]\\)?\\([^ \t\n]+\\)"))
  1458. (match-string 2))
  1459. ((not buffer-file-name) sh-shell-file)
  1460. ;; Checks that use `buffer-file-name' follow.
  1461. ((string-match "\\.m?spec\\'" buffer-file-name) "rpm")
  1462. ((string-match "[.]sh\\>" buffer-file-name) "sh")
  1463. ((string-match "[.]bash\\>" buffer-file-name) "bash")
  1464. ((string-match "[.]ksh\\>" buffer-file-name) "ksh")
  1465. ((string-match "[.]t?csh\\(rc\\)?\\>" buffer-file-name) "csh")
  1466. ((equal (file-name-nondirectory buffer-file-name) ".profile") "sh")
  1467. (t sh-shell-file))
  1468. nil nil)
  1469. (add-hook 'hack-local-variables-hook
  1470. #'sh-after-hack-local-variables nil t))
  1471. ;;;###autoload
  1472. (defalias 'shell-script-mode 'sh-mode)
  1473. (defun sh-font-lock-keywords (&optional keywords)
  1474. "Function to get simple fontification based on `sh-font-lock-keywords'.
  1475. This adds rules for comments and assignments."
  1476. (sh-feature sh-font-lock-keywords-var
  1477. (when (stringp (sh-feature sh-assignment-regexp))
  1478. (lambda (list)
  1479. `((,(sh-feature sh-assignment-regexp)
  1480. 1 font-lock-variable-name-face)
  1481. ,@keywords
  1482. ,@list
  1483. ,@executable-font-lock-keywords)))))
  1484. (defun sh-font-lock-keywords-1 (&optional builtins)
  1485. "Function to get better fontification including keywords."
  1486. (let ((keywords (concat "\\([;(){}`|&]\\|^\\)[ \t]*\\(\\("
  1487. (regexp-opt (sh-feature sh-leading-keywords) t)
  1488. "[ \t]+\\)?"
  1489. (regexp-opt (append (sh-feature sh-leading-keywords)
  1490. (sh-feature sh-other-keywords))
  1491. t))))
  1492. (sh-font-lock-keywords
  1493. `(,@(if builtins
  1494. `((,(concat keywords "[ \t]+\\)?"
  1495. (regexp-opt (sh-feature sh-builtins) t)
  1496. "\\>")
  1497. (2 font-lock-keyword-face nil t)
  1498. (6 font-lock-builtin-face))
  1499. ,@(sh-feature sh-font-lock-keywords-var-2)))
  1500. (,(concat keywords "\\)\\>")
  1501. 2 font-lock-keyword-face)
  1502. ,@(sh-feature sh-font-lock-keywords-var-1)))))
  1503. (defun sh-font-lock-keywords-2 ()
  1504. "Function to get better fontification including keywords and builtins."
  1505. (sh-font-lock-keywords-1 t))
  1506. ;;; Completion
  1507. (defun sh--vars-before-point ()
  1508. (save-excursion
  1509. (let ((vars ()))
  1510. (while (re-search-backward "^[ \t]*\\([[:alnum:]_]+\\)=" nil t)
  1511. (push (match-string 1) vars))
  1512. vars)))
  1513. ;; (defun sh--var-completion-table (string pred action)
  1514. ;; (complete-with-action action (sh--vars-before-point) string pred))
  1515. (defun sh--cmd-completion-table (string pred action)
  1516. (let ((cmds
  1517. (append (when (fboundp 'imenu--make-index-alist)
  1518. (mapcar #'car (imenu--make-index-alist)))
  1519. (mapcar (lambda (v) (concat v "="))
  1520. (sh--vars-before-point))
  1521. (locate-file-completion-table
  1522. exec-path exec-suffixes string pred t)
  1523. '("if" "while" "until" "for"))))
  1524. (complete-with-action action cmds string pred)))
  1525. (defun sh-completion-at-point-function ()
  1526. (save-excursion
  1527. (skip-chars-forward "[:alnum:]_")
  1528. (let ((end (point))
  1529. (_ (skip-chars-backward "[:alnum:]_"))
  1530. (start (point)))
  1531. (cond
  1532. ((eq (char-before) ?$)
  1533. (list start end (sh--vars-before-point)))
  1534. ((sh-smie--keyword-p)
  1535. (list start end #'sh--cmd-completion-table))))))
  1536. ;;; Indentation and navigation with SMIE.
  1537. (require 'smie)
  1538. ;; The SMIE code should generally be preferred, but it currently does not obey
  1539. ;; the various indentation custom-vars, and it misses some important features
  1540. ;; of the old code, mostly: sh-learn-line/buffer-indent, sh-show-indent,
  1541. ;; sh-name/save/load-style.
  1542. (defvar sh-use-smie t
  1543. "Whether to use the SMIE code for navigation and indentation.")
  1544. (defun sh-smie--keyword-p ()
  1545. "Non-nil if we're at a keyword position.
  1546. A keyword position is one where if we're looking at something that looks
  1547. like a keyword, then it is a keyword."
  1548. (let ((prev (funcall smie-backward-token-function)))
  1549. (if (zerop (length prev))
  1550. (looking-back "\\`\\|\\s(" (1- (point)))
  1551. (assoc prev smie-grammar))))
  1552. (defun sh-smie--newline-semi-p (&optional tok)
  1553. "Return non-nil if a newline should be treated as a semi-colon.
  1554. Here we assume that a newline should be treated as a semi-colon unless it
  1555. comes right after a special keyword.
  1556. This function does not pay attention to line-continuations.
  1557. If TOK is nil, point should be before the newline; otherwise, TOK is the token
  1558. before the newline and in that case point should be just before the token."
  1559. (save-excursion
  1560. (unless tok
  1561. (setq tok (funcall smie-backward-token-function)))
  1562. (if (and (zerop (length tok))
  1563. (looking-back "\\s(" (1- (point))))
  1564. nil
  1565. (not (numberp (nth 2 (assoc tok smie-grammar)))))))
  1566. ;;;; SMIE support for `sh'.
  1567. (defconst sh-smie-sh-grammar
  1568. (smie-prec2->grammar
  1569. (smie-bnf->prec2
  1570. '((exp) ;A constant, or a $var, or a sequence of them...
  1571. (cmd ("case" exp "in" branches "esac")
  1572. ("if" cmd "then" cmd "fi")
  1573. ("if" cmd "then" cmd "else" cmd "fi")
  1574. ("if" cmd "then" cmd "elif" cmd "then" cmd "fi")
  1575. ("if" cmd "then" cmd "elif" cmd "then" cmd "else" cmd "fi")
  1576. ("if" cmd "then" cmd "elif" cmd "then" cmd
  1577. "elif" cmd "then" cmd "else" cmd "fi")
  1578. ("while" cmd "do" cmd "done")
  1579. ("until" cmd "do" cmd "done")
  1580. ("for" exp "in" cmd "do" cmd "done")
  1581. ("for" exp "do" cmd "done")
  1582. ("select" exp "in" cmd "do" cmd "done") ;bash&zsh&ksh88.
  1583. ("repeat" exp "do" cmd "done") ;zsh.
  1584. (exp "always" exp) ;zsh.
  1585. (cmd "|" cmd) (cmd "|&" cmd)
  1586. (cmd "&&" cmd) (cmd "||" cmd)
  1587. (cmd ";" cmd) (cmd "&" cmd))
  1588. (rpattern (rpattern "|" rpattern))
  1589. (pattern (rpattern) ("case-(" rpattern))
  1590. (branches (branches ";;" branches)
  1591. (branches ";&" branches) (branches ";;&" branches) ;bash.
  1592. (pattern "case-)" cmd)))
  1593. '((assoc ";;" ";&" ";;&"))
  1594. '((assoc ";" "&") (assoc "&&" "||") (assoc "|" "|&")))))
  1595. (defconst sh-smie--sh-operators
  1596. (delq nil (mapcar (lambda (x)
  1597. (setq x (car x))
  1598. (and (stringp x)
  1599. (not (string-match "\\`[a-z]" x))
  1600. x))
  1601. sh-smie-sh-grammar)))
  1602. (defconst sh-smie--sh-operators-re (regexp-opt sh-smie--sh-operators))
  1603. (defconst sh-smie--sh-operators-back-re
  1604. (concat "\\(?:^\\|[^\\]\\)\\(?:\\\\\\\\\\)*"
  1605. "\\(" sh-smie--sh-operators-re "\\)"))
  1606. (defun sh-smie--sh-keyword-in-p ()
  1607. "Assuming we're looking at \"in\", return non-nil if it's a keyword.
  1608. Does not preserve point."
  1609. (let ((forward-sexp-function nil)
  1610. (words nil) ;We've seen words.
  1611. (newline nil) ;We've seen newlines after the words.
  1612. (res nil)
  1613. prev)
  1614. (while (not res)
  1615. (setq prev (funcall smie-backward-token-function))
  1616. (cond
  1617. ((zerop (length prev))
  1618. (cond
  1619. (newline (cl-assert words) (setq res 'word))
  1620. ((bobp) (setq res 'word))
  1621. (t
  1622. (setq words t)
  1623. (condition-case nil
  1624. (forward-sexp -1)
  1625. (scan-error (setq res 'unknown))))))
  1626. ((equal prev ";")
  1627. (if words (setq newline t)
  1628. (setq res 'keyword)))
  1629. ((member prev '("case" "for" "select")) (setq res 'keyword))
  1630. ((assoc prev smie-grammar) (setq res 'word))
  1631. (t
  1632. (if newline
  1633. (progn (cl-assert words) (setq res 'word))
  1634. (setq words t)))))
  1635. (eq res 'keyword)))
  1636. (defun sh-smie--sh-keyword-p (tok)
  1637. "Non-nil if TOK (at which we're looking) really is a keyword."
  1638. (cond
  1639. ((looking-at "[[:alnum:]_]+=") nil)
  1640. ((equal tok "in") (sh-smie--sh-keyword-in-p))
  1641. (t (sh-smie--keyword-p))))
  1642. (defun sh-smie--default-forward-token ()
  1643. (forward-comment (point-max))
  1644. (buffer-substring-no-properties
  1645. (point)
  1646. (progn (if (zerop (skip-syntax-forward "."))
  1647. (while (progn (skip-syntax-forward "w_'")
  1648. (looking-at "\\\\"))
  1649. (forward-char 2)))
  1650. (point))))
  1651. (defun sh-smie--default-backward-token ()
  1652. (forward-comment (- (point)))
  1653. (let ((pos (point))
  1654. (n (skip-syntax-backward ".")))
  1655. (if (or (zerop n)
  1656. (and (eq n -1)
  1657. (let ((p (point)))
  1658. (if (eq -1 (% (skip-syntax-backward "\\") 2))
  1659. t
  1660. (goto-char p)
  1661. nil))))
  1662. (while
  1663. (progn (skip-syntax-backward "w_'")
  1664. (or (not (zerop (skip-syntax-backward "\\")))
  1665. (when (eq ?\\ (char-before (1- (point))))
  1666. (let ((p (point)))
  1667. (forward-char -1)
  1668. (if (eq -1 (% (skip-syntax-backward "\\") 2))
  1669. t
  1670. (goto-char p)
  1671. nil))))))
  1672. (goto-char (- (point) (% (skip-syntax-backward "\\") 2))))
  1673. (buffer-substring-no-properties (point) pos)))
  1674. (defun sh-smie-sh-forward-token ()
  1675. (if (and (looking-at "[ \t]*\\(?:#\\|\\(\\s|\\)\\|$\\)")
  1676. (save-excursion
  1677. (skip-chars-backward " \t")
  1678. (not (bolp))))
  1679. (if (and (match-end 1) (not (nth 3 (syntax-ppss))))
  1680. ;; Right before a here-doc.
  1681. (let ((forward-sexp-function nil))
  1682. (forward-sexp 1)
  1683. ;; Pretend the here-document is a "newline representing a
  1684. ;; semi-colon", since the here-doc otherwise covers the newline(s).
  1685. ";")
  1686. (let ((semi (sh-smie--newline-semi-p)))
  1687. (forward-line 1)
  1688. (if (or semi (eobp)) ";"
  1689. (sh-smie-sh-forward-token))))
  1690. (forward-comment (point-max))
  1691. (cond
  1692. ((looking-at "\\\\\n") (forward-line 1) (sh-smie-sh-forward-token))
  1693. ((looking-at sh-smie--sh-operators-re)
  1694. (goto-char (match-end 0))
  1695. (let ((tok (match-string-no-properties 0)))
  1696. (if (and (memq (aref tok (1- (length tok))) '(?\; ?\& ?\|))
  1697. (looking-at "[ \t]*\\(?:#\\|$\\)"))
  1698. (forward-line 1))
  1699. tok))
  1700. (t
  1701. (let* ((pos (point))
  1702. (tok (sh-smie--default-forward-token)))
  1703. (cond
  1704. ((equal tok ")") "case-)")
  1705. ((equal tok "(") "case-(")
  1706. ((and tok (string-match "\\`[a-z]" tok)
  1707. (assoc tok smie-grammar)
  1708. (not
  1709. (save-excursion
  1710. (goto-char pos)
  1711. (sh-smie--sh-keyword-p tok))))
  1712. " word ")
  1713. (t tok)))))))
  1714. (defun sh-smie--looking-back-at-continuation-p ()
  1715. (save-excursion
  1716. (and (if (eq (char-before) ?\n) (progn (forward-char -1) t) (eolp))
  1717. (looking-back "\\(?:^\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\\\"
  1718. (line-beginning-position)))))
  1719. (defun sh-smie-sh-backward-token ()
  1720. (let ((bol (line-beginning-position)))
  1721. (forward-comment (- (point)))
  1722. (cond
  1723. ((and (bolp) (not (bobp))
  1724. (equal (syntax-after (1- (point))) (string-to-syntax "|"))
  1725. (not (nth 3 (syntax-ppss))))
  1726. ;; Right after a here-document.
  1727. (let ((forward-sexp-function nil))
  1728. (forward-sexp -1)
  1729. ;; Pretend the here-document is a "newline representing a
  1730. ;; semi-colon", since the here-doc otherwise covers the newline(s).
  1731. ";"))
  1732. ((< (point) bol)
  1733. (cond
  1734. ((sh-smie--looking-back-at-continuation-p)
  1735. (forward-char -1)
  1736. (funcall smie-backward-token-function))
  1737. ((sh-smie--newline-semi-p) ";")
  1738. (t (funcall smie-backward-token-function))))
  1739. ((looking-back sh-smie--sh-operators-back-re
  1740. (line-beginning-position) 'greedy)
  1741. (goto-char (match-beginning 1))
  1742. (match-string-no-properties 1))
  1743. (t
  1744. (let ((tok (sh-smie--default-backward-token)))
  1745. (cond
  1746. ((equal tok ")") "case-)")
  1747. ((equal tok "(") "case-(")
  1748. ((and tok (string-match "\\`[a-z]" tok)
  1749. (assoc tok smie-grammar)
  1750. (not (save-excursion (sh-smie--sh-keyword-p tok))))
  1751. " word ")
  1752. (t tok)))))))
  1753. (defcustom sh-indent-after-continuation t
  1754. "If non-nil, try to make sure text is indented after a line continuation."
  1755. :version "24.3"
  1756. :type 'boolean
  1757. :group 'sh-indentation)
  1758. (defun sh-smie--continuation-start-indent ()
  1759. "Return the initial indentation of a continued line.
  1760. May return nil if the line should not be treated as continued."
  1761. (save-excursion
  1762. (forward-line -1)
  1763. (unless (sh-smie--looking-back-at-continuation-p)
  1764. (current-indentation))))
  1765. (defun sh-smie-sh-rules (kind token)
  1766. (pcase (cons kind token)
  1767. (`(:elem . basic) sh-indentation)
  1768. (`(:after . "case-)") (- (sh-var-value 'sh-indent-for-case-alt)
  1769. (sh-var-value 'sh-indent-for-case-label)))
  1770. ((and `(:before . ,_)
  1771. ;; After a line-continuation, make sure the rest is indented.
  1772. (guard sh-indent-after-continuation)
  1773. (guard (save-excursion
  1774. (ignore-errors
  1775. (skip-chars-backward " \t")
  1776. (sh-smie--looking-back-at-continuation-p))))
  1777. (let initial (sh-smie--continuation-start-indent))
  1778. (guard (let* ((sh-indent-after-continuation nil)
  1779. (indent (smie-indent-calculate)))
  1780. (and (numberp indent) (numberp initial)
  1781. (<= indent initial)))))
  1782. `(column . ,(+ initial sh-indentation)))
  1783. (`(:before . ,(or `"(" `"{" `"[" "while" "if" "for" "case"))
  1784. (if (not (smie-rule-prev-p "&&" "||" "|"))
  1785. (when (smie-rule-hanging-p)
  1786. (smie-rule-parent))
  1787. (unless (smie-rule-bolp)
  1788. (while (equal "|" (nth 2 (smie-backward-sexp 'halfexp))))
  1789. `(column . ,(smie-indent-virtual)))))
  1790. ;; FIXME: Maybe this handling of ;; should be made into
  1791. ;; a smie-rule-terminator function that takes the substitute ";" as arg.
  1792. (`(:before . ,(or `";;" `";&" `";;&"))
  1793. (if (and (smie-rule-bolp) (looking-at ";;?&?[ \t]*\\(#\\|$\\)"))
  1794. (cons 'column (smie-indent-keyword ";"))
  1795. (smie-rule-separator kind)))
  1796. (`(:after . ,(or `";;" `";&" `";;&"))
  1797. (with-demoted-errors
  1798. (smie-backward-sexp token)
  1799. (cons 'column
  1800. (if (or (smie-rule-bolp)
  1801. (save-excursion
  1802. (and (member (funcall smie-backward-token-function)
  1803. '("in" ";;"))
  1804. (smie-rule-bolp))))
  1805. (current-column)
  1806. (smie-indent-calculate)))))
  1807. (`(:before . ,(or `"|" `"&&" `"||"))
  1808. (unless (smie-rule-parent-p token)
  1809. (smie-backward-sexp token)
  1810. `(column . ,(+ (funcall smie-rules-function :elem 'basic)
  1811. (smie-indent-virtual)))))
  1812. ;; Attempt at backward compatibility with the old config variables.
  1813. (`(:before . "fi") (sh-var-value 'sh-indent-for-fi))
  1814. (`(:before . "done") (sh-var-value 'sh-indent-for-done))
  1815. (`(:after . "else") (sh-var-value 'sh-indent-after-else))
  1816. (`(:after . "if") (sh-var-value 'sh-indent-after-if))
  1817. (`(:before . "then") (sh-var-value 'sh-indent-for-then))
  1818. (`(:before . "do") (sh-var-value 'sh-indent-for-do))
  1819. (`(:after . "do")
  1820. (sh-var-value (if (smie-rule-hanging-p)
  1821. 'sh-indent-after-loop-construct 'sh-indent-after-do)))
  1822. ;; sh-indent-after-done: aligned completely differently.
  1823. (`(:after . "in") (sh-var-value 'sh-indent-for-case-label))
  1824. ;; sh-indent-for-continuation: Line continuations are handled differently.
  1825. (`(:after . ,(or `"(" `"{" `"[")) (sh-var-value 'sh-indent-after-open))
  1826. ;; sh-indent-after-function: we don't handle it differently.
  1827. ))
  1828. ;; (defconst sh-smie-csh-grammar
  1829. ;; (smie-prec2->grammar
  1830. ;; (smie-bnf->prec2
  1831. ;; '((exp) ;A constant, or a $var, or a sequence of them...
  1832. ;; (elseifcmd (cmd)
  1833. ;; (cmd "else" "else-if" exp "then" elseifcmd))
  1834. ;; (cmd ("switch" branches "endsw")
  1835. ;; ("if" exp)
  1836. ;; ("if" exp "then" cmd "endif")
  1837. ;; ("if" exp "then" cmd "else" cmd "endif")
  1838. ;; ("if" exp "then" elseifcmd "endif")
  1839. ;; ;; ("if" exp "then" cmd "else" cmd "endif")
  1840. ;; ;; ("if" exp "then" cmd "else" "if" exp "then" cmd "endif")
  1841. ;; ;; ("if" exp "then" cmd "else" "if" exp "then" cmd
  1842. ;; ;; "else" cmd "endif")
  1843. ;; ;; ("if" exp "then" cmd "else" "if" exp "then" cmd
  1844. ;; ;; "else" "if" exp "then" cmd "endif")
  1845. ;; ("while" cmd "end")
  1846. ;; ("foreach" cmd "end")
  1847. ;; (cmd "|" cmd) (cmd "|&" cmd)
  1848. ;; (cmd "&&" cmd) (cmd "||" cmd)
  1849. ;; (cmd ";" cmd) (cmd "&" cmd))
  1850. ;; ;; This is a lie, but (combined with the corresponding disambiguation
  1851. ;; ;; rule) it makes it more clear that `case' and `default' are the key
  1852. ;; ;; separators and the `:' is a secondary tokens.
  1853. ;; (branches (branches "case" branches)
  1854. ;; (branches "default" branches)
  1855. ;; (exp ":" branches)))
  1856. ;; '((assoc "else" "then" "endif"))
  1857. ;; '((assoc "case" "default") (nonassoc ":"))
  1858. ;; '((assoc ";;" ";&" ";;&"))
  1859. ;; '((assoc ";" "&") (assoc "&&" "||") (assoc "|" "|&")))))
  1860. ;;;; SMIE support for `rc'.
  1861. (defconst sh-smie-rc-grammar
  1862. (smie-prec2->grammar
  1863. (smie-bnf->prec2
  1864. '((exp) ;A constant, or a $var, or a sequence of them...
  1865. (cmd (cmd "case" cmd)
  1866. ("if" exp)
  1867. ("switch" exp)
  1868. ("for" exp) ("while" exp)
  1869. (cmd "|" cmd) (cmd "|&" cmd)
  1870. (cmd "&&" cmd) (cmd "||" cmd)
  1871. (cmd ";" cmd) (cmd "&" cmd))
  1872. (pattern (pattern "|" pattern))
  1873. (branches (branches ";;" branches)
  1874. (branches ";&" branches) (branches ";;&" branches) ;bash.
  1875. (pattern "case-)" cmd)))
  1876. '((assoc ";;" ";&" ";;&"))
  1877. '((assoc "case") (assoc ";" "&") (assoc "&&" "||") (assoc "|" "|&")))))
  1878. (defun sh-smie--rc-after-special-arg-p ()
  1879. "Check if we're after the first arg of an if/while/for/... construct.
  1880. Returns the construct's token and moves point before it, if so."
  1881. (forward-comment (- (point)))
  1882. (when (looking-back ")\\|\\_<not" (- (point) 3))
  1883. (ignore-errors
  1884. (let ((forward-sexp-function nil))
  1885. (forward-sexp -1)
  1886. (car (member (funcall smie-backward-token-function)
  1887. '("if" "for" "switch" "while")))))))
  1888. (defun sh-smie--rc-newline-semi-p ()
  1889. "Return non-nil if a newline should be treated as a semi-colon.
  1890. Point should be before the newline."
  1891. (save-excursion
  1892. (let ((tok (funcall smie-backward-token-function)))
  1893. (if (or (when (equal tok "not") (forward-word 1) t)
  1894. (and (zerop (length tok)) (eq (char-before) ?\))))
  1895. (not (sh-smie--rc-after-special-arg-p))
  1896. (sh-smie--newline-semi-p tok)))))
  1897. (defun sh-smie-rc-forward-token ()
  1898. ;; FIXME: Code duplication with sh-smie-sh-forward-token.
  1899. (if (and (looking-at "[ \t]*\\(?:#\\|\\(\\s|\\)\\|$\\)")
  1900. (save-excursion
  1901. (skip-chars-backward " \t")
  1902. (not (bolp))))
  1903. (if (and (match-end 1) (not (nth 3 (syntax-ppss))))
  1904. ;; Right before a here-doc.
  1905. (let ((forward-sexp-function nil))
  1906. (forward-sexp 1)
  1907. ;; Pretend the here-document is a "newline representing a
  1908. ;; semi-colon", since the here-doc otherwise covers the newline(s).
  1909. ";")
  1910. (let ((semi (sh-smie--rc-newline-semi-p)))
  1911. (forward-line 1)
  1912. (if (or semi (eobp)) ";"
  1913. (sh-smie-rc-forward-token))))
  1914. (forward-comment (point-max))
  1915. (cond
  1916. ((looking-at "\\\\\n") (forward-line 1) (sh-smie-rc-forward-token))
  1917. ;; ((looking-at sh-smie--rc-operators-re)
  1918. ;; (goto-char (match-end 0))
  1919. ;; (let ((tok (match-string-no-properties 0)))
  1920. ;; (if (and (memq (aref tok (1- (length tok))) '(?\; ?\& ?\|))
  1921. ;; (looking-at "[ \t]*\\(?:#\\|$\\)"))
  1922. ;; (forward-line 1))
  1923. ;; tok))
  1924. (t
  1925. (let* ((pos (point))
  1926. (tok (sh-smie--default-forward-token)))
  1927. (cond
  1928. ;; ((equal tok ")") "case-)")
  1929. ((and tok (string-match "\\`[a-z]" tok)
  1930. (assoc tok smie-grammar)
  1931. (not
  1932. (save-excursion
  1933. (goto-char pos)
  1934. (sh-smie--keyword-p))))
  1935. " word ")
  1936. (t tok)))))))
  1937. (defun sh-smie-rc-backward-token ()
  1938. ;; FIXME: Code duplication with sh-smie-sh-backward-token.
  1939. (let ((bol (line-beginning-position)))
  1940. (forward-comment (- (point)))
  1941. (cond
  1942. ((and (bolp) (not (bobp))
  1943. (equal (syntax-after (1- (point))) (string-to-syntax "|"))
  1944. (not (nth 3 (syntax-ppss))))
  1945. ;; Right after a here-document.
  1946. (let ((forward-sexp-function nil))
  1947. (forward-sexp -1)
  1948. ;; Pretend the here-document is a "newline representing a
  1949. ;; semi-colon", since the here-doc otherwise covers the newline(s).
  1950. ";"))
  1951. ((< (point) bol) ;We skipped over a newline.
  1952. (cond
  1953. ;; A continued line.
  1954. ((and (eolp)
  1955. (looking-back "\\(?:^\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\\\"
  1956. (line-beginning-position)))
  1957. (forward-char -1)
  1958. (funcall smie-backward-token-function))
  1959. ((sh-smie--rc-newline-semi-p) ";")
  1960. (t (funcall smie-backward-token-function))))
  1961. ;; ((looking-back sh-smie--sh-operators-back-re
  1962. ;; (line-beginning-position) 'greedy)
  1963. ;; (goto-char (match-beginning 1))
  1964. ;; (match-string-no-properties 1))
  1965. (t
  1966. (let ((tok (sh-smie--default-backward-token)))
  1967. (cond
  1968. ;; ((equal tok ")") "case-)")
  1969. ((and tok (string-match "\\`[a-z]" tok)
  1970. (assoc tok smie-grammar)
  1971. (not (save-excursion (sh-smie--keyword-p))))
  1972. " word ")
  1973. (t tok)))))))
  1974. (defun sh-smie-rc-rules (kind token)
  1975. (pcase (cons kind token)
  1976. (`(:elem . basic) sh-indentation)
  1977. ;; (`(:after . "case") (or sh-indentation smie-indent-basic))
  1978. (`(:after . ";")
  1979. (if (smie-rule-parent-p "case")
  1980. (smie-rule-parent (sh-var-value 'sh-indent-after-case))))
  1981. (`(:before . "{")
  1982. (save-excursion
  1983. (when (sh-smie--rc-after-special-arg-p)
  1984. `(column . ,(current-column)))))
  1985. (`(:before . ,(or `"(" `"{" `"["))
  1986. (if (smie-rule-hanging-p) (smie-rule-parent)))
  1987. ;; FIXME: SMIE parses "if (exp) cmd" as "(if ((exp) cmd))" so "cmd" is
  1988. ;; treated as an arg to (exp) by default, which indents it all wrong.
  1989. ;; To handle it right, we should extend smie-indent-exps so that the
  1990. ;; preceding keyword can give special rules. Currently the only special
  1991. ;; rule we have is the :list-intro hack, which we use here to align "cmd"
  1992. ;; with "(exp)", which is rarely the right thing to do, but is better
  1993. ;; than nothing.
  1994. (`(:list-intro . ,(or `"for" `"if" `"while")) t)
  1995. ;; sh-indent-after-switch: handled implicitly by the default { rule.
  1996. ))
  1997. ;;; End of SMIE code.
  1998. (defvar sh-regexp-for-done nil
  1999. "A buffer-local regexp to match opening keyword for done.")
  2000. (defvar sh-kw-alist nil
  2001. "A buffer-local, since it is shell-type dependent, list of keywords.")
  2002. ;; ( key-word first-on-this on-prev-line )
  2003. ;; This is used to set `sh-kw-alist' which is a list of sublists each
  2004. ;; having 3 elements:
  2005. ;; a keyword
  2006. ;; a rule to check when the keyword appears on "this" line
  2007. ;; a rule to check when the keyword appears on "the previous" line
  2008. ;; The keyword is usually a string and is the first word on a line.
  2009. ;; If this keyword appears on the line whose indentation is to be
  2010. ;; calculated, the rule in element 2 is called. If this returns
  2011. ;; non-zero, the resulting point (which may be changed by the rule)
  2012. ;; is used as the default indentation.
  2013. ;; If it returned false or the keyword was not found in the table,
  2014. ;; then the keyword from the previous line is looked up and the rule
  2015. ;; in element 3 is called. In this case, however,
  2016. ;; `sh-get-indent-info' does not stop but may keep going and test
  2017. ;; other keywords against rules in element 3. This is because the
  2018. ;; preceding line could have, for example, an opening "if" and an
  2019. ;; opening "while" keyword and we need to add the indentation offsets
  2020. ;; for both.
  2021. ;;
  2022. (defconst sh-kw
  2023. '((sh
  2024. ("if" nil sh-handle-prev-if)
  2025. ("elif" sh-handle-this-else sh-handle-prev-else)
  2026. ("else" sh-handle-this-else sh-handle-prev-else)
  2027. ("fi" sh-handle-this-fi sh-handle-prev-fi)
  2028. ("then" sh-handle-this-then sh-handle-prev-then)
  2029. ("(" nil sh-handle-prev-open)
  2030. ("{" nil sh-handle-prev-open)
  2031. ("[" nil sh-handle-prev-open)
  2032. ("}" sh-handle-this-close nil)
  2033. (")" sh-handle-this-close nil)
  2034. ("]" sh-handle-this-close nil)
  2035. ("case" nil sh-handle-prev-case)
  2036. ("esac" sh-handle-this-esac sh-handle-prev-esac)
  2037. (case-label nil sh-handle-after-case-label) ;; ???
  2038. (";;" nil sh-handle-prev-case-alt-end) ;; ???
  2039. (";;&" nil sh-handle-prev-case-alt-end) ;Like ";;" with diff semantics.
  2040. (";&" nil sh-handle-prev-case-alt-end) ;Like ";;" with diff semantics.
  2041. ("done" sh-handle-this-done sh-handle-prev-done)
  2042. ("do" sh-handle-this-do sh-handle-prev-do))
  2043. ;; Note: we don't need specific stuff for bash and zsh shells;
  2044. ;; the regexp `sh-regexp-for-done' handles the extra keywords
  2045. ;; these shells use.
  2046. (rc
  2047. ("{" nil sh-handle-prev-open)
  2048. ("}" sh-handle-this-close nil)
  2049. ("case" sh-handle-this-rc-case sh-handle-prev-rc-case))))
  2050. (defun sh-set-shell (shell &optional no-query-flag insert-flag)
  2051. "Set this buffer's shell to SHELL (a string).
  2052. When used interactively, insert the proper starting #!-line,
  2053. and make the visited file executable via `executable-set-magic',
  2054. perhaps querying depending on the value of `executable-query'.
  2055. When this function is called noninteractively, INSERT-FLAG (the third
  2056. argument) controls whether to insert a #!-line and think about making
  2057. the visited file executable, and NO-QUERY-FLAG (the second argument)
  2058. controls whether to query about making the visited file executable.
  2059. Calls the value of `sh-set-shell-hook' if set."
  2060. (interactive (list (completing-read
  2061. (format "Shell \(default %s\): "
  2062. sh-shell-file)
  2063. ;; This used to use interpreter-mode-alist, but that is
  2064. ;; no longer appropriate now that uses regexps.
  2065. ;; Maybe there could be a separate variable that lists
  2066. ;; the shells, used here and to construct i-mode-alist.
  2067. ;; But the following is probably good enough:
  2068. (append (mapcar (lambda (e) (symbol-name (car e)))
  2069. sh-ancestor-alist)
  2070. '("csh" "rc" "sh"))
  2071. nil nil nil nil sh-shell-file)
  2072. (eq executable-query 'function)
  2073. t))
  2074. (if (string-match "\\.exe\\'" shell)
  2075. (setq shell (substring shell 0 (match-beginning 0))))
  2076. (setq sh-shell (sh-canonicalize-shell shell))
  2077. (if insert-flag
  2078. (setq sh-shell-file
  2079. (executable-set-magic shell (sh-feature sh-shell-arg)
  2080. no-query-flag insert-flag)))
  2081. (setq mode-line-process (format "[%s]" sh-shell))
  2082. (setq-local sh-shell-variables nil)
  2083. (setq-local sh-shell-variables-initialized nil)
  2084. (setq-local imenu-generic-expression
  2085. (sh-feature sh-imenu-generic-expression))
  2086. (let ((tem (sh-feature sh-mode-syntax-table-input)))
  2087. (when tem
  2088. (setq-local sh-mode-syntax-table
  2089. (apply 'sh-mode-syntax-table tem))
  2090. (set-syntax-table sh-mode-syntax-table)))
  2091. (dolist (var (sh-feature sh-variables))
  2092. (sh-remember-variable var))
  2093. (if (setq-local sh-indent-supported-here
  2094. (sh-feature sh-indent-supported))
  2095. (progn
  2096. (message "Setting up indent for shell type %s" sh-shell)
  2097. (let ((mksym (lambda (name)
  2098. (intern (format "sh-smie-%s-%s"
  2099. sh-indent-supported-here name)))))
  2100. (add-function :around (local 'smie--hanging-eolp-function)
  2101. (lambda (orig)
  2102. (if (looking-at "[ \t]*\\\\\n")
  2103. (goto-char (match-end 0))
  2104. (funcall orig))))
  2105. (smie-setup (symbol-value (funcall mksym "grammar"))
  2106. (funcall mksym "rules")
  2107. :forward-token (funcall mksym "forward-token")
  2108. :backward-token (funcall mksym "backward-token")))
  2109. (unless sh-use-smie
  2110. (setq-local parse-sexp-lookup-properties t)
  2111. (setq-local sh-kw-alist (sh-feature sh-kw))
  2112. (let ((regexp (sh-feature sh-kws-for-done)))
  2113. (if regexp
  2114. (setq-local sh-regexp-for-done
  2115. (sh-mkword-regexpr (regexp-opt regexp t)))))
  2116. (message "setting up indent stuff")
  2117. ;; sh-mode has already made indent-line-function local
  2118. ;; but do it in case this is called before that.
  2119. (setq-local indent-line-function 'sh-indent-line))
  2120. (if sh-make-vars-local
  2121. (sh-make-vars-local))
  2122. (message "Indentation setup for shell type %s" sh-shell))
  2123. (message "No indentation for this shell type.")
  2124. (setq-local indent-line-function 'sh-basic-indent-line))
  2125. (when font-lock-mode
  2126. (setq font-lock-set-defaults nil)
  2127. (font-lock-set-defaults)
  2128. (font-lock-flush))
  2129. (setq sh-shell-process nil)
  2130. (run-hooks 'sh-set-shell-hook))
  2131. (defun sh-feature (alist &optional function)
  2132. "Index ALIST by the current shell.
  2133. If ALIST isn't a list where every element is a cons, it is returned as is.
  2134. Else indexing follows an inheritance logic which works in two ways:
  2135. - Fall back on successive ancestors (see `sh-ancestor-alist') as long as
  2136. the alist contains no value for the current shell.
  2137. The ultimate default is always `sh'.
  2138. - If the value thus looked up is a list starting with `sh-append',
  2139. we call the function `sh-append' with the rest of the list as
  2140. arguments, and use the value. However, the next element of the
  2141. list is not used as-is; instead, we look it up recursively
  2142. in ALIST to allow the function called to define the value for
  2143. one shell to be derived from another shell.
  2144. The value thus determined is physically replaced into the alist.
  2145. If FUNCTION is non-nil, it is called with one argument,
  2146. the value thus obtained, and the result is used instead."
  2147. (or (if (consp alist)
  2148. ;; Check for something that isn't a valid alist.
  2149. (let ((l alist))
  2150. (while (and l (consp (car l)))
  2151. (setq l (cdr l)))
  2152. (if l alist)))
  2153. (let ((orig-sh-shell sh-shell))
  2154. (let ((sh-shell sh-shell)
  2155. elt val)
  2156. (while (and sh-shell
  2157. (not (setq elt (assq sh-shell alist))))
  2158. (setq sh-shell (cdr (assq sh-shell sh-ancestor-alist))))
  2159. ;; If the shell is not known, treat it as sh.
  2160. (unless elt
  2161. (setq elt (assq 'sh alist)))
  2162. (setq val (cdr elt))
  2163. (if (and (consp val)
  2164. (memq (car val) '(sh-append sh-modify)))
  2165. (setq val
  2166. (apply (car val)
  2167. ;; Refer to the value for a different shell,
  2168. ;; as a kind of inheritance.
  2169. (let ((sh-shell (car (cdr val))))
  2170. (sh-feature alist))
  2171. (cddr val))))
  2172. (if function
  2173. (setq sh-shell orig-sh-shell
  2174. val (funcall function val)))
  2175. val))))
  2176. ;; I commented this out because nobody calls it -- rms.
  2177. ;;(defun sh-abbrevs (ancestor &rest list)
  2178. ;; "If it isn't, define the current shell as abbrev table and fill that.
  2179. ;;Abbrev table will inherit all abbrevs from ANCESTOR, which is either an abbrev
  2180. ;;table or a list of (NAME1 EXPANSION1 ...). In addition it will define abbrevs
  2181. ;;according to the remaining arguments NAMEi EXPANSIONi ...
  2182. ;;EXPANSION may be either a string or a skeleton command."
  2183. ;; (or (if (boundp sh-shell)
  2184. ;; (symbol-value sh-shell))
  2185. ;; (progn
  2186. ;; (if (listp ancestor)
  2187. ;; (nconc list ancestor))
  2188. ;; (define-abbrev-table sh-shell ())
  2189. ;; (if (vectorp ancestor)
  2190. ;; (mapatoms (lambda (atom)
  2191. ;; (or (eq atom 0)
  2192. ;; (define-abbrev (symbol-value sh-shell)
  2193. ;; (symbol-name atom)
  2194. ;; (symbol-value atom)
  2195. ;; (symbol-function atom))))
  2196. ;; ancestor))
  2197. ;; (while list
  2198. ;; (define-abbrev (symbol-value sh-shell)
  2199. ;; (car list)
  2200. ;; (if (stringp (car (cdr list)))
  2201. ;; (car (cdr list))
  2202. ;; "")
  2203. ;; (if (symbolp (car (cdr list)))
  2204. ;; (car (cdr list))))
  2205. ;; (setq list (cdr (cdr list)))))
  2206. ;; (symbol-value sh-shell)))
  2207. (defun sh-append (ancestor &rest list)
  2208. "Return list composed of first argument (a list) physically appended to rest."
  2209. (nconc list ancestor))
  2210. (defun sh-modify (skeleton &rest list)
  2211. "Modify a copy of SKELETON by replacing I1 with REPL1, I2 with REPL2 ..."
  2212. (setq skeleton (copy-sequence skeleton))
  2213. (while list
  2214. (setcar (or (nthcdr (car list) skeleton)
  2215. (error "Index %d out of bounds" (car list)))
  2216. (car (cdr list)))
  2217. (setq list (nthcdr 2 list)))
  2218. skeleton)
  2219. (defun sh-basic-indent-line ()
  2220. "Indent a line for Sh mode (shell script mode).
  2221. Indent as far as preceding non-empty line, then by steps of `sh-indentation'.
  2222. Lines containing only comments are considered empty."
  2223. (interactive)
  2224. (let ((previous (save-excursion
  2225. (while (and (progn (beginning-of-line)
  2226. (not (bobp)))
  2227. (progn
  2228. (forward-line -1)
  2229. (back-to-indentation)
  2230. (or (eolp)
  2231. (eq (following-char) ?#)))))
  2232. (current-column)))
  2233. current)
  2234. (save-excursion
  2235. (indent-to (if (or (eq this-command 'newline-and-indent)
  2236. (and electric-indent-mode (eq this-command 'newline)))
  2237. previous
  2238. (if (< (current-column)
  2239. (setq current (progn (back-to-indentation)
  2240. (current-column))))
  2241. (if (eolp) previous 0)
  2242. (delete-region (point)
  2243. (progn (beginning-of-line) (point)))
  2244. (if (eolp)
  2245. (max previous (* (1+ (/ current sh-indentation))
  2246. sh-indentation))
  2247. (* (1+ (/ current sh-indentation)) sh-indentation))))))
  2248. (if (< (current-column) (current-indentation))
  2249. (skip-chars-forward " \t"))))
  2250. (defun sh-execute-region (start end &optional flag)
  2251. "Pass optional header and region to a subshell for noninteractive execution.
  2252. The working directory is that of the buffer, and only environment variables
  2253. are already set which is why you can mark a header within the script.
  2254. With a positive prefix ARG, instead of sending region, define header from
  2255. beginning of buffer to point. With a negative prefix ARG, instead of sending
  2256. region, clear header."
  2257. (interactive "r\nP")
  2258. (if flag
  2259. (setq sh-header-marker (if (> (prefix-numeric-value flag) 0)
  2260. (point-marker)))
  2261. (if sh-header-marker
  2262. (save-excursion
  2263. (let (buffer-undo-list)
  2264. (goto-char sh-header-marker)
  2265. (append-to-buffer (current-buffer) start end)
  2266. (shell-command-on-region (point-min)
  2267. (setq end (+ sh-header-marker
  2268. (- end start)))
  2269. sh-shell-file)
  2270. (delete-region sh-header-marker end)))
  2271. (shell-command-on-region start end (concat sh-shell-file " -")))))
  2272. (defun sh-remember-variable (var)
  2273. "Make VARIABLE available for future completing reads in this buffer."
  2274. (or (< (length var) sh-remember-variable-min)
  2275. (getenv var)
  2276. (assoc var sh-shell-variables)
  2277. (push (cons var var) sh-shell-variables))
  2278. var)
  2279. (defun sh-quoted-p ()
  2280. "Is point preceded by an odd number of backslashes?"
  2281. (eq -1 (% (save-excursion (skip-chars-backward "\\\\")) 2)))
  2282. ;; Indentation stuff.
  2283. (defun sh-must-support-indent ()
  2284. "Signal an error if the shell type for this buffer is not supported.
  2285. Also, the buffer must be in Shell-script mode."
  2286. (unless sh-indent-supported-here
  2287. (error "This buffer's shell does not support indentation through Emacs")))
  2288. (defun sh-make-vars-local ()
  2289. "Make the indentation variables local to this buffer.
  2290. Normally they already are local. This command is provided in case
  2291. variable `sh-make-vars-local' has been set to nil.
  2292. To revert all these variables to the global values, use
  2293. command `sh-reset-indent-vars-to-global-values'."
  2294. (interactive)
  2295. (mapc 'make-local-variable sh-var-list)
  2296. (message "Indentation variables are now local."))
  2297. (defun sh-reset-indent-vars-to-global-values ()
  2298. "Reset local indentation variables to the global values.
  2299. Then, if variable `sh-make-vars-local' is non-nil, make them local."
  2300. (interactive)
  2301. (mapc 'kill-local-variable sh-var-list)
  2302. (if sh-make-vars-local
  2303. (mapcar 'make-local-variable sh-var-list)))
  2304. ;; Theoretically these are only needed in shell and derived modes.
  2305. ;; However, the routines which use them are only called in those modes.
  2306. (defconst sh-special-keywords "then\\|do")
  2307. (defun sh-help-string-for-variable (var)
  2308. "Construct a string for `sh-read-variable' when changing variable VAR ."
  2309. (let ((msg (documentation-property var 'variable-documentation))
  2310. (msg2 ""))
  2311. (unless (memq var '(sh-first-lines-indent sh-indent-comment))
  2312. (setq msg2
  2313. (format "\n
  2314. You can enter a number (positive to increase indentation,
  2315. negative to decrease indentation, zero for no change to indentation).
  2316. Or, you can enter one of the following symbols which are relative to
  2317. the value of variable `sh-basic-offset'
  2318. which in this buffer is currently %s.
  2319. \t%s."
  2320. sh-basic-offset
  2321. (mapconcat (lambda (x)
  2322. (nth (1- (length x)) x))
  2323. sh-symbol-list "\n\t"))))
  2324. (concat
  2325. ;; The following shows the global not the local value!
  2326. ;; (format "Current value of %s is %s\n\n" var (symbol-value var))
  2327. msg msg2)))
  2328. (defun sh-read-variable (var)
  2329. "Read a new value for indentation variable VAR."
  2330. (let ((minibuffer-help-form `(sh-help-string-for-variable
  2331. (quote ,var)))
  2332. val)
  2333. (setq val (read-from-minibuffer
  2334. (format "New value for %s (press %s for help): "
  2335. var (single-key-description help-char))
  2336. (format "%s" (symbol-value var))
  2337. nil t))
  2338. val))
  2339. (defun sh-in-comment-or-string (start)
  2340. "Return non-nil if START is in a comment or string."
  2341. (save-excursion
  2342. (let ((state (syntax-ppss start)))
  2343. (or (nth 3 state) (nth 4 state)))))
  2344. (defun sh-goto-matching-if ()
  2345. "Go to the matching if for a fi.
  2346. This handles nested if..fi pairs."
  2347. (let ((found (sh-find-prev-matching "\\bif\\b" "\\bfi\\b" 1)))
  2348. (if found
  2349. (goto-char found))))
  2350. ;; Functions named sh-handle-this-XXX are called when the keyword on the
  2351. ;; line whose indentation is being handled contain XXX;
  2352. ;; those named sh-handle-prev-XXX are when XXX appears on the previous line.
  2353. (defun sh-handle-prev-if ()
  2354. (list '(+ sh-indent-after-if)))
  2355. (defun sh-handle-this-else ()
  2356. (if (sh-goto-matching-if)
  2357. ;; (list "aligned to if")
  2358. (list "aligned to if" '(+ sh-indent-for-else))
  2359. nil
  2360. ))
  2361. (defun sh-handle-prev-else ()
  2362. (if (sh-goto-matching-if)
  2363. (list '(+ sh-indent-after-if))
  2364. ))
  2365. (defun sh-handle-this-fi ()
  2366. (if (sh-goto-matching-if)
  2367. (list "aligned to if" '(+ sh-indent-for-fi))
  2368. nil
  2369. ))
  2370. (defun sh-handle-prev-fi ()
  2371. ;; Why do we have this rule? Because we must go back to the if
  2372. ;; to get its indent. We may continue back from there.
  2373. ;; We return nil because we don't have anything to add to result,
  2374. ;; the side affect of setting align-point is all that matters.
  2375. ;; we could return a comment (a string) but I can't think of a good one...
  2376. (sh-goto-matching-if)
  2377. nil)
  2378. (defun sh-handle-this-then ()
  2379. (let ((p (sh-goto-matching-if)))
  2380. (if p
  2381. (list '(+ sh-indent-for-then))
  2382. )))
  2383. (defun sh-handle-prev-then ()
  2384. (let ((p (sh-goto-matching-if)))
  2385. (if p
  2386. (list '(+ sh-indent-after-if))
  2387. )))
  2388. (defun sh-handle-prev-open ()
  2389. (save-excursion
  2390. (let ((x (sh-prev-stmt)))
  2391. (if (and x
  2392. (progn
  2393. (goto-char x)
  2394. (or
  2395. (looking-at "function\\b")
  2396. (looking-at "\\s-*\\S-+\\s-*()")
  2397. )))
  2398. (list '(+ sh-indent-after-function))
  2399. (list '(+ sh-indent-after-open)))
  2400. )))
  2401. (defun sh-handle-this-close ()
  2402. (forward-char 1) ;; move over ")"
  2403. (if (sh-safe-forward-sexp -1)
  2404. (list "aligned to opening paren")))
  2405. (defun sh-goto-matching-case ()
  2406. (let ((found (sh-find-prev-matching "\\bcase\\b" "\\besac\\b" 1)))
  2407. (if found (goto-char found))))
  2408. (defun sh-handle-prev-case ()
  2409. ;; This is typically called when point is on same line as a case
  2410. ;; we shouldn't -- and can't find prev-case
  2411. (if (looking-at ".*\\<case\\>")
  2412. (list '(+ sh-indent-for-case-label))
  2413. (error "We don't seem to be on a line with a case"))) ;; debug
  2414. (defun sh-handle-this-esac ()
  2415. (if (sh-goto-matching-case)
  2416. (list "aligned to matching case")))
  2417. (defun sh-handle-prev-esac ()
  2418. (if (sh-goto-matching-case)
  2419. (list "matching case")))
  2420. (defun sh-handle-after-case-label ()
  2421. (if (sh-goto-matching-case)
  2422. (list '(+ sh-indent-for-case-alt))))
  2423. (defun sh-handle-prev-case-alt-end ()
  2424. (if (sh-goto-matching-case)
  2425. (list '(+ sh-indent-for-case-label))))
  2426. (defun sh-safe-forward-sexp (&optional arg)
  2427. "Try and do a `forward-sexp', but do not error.
  2428. Return new point if successful, nil if an error occurred."
  2429. (condition-case nil
  2430. (progn
  2431. (forward-sexp (or arg 1))
  2432. (point)) ;; return point if successful
  2433. (error
  2434. (sh-debug "oops!(1) %d" (point))
  2435. nil))) ;; return nil if fail
  2436. (defun sh-goto-match-for-done ()
  2437. (let ((found (sh-find-prev-matching sh-regexp-for-done sh-re-done 1)))
  2438. (if found
  2439. (goto-char found))))
  2440. (defun sh-handle-this-done ()
  2441. (if (sh-goto-match-for-done)
  2442. (list "aligned to do stmt" '(+ sh-indent-for-done))))
  2443. (defun sh-handle-prev-done ()
  2444. (if (sh-goto-match-for-done)
  2445. (list "previous done")))
  2446. (defun sh-handle-this-do ()
  2447. (if (sh-goto-match-for-done)
  2448. (list '(+ sh-indent-for-do))))
  2449. (defun sh-handle-prev-do ()
  2450. (cond
  2451. ((save-restriction
  2452. (narrow-to-region (point) (line-beginning-position))
  2453. (sh-goto-match-for-done))
  2454. (sh-debug "match for done found on THIS line")
  2455. (list '(+ sh-indent-after-loop-construct)))
  2456. ((sh-goto-match-for-done)
  2457. (sh-debug "match for done found on PREV line")
  2458. (list '(+ sh-indent-after-do)))
  2459. (t
  2460. (message "match for done NOT found")
  2461. nil)))
  2462. ;; for rc:
  2463. (defun sh-find-prev-switch ()
  2464. "Find the line for the switch keyword matching this line's case keyword."
  2465. (re-search-backward "\\<switch\\>" nil t))
  2466. (defun sh-handle-this-rc-case ()
  2467. (if (sh-find-prev-switch)
  2468. (list '(+ sh-indent-after-switch))
  2469. ;; (list '(+ sh-indent-for-case-label))
  2470. nil))
  2471. (defun sh-handle-prev-rc-case ()
  2472. (list '(+ sh-indent-after-case)))
  2473. (defun sh-check-rule (n thing)
  2474. (let ((rule (nth n (assoc thing sh-kw-alist)))
  2475. (val nil))
  2476. (if rule
  2477. (progn
  2478. (setq val (funcall rule))
  2479. (sh-debug "rule (%d) for %s at %d is %s\n-> returned %s"
  2480. n thing (point) rule val)))
  2481. val))
  2482. (defun sh-get-indent-info ()
  2483. "Return indent-info for this line.
  2484. This is a list. nil means the line is to be left as is.
  2485. Otherwise it contains one or more of the following sublists:
  2486. \(t NUMBER\) NUMBER is the base location in the buffer that indentation is
  2487. relative to. If present, this is always the first of the
  2488. sublists. The indentation of the line in question is
  2489. derived from the indentation of this point, possibly
  2490. modified by subsequent sublists.
  2491. \(+ VAR\)
  2492. \(- VAR\) Get the value of variable VAR and add to or subtract from
  2493. the indentation calculated so far.
  2494. \(= VAR\) Get the value of variable VAR and *replace* the
  2495. indentation with its value. This only occurs for
  2496. special variables such as `sh-indent-comment'.
  2497. STRING This is ignored for the purposes of calculating
  2498. indentation, it is printed in certain cases to help show
  2499. what the indentation is based on."
  2500. ;; See comments before `sh-kw'.
  2501. (save-excursion
  2502. (let ((have-result nil)
  2503. this-kw
  2504. val
  2505. (result nil)
  2506. (align-point nil)
  2507. prev-line-end x)
  2508. (beginning-of-line)
  2509. ;; Note: setting result to t means we are done and will return nil.
  2510. ;;(This function never returns just t.)
  2511. (cond
  2512. ((or (nth 3 (syntax-ppss (point)))
  2513. (eq (get-text-property (point) 'face) sh-heredoc-face))
  2514. ;; String continuation -- don't indent
  2515. (setq result t)
  2516. (setq have-result t))
  2517. ((looking-at "\\s-*#") ; was (equal this-kw "#")
  2518. (if (bobp)
  2519. (setq result t) ;; return nil if 1st line!
  2520. (setq result (list '(= sh-indent-comment)))
  2521. ;; we still need to get previous line in case
  2522. ;; sh-indent-comment is t (indent as normal)
  2523. (setq align-point (sh-prev-line nil))
  2524. (setq have-result nil)
  2525. ))
  2526. ) ;; cond
  2527. (unless have-result
  2528. ;; Continuation lines are handled specially
  2529. (if (sh-this-is-a-continuation)
  2530. (progn
  2531. (setq result
  2532. (if (save-excursion
  2533. (beginning-of-line)
  2534. (not (memq (char-before (- (point) 2)) '(?\s ?\t))))
  2535. ;; By convention, if the continuation \ is not
  2536. ;; preceded by a SPC or a TAB it means that the line
  2537. ;; is cut at a place where spaces cannot be freely
  2538. ;; added/removed. I.e. do not indent the line.
  2539. (list '(= nil))
  2540. ;; We assume the line being continued is already
  2541. ;; properly indented...
  2542. ;; (setq prev-line-end (sh-prev-line))
  2543. (setq align-point (sh-prev-line nil))
  2544. (list '(+ sh-indent-for-continuation))))
  2545. (setq have-result t))
  2546. (beginning-of-line)
  2547. (skip-chars-forward " \t")
  2548. (setq this-kw (sh-get-kw)))
  2549. ;; Handle "this" keyword: first word on the line we're
  2550. ;; calculating indentation info for.
  2551. (if this-kw
  2552. (if (setq val (sh-check-rule 1 this-kw))
  2553. (progn
  2554. (setq align-point (point))
  2555. (sh-debug
  2556. "this - setting align-point to %d" align-point)
  2557. (setq result (append result val))
  2558. (setq have-result t)
  2559. ;; set prev-line to continue processing remainder
  2560. ;; of this line as a previous line
  2561. (setq prev-line-end (point))
  2562. ))))
  2563. (unless have-result
  2564. (setq prev-line-end (sh-prev-line 'end)))
  2565. (if prev-line-end
  2566. (save-excursion
  2567. ;; We start off at beginning of this line.
  2568. ;; Scan previous statements while this is <=
  2569. ;; start of previous line.
  2570. (goto-char prev-line-end)
  2571. (setq x t)
  2572. (while (and x (setq x (sh-prev-thing)))
  2573. (sh-debug "at %d x is: %s result is: %s" (point) x result)
  2574. (cond
  2575. ((and (equal x ")")
  2576. (equal (get-text-property (1- (point)) 'syntax-table)
  2577. sh-st-punc))
  2578. (sh-debug "Case label) here")
  2579. (setq x 'case-label)
  2580. (if (setq val (sh-check-rule 2 x))
  2581. (progn
  2582. (setq result (append result val))
  2583. (setq align-point (point))))
  2584. (or (bobp)
  2585. (forward-char -1))
  2586. ;; FIXME: This charset looks too much like a regexp. --Stef
  2587. (skip-chars-forward "[a-z0-9]*?")
  2588. )
  2589. ((string-match "[])}]" x)
  2590. (setq x (sh-safe-forward-sexp -1))
  2591. (if x
  2592. (progn
  2593. (setq align-point (point))
  2594. (setq result (append result
  2595. (list "aligned to opening paren")))
  2596. )))
  2597. ((string-match "[[({]" x)
  2598. (sh-debug "Checking special thing: %s" x)
  2599. (if (setq val (sh-check-rule 2 x))
  2600. (setq result (append result val)))
  2601. (forward-char -1)
  2602. (setq align-point (point)))
  2603. ((string-match "[\"'`]" x)
  2604. (sh-debug "Skipping back for %s" x)
  2605. ;; this was oops-2
  2606. (setq x (sh-safe-forward-sexp -1)))
  2607. ((stringp x)
  2608. (sh-debug "Checking string %s at %s" x (point))
  2609. (if (setq val (sh-check-rule 2 x))
  2610. ;; (or (eq t (car val))
  2611. ;; (eq t (car (car val))))
  2612. (setq result (append result val)))
  2613. ;; not sure about this test Wed Jan 27 23:48:35 1999
  2614. (setq align-point (point))
  2615. (unless (bolp)
  2616. (forward-char -1)))
  2617. (t
  2618. (error "Don't know what to do with %s" x))
  2619. )
  2620. ) ;; while
  2621. (sh-debug "result is %s" result)
  2622. )
  2623. (sh-debug "No prev line!")
  2624. (sh-debug "result: %s align-point: %s" result align-point)
  2625. )
  2626. (if align-point
  2627. ;; was: (setq result (append result (list (list t align-point))))
  2628. (setq result (append (list (list t align-point)) result))
  2629. )
  2630. (sh-debug "result is now: %s" result)
  2631. (or result
  2632. (setq result (list (if prev-line-end
  2633. (list t prev-line-end)
  2634. (list '= 'sh-first-lines-indent)))))
  2635. (if (eq result t)
  2636. (setq result nil))
  2637. (sh-debug "result is: %s" result)
  2638. result
  2639. ) ;; let
  2640. ))
  2641. (defun sh-get-indent-var-for-line (&optional info)
  2642. "Return the variable controlling indentation for this line.
  2643. If there is not [just] one such variable, return a string
  2644. indicating the problem.
  2645. If INFO is supplied it is used, else it is calculated."
  2646. (let ((var nil)
  2647. (result nil)
  2648. (reason nil)
  2649. sym elt)
  2650. (or info
  2651. (setq info (sh-get-indent-info)))
  2652. (if (null info)
  2653. (setq result "this line to be left as is")
  2654. (while (and info (null result))
  2655. (setq elt (car info))
  2656. (cond
  2657. ((stringp elt)
  2658. (setq reason elt)
  2659. )
  2660. ((not (listp elt))
  2661. (error "sh-get-indent-var-for-line invalid elt: %s" elt))
  2662. ;; so it is a list
  2663. ((eq t (car elt))
  2664. ) ;; nothing
  2665. ((symbolp (setq sym (nth 1 elt)))
  2666. ;; A bit of a kludge - when we see the sh-indent-comment
  2667. ;; ignore other variables. Otherwise it is tricky to
  2668. ;; "learn" the comment indentation.
  2669. (if (eq var 'sh-indent-comment)
  2670. (setq result var)
  2671. (if var
  2672. (setq result
  2673. "this line is controlled by more than 1 variable.")
  2674. (setq var sym))))
  2675. (t
  2676. (error "sh-get-indent-var-for-line invalid list elt: %s" elt)))
  2677. (setq info (cdr info))
  2678. ))
  2679. (or result
  2680. (setq result var))
  2681. (or result
  2682. (setq result reason))
  2683. (if (null result)
  2684. ;; e.g. just had (t POS)
  2685. (setq result "line has default indentation"))
  2686. result))
  2687. ;; Finding the previous line isn't trivial.
  2688. ;; We must *always* go back one more and see if that is a continuation
  2689. ;; line -- it is the PREVIOUS line which is continued, not the one
  2690. ;; we are going to!
  2691. ;; Also, we want to treat a whole "here document" as one big line,
  2692. ;; because we may want to a align to the beginning of it.
  2693. ;;
  2694. ;; What we do:
  2695. ;; - go back to previous non-empty line
  2696. ;; - if this is in a here-document, go to the beginning of it
  2697. ;; - while previous line is continued, go back one line
  2698. (defun sh-prev-line (&optional end)
  2699. "Back to end of previous non-comment non-empty line.
  2700. Go to beginning of logical line unless END is non-nil, in which case
  2701. we go to the end of the previous line and do not check for continuations."
  2702. (save-excursion
  2703. (beginning-of-line)
  2704. (forward-comment (- (point-max)))
  2705. (unless end (beginning-of-line))
  2706. (when (and (not (bobp))
  2707. (equal (get-text-property (1- (point)) 'face)
  2708. sh-heredoc-face))
  2709. (let ((p1 (previous-single-property-change (1- (point)) 'face)))
  2710. (when p1
  2711. (goto-char p1)
  2712. (if end
  2713. (end-of-line)
  2714. (beginning-of-line)))))
  2715. (unless end
  2716. ;; we must check previous lines to see if they are continuation lines
  2717. ;; if so, we must return position of first of them
  2718. (while (and (sh-this-is-a-continuation)
  2719. (>= 0 (forward-line -1))))
  2720. (beginning-of-line)
  2721. (skip-chars-forward " \t"))
  2722. (point)))
  2723. (defun sh-prev-stmt ()
  2724. "Return the address of the previous stmt or nil."
  2725. ;; This is used when we are trying to find a matching keyword.
  2726. ;; Searching backward for the keyword would certainly be quicker, but
  2727. ;; it is hard to remove "false matches" -- such as if the keyword
  2728. ;; appears in a string or quote. This way is slower, but (I think) safer.
  2729. (interactive)
  2730. (save-excursion
  2731. (let ((going t)
  2732. (start (point))
  2733. (found nil)
  2734. (prev nil))
  2735. (skip-chars-backward " \t;|&({[")
  2736. (while (and (not found)
  2737. (not (bobp))
  2738. going)
  2739. ;; Do a backward-sexp if possible, else backup bit by bit...
  2740. (if (sh-safe-forward-sexp -1)
  2741. (progn
  2742. (if (looking-at sh-special-keywords)
  2743. (progn
  2744. (setq found prev))
  2745. (setq prev (point))
  2746. ))
  2747. ;; backward-sexp failed
  2748. (if (zerop (skip-chars-backward " \t()[\]{};`'"))
  2749. (forward-char -1))
  2750. (if (bolp)
  2751. (let ((back (sh-prev-line nil)))
  2752. (if back
  2753. (goto-char back)
  2754. (setq going nil)))))
  2755. (unless found
  2756. (skip-chars-backward " \t")
  2757. (if (or (and (bolp) (not (sh-this-is-a-continuation)))
  2758. (eq (char-before) ?\;)
  2759. (looking-at "\\s-*[|&]"))
  2760. (setq found (point)))))
  2761. (if found
  2762. (goto-char found))
  2763. (if found
  2764. (progn
  2765. (skip-chars-forward " \t|&({[")
  2766. (setq found (point))))
  2767. (if (>= (point) start)
  2768. (progn
  2769. (debug "We didn't move!")
  2770. (setq found nil))
  2771. (or found
  2772. (sh-debug "Did not find prev stmt.")))
  2773. found)))
  2774. (defun sh-get-word ()
  2775. "Get a shell word skipping whitespace from point."
  2776. (interactive)
  2777. (skip-chars-forward "\t ")
  2778. (let ((start (point)))
  2779. (while
  2780. (if (looking-at "[\"'`]")
  2781. (sh-safe-forward-sexp)
  2782. ;; (> (skip-chars-forward "^ \t\n\"'`") 0)
  2783. (> (skip-chars-forward "-_$[:alnum:]") 0)
  2784. ))
  2785. (buffer-substring start (point))
  2786. ))
  2787. (defun sh-prev-thing ()
  2788. "Return the previous thing this logical line."
  2789. ;; This is called when `sh-get-indent-info' is working backwards on
  2790. ;; the previous line(s) finding what keywords may be relevant for
  2791. ;; indenting. It moves over sexps if possible, and will stop
  2792. ;; on a ; and at the beginning of a line if it is not a continuation
  2793. ;; line.
  2794. ;;
  2795. ;; Added a kludge for ";;"
  2796. ;; Possible return values:
  2797. ;; nil - nothing
  2798. ;; a string - possibly a keyword
  2799. ;;
  2800. (if (bolp)
  2801. nil
  2802. (let ((start (point))
  2803. (min-point (if (sh-this-is-a-continuation)
  2804. (sh-prev-line nil)
  2805. (line-beginning-position))))
  2806. (skip-chars-backward " \t;" min-point)
  2807. (if (looking-at "\\s-*;[;&]")
  2808. ;; (message "Found ;; !")
  2809. ";;"
  2810. (skip-chars-backward "^)}];\"'`({[" min-point)
  2811. (let ((c (if (> (point) min-point) (char-before))))
  2812. (sh-debug "stopping at %d c is %s start=%d min-point=%d"
  2813. (point) c start min-point)
  2814. (if (not (memq c '(?\n nil ?\;)))
  2815. ;; c -- return a string
  2816. (char-to-string c)
  2817. ;; Return the leading keyword of the "command" we supposedly
  2818. ;; skipped over. Maybe we skipped too far (e.g. past a `do' or
  2819. ;; `then' that precedes the actual command), so check whether
  2820. ;; we're looking at such a keyword and if so, move back forward.
  2821. (let ((boundary (point))
  2822. kwd next)
  2823. (while
  2824. (progn
  2825. ;; Skip forward over white space newline and \ at eol.
  2826. (skip-chars-forward " \t\n\\\\" start)
  2827. (if (>= (point) start)
  2828. (progn
  2829. (sh-debug "point: %d >= start: %d" (point) start)
  2830. nil)
  2831. (if next (setq boundary next))
  2832. (sh-debug "Now at %d start=%d" (point) start)
  2833. (setq kwd (sh-get-word))
  2834. (if (member kwd (sh-feature sh-leading-keywords))
  2835. (progn
  2836. (setq next (point))
  2837. t)
  2838. nil))))
  2839. (goto-char boundary)
  2840. kwd)))))))
  2841. (defun sh-this-is-a-continuation ()
  2842. "Return non-nil if current line is a continuation of previous line."
  2843. (save-excursion
  2844. (and (zerop (forward-line -1))
  2845. (looking-at ".*\\\\$")
  2846. (not (nth 4 (parse-partial-sexp (match-beginning 0) (match-end 0)
  2847. nil nil nil t))))))
  2848. (defun sh-get-kw (&optional where and-move)
  2849. "Return first word of line from WHERE.
  2850. If AND-MOVE is non-nil then move to end of word."
  2851. (let ((start (point)))
  2852. (if where
  2853. (goto-char where))
  2854. (prog1
  2855. (buffer-substring (point)
  2856. (progn (skip-chars-forward "^ \t\n;&|")(point)))
  2857. (unless and-move
  2858. (goto-char start)))))
  2859. (defun sh-find-prev-matching (open close &optional depth)
  2860. "Find a matching token for a set of opening and closing keywords.
  2861. This takes into account that there may be nested open..close pairings.
  2862. OPEN and CLOSE are regexps denoting the tokens to be matched.
  2863. Optional parameter DEPTH (usually 1) says how many to look for."
  2864. (let ((parse-sexp-ignore-comments t)
  2865. (forward-sexp-function nil)
  2866. prev)
  2867. (setq depth (or depth 1))
  2868. (save-excursion
  2869. (condition-case nil
  2870. (while (and
  2871. (/= 0 depth)
  2872. (not (bobp))
  2873. (setq prev (sh-prev-stmt)))
  2874. (goto-char prev)
  2875. (save-excursion
  2876. (if (looking-at "\\\\\n")
  2877. (progn
  2878. (forward-char 2)
  2879. (skip-chars-forward " \t")))
  2880. (cond
  2881. ((looking-at open)
  2882. (setq depth (1- depth))
  2883. (sh-debug "found open at %d - depth = %d" (point) depth))
  2884. ((looking-at close)
  2885. (setq depth (1+ depth))
  2886. (sh-debug "found close - depth = %d" depth))
  2887. (t
  2888. ))))
  2889. (error nil))
  2890. (if (eq depth 0)
  2891. prev ;; (point)
  2892. nil)
  2893. )))
  2894. (defun sh-var-value (var &optional ignore-error)
  2895. "Return the value of variable VAR, interpreting symbols.
  2896. It can also return t or nil.
  2897. If an invalid value is found, throw an error unless Optional argument
  2898. IGNORE-ERROR is non-nil."
  2899. (let ((val (symbol-value var)))
  2900. (cond
  2901. ((numberp val)
  2902. val)
  2903. ((eq val t)
  2904. val)
  2905. ((null val)
  2906. val)
  2907. ((eq val '+)
  2908. sh-basic-offset)
  2909. ((eq val '-)
  2910. (- sh-basic-offset))
  2911. ((eq val '++)
  2912. (* 2 sh-basic-offset))
  2913. ((eq val '--)
  2914. (* 2 (- sh-basic-offset)))
  2915. ((eq val '*)
  2916. (/ sh-basic-offset 2))
  2917. ((eq val '/)
  2918. (/ (- sh-basic-offset) 2))
  2919. (t
  2920. (funcall (if ignore-error #'message #'error)
  2921. "Don't know how to handle %s's value of %s" var val)
  2922. 0))))
  2923. (defun sh-set-var-value (var value &optional no-symbol)
  2924. "Set variable VAR to VALUE.
  2925. Unless optional argument NO-SYMBOL is non-nil, then if VALUE is
  2926. can be represented by a symbol then do so."
  2927. (cond
  2928. (no-symbol
  2929. (set var value))
  2930. ((= value sh-basic-offset)
  2931. (set var '+))
  2932. ((= value (- sh-basic-offset))
  2933. (set var '-))
  2934. ((eq value (* 2 sh-basic-offset))
  2935. (set var '++))
  2936. ((eq value (* 2 (- sh-basic-offset)))
  2937. (set var '--))
  2938. ((eq value (/ sh-basic-offset 2))
  2939. (set var '*))
  2940. ((eq value (/ (- sh-basic-offset) 2))
  2941. (set var '/))
  2942. (t
  2943. (set var value)))
  2944. )
  2945. (defun sh-calculate-indent (&optional info)
  2946. "Return the indentation for the current line.
  2947. If INFO is supplied it is used, else it is calculated from current line."
  2948. (let ((ofs 0)
  2949. (base-value 0)
  2950. elt a b val)
  2951. (or info
  2952. (setq info (sh-get-indent-info)))
  2953. (when info
  2954. (while info
  2955. (sh-debug "info: %s ofs=%s" info ofs)
  2956. (setq elt (car info))
  2957. (cond
  2958. ((stringp elt)) ;; do nothing?
  2959. ((listp elt)
  2960. (setq a (car (car info)))
  2961. (setq b (nth 1 (car info)))
  2962. (cond
  2963. ((eq a t)
  2964. (save-excursion
  2965. (goto-char b)
  2966. (setq val (current-indentation)))
  2967. (setq base-value val))
  2968. ((symbolp b)
  2969. (setq val (sh-var-value b))
  2970. (cond
  2971. ((eq a '=)
  2972. (cond
  2973. ((null val)
  2974. ;; no indentation
  2975. ;; set info to nil so we stop immediately
  2976. (setq base-value nil ofs nil info nil))
  2977. ((eq val t) (setq ofs 0)) ;; indent as normal line
  2978. (t
  2979. ;; The following assume the (t POS) come first!
  2980. (setq ofs val base-value 0)
  2981. (setq info nil)))) ;; ? stop now
  2982. ((eq a '+) (setq ofs (+ ofs val)))
  2983. ((eq a '-) (setq ofs (- ofs val)))
  2984. (t
  2985. (error "sh-calculate-indent invalid a a=%s b=%s" a b))))
  2986. (t
  2987. (error "sh-calculate-indent invalid elt: a=%s b=%s" a b))))
  2988. (t
  2989. (error "sh-calculate-indent invalid elt %s" elt)))
  2990. (sh-debug "a=%s b=%s val=%s base-value=%s ofs=%s"
  2991. a b val base-value ofs)
  2992. (setq info (cdr info)))
  2993. ;; return value:
  2994. (sh-debug "at end: base-value: %s ofs: %s" base-value ofs)
  2995. (cond
  2996. ((or (null base-value)(null ofs))
  2997. nil)
  2998. ((and (numberp base-value)(numberp ofs))
  2999. (sh-debug "base (%d) + ofs (%d) = %d"
  3000. base-value ofs (+ base-value ofs))
  3001. (+ base-value ofs)) ;; return value
  3002. (t
  3003. (error "sh-calculate-indent: Help. base-value=%s ofs=%s"
  3004. base-value ofs)
  3005. nil)))))
  3006. (defun sh-indent-line ()
  3007. "Indent the current line."
  3008. (interactive)
  3009. (let ((indent (sh-calculate-indent))
  3010. (pos (- (point-max) (point))))
  3011. (when indent
  3012. (beginning-of-line)
  3013. (skip-chars-forward " \t")
  3014. (indent-line-to indent)
  3015. ;; If initial point was within line's indentation,
  3016. ;; position after the indentation. Else stay at same point in text.
  3017. (if (> (- (point-max) pos) (point))
  3018. (goto-char (- (point-max) pos))))))
  3019. (defun sh-blink (blinkpos &optional msg)
  3020. "Move cursor momentarily to BLINKPOS and display MSG."
  3021. ;; We can get here without it being a number on first line
  3022. (if (numberp blinkpos)
  3023. (save-excursion
  3024. (goto-char blinkpos)
  3025. (if msg (message "%s" msg) (message nil))
  3026. (sit-for blink-matching-delay))
  3027. (if msg (message "%s" msg) (message nil))))
  3028. (defun sh-show-indent (arg)
  3029. "Show the how the current line would be indented.
  3030. This tells you which variable, if any, controls the indentation of
  3031. this line.
  3032. If optional arg ARG is non-null (called interactively with a prefix),
  3033. a pop up window describes this variable.
  3034. If variable `sh-blink' is non-nil then momentarily go to the line
  3035. we are indenting relative to, if applicable."
  3036. (interactive "P")
  3037. (sh-must-support-indent)
  3038. (if sh-use-smie
  3039. (smie-config-show-indent)
  3040. (let* ((info (sh-get-indent-info))
  3041. (var (sh-get-indent-var-for-line info))
  3042. (curr-indent (current-indentation))
  3043. val msg)
  3044. (if (stringp var)
  3045. (message "%s" (setq msg var))
  3046. (setq val (sh-calculate-indent info))
  3047. (if (eq curr-indent val)
  3048. (setq msg (format "%s is %s" var (symbol-value var)))
  3049. (setq msg
  3050. (if val
  3051. (format "%s (%s) would change indent from %d to: %d"
  3052. var (symbol-value var) curr-indent val)
  3053. (format "%s (%s) would leave line as is"
  3054. var (symbol-value var)))
  3055. ))
  3056. (if (and arg var)
  3057. (describe-variable var)))
  3058. (if sh-blink
  3059. (let ((info (sh-get-indent-info)))
  3060. (if (and info (listp (car info))
  3061. (eq (car (car info)) t))
  3062. (sh-blink (nth 1 (car info)) msg)
  3063. (message "%s" msg)))
  3064. (message "%s" msg))
  3065. )))
  3066. (defun sh-set-indent ()
  3067. "Set the indentation for the current line.
  3068. If the current line is controlled by an indentation variable, prompt
  3069. for a new value for it."
  3070. (interactive)
  3071. (sh-must-support-indent)
  3072. (if sh-use-smie
  3073. (smie-config-set-indent)
  3074. (let* ((info (sh-get-indent-info))
  3075. (var (sh-get-indent-var-for-line info))
  3076. val old-val indent-val)
  3077. (if (stringp var)
  3078. (message "Cannot set indent - %s" var)
  3079. (setq old-val (symbol-value var))
  3080. (setq val (sh-read-variable var))
  3081. (condition-case nil
  3082. (progn
  3083. (set var val)
  3084. (setq indent-val (sh-calculate-indent info))
  3085. (if indent-val
  3086. (message "Variable: %s Value: %s would indent to: %d"
  3087. var (symbol-value var) indent-val)
  3088. (message "Variable: %s Value: %s would leave line as is."
  3089. var (symbol-value var)))
  3090. ;; I'm not sure about this, indenting it now?
  3091. ;; No. Because it would give the impression that an undo would
  3092. ;; restore thing, but the value has been altered.
  3093. ;; (sh-indent-line)
  3094. )
  3095. (error
  3096. (set var old-val)
  3097. (message "Bad value for %s, restoring to previous value %s"
  3098. var old-val)
  3099. (sit-for 1)
  3100. nil))
  3101. ))))
  3102. (defun sh-learn-line-indent (arg)
  3103. "Learn how to indent a line as it currently is indented.
  3104. If there is an indentation variable which controls this line's indentation,
  3105. then set it to a value which would indent the line the way it
  3106. presently is.
  3107. If the value can be represented by one of the symbols then do so
  3108. unless optional argument ARG (the prefix when interactive) is non-nil."
  3109. (interactive "*P")
  3110. (sh-must-support-indent)
  3111. (if sh-use-smie
  3112. (smie-config-set-indent)
  3113. ;; I'm not sure if we show allow learning on an empty line.
  3114. ;; Though it might occasionally be useful I think it usually
  3115. ;; would just be confusing.
  3116. (if (save-excursion
  3117. (beginning-of-line)
  3118. (looking-at "\\s-*$"))
  3119. (message "sh-learn-line-indent ignores empty lines.")
  3120. (let* ((info (sh-get-indent-info))
  3121. (var (sh-get-indent-var-for-line info))
  3122. ival sval diff new-val
  3123. (no-symbol arg)
  3124. (curr-indent (current-indentation)))
  3125. (cond
  3126. ((stringp var)
  3127. (message "Cannot learn line - %s" var))
  3128. ((eq var 'sh-indent-comment)
  3129. ;; This is arbitrary...
  3130. ;; - if curr-indent is 0, set to curr-indent
  3131. ;; - else if it has the indentation of a "normal" line,
  3132. ;; then set to t
  3133. ;; - else set to curr-indent.
  3134. (setq sh-indent-comment
  3135. (if (= curr-indent 0)
  3136. 0
  3137. (let* ((sh-indent-comment t)
  3138. (val2 (sh-calculate-indent info)))
  3139. (if (= val2 curr-indent)
  3140. t
  3141. curr-indent))))
  3142. (message "%s set to %s" var (symbol-value var))
  3143. )
  3144. ((numberp (setq sval (sh-var-value var)))
  3145. (setq ival (sh-calculate-indent info))
  3146. (setq diff (- curr-indent ival))
  3147. (sh-debug "curr-indent: %d ival: %d diff: %d var:%s sval %s"
  3148. curr-indent ival diff var sval)
  3149. (setq new-val (+ sval diff))
  3150. ;; I commented out this because someone might want to replace
  3151. ;; a value of `+' with the current value of sh-basic-offset
  3152. ;; or vice-versa.
  3153. ;;(if (= 0 diff)
  3154. ;; (message "No change needed!")
  3155. (sh-set-var-value var new-val no-symbol)
  3156. (message "%s set to %s" var (symbol-value var))
  3157. )
  3158. (t
  3159. (debug)
  3160. (message "Cannot change %s" var)))))))
  3161. (defun sh-mark-init (buffer)
  3162. "Initialize a BUFFER to be used by `sh-mark-line'."
  3163. (with-current-buffer (get-buffer-create buffer)
  3164. (erase-buffer)
  3165. (occur-mode)))
  3166. (defun sh-mark-line (message point buffer &optional add-linenum occur-point)
  3167. "Insert MESSAGE referring to location POINT in current buffer into BUFFER.
  3168. Buffer BUFFER is in `occur-mode'.
  3169. If ADD-LINENUM is non-nil the message is preceded by the line number.
  3170. If OCCUR-POINT is non-nil then the line is marked as a new occurrence
  3171. so that `occur-next' and `occur-prev' will work."
  3172. (let ((m1 (make-marker))
  3173. start
  3174. (line ""))
  3175. (when point
  3176. (set-marker m1 point (current-buffer))
  3177. (if add-linenum
  3178. (setq line (format "%d: " (1+ (count-lines 1 point))))))
  3179. (save-excursion
  3180. (if (get-buffer buffer)
  3181. (set-buffer (get-buffer buffer))
  3182. (set-buffer (get-buffer-create buffer))
  3183. (occur-mode)
  3184. )
  3185. (goto-char (point-max))
  3186. (setq start (point))
  3187. (let ((inhibit-read-only t))
  3188. (insert line)
  3189. (if occur-point
  3190. (setq occur-point (point)))
  3191. (insert message)
  3192. (if point
  3193. (add-text-properties
  3194. start (point)
  3195. '(mouse-face highlight
  3196. help-echo "mouse-2: go to the line where I learned this")))
  3197. (insert "\n")
  3198. (when point
  3199. (put-text-property start (point) 'occur-target m1)
  3200. (if occur-point
  3201. (put-text-property start occur-point
  3202. 'occur-match t))
  3203. )))))
  3204. ;; Is this really worth having?
  3205. (defvar sh-learned-buffer-hook nil
  3206. "An abnormal hook, called with an alist of learned variables.")
  3207. ;; Example of how to use sh-learned-buffer-hook
  3208. ;;
  3209. ;; (defun what-i-learned (list)
  3210. ;; (let ((p list))
  3211. ;; (with-current-buffer "*scratch*"
  3212. ;; (goto-char (point-max))
  3213. ;; (insert "(setq\n")
  3214. ;; (while p
  3215. ;; (insert (format " %s %s \n"
  3216. ;; (nth 0 (car p)) (nth 1 (car p))))
  3217. ;; (setq p (cdr p)))
  3218. ;; (insert ")\n")
  3219. ;; )))
  3220. ;;
  3221. ;; (add-hook 'sh-learned-buffer-hook 'what-i-learned)
  3222. ;; Originally this was sh-learn-region-indent (beg end)
  3223. ;; However, in practice this was awkward so I changed it to
  3224. ;; use the whole buffer. Use narrowing if need be.
  3225. (defun sh-learn-buffer-indent (&optional arg)
  3226. "Learn how to indent the buffer the way it currently is.
  3227. Output in buffer \"*indent*\" shows any lines which have conflicting
  3228. values of a variable, and the final value of all variables learned.
  3229. When called interactively, pop to this buffer automatically if
  3230. there are any discrepancies.
  3231. If no prefix ARG is given, then variables are set to numbers.
  3232. If a prefix arg is given, then variables are set to symbols when
  3233. applicable -- e.g. to symbol `+' if the value is that of the
  3234. basic indent.
  3235. If a positive numerical prefix is given, then `sh-basic-offset'
  3236. is set to the prefix's numerical value.
  3237. Otherwise, sh-basic-offset may or may not be changed, according
  3238. to the value of variable `sh-learn-basic-offset'.
  3239. Abnormal hook `sh-learned-buffer-hook' if non-nil is called when the
  3240. function completes. The function is abnormal because it is called
  3241. with an alist of variables learned. This feature may be changed or
  3242. removed in the future.
  3243. This command can often take a long time to run."
  3244. (interactive "P")
  3245. (sh-must-support-indent)
  3246. (if sh-use-smie
  3247. (smie-config-guess)
  3248. (save-excursion
  3249. (goto-char (point-min))
  3250. (let ((learned-var-list nil)
  3251. (out-buffer "*indent*")
  3252. (num-diffs 0)
  3253. previous-set-info
  3254. (max 17)
  3255. vec
  3256. msg
  3257. (comment-col nil) ;; number if all same, t if seen diff values
  3258. (comments-always-default t) ;; nil if we see one not default
  3259. initial-msg
  3260. (specified-basic-offset (and arg (numberp arg)
  3261. (> arg 0)))
  3262. (linenum 0)
  3263. suggested)
  3264. (setq vec (make-vector max 0))
  3265. (sh-mark-init out-buffer)
  3266. (if specified-basic-offset
  3267. (progn
  3268. (setq sh-basic-offset arg)
  3269. (setq initial-msg
  3270. (format "Using specified sh-basic-offset of %d"
  3271. sh-basic-offset)))
  3272. (setq initial-msg
  3273. (format "Initial value of sh-basic-offset: %s"
  3274. sh-basic-offset)))
  3275. (while (< (point) (point-max))
  3276. (setq linenum (1+ linenum))
  3277. ;; (if (zerop (% linenum 10))
  3278. (message "line %d" linenum)
  3279. ;; )
  3280. (unless (looking-at "\\s-*$") ;; ignore empty lines!
  3281. (let* ((sh-indent-comment t) ;; info must return default indent
  3282. (info (sh-get-indent-info))
  3283. (var (sh-get-indent-var-for-line info))
  3284. sval ival diff new-val
  3285. (curr-indent (current-indentation)))
  3286. (cond
  3287. ((null var)
  3288. nil)
  3289. ((stringp var)
  3290. nil)
  3291. ((numberp (setq sval (sh-var-value var 'no-error)))
  3292. ;; the numberp excludes comments since sval will be t.
  3293. (setq ival (sh-calculate-indent))
  3294. (setq diff (- curr-indent ival))
  3295. (setq new-val (+ sval diff))
  3296. (sh-set-var-value var new-val 'no-symbol)
  3297. (unless (looking-at "\\s-*#") ;; don't learn from comments
  3298. (if (setq previous-set-info (assoc var learned-var-list))
  3299. (progn
  3300. ;; it was already there, is it same value ?
  3301. (unless (eq (symbol-value var)
  3302. (nth 1 previous-set-info))
  3303. (sh-mark-line
  3304. (format "Variable %s was set to %s"
  3305. var (symbol-value var))
  3306. (point) out-buffer t t)
  3307. (sh-mark-line
  3308. (format " but was previously set to %s"
  3309. (nth 1 previous-set-info))
  3310. (nth 2 previous-set-info) out-buffer t)
  3311. (setq num-diffs (1+ num-diffs))
  3312. ;; (delete previous-set-info learned-var-list)
  3313. (setcdr previous-set-info
  3314. (list (symbol-value var) (point)))
  3315. )
  3316. )
  3317. (setq learned-var-list
  3318. (append (list (list var (symbol-value var)
  3319. (point)))
  3320. learned-var-list)))
  3321. (if (numberp new-val)
  3322. (progn
  3323. (sh-debug
  3324. "This line's indent value: %d" new-val)
  3325. (if (< new-val 0)
  3326. (setq new-val (- new-val)))
  3327. (if (< new-val max)
  3328. (aset vec new-val (1+ (aref vec new-val))))))
  3329. ))
  3330. ((eq var 'sh-indent-comment)
  3331. (unless (= curr-indent (sh-calculate-indent info))
  3332. ;; this is not the default indentation
  3333. (setq comments-always-default nil)
  3334. (if comment-col ;; then we have see one before
  3335. (or (eq comment-col curr-indent)
  3336. (setq comment-col t)) ;; seen a different one
  3337. (setq comment-col curr-indent))
  3338. ))
  3339. (t
  3340. (sh-debug "Cannot learn this line!!!")
  3341. ))
  3342. (sh-debug
  3343. "at %s learned-var-list is %s" (point) learned-var-list)
  3344. ))
  3345. (forward-line 1)
  3346. ) ;; while
  3347. (if sh-debug
  3348. (progn
  3349. (setq msg (format
  3350. "comment-col = %s comments-always-default = %s"
  3351. comment-col comments-always-default))
  3352. ;; (message msg)
  3353. (sh-mark-line msg nil out-buffer)))
  3354. (cond
  3355. ((eq comment-col 0)
  3356. (setq msg "\nComments are all in 1st column.\n"))
  3357. (comments-always-default
  3358. (setq msg "\nComments follow default indentation.\n")
  3359. (setq comment-col t))
  3360. ((numberp comment-col)
  3361. (setq msg (format "\nComments are in col %d." comment-col)))
  3362. (t
  3363. (setq msg "\nComments seem to be mixed, leaving them as is.\n")
  3364. (setq comment-col nil)
  3365. ))
  3366. (sh-debug msg)
  3367. (sh-mark-line msg nil out-buffer)
  3368. (sh-mark-line initial-msg nil out-buffer t t)
  3369. (setq suggested (sh-guess-basic-offset vec))
  3370. (if (and suggested (not specified-basic-offset))
  3371. (let ((new-value
  3372. (cond
  3373. ;; t => set it if we have a single value as a number
  3374. ((and (eq sh-learn-basic-offset t) (numberp suggested))
  3375. suggested)
  3376. ;; other non-nil => set it if only one value was found
  3377. (sh-learn-basic-offset
  3378. (if (numberp suggested)
  3379. suggested
  3380. (if (= (length suggested) 1)
  3381. (car suggested))))
  3382. (t
  3383. nil))))
  3384. (if new-value
  3385. (progn
  3386. (setq learned-var-list
  3387. (append (list (list 'sh-basic-offset
  3388. (setq sh-basic-offset new-value)
  3389. (point-max)))
  3390. learned-var-list))
  3391. ;; Not sure if we need to put this line in, since
  3392. ;; it will appear in the "Learned variable settings".
  3393. (sh-mark-line
  3394. (format "Changed sh-basic-offset to: %d" sh-basic-offset)
  3395. nil out-buffer))
  3396. (sh-mark-line
  3397. (if (listp suggested)
  3398. (format "Possible value(s) for sh-basic-offset: %s"
  3399. (mapconcat 'int-to-string suggested " "))
  3400. (format "Suggested sh-basic-offset: %d" suggested))
  3401. nil out-buffer))))
  3402. (setq learned-var-list
  3403. (append (list (list 'sh-indent-comment comment-col (point-max)))
  3404. learned-var-list))
  3405. (setq sh-indent-comment comment-col)
  3406. (let ((name (buffer-name)))
  3407. (sh-mark-line "\nLearned variable settings:" nil out-buffer)
  3408. (if arg
  3409. ;; Set learned variables to symbolic rather than numeric
  3410. ;; values where possible.
  3411. (dolist (learned-var (reverse learned-var-list))
  3412. (let ((var (car learned-var))
  3413. (val (nth 1 learned-var)))
  3414. (when (and (not (eq var 'sh-basic-offset))
  3415. (numberp val))
  3416. (sh-set-var-value var val)))))
  3417. (dolist (learned-var (reverse learned-var-list))
  3418. (let ((var (car learned-var)))
  3419. (sh-mark-line (format " %s %s" var (symbol-value var))
  3420. (nth 2 learned-var) out-buffer)))
  3421. (with-current-buffer out-buffer
  3422. (goto-char (point-min))
  3423. (let ((inhibit-read-only t))
  3424. (insert
  3425. (format "Indentation values for buffer %s.\n" name)
  3426. (format "%d indentation variable%s different values%s\n\n"
  3427. num-diffs
  3428. (if (= num-diffs 1)
  3429. " has" "s have")
  3430. (if (zerop num-diffs)
  3431. "." ":"))))))
  3432. ;; Are abnormal hooks considered bad form?
  3433. (run-hook-with-args 'sh-learned-buffer-hook learned-var-list)
  3434. (and (called-interactively-p 'any)
  3435. (or sh-popup-occur-buffer (> num-diffs 0))
  3436. (pop-to-buffer out-buffer))))))
  3437. (defun sh-guess-basic-offset (vec)
  3438. "See if we can determine a reasonable value for `sh-basic-offset'.
  3439. This is experimental, heuristic and arbitrary!
  3440. Argument VEC is a vector of information collected by
  3441. `sh-learn-buffer-indent'.
  3442. Return values:
  3443. number - there appears to be a good single value
  3444. list of numbers - no obvious one, here is a list of one or more
  3445. reasonable choices
  3446. nil - we couldn't find a reasonable one."
  3447. (let* ((max (1- (length vec)))
  3448. (i 1)
  3449. (totals (make-vector max 0)))
  3450. (while (< i max)
  3451. (cl-incf (aref totals i) (* 4 (aref vec i)))
  3452. (if (zerop (% i 2))
  3453. (cl-incf (aref totals i) (aref vec (/ i 2))))
  3454. (if (< (* i 2) max)
  3455. (cl-incf (aref totals i) (aref vec (* i 2))))
  3456. (setq i (1+ i)))
  3457. (let ((x nil)
  3458. (result nil)
  3459. tot sum p)
  3460. (setq i 1)
  3461. (while (< i max)
  3462. (if (/= (aref totals i) 0)
  3463. (push (cons i (aref totals i)) x))
  3464. (setq i (1+ i)))
  3465. (setq x (sort (nreverse x) (lambda (a b) (> (cdr a) (cdr b)))))
  3466. (setq tot (apply '+ (append totals nil)))
  3467. (sh-debug (format "vec: %s\ntotals: %s\ntot: %d"
  3468. vec totals tot))
  3469. (cond
  3470. ((zerop (length x))
  3471. (message "no values!")) ;; we return nil
  3472. ((= (length x) 1)
  3473. (message "only value is %d" (car (car x)))
  3474. (setq result (car (car x)))) ;; return single value
  3475. ((> (cdr (car x)) (/ tot 2))
  3476. ;; 1st is > 50%
  3477. (message "basic-offset is probably %d" (car (car x)))
  3478. (setq result (car (car x)))) ;; again, return a single value
  3479. ((>= (cdr (car x)) (* 2 (cdr (car (cdr x)))))
  3480. ;; 1st is >= 2 * 2nd
  3481. (message "basic-offset could be %d" (car (car x)))
  3482. (setq result (car (car x))))
  3483. ((>= (+ (cdr (car x))(cdr (car (cdr x)))) (/ tot 2))
  3484. ;; 1st & 2nd together >= 50% - return a list
  3485. (setq p x sum 0 result nil)
  3486. (while (and p
  3487. (<= (setq sum (+ sum (cdr (car p)))) (/ tot 2)))
  3488. (setq result (append result (list (car (car p)))))
  3489. (setq p (cdr p)))
  3490. (message "Possible choices for sh-basic-offset: %s"
  3491. (mapconcat 'int-to-string result " ")))
  3492. (t
  3493. (message "No obvious value for sh-basic-offset. Perhaps %d"
  3494. (car (car x)))
  3495. ;; result is nil here
  3496. ))
  3497. result)))
  3498. ;; ========================================================================
  3499. ;; Styles -- a quick and dirty way of saving the indentation settings.
  3500. (defvar sh-styles-alist nil
  3501. "A list of all known shell indentation styles.")
  3502. (defun sh-name-style (name &optional confirm-overwrite)
  3503. "Name the current indentation settings as a style called NAME.
  3504. If this name exists, the command will prompt whether it should be
  3505. overwritten if
  3506. - - it was called interactively with a prefix argument, or
  3507. - - called non-interactively with optional CONFIRM-OVERWRITE non-nil."
  3508. ;; (interactive "sName for this style: ")
  3509. (interactive
  3510. (list
  3511. (read-from-minibuffer "Name for this style? " )
  3512. (not current-prefix-arg)))
  3513. (let ((slist (cons name
  3514. (mapcar (lambda (var) (cons var (symbol-value var)))
  3515. sh-var-list)))
  3516. (style (assoc name sh-styles-alist)))
  3517. (if style
  3518. (if (and confirm-overwrite
  3519. (not (y-or-n-p "This style exists. Overwrite it? ")))
  3520. (message "Not changing style %s" name)
  3521. (message "Updating style %s" name)
  3522. (setcdr style (cdr slist)))
  3523. (message "Creating new style %s" name)
  3524. (push slist sh-styles-alist))))
  3525. (defun sh-load-style (name)
  3526. "Set shell indentation values for this buffer from those in style NAME."
  3527. (interactive (list (completing-read
  3528. "Which style to use for this buffer? "
  3529. sh-styles-alist nil t)))
  3530. (let ((sl (assoc name sh-styles-alist)))
  3531. (if (null sl)
  3532. (error "sh-load-style - style %s not known" name)
  3533. (dolist (var (cdr sl))
  3534. (set (car var) (cdr var))))))
  3535. (defun sh-save-styles-to-buffer (buff)
  3536. "Save all current styles in elisp to buffer BUFF.
  3537. This is always added to the end of the buffer."
  3538. (interactive
  3539. (list
  3540. (read-from-minibuffer "Buffer to save styles in? " "*scratch*")))
  3541. (with-current-buffer (get-buffer-create buff)
  3542. (goto-char (point-max))
  3543. (insert "\n")
  3544. (pp `(setq sh-styles-alist ',sh-styles-alist) (current-buffer))))
  3545. ;; statement syntax-commands for various shells
  3546. ;; You are welcome to add the syntax or even completely new statements as
  3547. ;; appropriate for your favorite shell.
  3548. (defconst sh-non-closing-paren
  3549. ;; If we leave it rear-sticky, calling `newline' ends up inserting a \n
  3550. ;; that inherits this property, which then confuses the indentation.
  3551. (propertize ")" 'syntax-table sh-st-punc 'rear-nonsticky t))
  3552. (define-skeleton sh-case
  3553. "Insert a case/switch statement. See `sh-feature'."
  3554. (csh "expression: "
  3555. "switch( " str " )" \n
  3556. > "case " (read-string "pattern: ") ?: \n
  3557. > _ \n
  3558. "breaksw" \n
  3559. ( "other pattern, %s: "
  3560. < "case " str ?: \n
  3561. > _ \n
  3562. "breaksw" \n)
  3563. < "default:" \n
  3564. > _ \n
  3565. resume:
  3566. < < "endsw" \n)
  3567. (es)
  3568. (rc "expression: "
  3569. > "switch( " str " ) {" \n
  3570. > "case " (read-string "pattern: ") \n
  3571. > _ \n
  3572. ( "other pattern, %s: "
  3573. "case " str > \n
  3574. > _ \n)
  3575. "case *" > \n
  3576. > _ \n
  3577. resume:
  3578. ?\} > \n)
  3579. (sh "expression: "
  3580. > "case " str " in" \n
  3581. ( "pattern, %s: "
  3582. > str sh-non-closing-paren \n
  3583. > _ \n
  3584. ";;" \n)
  3585. > "*" sh-non-closing-paren \n
  3586. > _ \n
  3587. resume:
  3588. "esac" > \n))
  3589. (define-skeleton sh-for
  3590. "Insert a for loop. See `sh-feature'."
  3591. (csh sh-modify sh
  3592. 1 ""
  3593. 2 "foreach "
  3594. 4 " ( "
  3595. 6 " )"
  3596. 15 '<
  3597. 16 "end")
  3598. (es sh-modify rc
  3599. 4 " = ")
  3600. (rc sh-modify sh
  3601. 2 "for( "
  3602. 6 " ) {"
  3603. 15 ?\} )
  3604. (sh "Index variable: "
  3605. > "for " str " in " _ "; do" \n
  3606. > _ | ?$ & (sh-remember-variable str) \n
  3607. "done" > \n))
  3608. (define-skeleton sh-indexed-loop
  3609. "Insert an indexed loop from 1 to n. See `sh-feature'."
  3610. (bash sh-modify posix)
  3611. (csh "Index variable: "
  3612. "@ " str " = 1" \n
  3613. "while( $" str " <= " (read-string "upper limit: ") " )" \n
  3614. > _ ?$ str \n
  3615. "@ " str "++" \n
  3616. < "end" \n)
  3617. (es sh-modify rc
  3618. 4 " =")
  3619. (ksh88 "Index variable: "
  3620. > "integer " str "=0" \n
  3621. > "while (( ( " str " += 1 ) <= "
  3622. (read-string "upper limit: ")
  3623. " )); do" \n
  3624. > _ ?$ (sh-remember-variable str) > \n
  3625. "done" > \n)
  3626. (posix "Index variable: "
  3627. > str "=1" \n
  3628. "while [ $" str " -le "
  3629. (read-string "upper limit: ")
  3630. " ]; do" \n
  3631. > _ ?$ str \n
  3632. str ?= (sh-add (sh-remember-variable str) 1) \n
  3633. "done" > \n)
  3634. (rc "Index variable: "
  3635. > "for( " str " in" " `{awk 'BEGIN { for( i=1; i<="
  3636. (read-string "upper limit: ")
  3637. "; i++ ) print i }'`}) {" \n
  3638. > _ ?$ (sh-remember-variable str) \n
  3639. ?\} > \n)
  3640. (sh "Index variable: "
  3641. > "for " str " in `awk 'BEGIN { for( i=1; i<="
  3642. (read-string "upper limit: ")
  3643. "; i++ ) print i }'`; do" \n
  3644. > _ ?$ (sh-remember-variable str) \n
  3645. "done" > \n))
  3646. (defun sh-shell-initialize-variables ()
  3647. "Scan the buffer for variable assignments.
  3648. Add these variables to `sh-shell-variables'."
  3649. (message "Scanning buffer `%s' for variable assignments..." (buffer-name))
  3650. (save-excursion
  3651. (goto-char (point-min))
  3652. (setq sh-shell-variables-initialized t)
  3653. (while (search-forward "=" nil t)
  3654. (sh-assignment 0)))
  3655. (message "Scanning buffer `%s' for variable assignments...done"
  3656. (buffer-name)))
  3657. (defvar sh-add-buffer)
  3658. (defun sh-add-completer (string predicate code)
  3659. "Do completion using `sh-shell-variables', but initialize it first.
  3660. This function is designed for use as the \"completion table\",
  3661. so it takes three arguments:
  3662. STRING, the current buffer contents;
  3663. PREDICATE, the predicate for filtering possible matches;
  3664. CODE, which says what kind of things to do.
  3665. CODE can be nil, t or `lambda'.
  3666. nil means to return the best completion of STRING, or nil if there is none.
  3667. t means to return a list of all possible completions of STRING.
  3668. `lambda' means to return t if STRING is a valid completion as it stands."
  3669. (let ((vars
  3670. (with-current-buffer sh-add-buffer
  3671. (or sh-shell-variables-initialized
  3672. (sh-shell-initialize-variables))
  3673. (nconc (mapcar (lambda (var)
  3674. (substring var 0 (string-match "=" var)))
  3675. process-environment)
  3676. sh-shell-variables))))
  3677. (complete-with-action code vars string predicate)))
  3678. (defun sh-add (var delta)
  3679. "Insert an addition of VAR and prefix DELTA for Bourne (type) shell."
  3680. (interactive
  3681. (let ((sh-add-buffer (current-buffer)))
  3682. (list (completing-read "Variable: " 'sh-add-completer)
  3683. (prefix-numeric-value current-prefix-arg))))
  3684. (insert (sh-feature '((bash . "$(( ")
  3685. (ksh88 . "$(( ")
  3686. (posix . "$(( ")
  3687. (rc . "`{expr $")
  3688. (sh . "`expr $")
  3689. (zsh . "$[ ")))
  3690. (sh-remember-variable var)
  3691. (if (< delta 0) " - " " + ")
  3692. (number-to-string (abs delta))
  3693. (sh-feature '((bash . " ))")
  3694. (ksh88 . " ))")
  3695. (posix . " ))")
  3696. (rc . "}")
  3697. (sh . "`")
  3698. (zsh . " ]")))))
  3699. (define-skeleton sh-function
  3700. "Insert a function definition. See `sh-feature'."
  3701. (bash sh-modify ksh88
  3702. 3 "() {")
  3703. (ksh88 "name: "
  3704. "function " str " {" \n
  3705. > _ \n
  3706. < "}" \n)
  3707. (rc sh-modify ksh88
  3708. 1 "fn ")
  3709. (sh ()
  3710. "() {" \n
  3711. > _ \n
  3712. < "}" \n))
  3713. (define-skeleton sh-if
  3714. "Insert an if statement. See `sh-feature'."
  3715. (csh "condition: "
  3716. "if( " str " ) then" \n
  3717. > _ \n
  3718. ( "other condition, %s: "
  3719. < "else if( " str " ) then" \n
  3720. > _ \n)
  3721. < "else" \n
  3722. > _ \n
  3723. resume:
  3724. < "endif" \n)
  3725. (es "condition: "
  3726. > "if { " str " } {" \n
  3727. > _ \n
  3728. ( "other condition, %s: "
  3729. "} { " str " } {" > \n
  3730. > _ \n)
  3731. "} {" > \n
  3732. > _ \n
  3733. resume:
  3734. ?\} > \n)
  3735. (rc "condition: "
  3736. > "if( " str " ) {" \n
  3737. > _ \n
  3738. ( "other condition, %s: "
  3739. "} else if( " str " ) {" > \n
  3740. > _ \n)
  3741. "} else {" > \n
  3742. > _ \n
  3743. resume:
  3744. ?\} > \n)
  3745. (sh "condition: "
  3746. '(setq input (sh-feature sh-test))
  3747. > "if " str "; then" \n
  3748. > _ \n
  3749. ( "other condition, %s: "
  3750. > "elif " str "; then" > \n
  3751. > \n)
  3752. "else" > \n
  3753. > \n
  3754. resume:
  3755. "fi" > \n))
  3756. (define-skeleton sh-repeat
  3757. "Insert a repeat loop definition. See `sh-feature'."
  3758. (es nil
  3759. > "forever {" \n
  3760. > _ \n
  3761. ?\} > \n)
  3762. (zsh "factor: "
  3763. > "repeat " str "; do" > \n
  3764. > \n
  3765. "done" > \n))
  3766. ;;;(put 'sh-repeat 'menu-enable '(sh-feature sh-repeat))
  3767. (define-skeleton sh-select
  3768. "Insert a select statement. See `sh-feature'."
  3769. (ksh88 "Index variable: "
  3770. > "select " str " in " _ "; do" \n
  3771. > ?$ str \n
  3772. "done" > \n)
  3773. (bash sh-append ksh88))
  3774. ;;;(put 'sh-select 'menu-enable '(sh-feature sh-select))
  3775. (define-skeleton sh-tmp-file
  3776. "Insert code to setup temporary file handling. See `sh-feature'."
  3777. (bash sh-append ksh88)
  3778. (csh (file-name-nondirectory (buffer-file-name))
  3779. "set tmp = `mktemp -t " str ".XXXXXX`" \n
  3780. "onintr exit" \n _
  3781. (and (goto-char (point-max))
  3782. (not (bolp))
  3783. ?\n)
  3784. "exit:\n"
  3785. "rm $tmp* >&/dev/null" > \n)
  3786. (es (file-name-nondirectory (buffer-file-name))
  3787. > "local( signals = $signals sighup sigint;" \n
  3788. > "tmp = `{ mktemp -t " str ".XXXXXX } ) {" \n
  3789. > "catch @ e {" \n
  3790. > "rm $tmp^* >[2]/dev/null" \n
  3791. "throw $e" \n
  3792. "} {" > \n
  3793. _ \n
  3794. ?\} > \n
  3795. ?\} > \n)
  3796. (ksh88 sh-modify sh
  3797. 7 "EXIT")
  3798. (rc (file-name-nondirectory (buffer-file-name))
  3799. > "tmp = `{ mktemp -t " str ".XXXXXX }" \n
  3800. "fn sigexit { rm $tmp^* >[2]/dev/null }" \n)
  3801. (sh (file-name-nondirectory (buffer-file-name))
  3802. > "TMP=`mktemp -t " str ".XXXXXX`" \n
  3803. "trap \"rm $TMP* 2>/dev/null\" " ?0 \n))
  3804. (define-skeleton sh-until
  3805. "Insert an until loop. See `sh-feature'."
  3806. (sh "condition: "
  3807. '(setq input (sh-feature sh-test))
  3808. > "until " str "; do" \n
  3809. > _ \n
  3810. "done" > \n))
  3811. ;;;(put 'sh-until 'menu-enable '(sh-feature sh-until))
  3812. (define-skeleton sh-while
  3813. "Insert a while loop. See `sh-feature'."
  3814. (csh sh-modify sh
  3815. 2 ""
  3816. 3 "while( "
  3817. 5 " )"
  3818. 10 '<
  3819. 11 "end")
  3820. (es sh-modify sh
  3821. 3 "while { "
  3822. 5 " } {"
  3823. 10 ?\} )
  3824. (rc sh-modify sh
  3825. 3 "while( "
  3826. 5 " ) {"
  3827. 10 ?\} )
  3828. (sh "condition: "
  3829. '(setq input (sh-feature sh-test))
  3830. > "while " str "; do" \n
  3831. > _ \n
  3832. "done" > \n))
  3833. (define-skeleton sh-while-getopts
  3834. "Insert a while getopts loop. See `sh-feature'.
  3835. Prompts for an options string which consists of letters for each recognized
  3836. option followed by a colon `:' if the option accepts an argument."
  3837. (bash sh-modify sh
  3838. 18 "${0##*/}")
  3839. (csh nil
  3840. "while( 1 )" \n
  3841. > "switch( \"$1\" )" \n
  3842. '(setq input '("- x" . 2))
  3843. > >
  3844. ( "option, %s: "
  3845. < "case " '(eval str)
  3846. '(if (string-match " +" str)
  3847. (setq v1 (substring str (match-end 0))
  3848. str (substring str 0 (match-beginning 0)))
  3849. (setq v1 nil))
  3850. str ?: \n
  3851. > "set " v1 & " = $2" | -4 & _ \n
  3852. (if v1 "shift") & \n
  3853. "breaksw" \n)
  3854. < "case --:" \n
  3855. > "shift" \n
  3856. < "default:" \n
  3857. > "break" \n
  3858. resume:
  3859. < < "endsw" \n
  3860. "shift" \n
  3861. < "end" \n)
  3862. (ksh88 sh-modify sh
  3863. 16 "print"
  3864. 18 "${0##*/}"
  3865. 37 "OPTIND-1")
  3866. (posix sh-modify sh
  3867. 18 "$(basename $0)")
  3868. (sh "optstring: "
  3869. > "while getopts :" str " OPT; do" \n
  3870. > "case $OPT in" \n
  3871. '(setq v1 (append (vconcat str) nil))
  3872. ( (prog1 (if v1 (char-to-string (car v1)))
  3873. (if (eq (nth 1 v1) ?:)
  3874. (setq v1 (nthcdr 2 v1)
  3875. v2 "\"$OPTARG\"")
  3876. (setq v1 (cdr v1)
  3877. v2 nil)))
  3878. > str "|+" str sh-non-closing-paren \n
  3879. > _ v2 \n
  3880. > ";;" \n)
  3881. > "*" sh-non-closing-paren \n
  3882. > "echo" " \"usage: " "`basename $0`"
  3883. " [+-" '(setq v1 (point)) str
  3884. '(save-excursion
  3885. (while (search-backward ":" v1 t)
  3886. (replace-match " ARG] [+-" t t)))
  3887. (if (eq (preceding-char) ?-) -5)
  3888. (if (and (sequencep v1) (length v1)) "] " "} ")
  3889. "[--] ARGS...\"" \n
  3890. "exit 2" > \n
  3891. "esac" >
  3892. \n "done"
  3893. > \n
  3894. "shift " (sh-add "OPTIND" -1) \n
  3895. "OPTIND=1" \n))
  3896. (defun sh-assignment (arg)
  3897. "Remember preceding identifier for future completion and do self-insert."
  3898. (interactive "p")
  3899. (self-insert-command arg)
  3900. (if (<= arg 1)
  3901. (sh-remember-variable
  3902. (save-excursion
  3903. (if (re-search-forward (sh-feature sh-assignment-regexp)
  3904. (prog1 (point)
  3905. (beginning-of-line 1))
  3906. t)
  3907. (match-string 1))))))
  3908. (defun sh-maybe-here-document (arg)
  3909. "Insert self. Without prefix, following unquoted `<' inserts here document.
  3910. The document is bounded by `sh-here-document-word'."
  3911. (declare (obsolete sh-electric-here-document-mode "24.3"))
  3912. (interactive "*P")
  3913. (self-insert-command (prefix-numeric-value arg))
  3914. (or arg (sh--maybe-here-document)))
  3915. (defun sh--maybe-here-document ()
  3916. (or (not (looking-back "[^<]<<" (line-beginning-position)))
  3917. (save-excursion
  3918. (backward-char 2)
  3919. (or (sh-quoted-p)
  3920. (sh--inside-noncommand-expression (point))))
  3921. (nth 8 (syntax-ppss))
  3922. (let ((tabs (if (string-match "\\`-" sh-here-document-word)
  3923. (make-string (/ (current-indentation) tab-width) ?\t)
  3924. ""))
  3925. (delim (replace-regexp-in-string "['\"]" ""
  3926. sh-here-document-word)))
  3927. (insert sh-here-document-word)
  3928. (or (eolp) (looking-at "[ \t]") (insert ?\s))
  3929. (end-of-line 1)
  3930. (while
  3931. (sh-quoted-p)
  3932. (end-of-line 2))
  3933. (insert ?\n tabs)
  3934. (save-excursion
  3935. (insert ?\n tabs (replace-regexp-in-string
  3936. "\\`-?[ \t]*" "" delim))))))
  3937. (define-minor-mode sh-electric-here-document-mode
  3938. "Make << insert a here document skeleton."
  3939. nil nil nil
  3940. (if sh-electric-here-document-mode
  3941. (add-hook 'post-self-insert-hook #'sh--maybe-here-document nil t)
  3942. (remove-hook 'post-self-insert-hook #'sh--maybe-here-document t)))
  3943. ;; various other commands
  3944. (defun sh-beginning-of-command ()
  3945. ;; FIXME: Redefine using SMIE.
  3946. "Move point to successive beginnings of commands."
  3947. (interactive)
  3948. (if (re-search-backward sh-beginning-of-command nil t)
  3949. (goto-char (match-beginning 2))))
  3950. (defun sh-end-of-command ()
  3951. ;; FIXME: Redefine using SMIE.
  3952. "Move point to successive ends of commands."
  3953. (interactive)
  3954. (if (re-search-forward sh-end-of-command nil t)
  3955. (goto-char (match-end 1))))
  3956. ;; Backslashification. Stolen from make-mode.el.
  3957. (defun sh-backslash-region (from to delete-flag)
  3958. "Insert, align, or delete end-of-line backslashes on the lines in the region.
  3959. With no argument, inserts backslashes and aligns existing backslashes.
  3960. With an argument, deletes the backslashes.
  3961. This function does not modify the last line of the region if the region ends
  3962. right at the start of the following line; it does not modify blank lines
  3963. at the start of the region. So you can put the region around an entire
  3964. shell command and conveniently use this command."
  3965. (interactive "r\nP")
  3966. (save-excursion
  3967. (goto-char from)
  3968. (let ((column sh-backslash-column)
  3969. (endmark (make-marker)))
  3970. (move-marker endmark to)
  3971. ;; Compute the smallest column number past the ends of all the lines.
  3972. (if sh-backslash-align
  3973. (progn
  3974. (if (not delete-flag)
  3975. (while (< (point) to)
  3976. (end-of-line)
  3977. (if (= (preceding-char) ?\\)
  3978. (progn (forward-char -1)
  3979. (skip-chars-backward " \t")))
  3980. (setq column (max column (1+ (current-column))))
  3981. (forward-line 1)))
  3982. ;; Adjust upward to a tab column, if that doesn't push
  3983. ;; past the margin.
  3984. (if (> (% column tab-width) 0)
  3985. (let ((adjusted (* (/ (+ column tab-width -1) tab-width)
  3986. tab-width)))
  3987. (if (< adjusted (window-width))
  3988. (setq column adjusted))))))
  3989. ;; Don't modify blank lines at start of region.
  3990. (goto-char from)
  3991. (while (and (< (point) endmark) (eolp))
  3992. (forward-line 1))
  3993. ;; Add or remove backslashes on all the lines.
  3994. (while (and (< (point) endmark)
  3995. ;; Don't backslashify the last line
  3996. ;; if the region ends right at the start of the next line.
  3997. (save-excursion
  3998. (forward-line 1)
  3999. (< (point) endmark)))
  4000. (if (not delete-flag)
  4001. (sh-append-backslash column)
  4002. (sh-delete-backslash))
  4003. (forward-line 1))
  4004. (move-marker endmark nil))))
  4005. (defun sh-append-backslash (column)
  4006. (end-of-line)
  4007. ;; Note that "\\\\" is needed to get one backslash.
  4008. (if (= (preceding-char) ?\\)
  4009. (progn (forward-char -1)
  4010. (delete-horizontal-space)
  4011. (indent-to column (if sh-backslash-align nil 1)))
  4012. (indent-to column (if sh-backslash-align nil 1))
  4013. (insert "\\")))
  4014. (defun sh-delete-backslash ()
  4015. (end-of-line)
  4016. (or (bolp)
  4017. (progn
  4018. (forward-char -1)
  4019. (if (looking-at "\\\\")
  4020. (delete-region (1+ (point))
  4021. (progn (skip-chars-backward " \t") (point)))))))
  4022. (provide 'sh-script)
  4023. ;;; sh-script.el ends here