ÿØÿà JFIF    ÿÛ „  ( %"1!%)+...383,7(-.+  -+++--++++---+-+-----+---------------+---+-++7-----ÿÀ  ß â" ÿÄ     ÿÄ H    !1AQaq"‘¡2B±ÁÑð#R“Ò Tbr‚²á3csƒ’ÂñDS¢³$CÿÄ   ÿÄ %  !1AQa"23‘ÿÚ   ? ôÿ ¨pŸªáÿ —åYõõ\?àÒü©ŠÄï¨pŸªáÿ —åYõõ\?àÓü©ŠÄá 0Ÿªáÿ Ÿå[úƒ ú®ði~TÁbqÐ8OÕpÿ ƒOò¤Oè`–RÂáœá™êi€ßÉ< FtŸI“öÌ8úDf´°å}“¾œ6  öFá°y¥jñÇh†ˆ¢ã/ÃÐ:ªcÈ "Y¡ðÑl>ÿ ”ÏËte:qž\oäŠe÷󲍷˜HT4&ÿ ÓÐü6ö®¿øþßèô Ÿ•7Ñi’•j|“ñì>b…þS?*Óôÿ ÓÐü*h¥£ír¶ü UãS炟[AÐaè[ûª•õ&õj?†Éö+EzP—WeÒírJFt ‘BŒ†Ï‡%#tE Øz ¥OÛ«!1›üä±Í™%ºÍãö]°î(–:@<‹ŒÊö×òÆt¦ãº+‡¦%ÌÁ²h´OƒJŒtMÜ>ÀÜÊw3Y´•牋4ǍýʏTì>œú=Íwhyë,¾Ôò×õ¿ßÊa»«þˆѪQ|%6ž™A õ%:øj<>É—ÿ Å_ˆCbõ¥š±ý¯Ýƒï…¶|RëócÍf溪“t.СøTÿ *Ä¿-{†çàczůŽ_–^XþŒ±miB[X±d 1,é”zEù»& î9gœf™9Ð'.;—™i}!ôšåîqêÛ٤ёý£½ÆA–àôe"A$˝Úsäÿ ÷Û #°xŸëí(l »ý3—¥5m! rt`†0~'j2(]S¦¦kv,ÚÇ l¦øJA£Šƒ J3E8ÙiŽ:cÉžúeZ°€¯\®kÖ(79«Ž:¯X”¾³Š&¡* ….‰Ž(ÜíŸ2¥ª‡×Hi²TF¤ò[¨íÈRëÉ䢍mgÑ.Ÿ<öäS0í„ǹÁU´f#Vß;Õ–…P@3ío<ä-±»Ž.L|kªÀê›fÂ6@»eu‚|ÓaÞÆŸ…¨ááå>åŠ?cKü6ùTÍÆ”†sĤÚ;H2RÚ†õ\Ö·Ÿn'¾ ñ#ºI¤Å´%çÁ­‚â7›‹qT3Iï¨ÖÚ5I7Ë!ÅOóŸ¶øÝñØôת¦$Tcö‘[«Ö³šÒ';Aþ ¸èíg A2Z"i¸vdÄ÷.iõ®§)¿]¤À†–‡É&ä{V¶iŽ”.Ó×Õÿ û?h¬Mt–íª[ÿ Ñÿ ÌV(í}=ibÔ¡›¥¢±b Lô¥‡piη_Z<‡z§èŒ)iÖwiÇ 2hÙ3·=’d÷8éŽ1¦¸c¤µ€7›7Ø ð\á)} ¹fËí›pAÃL%âc2 í§æQz¿;T8sæ°qø)QFMð‰XŒÂ±N¢aF¨…8¯!U  Z©RÊ ÖPVÄÀÍin™Ì-GˆªÅËŠ›•zË}º±ŽÍFò¹}Uw×#ä5B¤{î}Ð<ÙD é©¤&‡ïDbàÁôMÁ." ¤‡ú*õ'VŽ|¼´Úgllº¼klz[Æüï÷Aób‡Eÿ dÑ»Xx9ÃÜ£ÁT/`¼¸vI±Ýµ·Ë‚“G³þ*Ÿû´r|*}<¨îºœ @¦mÄ’M¹”.œ«Y–|6ÏU¤jç¥ÕÞqO ˜kDÆÁ¨5ÿ š;ÐЦ¦€GÙk \ –Þ=â¼=SͧµªS°ÚÍpÜãQűÀõ¬?ÃÁ1Ñ•õZà?hóœ€ L¦l{Y*K˜Ù›zc˜–ˆâ ø+¾ ­-Ök¥%ùEÜA'}ˆ><ÊIè“bpÍ/qÞâvoX€w,\úªò6Z[XdÒæ­@Ö—€$òJí#é>'°Ú ôª˜<)4ryÙ£|óAÅn5žêŸyÒäMÝ2{"}‰–¤l÷ûWX\l¾Á¸góÉOÔ /óñB¤f¸çñ[.P˜ZsÊË*ßT܈§QN¢’¡¨§V¼(Üù*eÕ“”5T¨‹Âê¥FŒã½Dü[8'Ò¥a…Ú¶k7a *•›¼'Ò·\8¨ª\@\õ¢¦íq+DÙrmÎ…_ªæ»ŠÓœ¡¯’Ré9MÅ×D™lælffc+ŒÑ,ý™ÿ ¯þǤ=Å’Á7µ÷ÚÛ/“Ü€ñýã¼àí¾ÕÑ+ƒ,uµMâÀÄbm:ÒÎPæ{˜Gz[ƒ¯«® KHà`ߨŠéí¯P8Aq.C‰ à€kòpj´kN¶qô€…Õ,ÜNŠª-­{Zö’æû44‰sŽè‰îVíRœÕm" 6?³D9¡ÇTíÅꋇ`4«¸ÝÁô ï’ýorqКÇZ«x4Žâéþuïf¹µö[P ,Q£éaX±`PÉÍZ ¸äYúg üAx ’6Lê‚xÝÓ*äQ  Ï’¨hÍ =²,6ï#rÃ<¯–£»ƒ‹,–ê•€ aÛsñ'%Æ"®ÛüìBᝠHÚ3ß°©$“XnœÖ’î2ËTeûìxîß ¦å¿çÉ ðK§þ{‘t‚Ϋ¬jéîZ[ ”š7L¥4VÚCE×]m¤Øy”ä4-dz£œ§¸x.*ãÊÊ b÷•h:©‡¦s`BTÁRû¾g⻩‹jø sF¢àJøFl‘È•Xᓁà~*j¯ +(ÚÕ6-£¯÷GŠØy‚<Ç’.F‹Hœw(+)ÜÜâÈzÄäT§FߘãÏ;DmVœ3Àu@mÚüXÝü•3B¨òÌÁÛ<·ÃÜ z,Ì@õÅ·d2]ü8s÷IôÞ¯^Ç9¢u„~ëAŸï4«M? K]­ÅàPl@s_ p:°¬ZR”´›JC[CS.h‹ƒïËœ«Æ]–÷ó‚wR×k7X‰k›‘´ù¦=¡«‰¨¨Â')—71ó’c‡Ðúµ `é.{§p¹ój\Ž{1h{o±Ý=áUÊïGÖŒõ–-BÄm+AZX¶¡ ïHðæ¥JmÙ;…䡟ˆ¦ ° äšiÉg«$üMk5¤L“’çÊvïâï ,=f“"íἊ5ô¬x6{ɏžID0e¸vçmi'︧ºð9$ò¹÷*£’9ÿ ²TÔ…×>JV¥}Œ}$p[bÔ®*[jzS*8 ”·T›Í–ñUîƒwo$áè=LT™ç—~ô·¤ÈÚ$榍q‰„+´kFm)ž‹©i–ËqÞŠ‰à¶ü( ‚•§ •°ò·‡#5ª•µÊ﯅¡X¨šÁ*F#TXJÊ ušJVÍ&=iÄs1‚3•'fý§5Ñ<=[íÞ­ PÚ;ѱÌ_~Ä££8rÞ ²w;’hDT°>ÈG¬8Á²ÚzŽ®ò®qZcqJêäÞ-ö[ܘbň±çb“ж31²n×iƒðÕ;1¶þÉ ªX‰,ßqÏ$>•î íZ¥Z 1{ç൵+ƒÕµ¥°T$§K]á»Ûï*·¤tMI’ÂZbŽÕiÒ˜}bÓ0£ª5›¨ [5Ž^ÝœWøÂÝh° ¢OWun£¤5 a2Z.G2³YL]jåtì”ä ÁÓ‘%"©<Ôúʰsº UZvä‡ÄiÆÒM .÷V·™ø#kèýiíÌ–ª)µT[)BˆõÑ xB¾B€ÖT¨.¥~ð@VĶr#¸ü*åZNDŽH;âi ],©£öØpù(šºãö¼T.uCê•4@ÿ GÕÛ)Cx›®0ø#:ÏðFÒbR\(€€Ä®fã4Þ‰Fä¯HXƒÅ,†öEÑÔÜ]Öv²?tLÃvBY£ú6Êu5ÅAQ³1‘’¬x–HŒÐ‡ ^ ¸KwJôÖŽ5×CÚ¨vÜ«/B0$×k°=ðbÇ(Ï)w±A†Á† 11Í=èQšµ626ŒÜ/`G«µ<}—-Ö7KEHÈÉðóȤmݱû±·ø«Snmá=“䫚mݱŸ¡¶~ó·“äUóJæúòB|E LêŽy´jDÔ$G¢þÐñ7óR8ýÒ…Ç› WVe#·Ÿ p·Fx~•ݤF÷0Èÿ K¯æS<6’¡WШ; ´ÿ ¥Êø\Òuî†åÝ–VNœkÒ7oòX¨Á­Ø÷FÎÑä±g÷ÿ M~Çî=p,X´ ÝÌÚÅ‹’ÃjÖ.ØöÏñ qïQ¤ÓZE†° =6·]܈ s¸>v•Ž^Ý\wq9r‰Î\¸¡kURÒ$­*‹Nq?Þª*!sŠÆ:TU_u±T+øX¡ ®¹¡,ÄâÃBTsÜ$Ø›4m椴zÜK]’’›Pƒ @€#â˜`é¹=I‡fiV•Ôî“nRm+µFPOhÍ0B£ €+¬5c v•:P'ÒyÎ ‰V~‚Ó†ÖuókDoh$å\*ö%Ю=£«…aȼ½÷Û.-½VŒŠ¼'lyî±1¬3ó#ÞE¿ÔS¤gV£m›=§\û"—WU¤ÚǼÿ ÂnÁGŒÃ ‚õN D³õNÚíŒÕ;HôyÄÈ©P¹Ä{:?R‘Ô¨âF÷ø£bÅó® JS|‚R÷ivýáâ€Æé¡è³´IئÑT!§˜•ت‚¬â@q€wnïCWÄ@JU€ê¯m6]Ï:£âx'+ÒðXvÓ¦Úm=–´7œ $ì“B£~p%ÕŸUþ« N@¼üï~w˜ñø5®—'Ôe»¤5ã//€ž~‰Tþ›Å7•#¤× Íö pÄ$ùeåì*«ÓŠEØWEÈsßg ¦ûvžSsLpºÊW–âµEWöˬH; ™!CYõZ ÃÄf æ#1W. \uWâ\,\Çf j’<qTbên›Î[vxx£ë 'ö¨1›˜ÀM¼Pÿ H)ƒêêŒA7s,|F“ 꺸k³9Ìö*ç®;Ö!Ö$Eiž•¹ÒÚ†ýóéÝû¾ÕS®ó$’NÝäŸz¤5r¦ãÄÃD÷Üø!°ø‡Ô&@m™Ì^Ãä­d q5Lnÿ N;.6½·N|#ä"1Nƒx“ã<3('&ñßt  ~ªu”1Tb㫨9ê–›–bìd$ߣ=#ÕãÒmU¯eí$EFù5ýYô櫨æì™Ç—±ssM]·á¿0ÕåJRÓªîiƒ+O58ÖñªŠÒx" \µâá¨i’¤i —Ö ” M+M¤ë9‚‰A¦°Qõ¾ßøK~¼Ã‘g…Ö´~÷Ï[3GUœÒ½#…kàÔ®Ò”‰³·dWV‰IP‰Ú8u¹”E ÖqLj¾êÕCBš{A^Âß;–¨`¯¬ìö ˼ ×tìø.tƐm*n¨y4o&Àx¥n¦×î‡aupáÛj8¿m›è¶ã!o½;ß0y^ý×^EÑ¿ÒjzŒ­)vÚÑnÄL …^ªô× ‡—‚3k Îý­hï]içå–îÏ*÷ñþ»Ô CÒjøjÍznˆ´ ¹#b'Fô‹ ‰v¥'’à'T´ƒHýÍ%M‰ ƒ&ÆÇŒï1 ‘ –Þ ‰i¬s žR-Ÿ kЬá¬7:þ 0ŒÅÒÕ/aÙ¬ÃÝ#Úøœ ©aiVc‰. ¹¦ãµ” ›Yg¦›ÆÎýº°f³7ƒhá·¸­}&D9¡ÂsÉÙÞèŠõØàC™¨ñbFC|´Ü(ŸƒÚÒ-%»'a Ì¿)ËÇn¿úÿ ÞŽX…4ÊÅH^ôΑí@ù¹Eh¶“L8Çjù ¼ÎåVªóR©Ï5uà V4lZß®=€xÖŸ–ÑÈ ÷”¨°¾__yM1tÉ?uÆþIkÄgæ@þ[¢†°XÃJ£j·:nkÅ¢u ‘}âGzö­/IµèЬ¼48q¦F°ŽR¼=ûì{´¯RýicS ÕÛ íNtÍÙï£,w4rêì®»~x(©Uñ§#Ñ&œÕ¤>ÎåÍÓ9’Ö{9eV­[Öjâ²ãu]˜å2›qÑšÕJç0€sÄ|Êëè0튔bÁ>“{×_F`Ø©ºê:µä,v¤ðfc1±"«ÔÍän1#=· Âøv~H½ÐßA¾¿Ü€Óš]Õ; I¾÷ç‚Qi†î¹9ywÔKG˜áñ zQY—§ÃÕZ07§X‚ Áh;ÁM)iÌCH-¯T‘ë|A0{Ò½LÚ–TâÖkÜ’dÀ“rmm»”جPF³ÖcbE§T€ÒxKºû’Ó®7±²(\4ŽÃ¸Uu@j™yĵ;³µ!Á¢b.W¤=mõ´êµK k ¸K^ÜÛ#p*Ü14qkZç5ïë †°5Ï%ÍÛ<Õ¤×Ô¥ê†C Õ´¼ú$ƒÖ“”]Ù¬qÞÚ[4©ý!ûÏ—Áb쳐XµA¬â~`›Çr¸8ìùÝ䫦<>ä÷«?xs´ÇÑ /á;¹øüÊÈÙà{"@Žïzâ¬[âß‚ U_<ÇŸ½4èN˜ú61®qŠu ¦þF£»äJ_ˆÙÎ~ ÞAã–݄ϗrŠD;xTž‘ô`É«…suãO`?³à™ô Lý#Íc5öoæØ‚y´´÷«ZR§<&JÇ+éâô´€i!Àˆ0æAoàðLèÖ-2ŸõW.’t^–(KÁmHµV@xÜÇy®Ñø­â^:Ú3w· 7½¹°ñ¸â¹®:',«Mœ—n­Á+Ãbš LÈ‘ÄnRÓÅœ%¦²‰¨ùQ:¤f‚ "PÕtô¸…cæl…&˜Ú˜Ôkv‹ž+vŠ,=¢v­6—Xy*¥t£«<™:“aîϲ=¦6rO]XI¿Œ÷¤zÚ­›¶ 6÷”w\d ü~v®ˆÌk«^m<ÿ ¢‰Õ\)ùºŽ;… lîÙÅEŠ®cѾ@vnMÏ,¼“ñ•ŽBxðÃzãÇç%3ˆ"}Ù•Åî> BÉú;Ò]V+P˜F_´ßé> Øše|ï‡ÄOmFæÇ ãqÞ$/xÐx­z`ï9"œÜij‚!7.\Td…9M‡•iŽ‹¾‘50ÞŽn¥ß4ÉôO ¹*í^QêËÜÇÌ8=ާs‰'ÂëÙ«á%Pú[O †ÅP¯Vsް.‰,kc¶ ¬A9n˜XÎ-ÞšN["¹QÕ‰ƒMýÁߺXJæÍaLj¾×Ãmã¾ãÚ uñÒþåQô¦¥ /ÄUx:‚ÍÜ’ Đ©ØÝ3V¨‰ÕnÐ6ó*óúK­«…c ¯U òhsý­jóÔj#,ímŒRµ«lbïUTŒÑ8†Ä0œÏr`ð¡¬É Ї ë"À² ™ 6¥ f¶ ¢ÚoܱԷ-<Àî)†a¶ž'Ú»¨TXqØæ¶÷YÄHy˜9ÈIW­YÀuMFë ºÏ’AqÌ4·/Ú †ô'i$øä­=Ä Ý|öK×40è|È6p‘0§)o¥ctî§H+CA-“ xØ|ÐXАç l8íºð3Ø:³¤¬KX¯UÿÙ ;; csh-mode.el --- csh (and tcsh) script editing mode for Emacs. ;; ;; Version: 1.2 ;; Date: April 2, 1999 ;; Maintainer: Dan Harkless ;; ;; Description: ;; csh and tcsh script editing mode for Emacs. ;; ;; Installation: ;; Put csh-mode.el in some directory in your load-path and load it. ;; ;; Usage: ;; This major mode assists shell script writers with indentation ;; control and control structure construct matching in much the same ;; fashion as other programming language modes. Invoke describe-mode ;; for more information. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Author key: ;; DH - Dan Harkless ;; CM - Carlo Migliorini ;; JR - Jack Repenning ;; GE - Gary Ellison ;; ;; *** REVISION HISTORY *** ;; ;; DATE MOD. BY REASON FOR MODIFICATION ;; --------- -- -------------------------------------------------------------- ;; 2 Apr 99 DH 1.2: Noticed an out-of-date comment referencing .bashrc etc. ;; 11 Dec 96 DH 1.1: ksh-mode just indented continuation lines by 1 space. ;; csh-mode looks at the first line and indents properly to line ;; up under the open-paren, quote, or command. ;; 11 Dec 96 DH Added fontification for history substitutions. ;; 10 Dec 96 DH Added indentation and fontification for labels. Added ;; fontification for variables and backquoted strings. ;; 9 Dec 96 DH 1.0: Brought csh-mode up to the level of functionality of ;; the original ksh-mode. ;; 7 Oct 96 CM 0.1: Hacked ksh-mode.el into minimally functional csh-mode.el ;; by doing search-and-replace and some keyword changes. ;; 8 Aug 96 JR (Last modification to ksh-mode 2.6.) ;; [...] ;; 19 Jun 92 GE (Conception of ksh-mode.) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defconst csh-mode-version "1.2" "*Version number of this version of csh-mode") (defvar csh-mode-hook '(lambda () (auto-fill-mode 1)) "Hook to run each time csh-mode is entered.") ;; ;; -------------------------------------------> Variables controlling completion ;; (defvar csh-completion-list '()) (make-variable-buffer-local 'csh-completion-list) (set-default 'csh-completion-list '()) ;; ;; -type- : type number, 0:misc, 1:variable, 2:function ;; -regexp-: regexp used to parse the script ;; -match- : used by match-beginning/end to pickup target ;; (defvar csh-completion-type-misc 0) (defvar csh-completion-regexp-var "\\([A-Za-z_0-9]+\\)=") (defvar csh-completion-type-var 1) (defvar csh-completion-match-var 1) (defvar csh-completion-regexp-var2 "\\$\\({\\|{#\\)?\\([A-Za-z_0-9]+\\)[#%:}]?") (defvar csh-completion-match-var2 2) (defvar csh-completion-regexp-function "\\(function\\)?[ \t]*\\([A-Za-z_0-9]+\\)[ \t]*([ \t]*)") (defvar csh-completion-type-function 2) (defvar csh-completion-match-function 2) ;; ;; ------------------------------------> Variables controlling indentation style ;; (defvar csh-indent 4 "*Indentation of csh statements with respect to containing block. A value of nil indicates compound list keyword \(\"do\" and \"then\"\) alignment.") (defvar csh-case-item-offset csh-indent "*Additional indentation for case items within a case statement.") (defvar csh-case-indent nil "*Additional indentation for statements under case items.") (defvar csh-comment-regexp "^\\s *#" "*Regular expression used to recognize comments. Customize to support csh-like languages.") (defvar csh-match-and-tell t "*If non-nil echo in the minibuffer the matching compound command for the \"breaksw\", \"end\", or \"endif\".") (defvar csh-tab-always-indent t "*Controls the operation of the TAB key. If t (the default), always reindent the current line. If nil, indent the current line only if point is at the left margin or in the line's indentation; otherwise insert a tab.") ;; ;; ----------------------------------------> Constants containing syntax regexps ;; (defconst csh-case-default-re "^\\s *\\(case\\|default\\)\\b" "Regexp used to locate grouping keywords case and default" ) (defconst csh-case-item-re "^\\s *\\(case .*\\|default\\):" "Regexp used to match case-items") (defconst csh-end-re "^\\s *end\\b" "Regexp used to match keyword: end") (defconst csh-endif-re "^\\s *endif\\b" "Regexp used to match keyword: endif") (defconst csh-endsw-re "^\\s *endsw\\b" "Regexp used to match keyword: endsw") (defconst csh-else-re "^\\s *\\belse\\(\\b\\|$\\)" "Regexp used to match keyword: else") (defconst csh-else-if-re "^\\s *\\belse if\\(\\b\\|$\\)" "Regexp used to match keyword pair: else if") (defconst csh-if-re "^\\s *if\\b.+\\(\\\\\\|\\bthen\\b\\)" "Regexp used to match non-one-line if statements") (defconst csh-iteration-keywords-re "^[^#\n]*\\s\"*\\b\\(while\\|foreach\\)\\b" "Match one of the keywords: while, foreach") (defconst csh-keywords-re "^\\s *\\(else\\b\\|foreach\\b\\|if\\b.+\\(\\\\\\|\\bthen\\b\\)\\|switch\\b\\|while\\b\\)" "Regexp used to detect compound command keywords: else, if, foreach, while") (defconst csh-label-re "^\\s *[^!#$\n ]+:" "Regexp used to match flow-control labels") (defconst csh-multiline-re "^.*\\\\$" "Regexp used to match a line with a statement using more lines.") (defconst csh-switch-re "^\\s *switch\\b" "Regexp used to match keyword: switch") ;; ;; ----------------------------------------> Variables controlling fontification ;; (defvar csh-keywords '("@" "alias" "bg" "break" "breaksw" "case" "cd" "chdir" "continue" "default" "dirs" "echo" "else" "end" "endif" "endsw" "eval" "exec" "exit" "fg" "foreach" "glob" "goto" "hashstat" "history" "if" "jobs" "kill" "limit" "login" "logout" "limit" "notify" "onintr" "popd" "printenv" "pushd" "rehash" "repeat" "set" "setenv" "shift" "source" "stop" "suspend" "switch" "then" "time" "umask" "unalias" "unhash" "unlimit" "unset" "unsetenv" "wait" "while" ;; tcsh-keywords "alloc" "bindkey" "builtins" "complete" "echotc" "filetest" "hup" "log" "ls-F" "nice" "nohup" "sched" "settc" "setty" "telltc" "uncomplete" "where" "which")) (require 'font-lock) ; need to do this before referring to font-lock-* below (defconst csh-font-lock-keywords ;; NOTE: The order of some of the items in this list is significant. Do not ;; alphabetize or otherwise blindly rearrange. (list ;; Comments on line 1, which are missed by syntactic fontification. '("^#.*" 0 font-lock-comment-face) ;; Label definitions (1 means first parenthesized exp in regexp). '("^\\s *\\([^!#$\n ]+\\):" 1 font-lock-function-name-face) ;; Label references. '("\\b\\(goto\\|onintr\\)\\b\\s +\\([^!#$ \n\t]+\\)" 2 font-lock-function-name-face) ;; Variable settings. '("\\(@\\|set\\|setenv\\)\\s +\\([0-9A-Za-z_]+\\b\\)" 2 font-lock-variable-name-face) ;; Variable references not inside of strings. '("\\$[][0-9A-Za-z_#:?]+" 0 font-lock-variable-name-face) ;; Backquoted strings. 'keep' means to just fontify non-fontified text. '("`\\(.*\\)`" 1 font-lock-reference-face keep) ;; NOTE: The following variables need to be anchored to the beginning of ;; line to prevent re-fontifying text in comments. Due to this, we ;; can only catch a finite number of occurrences. More can be added. ;; The 't' means to override previous fontification. ;; ;; Variable references inside of " strings. '("^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*\"" 1 font-lock-variable-name-face t) ; 1 '("^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*\\$[][0-9A-Za-z_#:?]+.*\"" 1 font-lock-variable-name-face t) ; 2 (cons (concat "^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*" "\\$[][0-9A-Za-z_#:?]+.*\\$[][0-9A-Za-z_#:?]+.*\"") (list 1 font-lock-variable-name-face t)) ; 3 ;; ;; History substitutions. '("^![^~= \n\t]+" 0 font-lock-reference-face t) ; BOL '("^[^#\n]*[^#\\\n]\\(![^~= \n\t]+\\)" 1 font-lock-reference-face t) ; 1 '("^[^#\n]*[^#\\\n]\\(![^~= \n\t]+\\).*![^~= \n\t]+" 1 font-lock-reference-face t) ; 2 ;; Keywords. (cons (concat "\\(\\<" (mapconcat 'identity csh-keywords "\\>\\|\\<") "\\>\\)") 1) )) (put 'csh-mode 'font-lock-keywords 'csh-font-lock-keywords) ;; ;; -------------------------------------------------------> Mode-specific tables ;; (defvar csh-mode-abbrev-table nil "Abbrev table used while in csh mode.") (define-abbrev-table 'csh-mode-abbrev-table ()) (defvar csh-mode-map nil "Keymap used in csh mode") (if csh-mode-map () (setq csh-mode-map (make-sparse-keymap)) ;;(define-key csh-mode-map "\177" 'backward-delete-char-untabify) (define-key csh-mode-map "\C-c\t" 'csh-completion-init-and-pickup) (define-key csh-mode-map "\C-j" 'reindent-then-newline-and-indent) (define-key csh-mode-map "\e\t" 'csh-complete-symbol) (define-key csh-mode-map "\n" 'reindent-then-newline-and-indent) (define-key csh-mode-map '[return] 'reindent-then-newline-and-indent) (define-key csh-mode-map "\t" 'csh-indent-command) ;;(define-key csh-mode-map "\t" 'csh-indent-line) ) (defvar csh-mode-syntax-table nil "Syntax table used while in csh mode.") (if csh-mode-syntax-table ;; If it's already set up, don't change it. () ;; Else, create it from the standard table and modify entries that need to be. (setq csh-mode-syntax-table (make-syntax-table)) (modify-syntax-entry ?& "." csh-mode-syntax-table) ; & -punctuation (modify-syntax-entry ?* "." csh-mode-syntax-table) ; * -punctuation (modify-syntax-entry ?- "." csh-mode-syntax-table) ; - -punctuation (modify-syntax-entry ?= "." csh-mode-syntax-table) ; = -punctuation (modify-syntax-entry ?+ "." csh-mode-syntax-table) ; + -punctuation (modify-syntax-entry ?| "." csh-mode-syntax-table) ; | -punctuation (modify-syntax-entry ?< "." csh-mode-syntax-table) ; < -punctuation (modify-syntax-entry ?> "." csh-mode-syntax-table) ; > -punctuation (modify-syntax-entry ?/ "." csh-mode-syntax-table) ; / -punctuation (modify-syntax-entry ?\' "\"" csh-mode-syntax-table) ; ' -string quote (modify-syntax-entry ?. "w" csh-mode-syntax-table) ; . -word constituent (modify-syntax-entry ?? "w" csh-mode-syntax-table) ; ? -word constituent ;; \n - comment ender, first character of 2-char comment sequence (modify-syntax-entry ?\n "> 1" csh-mode-syntax-table) ; # -word constituent ;; - whitespace, first character of 2-char comment sequence (modify-syntax-entry ? " 1" csh-mode-syntax-table) ; ;; \t - whitespace, first character of 2-char comment sequence (modify-syntax-entry ?\t " 1" csh-mode-syntax-table) ; # -word constituent ;; # - word constituent, second character of 2-char comment sequence (modify-syntax-entry ?# "w 2" csh-mode-syntax-table) ; # -word constituent ) ;; ;; ------------------------------------------------------------------> Functions ;; (defun csh-current-line () "Return the vertical position of point in the buffer. Top line is 1." (+ (count-lines (point-min) (point)) (if (= (current-column) 0) 1 0)) ) (defun csh-get-compound-level (begin-re end-re anchor-point &optional balance-list) "Determine how much to indent this structure. Return a list (level line) of the matching compound command or nil if no match found." (let* (;; Locate the next compound begin keyword bounded by point-min (match-point (if (re-search-backward begin-re (point-min) t) (match-beginning 0) 0)) (nest-column (if (zerop match-point) 1 (progn (goto-char match-point) (current-indentation)))) (nest-list (cons 0 0)) ;; sentinel cons since cdr is >= 1 ) (if (zerop match-point) nil ;; graceful exit from recursion (progn (if (nlistp balance-list) (setq balance-list (list))) ;; Now search forward from matching start keyword for end keyword (while (and (consp nest-list) (zerop (cdr nest-list)) (re-search-forward end-re anchor-point t)) (if (not (memq (point) balance-list)) (progn (setq balance-list (cons (point) balance-list)) (goto-char match-point) ;; beginning of compound cmd (setq nest-list (csh-get-compound-level begin-re end-re anchor-point balance-list)) ))) (cond ((consp nest-list) (if (zerop (cdr nest-list)) (progn (goto-char match-point) (cons nest-column (csh-current-line))) nest-list)) (t nil) ) ) ) ) ) (defun csh-get-nest-level () "Return a 2 element list (nest-level nest-line) describing where the current line should nest." (let ((case-fold-search) (level)) (save-excursion (forward-line -1) (while (and (not (bobp)) (null level)) (if (and (not (looking-at "^\\s *$")) (not (save-excursion (forward-line -1) (beginning-of-line) (looking-at csh-multiline-re))) (not (looking-at csh-comment-regexp))) (setq level (cons (current-indentation) (csh-current-line))) (forward-line -1) );; if );; while (if (null level) (cons (current-indentation) (csh-current-line)) level) ) ) ) (defun csh-get-nester-column (nest-line) "Return the column to indent to with respect to nest-line taking into consideration keywords and other nesting constructs." (save-excursion (let ((fence-post) (case-fold-search) (start-line (csh-current-line))) ;; ;; Handle case item indentation constructs for this line (cond ((looking-at csh-case-item-re) ;; This line is a case item... (save-excursion (goto-line nest-line) (let ((fence-post (save-excursion (end-of-line) (point)))) (cond ((re-search-forward csh-switch-re fence-post t) ;; If this is the first case under the switch, indent. (goto-char (match-beginning 0)) (+ (current-indentation) csh-case-item-offset)) ((re-search-forward csh-case-item-re fence-post t) ;; If this is another case right under a previous case ;; without intervening code, stay at the same ;; indentation. (goto-char (match-beginning 0)) (current-indentation)) (t ;; Else, this is a new case. Outdent. (- (current-indentation) csh-case-item-offset)) ) ))) (t;; Not a case-item. What to do relative to the nest-line? (save-excursion (goto-line nest-line) (setq fence-post (save-excursion (end-of-line) (point))) (save-excursion (cond ;; ;; Check if we are in a continued statement ((and (looking-at csh-multiline-re) (save-excursion (goto-line (1- start-line)) (looking-at csh-multiline-re))) (if (looking-at ".*[\'\"]\\\\") ;; If this is a continued string, indent under ;; opening quote. (progn (re-search-forward "[\'\"]") (forward-char -1)) (if (looking-at ".*([^\)\n]*\\\\") ;; Else if this is a continued parenthesized ;; list, indent after paren. (re-search-forward "(" fence-post t) ;; Else, indent after whitespace after first word. (re-search-forward "[^ \t]+[ \t]+" fence-post t))) (current-column)) ;; In order to locate the column of the keyword, ;; which might be embedded within a case-item, ;; it is necessary to use re-search-forward. ;; Search by literal case, since shell is ;; case-sensitive. ((re-search-forward csh-keywords-re fence-post t) (goto-char (match-beginning 1)) (if (looking-at csh-switch-re) (+ (current-indentation) csh-case-item-offset) (+ (current-indentation) (if (null csh-indent) 2 csh-indent) ))) ((re-search-forward csh-case-default-re fence-post t) (if (null csh-indent) (progn (goto-char (match-end 1)) (+ (current-indentation) 1)) (progn (goto-char (match-beginning 1)) (+ (current-indentation) csh-indent)) )) ;; ;; Now detect first statement under a case item ((looking-at csh-case-item-re) (if (null csh-case-indent) (progn (re-search-forward csh-case-item-re fence-post t) (goto-char (match-end 1)) (+ (current-column) 1)) (+ (current-indentation) csh-case-indent))) ;; ;; If this is the first statement under a control-flow ;; label, indent one level. ((csh-looking-at-label) (+ (current-indentation) csh-indent)) ;; This is hosed when using current-column ;; and there is a multi-command expression as the ;; nester. (t (current-indentation))) ) ));; excursion over );; Not a case-item );;let );; excursion );; defun (defun csh-indent-command () "Indent current line relative to containing block and allow for csh-tab-always-indent customization" (interactive) (let (case-fold-search) (cond ((save-excursion (skip-chars-backward " \t") (bolp)) (csh-indent-line)) (csh-tab-always-indent (save-excursion (csh-indent-line))) (t (insert-tab)) )) ) (defun csh-indent-line () "Indent current line as far as it should go according to the syntax/context" (interactive) (let (case-fold-search) (save-excursion (beginning-of-line) (if (bobp) nil ;; ;; Align this line to current nesting level (let* ( (level-list (csh-get-nest-level)) ; Where to nest against ;; (last-line-level (car level-list)) (this-line-level (current-indentation)) (nester-column (csh-get-nester-column (cdr level-list))) (struct-match (csh-match-structure-and-reindent)) ) (if struct-match (setq nester-column struct-match)) (if (eq nester-column this-line-level) nil (beginning-of-line) (let ((beg (point))) (back-to-indentation) (delete-region beg (point))) (indent-to nester-column)) );; let* );; if );; excursion ;; ;; Position point on this line (let* ( (this-line-level (current-indentation)) (this-bol (save-excursion (beginning-of-line) (point))) (this-point (- (point) this-bol)) ) (cond ((> this-line-level this-point);; point in initial white space (back-to-indentation)) (t nil) );; cond );; let* );; let );; defun (defun csh-indent-region (start end) "From start to end, indent each line." ;; The algorithm is just moving through the region line by line with ;; the match noise turned off. Only modifies nonempty lines. (save-excursion (let (csh-match-and-tell (endmark (copy-marker end))) (goto-char start) (beginning-of-line) (setq start (point)) (while (> (marker-position endmark) start) (if (not (and (bolp) (eolp))) (csh-indent-line)) (forward-line 1) (setq start (point))) (set-marker endmark nil) ) ) ) (defun csh-line-to-string () "From point, construct a string from all characters on current line" (skip-chars-forward " \t") ;; skip tabs as well as spaces (buffer-substring (point) (progn (end-of-line 1) (point)))) (defun csh-looking-at-label () "Return true if current line is a label (not the default: case label)." (and (looking-at csh-label-re) (not (looking-at "^\\s *default:")))) (defun csh-match-indent-level (begin-re end-re) "Match the compound command and indent. Return nil on no match, indentation to use for this line otherwise." (interactive) (let* ((case-fold-search) (nest-list (save-excursion (csh-get-compound-level begin-re end-re (point)) )) ) ;; bindings (if (null nest-list) (progn (if csh-match-and-tell (message "No matching compound command")) nil) ;; Propagate a miss. (let* ( (nest-level (car nest-list)) (match-line (cdr nest-list)) ) ;; bindings (if csh-match-and-tell (save-excursion (goto-line match-line) (message "Matched ... %s" (csh-line-to-string)) ) ;; excursion ) ;; if csh-match-and-tell nest-level ;;Propagate a hit. ) ;; let* ) ;; if ) ;; let* ) ;; defun csh-match-indent-level (defun csh-match-structure-and-reindent () "If the current line matches one of the indenting keywords or one of the control structure ending keywords then reindent. Also if csh-match-and-tell is non-nil the matching structure will echo in the minibuffer" (interactive) (let (case-fold-search) (save-excursion (beginning-of-line) (cond ((looking-at csh-else-re) (csh-match-indent-level csh-if-re csh-endif-re)) ((looking-at csh-else-if-re) (csh-match-indent-level csh-if-re csh-endif-re)) ((looking-at csh-endif-re) (csh-match-indent-level csh-if-re csh-endif-re)) ((looking-at csh-end-re) (csh-match-indent-level csh-iteration-keywords-re csh-end-re)) ((looking-at csh-endsw-re) (csh-match-indent-level csh-switch-re csh-endsw-re)) ((csh-looking-at-label) ;; Flush control-flow labels left since they don't nest. 0) ;; (t nil) );; cond ) )) ;;;###autoload (defun csh-mode () "csh-mode 2.0 - Major mode for editing csh and tcsh scripts. Special key bindings and commands: \\{csh-mode-map} Variables controlling indentation style: csh-indent Indentation of csh statements with respect to containing block. Default value is 4. csh-case-indent Additional indentation for statements under case items. Default value is nil which will align the statements one position past the \")\" of the pattern. csh-case-item-offset Additional indentation for case items within a case statement. Default value is 2. csh-tab-always-indent Controls the operation of the TAB key. If t (the default), always reindent the current line. If nil, indent the current line only if point is at the left margin or in the line's indentation; otherwise insert a tab. csh-match-and-tell If non-nil echo in the minibuffer the matching compound command for the \"done\", \"}\", \"fi\", or \"endsw\". Default value is t. csh-comment-regexp Regular expression used to recognize comments. Customize to support csh-like languages. Default value is \"\^\\\\s *#\". Style Guide. By setting (setq csh-indent default-tab-width) The following style is obtained: if [ -z $foo ] then bar # <-- csh-group-offset is additive to csh-indent foo fi By setting (setq csh-indent default-tab-width) (setq csh-group-offset (- 0 csh-indent)) The following style is obtained: if [ -z $foo ] then bar foo fi By setting (setq csh-case-item-offset 1) (setq csh-case-indent nil) The following style is obtained: case x in * foo) bar # <-- csh-case-item-offset baz;; # <-- csh-case-indent aligns with \")\" foobar) foo bar;; endsw By setting (setq csh-case-item-offset 1) (setq csh-case-indent 6) The following style is obtained: case x in * foo) bar # <-- csh-case-item-offset baz;; # <-- csh-case-indent foobar) foo bar;; endsw Installation: Put csh-mode.el in some directory in your load-path. Put the following forms in your .emacs file. (setq auto-mode-alist (append auto-mode-alist (list '(\"\\\\.csh$\" . csh-mode) '(\"\\\\.login\" . csh-mode)))) (setq csh-mode-hook (function (lambda () (font-lock-mode 1) ;; font-lock the buffer (setq csh-indent 8) (setq csh-tab-always-indent t) (setq csh-match-and-tell t) (setq csh-align-to-keyword t) ;; Turn on keyword alignment )))" (interactive) (kill-all-local-variables) (use-local-map csh-mode-map) (setq major-mode 'csh-mode) (setq mode-name "Csh") (setq local-abbrev-table csh-mode-abbrev-table) (set-syntax-table csh-mode-syntax-table) (make-local-variable 'indent-line-function) (setq indent-line-function 'csh-indent-line) (make-local-variable 'indent-region-function) (setq indent-region-function 'csh-indent-region) (make-local-variable 'comment-start) (setq comment-start "# ") (make-local-variable 'comment-end) (setq comment-end "") (make-local-variable 'comment-column) (setq comment-column 32) (make-local-variable 'comment-start-skip) (setq comment-start-skip "#+ *") ;; ;; config font-lock mode (make-local-variable 'font-lock-keywords) (setq font-lock-keywords csh-font-lock-keywords) ;; ;; Let the user customize (run-hooks 'csh-mode-hook) ) ;; defun ;; ;; Completion code supplied by Haavard Rue . ;; ;; ;; add a completion with a given type to the list ;; (defun csh-addto-alist (completion type) (setq csh-completion-list (append csh-completion-list (list (cons completion type))))) (defun csh-bol-point () (save-excursion (beginning-of-line) (point))) (defun csh-complete-symbol () "Perform completion." (interactive) (let* ((case-fold-search) (end (point)) (beg (unwind-protect (save-excursion (backward-sexp 1) (while (= (char-syntax (following-char)) ?\') (forward-char 1)) (point)))) (pattern (buffer-substring beg end)) (predicate ;; ;; ` or $( mark a function ;; (save-excursion (goto-char beg) (if (or (save-excursion (backward-char 1) (looking-at "`")) (save-excursion (backward-char 2) (looking-at "\\$("))) (function (lambda (sym) (equal (cdr sym) csh-completion-type-function))) ;; ;; a $, ${ or ${# mark a variable ;; (if (or (save-excursion (backward-char 1) (looking-at "\\$")) (save-excursion (backward-char 2) (looking-at "\\${")) (save-excursion (backward-char 3) (looking-at "\\${#"))) (function (lambda (sym) (equal (cdr sym) csh-completion-type-var))) ;; ;; don't know. use 'em all ;; (function (lambda (sym) t)))))) ;; (completion (try-completion pattern csh-completion-list predicate))) ;; (cond ((eq completion t)) ;; ;; oops, what is this ? ;; ((null completion) (message "Can't find completion for \"%s\"" pattern)) ;; ;; insert ;; ((not (string= pattern completion)) (delete-region beg end) (insert completion)) ;; ;; write possible completion in the minibuffer, ;; use this instead of a seperate buffer (usual) ;; (t (let ((list (all-completions pattern csh-completion-list predicate)) (string "")) (while list (progn (setq string (concat string (format "%s " (car list)))) (setq list (cdr list)))) (message string)))))) ;; ;; init the list and pickup all ;; (defun csh-completion-init-and-pickup () (interactive) (let (case-fold-search) (csh-completion-list-init) (csh-pickup-all))) ;; ;; init the list ;; (defun csh-completion-list-init () (interactive) (setq csh-completion-list (list (cons "break" csh-completion-type-misc) (cons "breaksw" csh-completion-type-misc) (cons "case" csh-completion-type-misc) (cons "continue" csh-completion-type-misc) (cons "endif" csh-completion-type-misc) (cons "exit" csh-completion-type-misc) (cons "foreach" csh-completion-type-misc) (cons "if" csh-completion-type-misc) (cons "while" csh-completion-type-misc)))) (defun csh-eol-point () (save-excursion (end-of-line) (point))) (defun csh-pickup-all () "Pickup all completions in buffer." (interactive) (csh-pickup-completion-driver (point-min) (point-max) t)) (defun csh-pickup-completion (regexp type match pmin pmax) "Pickup completion in region and addit to the list, if not already there." (let ((i 0) kw obj) (save-excursion (goto-char pmin) (while (and (re-search-forward regexp pmax t) (match-beginning match) (setq kw (buffer-substring (match-beginning match) (match-end match)))) (progn (setq obj (assoc kw csh-completion-list)) (if (or (equal nil obj) (and (not (equal nil obj)) (not (= type (cdr obj))))) (progn (setq i (1+ i)) (csh-addto-alist kw type)))))) i)) (defun csh-pickup-completion-driver (pmin pmax message) "Driver routine for csh-pickup-completion." (if message (message "pickup completion...")) (let* ( (i1 (csh-pickup-completion csh-completion-regexp-var csh-completion-type-var csh-completion-match-var pmin pmax)) (i2 (csh-pickup-completion csh-completion-regexp-var2 csh-completion-type-var csh-completion-match-var2 pmin pmax)) (i3 (csh-pickup-completion csh-completion-regexp-function csh-completion-type-function csh-completion-match-function pmin pmax))) (if message (message "pickup %d variables and %d functions." (+ i1 i2) i3)))) (defun csh-pickup-this-line () "Pickup all completions in current line." (interactive) (csh-pickup-completion-driver (csh-bol-point) (csh-eol-point) nil)) (provide 'csh-mode) ;;; csh-mode.el ends here