fXdZddlmZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl mZddlmZdZeddZd0d Zd Zd Zd0d Zd ZdZeddZd0dZeddZeddZeddZdZdZ d0dZ! d0dZ"dZ#dZ$e#e$zZ%dZ&dZ'dZ(dZ)dZ*gdZ+gdZ,gd Z-gd!Z.d"gZ/edd#Z0d$Z1d%Z2d0d&Z3d'Z4 d0d(Z5d0d)Z6d*Z7d1d+Z8d,Z9d-Z:d.Z;e Dialect aware s-expression indenter )print_functionN) lru_cache)pprintz2.1.2)maxsizec Ptjdd}|jddd|jdd d d d d |jddddd d|jdddddd |jddddd|jdd d!d"d#d |jd$d%d&d'd(d |jd)d*d+d,d |jd-d.d/d0d1d|jd2d3d4d5d d6|jd7d8d9td:;|jdd?td@;|jdAdBdCtd:D|jdEdFdGdHdIt zJ|jdKdLdMdNtdO;|jdPdQdRdSdTtt jD|jdUdVdWdXtdYD|jdZd[d\d]td^D|jd_d`dadbdc|jdddedfdgdhdc|jdidjdkdc|S)lz Return command line parser z#Dialect-aware s-expression indenteryasi) descriptionprogfileszWList of files to be indented. Will indent from standard input if no files are specified*)helpnargsz-ncz --no-compactz--nccompactz$Do not compact the code, just indent store_false)destr actionz-nbz --no-backupz--nbbackupz>Do not create a backup file even if --backup-dir is specified )rrr z-nmz --no-modifyz--nmmodifyzDo not modify the filez--diffz-diff output_diffz3Prints unified diff of the initial and final result store_truez-nwz --no-warningz--nwwarningzDo not display warningsz-nrz--no-rcz--nrread_rcz1Ignore any rc files in the current or home folderz --no-outputz -no-outputoutputz$Suppress output of the indented codez-cz--colorz-color colour_diffzDisplay diff text in colorz-nez --no-exitz--neexitz;Instructs the program not to exit when a warning is raised.z-o output_filezPath/name of output file)rr typedefaultz--tabz-tabtab_sizezIndent with tabs using the specified tabwidth. A tab is assumed equal to 4 spaces by default when expanding the tabs in the input filez --dialectz-dialectzUse Scheme keywords)r rrz-vz --versionversionzPrints script versionzyasi v%s)rr r"z-suffixz--suffix backup_suffixzBackup file suffixz .yasi.bak~z-bdz --backup-dirz--bdz -backup-dirz4The directory where the backup file is to be writtenz-isz --indent-sizez--iszThe number of spaces per indentz-diz--default-indentz--dizsThe indent level to be used in case a function's argument is in the next line. Vim uses 2, the most common being 1.z-icz--indent-commentsz--icz[If true, comment lines will be indented possibly messing with any deliberate comment layout)r rz-uniz --uniformz-uniformz--unizdDictates whether the if-clause and else-clause of an if-likeblock should have the same indent level.z -parallelz --parallelz#Process the given files in parallel)argparseArgumentParser add_argumentstrint __version__osgetcwd)parsers M/var/lib/jenkins/workspace/mettalog/venv/lib/python3.12/site-packages/yasi.pycreate_args_parserr0%s $ $9HF 'T!#  ~vI 3MK  }f8M MO  }f8 %m= ' B  ~vI &}>  y&y @ |( 3MK  i ),@  {F JL  = 'c2? jP "   Z "b:  k) $j;.FH :O:N ,(  ~v} C "))+'   . !  !6X !    "F5=IK  Z3   \ 2 Mc|tjdd}t|tr|j }t|t j r|St}|j|}|jj|_ |jdvr*|jdj|jtjj|j |_tjj#|j s*|jdj|j t%|j&dkDr|j(r|jd|j&s-|j*r|j(sd|_d|_d|_|j0rd|_|S)zK Reads command-line arguments >>> parse_args('--indent-comments') Nr%)lispnewlispclojureschemeallrz!`{0}' is not a recognized dialectzDirectory `{0}' does not existz;Cannot use the -o flag when more than one file is specifiedF)sysargv isinstancer)splitr& Namespacer0 parse_argsdialectlowererrorformatr,path expanduser backup_direxistslenr rrrrr) argumentsr.argss r/r=r=xsK HHQRL )S!OO% )X//0  !F   Y 'D<<%%'DL ||NN 8?? MNgg((9DO 77>>$// * 5< str >>> read_file(r'C:\mine\test.lisp') r'(print "No, no, there's \r\nlife in him!. ")\r\n\r\n' The file is read in binary mode in order to preserve original line endings. Line ending Binary mode Text mode CRLF CRLF LF CR CR LF  ---- Warning: File `' does not exist...rbzutf-8N)r,rBrE current_timeopenreaddecode)fnamefps r/ read_filerTsb 77>>% " >5#"" eT )bwwy()))s A++A4cRtjdtjS)zx current_time() -> str >>> current_time() 14:28:04 Returns the current local time in 24 clock system. z%X)timestrftime localtimer1r/rNrNs == 0 22r1ctt|}|j}tjj |sJdt d|dtjj tjj |sJdt d|d|tjztjj|dz|jz} tj||y#t$r4d}t ||f}tjj||zYywxYw)z backup_source_file(fname : str) >>> backup_source_file('~/Desktop/lisp/test.lisp') Create a backup copy of the source file. rJrKrLz-- Warning: Directory `r%z^ --%s-- Warning: Couldn't backup the file `%s' in `%s', check if you have enough permissions. N)r=rDr,rBrErNabspathsepr;r#shutilcopyfileIOErrorr8stderrwrite)rRrHrD backup_namemessagetpls r/backup_source_fileres d DJ 77>>% T>"''//*5 6YAMQV WY 6rvv% e( str >>> md5sum('Keyboard not found!! Press F1 to continue...') 'ad98cde09016d2e99a726966a4291acf' Returns a checksum to be used to determine whether the file has changed. A simple textual comparison can still do the work )hashlibmd5 hexdigest)contents r/md5sumrks ;;w  ) ) ++r1cFt|vrtSt|vrtStS)z find_line_ending(string : str) -> str >>> find_line_ending('Elementary my dear Watson. \r') '\r' Find the line ending in the file so that we can try to preserve it. )CRLFCRLFstrings r/find_line_endingrrs! v~  V| Ir1cztjdd|}tjdd|tj}tjdd|}tjdd|}tjdd |}tjd d|}tjd d|}tjd d|}tjd d|}tjdd|}tjdd|}tjdd|}tjdd|}|S)z trim(string : str) -> str Uses every usefull hack to try and reduce extra whitespace without messing with character literals z[ ]*$rz([^\\(\[, {@~`'#^])(\(|\[|{)z\1 \2z(\)|\]|})(\[|\(|{)z[ ]*(\)|\]|})z\1z[ ]{2,} z(\))[ \t]*(?=(\)))z(\])[ \t]*(?=(\]))z(})[ \t]*(?=(}))z(\()[ \t]*(?=(\())z(\[)[ \t]*(?=(\[))z({)[ \t]*(?=({))^[ ]*z('|`)[ ]+(\(|\[|{)z\1\2)resubXrps r/trimrysVVIr6 *F VV76244 PF VV)8V int >>> find_trim_limit(r'(list #\; #")') 14 >>> find_trim_limit(r'(list ; ")') 6 >>> find_trim_limit(r'(list " ;)') 7 The function attempts to identify upto which point we are supposed to trim so that we don't mess with strings or any aligned comments. It does this by comparing the positions of semicolons and double quotes. It doesn't consider the multiline comment marker. If your code uses multiline comments(#| ... |#), you'll have to use --no-compact mode z ([^\\];)|(^;)z ([^\\]")|(^")r!z[ ]*;r4{\[text\])r=rvsearchendstartr>minrF) rqrH comment_start string_startlimitbrace_string_starttag_string_startpos_lstxs r/find_trim_limitr sa" d DII.7M99-v6L".L   BE+8M%%'bM )V4::<  ||y YYsF399Z89K/335QS5E+//12,.>?%1b111 LEu{ 5 "E L " " L "F  L#2s 5 EEc|sy|dk(r%tjd|tjS|dk(rtjd|S|dk(rtjd|S|dk(rtjd |Sy) ap is_macro_name(func_name : str, dialect : str) -> bool >>> is_macro_name('yacc:define-parser') True Tests if a word is a macro using the language's/dialect's convention, e.g macros in Lisp usually start with 'def' and 'with' in Scheme. Saves the effort of finding all the macros in Lisp/Scheme/Clojure/newLISP and storing them in a list. Fr3z^(macro|def|do|with-)r6z^(call-|def|with-)r5z ^(def|with)r4z ^(macro|def))rvr}I) func_namer>s r/ is_macro_namerFsy &yy0)RTTBB(yy-y99)yy 22)yy33 r1c|j|}|ddk(r|d=|Dcgc]}||z }}|S|Dcgc]}||z }}|dj||d<|Scc}wcc}w)a split_preserve(string : str, sep : str) -> [str] >>> split_preserve(''' "My dear Holmes, " said I, "this is too much. You would certainly have been burned, had you lived a few centuries ago. ''', '\n') ['\n', ' "My dear Holmes, " said I, "this is too much. You would certainly\n', ' have been burned, had you lived a few centuries ago.\n', ' '] Splits the string and sticks the separator back to every string in the list. r!r)r;rstrip)rqr\str_listrs r/split_preserver_s ||C H|r RL%-.AG.. O*22AC22|**3/ O/ 3s A A!c.tjd|S)z all_whitespace(string : str) -> bool >>> all_whitespace(' ') True Returns True if a string has only whitespace. z ^[ ]*( | |$))rvr}rps r/all_whitespacers 99' 00r1ct|}|jdkr|jdS|j|jS)zP tabify(text : str, args : argparse.Namespace|str) -> str Expands tabs r%)r=r expandtabs)textrHs r/detabifyrs< d D }}qq!! ??4== ))r1c|t|}|jdkr|Sd|jz}|j|dS)z tabify(text : str, args : argparse.Namespace|str) -> str >>> tabify(' (println "hello world")', '--tab=3') ' (println "hello world")' Replace spaces with tabs r%rt )r=r replace)rrH tab_equivs r/tabifyrs> d D }}q dmm#I << 4 ((r1c~t|}|jrjt||}tjd|tj }|r|j r|j}|d|}||d}t|}||z}ntjdd|d}|}|r|dd}d |z} t| |} | |z|fS) a& pad_leading_whitespace(string : str, current_level : int, zero_level : int) -> str >>> pad_leading_whitespace("(print 'Yello)") " (print 'Yello)" Takes a string and indents it using the current indentation level and the zero level. ^[ ]*;rNz^[ ]+r)countr! indent_levelrt) r=rrrvr}Mindent_commentsr~ryrwr) rq zero_levelblistrH trim_limit comment_linesubstr1substr2rpaddings r/pad_leading_whitespacers d D ||%VT2 yyVRTT: D00%))+J:&%w-7" 2vQ7L Ry0 L GWd#G V \ ))r1cvt|}tjd|tj}|jrd}|j sA|gk(r<|s:t ||}tjd|}|r|jdz }nd}|r||dfS|s!t|st||||\} } || | fS||dfS)a indent_line(zerolevel : int, bracket_list : list, line : str, in_comment : bool, in_symbol_region : bool, args : string|list) Most important function in the indentation process. It uses the bracket locations stored in the list to indent the line. rFz^[ ]+[^; ) ]r%r) r=rvr}rrrrr~rr) zerolevel bracket_listline in_commentin_symbol_regionrHr_lineleading_spaces curr_line current_levels r/ indent_liners d D99Zrtt4L  < '**,q0II$!! t 4$:$ :F$N =)]22 dA r1  r%r$r)+definez local-odd?whenbegincasez local-even?doz call-with-bytevector-output-portzcall-with-input-filecall-with-portzcall-with-current-continuationzopen-file-input-portrzcall-with-valueszcall-with-output-filezcall-with-string-output-portz define-syntaxifletlet*libraryunlesslambdaz syntax-rulesz syntax-casez let-syntaxzletrec*letrecz let-valuesz let*-valueszwith-exception-handlerzwith-input-from-filezwith-interrupts-disabledwith-input-from-stringzwith-output-to-filezwith-input-from-portwith-output-to-stringzwith-source-pathz with-syntaxz with-implicitzwith-error-handlermodule parameterize)%defnfndorundoseqlooprrdefmacrobindingdotonsz:import defstructcondpcommentrzwhen-letz->z->>z extend-typereifyrzwhen-notproxydotimestryfinallyforletfncatchiteratewhilezwith-local-varslockingdefmulti defmethodextend)3z:implementationz:methodrdefclass defconstant defgenericdefimplementationzdefine-conditionzdefine-implementation-package definterfacerr defpackage defprojectdeftypedefundefvarzdo-external-symbolsdolistrecase etypecasefletz handler-bindrrrrzprint-unreadable-objectmacrolet defparameter with-slotstypecaserrprog1rzwith-open-filerrblockz handler-caserz eval-whentagbodyz ignore-errorslabelsmultiple-value-bindprognzunwind-protectcollect)rrrrrrrthrowrz lambda-macrorrletexrdostringrletndoargs define-macrountilzdo-untilzdo-whilezfor-allzfind-allrrcd}tjjd|z}tjj|r tjj |}n!tjj|sd}d}|r$t |5}|j }dddi}|rtj|}tjt|S#1swY [str, str] Takes a lisp dialect name and returns a list of keywords that increase indentation by two spaces and those that can be one-armed like 'if' r3)rzdestructuring-bindrdo*)rrrr6)rrrr5rr4r7)r>rrr*IF_LIKE LISP_KEYWORDSSCHEME_KEYWORDSCLOJURE_KEYWORDSNEWLISP_KEYWORDSrKEYWORD1KEYWORD2KEYWORD4rr update)rHr>keywords two_spacers two_armed local_binders rc_keywordss r/ add_keywordsr#Ps! llG&&s+HKIM&# OO 77 H % 00  I & R '" I & R  E #o58HH  $[(HEH$Y(CH$]HhGH ||#o  G,- Or1ct|}d}||dzd}tjd|rd}||gS|t|dz k7r||dzdk(rtjd|}|r5|j |j z dz }|j }nd}tjd||d}|r|j |zdz}n|dz}tj d||dz ||dz djdzdr||jz}||gStjd |}|r|j }nd}tj d ||jddr||jz}||gS) a find_first_arg_pos(bracket_offset : int, curr_line : str) -> [int, int] Arguments: bracket_offset - The position of the bracket in the current line e.g " ( list 'timey 'wimey )" --> 4 " ( list 'timey 'wimey )" --> 1 "( list 'timey 'wimey )" --> 0 >>> find_first_arg_pos(0, "( list 'one-sheep 'two-sheep )") [11, 5] Returns the position of the first argument to the function relative to the position of the opening bracket and the number of spaces between the opening bracket and the function name. The two values will to be used to align the other arguments in the subsequent line rr%Nz ^[ ]*($| )rtz +[^)\]]| \)z +([^)])|( *(\(|\[))z^[ ]*(#\||;|$| )z +([^)} ])|( *(\(|\[|{))z ^[ ]*(;|$| )) r=rvr}rFr~rmatchfinddefault_indent)bracket_offsetrrHspaces_before_funcsublinearg_posr%r~s r/find_first_arg_posr,ys" d D*+,G yy'*F ' ((C S^a/ /Inq>P4QUX4XIIng6E%*YY[5;;=%@1%D"iikii 6 FG!++-*<rrruniform indent_sizeKEYWORD3r9 IndexError)rrcharrr< first_arg_pos first_itemin_list_literal lead_spacesrHrpos_hashis_macro two_spacer parent_funcnon_bind_blocks r/ _push_to_listrWs d DD!H!#% & 6& HY 5HHXi0Xx4HHJ$#+$#+$,,):S#- )  (#.9=4:DAQAQ8Q$T  b '2V';d>N>N'NH^ $ i H ,'2V';q4CSCS?S'TH^ $JJx  "gk* 2Rs2w{7Ks7R K H ,^&,t/?/?&?CGN # J   J sAE EEc t|}t|}d}d}d}g}d}d}d} d} g} d} |xs| xs | xs|xs|} d}d}t|}t||}g}g}g}|D]}d}|}t |||| | |\}}}|j |d}t j||}|r$t j|t|d||}d}|D]}||dz|dz}||dz |}||dzd}|rd}|dz })|dk(r|s|sd }|d k(s|d k(r(|jd k(r| s|d k(r|jd k(sn|jdvrS|dk(rN|sL|d k(r| s| j ||f| dz } n,| r|d k(r| dz} | jn| s | rd} d} n||f} d } | s~| s||sz|dk(r||f}t| }|jd k(rV|sT|dk(r|j ||f|dz }n6|dk(r1|r|jnd} | ||d}!|j |!|dz}|dk(r[|jd k(rL|sJ|sHt jd|||dzr d }|dk(r%||f}n t jd|||dzrd}d}|xs| xs | xs|xs|} | r|dz }||z tt jd|dz|z }"|dvrs|dvr|jdvr|dz } t|||\}#}$|d|#dz j!dj#}%d}&t j$d|d|dzrd }&t j$d|r|j!dj#}%|&rd}%|%d vrt j$d|j'}'||'d}|t j$d!|j)dj!}|d|j+d"}(|(dk7r t,||(<t j$d!||dzdj'|zdz})t/|dd|%||||#|)|&|$| }n0|d#vr,|d$vr|jdvr|dz }t1||dd||"||}|r{|d%vrw||d&d't2k(re|d(vst j$d)|s|d&d*xxdz cc<|d&d*dk(r0|d&d+xx|j4rdn |j6zcc<d,|d&d*<|dz }|dz }|||| | ||| | ||||d- }*|*S).a indented_code(string : str, fname : str) -> [...] Arguments: fpath: Simply used in formatting the warning messages >>> indent_code("(print 'Hello)") {'bracket_locations': [], 'comment_locations': [], 'in_comment': 0, 'in_newlisp_tag_string': False, 'in_string': False, 'in_symbol_with_space': False, 'indented_code': ['(print ', " 'Hello)"], 'last_quote_location': (), 'last_symbol_location': (), 'message_stack': [], 'newlisp_brace_locations': [], 'original_code': ['(print ', "'Hello)"], 'first_tag_string': ()} The last entry in the list is the indented string. FrrYr%rur$N\T;#r4r6)r5r4|"r{}z.Attempt to close a non-existent newLISP stringr5r/r|z \[/text\])r1r/r{)r/r{)r3r4z)] z[^#]('|`|#)([ ]*\(|\[)($| )z^[^ ]+[ ]*($| )r)rrz[ ]*rt)r.r0r^)r.r^)rtrr!r)rtrrz^[ ]*(;|#\||$| )rFri) message_stackfirst_tag_stringin_newlisp_tag_stringlast_symbol_locationcomment_locationsnewlisp_brace_locations in_stringrin_symbol_with_spacebracket_locationslast_quote_location original_code indented_code)r=r#rrrrr9rvfindallrwrr>r8boolr%rFr,stripr?r}r~rr&rrWrDrrIrJ)+rjrHrrfin_newlisp_stringrbrerarrrgrdrcrr3ri line_ending code_linesrkrhr`rescapedrrregexrQr< curr_char next_char prev_charsubstrrcrC real_positionrNr)rrP end_of_space macro_namerOress+ r/ indent_coder|s2 d DD!HI! JJ !3J32F332 K"=1K {;JMM /:*:K:> :JD/R+ I| Y'jj 2 uh{1~t&DiPI"I!&1*VaZ8I!&1*V4Ivz{+F! D ):CXS Y#%5$,,):S,#%$,,(*B ||#99i3>N%#,@%,,k6-BC!OJI$4!OJ%))+#+/1,/4,0;V/D,/3, )J:O#+6*?'$(O 3I<<9,Y!C'/66 V7LM)Q.)"c)23779&VG'.(3*0,L *00>)Q.)CDLLI$=&)88J &!(DE,0)'2-,7+@(XXk9VFQJ+GH,1)')$( >J >:N >$ >(=  !  $j0BJJy$/2346BCMO+ *t||?R/RaKF'vy$?2 1"1]Q%67==kJPPR "'99=y6TU:?VW&*O993V< & [ 9 ? ? AI" !#I <<$&99Y#?#C#C#EL#LM2F#BIIh$?$E$E$G$HIOOQF!'(9S)9!:J!R'/7,  YYx6A:;1GHLLNQWWZ[[ $12CA2F 2;[&2?2A2Dd %L! o- *t||?R/RaKF$29>OPQ>R3> 39=%J!!Y+%=.r2;?@HLO3 "7C&b)(3q83$R(2a7%b).9!\\t/?/?@97:%b)(3 aKF_#` q AD',!6 4.#: 4.2#& C Jr1c ddlj fd}fd}fd}t jd}|D]]}|jdr |||jd r ||7|j|r ||Qt|d _y#t$r&tdjt |YywxYw) zM colour_diff(diff_lines : lst) Print diff text to terminal in color rNrc|tjj|zjjzdy)z Print added line in green rr~N)printForeGREENWHITErcoloramas r/p_greenzcolour_diff..p_greenCs+ hmm!!D(8==+>+>>BGr1c|tjj|zjjzdy)z% Print diff section header in yellow rrN)rrYELLOWrrs r/p_yellowzcolour_diff..p_yellowGs+ hmm""T)HMM,?,??RHr1c|tjj|zjjzdy)z Print removed line in red rrN)rrREDrrs r/p_redzcolour_diff..p_redKs+ hmm$&)<)<<"Er1z!@@\s+-\d\d,\d\d\s\+\d\d,\d\d\s+@@-+r) r ImportErrorrjoinlistinitrvcompile startswithr}) diff_linesrrrsectionrrs @r/rr4s   MMOHIFjj<=G ??3  $K __S ! DM ^^D ! TN $B '  bggd:&'(sB,C  C c~tjj|}t|}|dD]}|js|j r5||d<t jjdjd"i|Qt jjdjd"i||drN|dD]F}|d}|d}|d}d } |js!t jj| ||||fzH|d rD|d D]<} d } |jst jj| || d | d fz>|drA|dD]9} d} |f| z} |jst jj| | z;|dr9d} |f|dz} |jr"t jj| | z|dr9d} |f|dz} |jr"t jj| | z|dr9d} |f|dz} |jr"t jj| | z|j} | s|} |d}dj|}||dk(rl|j r`d} t jj| |z| |k7r6t| d5}|j|jddddyy|jrWtj |d|d }|j"r t#|n=t%djt'|n|j(r t%|d!|j*r6t| d5}|j|jddddyy#1swYyxYw#1swYyxYw)#z _post_indentation(res : dict): Called after the string has been indented appropriately. It takes care of writing the file and checking for unclosed strings or comments. r`rRz {fname}:{line}:{column}: {msg}z :{line}:{column}: {msg}rhr3r4r2z %s:%d:%d: Unmatched `%s'rez( %s:%d:%d: Unclosed newLISP brace stringrr%rdz% %s:%d:%d: Unclosed multiline commentrcz %s:%d:%d: Unclosed symbolrfz( %s:%d:%d: String extends to end-of-filerirbz, %s:%d:%d: Tag string extends to end-of-filerarkrrjz>File '%s' has already been formatted. Leaving it unchanged... wbutf8N)nrrY)r,rBbasenamer=rr r8r`rarArrrOencoderdifflib unified_diffrrrrr)r{rHfpathrRr6r:rr7r2rcbracerrdrrk indent_result indented_filediffs r/_post_indentationrZs GG  U #E d D?# <<zz$G    !J!C!J!J!QS!QR   !C!G(W$C||   3/ 0  !"/h344 << JJ  Ws] + ;=h233 << JJ  Ws] + "#Ah/00 << JJ  Ws] +""K  (MGGM*MO,,S 5) % k4( BM##M$8$8$@A B B    ''O(rs&  8#   4OOd%P)"3(, ,  4>6r 40 4@ 411* ) *H%V   Bw      5"  & 4..($R:)z*^%)4nWt# LYBx%. 2F  zFs&878sD D)(D)