{ "info": { "author": "Mathew Ng'etich", "author_email": "kipkoechmathew@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Topic :: Software Development :: Quality Assurance" ], "description": "|Build Status| |Latest tag| |pypi downloads|\n\nyasi - yet another s-expression indenter\n----------------------------------------\n\n- `Introduction <#introduction>`__\n- `Installation <#installation>`__\n- `Features <#features>`__\n- `Command Line Arguments <#command-line-arguments>`__\n- `Hanging Indentation <#hanging-indentation>`__\n- `Customization <#customization>`__\n- `About the default indent <#about-the-default-indent>`__\n- `What yasi does not handle <#what-yasi-does-not-handle>`__\n- `Modifications to lispindent <#modifications-to-lispindent>`__\n- `Editor Integration <#editor-integration>`__\n- `Lispindent2 Issues <#lispindent2-issues>`__\n- `lispindent2 Command Line\n Options <#lispindent2-command-line-options>`__\n\nIntroduction\n~~~~~~~~~~~~\n\nyasi is a dialect-aware s-expression indenter that tries to improve on\n`Dorai's indenter `__ and *Vim's*\nbuilt in indenter. It can handle *Common Lisp*, *Clojure*, *Scheme* and\n*newLISP* code and their unique syntaxes.\n\nIt's mainly a batch mode indenter inspired by Dorai's\n`lispindent.lisp `__\nthat was written first in *Python* and later translated to *newLISP*.\n\nIts style of indentation is very close to that of *lispindent.lisp* and\ntries to follow `these style\nguidelines `__ where reasonable.\n\nIt should find most use with programmers who use any other editor other\nthan Emacs which provides excellent indentation for lisp-like forms and\ns-expressions out of the box.\n\nI made this because there weren't any good enough tools out there that\ncould indent the code I would copy/paste and run from tutorials when I\nwas starting out with Lisp.\n\nInstallation\n~~~~~~~~~~~~\n\nFrom pypi:\n\n::\n\n pip install --upgrade yasi\n\nFeatures\n~~~~~~~~\n\n*yasi's* indentation relies heavily on regular expressions that give it\nan edge over its counterpart *lispindent.lisp*. Its features include:\n\n- Support for the different mainstream Lisps out there giving you the\n correct indentation of a form according to the dialect's\n syntax/semantic. e.g. The ``do`` keyword which is a looping construct\n in *Common Lisp* and sequential execution in *Clojure*. The keyword\n should look like this in the two dialects:\n\n.. code:: lisp\n\n ;; In Common Lisp\n (do ((j 0 (+ j 1)))\n (nil) ;Do forever.\n (format t \"~%Input ~D:\" j)\n (let ((item (read)))\n (if (null item) (return) ;Process items until NIL seen.\n (format t \"~&Output ~D: ~S\" j item))))\n\n.. code:: clojure\n\n ;; In Clojure\n (do\n (println \"LOG: Computing...\")\n (+ 1 1))\n\n- Ability to trim extraneous whitespace and compact code\n\n- Issues warnings for possible errors in code like unmatched brackets\n and unclosed strings\n\n- Correct indentation of user defined macros\n\n- Supports additional keywords through a config file in the current or\n home directory\n\n- Correct indentation of ``flets`` and ``labels``, something that\n doesn't come out of the box even in Emacs\n\n- Indentation from standard input\n\n- The python version can output a unified diff between the initial and\n indented code\n\nCommand Line Arguments\n~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n usage: yasi [-h] [-nc] [-nb] [-nm] [--diff] [-nw] [-nr] [--no-output] [-c]\n [-ne] [-o OUTPUT_FILE] [--tab TAB_SIZE] [--dialect DIALECT] [-v]\n [-suffix BACKUP_SUFFIX] [-bd BACKUP_DIR] [-is INDENT_SIZE]\n [-di DEFAULT_INDENT] [-ic] [-uni]\n [files [files ...]]\n\n Dialect-aware s-expression indenter\n\n positional arguments:\n files List of files to be indented. Will indent from\n standard input if no files are specified\n\n optional arguments:\n -h, --help show this help message and exit\n -nc, --no-compact, --nc\n Do not compact the code, just indent\n -nb, --no-backup, --nb\n Do not create a backup file even if --backup-dir is\n specified\n -nm, --no-modify, --nm\n Do not modify the file\n --diff, -diff Prints unified diff of the initial and final result\n -nw, --no-warning, --nw\n Do not display warnings\n -nr, --no-rc, --nr Ignore any rc files in the current or home folder\n --no-output, -no-output\n Suppress output of the indented code\n -c, --color, -color Display diff text in color\n -ne, --no-exit, --ne Instructs the program not to exit when a warning is\n raised.\n -o OUTPUT_FILE Path/name of output file\n --tab TAB_SIZE, -tab TAB_SIZE\n Indent with tabs using the specified tabwidth. A tab\n is assumed equal to 4 spaces by default when expanding\n the tabs in the input file\n --dialect DIALECT, -dialect DIALECT\n Use Scheme keywords\n -v, --version Prints script version\n -suffix BACKUP_SUFFIX, --suffix BACKUP_SUFFIX\n Backup file suffix\n -bd BACKUP_DIR, --backup-dir BACKUP_DIR, --bd BACKUP_DIR, -backup-dir BACKUP_DIR\n The directory where the backup file is to be written\n -is INDENT_SIZE, --indent-size INDENT_SIZE, --is INDENT_SIZE\n The number of spaces per indent\n -di DEFAULT_INDENT, --default-indent DEFAULT_INDENT, --di DEFAULT_INDENT\n The indent level to be used in case a function's\n argument is in the next line. Vim uses 2, the most\n common being 1.\n -ic, --indent-comments, --ic\n If true, comment lines will be indented possibly\n messing with any deliberate comment layout\n -uni, --uniform, -uniform, --uni\n Dictates whether the if-clause and else-clause of an\n if-likeblock should have the same indent level.\n\nHanging Indentation\n~~~~~~~~~~~~~~~~~~~\n\nThis is where the indented code block is not flush with the left margin.\nLispindent does this by default although differently to the way it's\nimplemented in yasi. The effect is obtained by passing **--no-compact**\nto the script. Here's how hanging indentation in lispindent and yasi\ndiffers:\n\nInitial code:\n\n.. code:: lisp\n\n ;; Comment\n (if (not (empty? macro-name))\n (push (list macro-name KEYWORD1) keyword-lst)\n nil)\n\n (if (not (empty? macro-name))\n (push (list macro-name KEYWORD1) keyword-lst)\n nil)\n\n (exit)\n\nCalling yasi on the file with **--no-compact**:\n\n.. code:: lisp\n\n ;; Comment\n (if (not (empty? macro-name))\n (push (list macro-name KEYWORD1) keyword-lst)\n nil)\n\n (if (not (empty? macro-name))\n (push (list macro-name KEYWORD1) keyword-lst)\n nil)\n\n (exit)\n\nHow lispindent does it(the number of spaces at the start of first block\ndefines where the rest of the blocks in the file will start):\n\n.. code:: lisp\n\n ;; Comment\n (if (not (empty? macro-name))\n (push (list macro-name KEYWORD1) keyword-lst)\n nil)\n \n (if (not (empty? macro-name))\n (push (list macro-name KEYWORD1) keyword-lst)\n nil)\n \n (exit)\n\nCustomization\n~~~~~~~~~~~~~\n\nCustomization is done similarly to the way it's done in lispindent -\nkeywords are associated with numbers that determine the next line's\nindentation level.\n\nThe additional keywords are defined in a **.yasirc.json** file placed in\nthe current working directory of in the home folder. Should there be\nconfiguration files in both directories the one in the current working\ndirectory will be preferred.\n\nA typical config file looks like this:\n\n.. code:: javascript\n\n {\n \"scheme\": {\n \"do\": 2,\n \"if\": 2\n },\n \"lisp\": {\n \"do\": 2,\n \"if\": 2\n },\n \"clojure\": {\n \"do\": 2,\n \"if\": 2\n },\n \"newlisp\": {\n \"do\": 2,\n \"if\": 2\n }\n }\n\nThe numbers are described below(assuming standard indentation size of 2\nspaces):\n\n- **0** - Associating a keyword with zero turns it into a normal\n function i.e removes keywordness\n\n.. code:: lisp\n\n (do-the-boogie (= 12 44)\n (print \"if clause\")\n (print \"else clause\"))\n\n- **1** - Causes the subforms of the function to be indented uniformly\n by a unit indentation size(which can be changed)\n\n.. code:: lisp\n\n (do-the-boogie (= 12 44)\n (print \"if clause\")\n (print \"else clause\"))\n\n- **2** - Distinguishes the first subform by giving it a greater\n indentation than the rest of the subforms the same way the standard\n if expression is indented. The first subform has twice the\n indentation size as the rest.\n\n.. code:: lisp\n\n (do-the-boogie (= 12 44)\n (print \"if clause\")\n (print \"else clause\"))\n\n- **3** - Subforms will be indented uniformly by twice the indentation\n size\n\n.. code:: lisp\n\n (do-the-boogie (= 12 44)\n (print \"if clause\")\n (print \"else clause\"))\n\n- **4** - Indents by a unit like a 1-keyword but also its local\n functions\n\n.. code:: lisp\n\n (letfn [(six-times [y]\n (* (twice y) 3))\n (twice [x]\n (* x 2))]\n (println \"Twice 15 =\" (twice 15))\n (println \"Six times 15 =\" (six-times 15)))\n\nThe standard indentation(assuming ``letfn`` is just another function)\nwould be:\n\n.. code:: lisp\n\n (letfn [(six-times [y]\n (* (twice y) 3))\n (twice [x]\n (* x 2))]\n (println \"Twice 15 =\" (twice 15))\n (println \"Six times 15 =\" (six-times 15)))\n\nAbout the default indent\n^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe *--default-indent* comes in in expressions whose subforms usually\nstart in the subsequent lines. Like in a ``cond`` expression:\n\n.. code:: lisp\n\n (cond\n ((> this that) 'Yes)\n ((= those these) 'No))\n\nThis above result would be the standard/expected indentation. However\none might prefer to have the subforms to start two spaces past the head\nof the expression like this.\n\n.. code:: lisp\n\n (cond\n ((> newLISP CL) 'Yes)\n ((= Clojure Lisp) 'No))\n\nThis is *Vim's* default style of indentation. That option enables you to\nspecify the amount you want, for example to achieve the style above, you\npass the parameter like so:\n\n.. code:: shell\n\n yasi.py test.lisp --lisp --default-indent 2\n\n--------------\n\nWhat yasi does not handle\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThere are some syntaxes used in some dialects of Scheme that didn't seem\nworth the effort implementing. An example is *MzScheme* and *Gauche's*\nuse of ``#//`` or ``#[]`` for regular expressions.\n\nModifications to lispindent\n^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nI made a couple of modifications to *lispindent.lisp* and renamed it to\n*lispindent2.lisp*. The changes include:\n\n- Added comments for some sections of the program that took me time to\n understand\n\n- It can now indent files from the command line without the need to\n redirect file contents to the program. The original one was purely\n intended to be used as a filter script indenting only from standard\n input.\n\n- *lispindent2.lisp* indents *Clojure's* *vectors* and *sets* better,\n i.e with an indentation level of 1, without affecting *Lisp's* or\n *Scheme's indentation*. It uses the file's extension to determine if\n it's looking at *Clojure* code. e.g.\n\n.. code:: clojure\n\n ;; lispindent2.lisp's indentation\n (print {define \"The keyword does not affect indentation\"\n })\n\n.. code:: clojure\n\n ;; lispindent.lisp's indentation\n (print {define \"The keyword does not affect indentation\"\n })\n\n- *lispindent2.lisp* ignores any code in a multiline comment and won't\n be affected by any unclosed brackets inside the comment like the\n original version. Unfortunately, its method of detecting multiline\n comments is rather naive and introduces a bug in the code. Refer to\n its issues below.\n\n- *lispindent2.lisp* writes files using *LF* line endings be default.\n It's less irritating than *CRLF* endings which usually light up in an\n annoying way in *Vim*.\n\nEditor Integration\n^^^^^^^^^^^^^^^^^^\n\nyasi's ability to format code from standard input makes it a suitable\ncandidate for the ``equalprg`` setting in Vim. Add this in your\n**.vimrc** and you're good to go.\n\n.. code:: vim\n\n au filetype clojure,lisp,scheme,newlisp setlocal equalprg=yasi.py\\ --indent-comments\n\nYou can then indent a function/block by providing the motion after the\n``=`` sign e.g ``=%``\n\nYou can also checkout these other projects for proper integration\nwithout invoking it externally as a filter script for example:\n\n- Vim plugin: https://github.com/nkmathew/vim-newlisp-yasi\n- Sublime Text 2/3 plugin: https://github.com/nkmathew/sublime-yasi\n\nlispindent2 Issues\n^^^^^^^^^^^^^^^^^^\n\nI inadvertently added a bug in an attempt to prevent it from evaluating\nbrackets inside multiline comments in Common Lisp and symbols with\nwhitespace in Scheme.\n\nIt uses the pipe character(\\|) to track whether the comment it's still\nin a multiline comment meaning an odd number of pipes in a multiline\ncomment will yield a wrong indentation e.g.:\n\n.. code:: lisp\n\n #|*******************************************************************|\n | This is a multiline comment that will trip the indenter |\n | because the odd number of pipes will cause `multiline-commentp` |\n | to be true after this comment. It means the rest of the code |\n | won't be indented because it thinks it's still in a comment. |\n Total pipes=11(odd)\n |#\n (print (cons\n 'Hello ;; This line and the one below won't change\n 'World\n ))\n\nI don't find this to be a major issue because multiline comments are\nrarely used, the common use case being to comment out regions of code\nwhen debugging.\n\n*lispindent2.lisp* uses the *Lisp* reader function ``read-from-string``\nto get lisp forms and atoms from the read string.\n\nThe downside of this is that ``read-from-string`` will fail when the\ncode in the string is 'malformed'. For example, if it finds that the dot\noperator used for consing in *Common Lisp* comes after the opening\nbracket, it will raise a fatal error. This means that any *Clojure* code\nthat tries to use the dot operator to access a class method will not be\nindented because of the error. An example is this code:\n\n.. code:: clojure\n\n (defmacro chain\n ([x form] `(. ~x ~form))\n ([x form & more] `(chain (. ~x ~form) ~@more)))\n\n*lispindent2.lisp* uses the ``ignore-errors`` macro as a workaround.\nDoing that means that it can't run in *GNU Common Lisp* because it\ndoesn't have the macro.\n\nlispindent2 Command Line Options\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n +---------------------------------------------------------------------------+\n | Usage: lispindent2.lisp [[] [--no-modify] [--no-output]] |\n | --no-output ;; Don't output the indented code, false by default |\n | --no-modify ;; Don't modify the file, false by default |\n +---------------------------------------------------------------------------+\n\n.. |Build Status| image:: https://travis-ci.org/nkmathew/yasi-sexp-indenter.svg?branch=master\n :target: https://travis-ci.org/nkmathew/yasi-sexp-indenter\n.. |Latest tag| image:: https://img.shields.io/github/tag/nkmathew/yasi-sexp-indenter.svg\n :target: https://github.com/nkmathew/yasi-sexp-indenter/releases\n.. |pypi downloads| image:: https://img.shields.io/pypi/dm/yasi.svg\n :target: https://pypi.python.org/pypi/yasi", "description_content_type": null, "docs_url": null, "download_url": "https://github.com/nkmathew/yasi-sexp-indenter/zipball/master", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/nkmathew/yasi-sexp-indenter", "keywords": "scheme,formatter,newlisp,beautifier,clojure,lisp,indenter", "license": "UNKNOWN", "maintainer": null, "maintainer_email": null, "name": "yasi", "package_url": "https://pypi.org/project/yasi/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/yasi/", "project_urls": { "Download": "https://github.com/nkmathew/yasi-sexp-indenter/zipball/master", "Homepage": "https://github.com/nkmathew/yasi-sexp-indenter" }, "release_url": "https://pypi.org/project/yasi/2.0.1/", "requires_dist": null, "requires_python": null, "summary": "A dialect aware s-expression indenter", "version": "2.0.1" }, "last_serial": 1922715, "releases": { "0.2.1": [ { "comment_text": "", "digests": { "md5": "c5154fed57e95db5aea3f6dcea1052c3", "sha256": "854e2f1c530696d22b35fdac471dad14a2caa88894e1175b8f3cd7e9f3657403" }, "downloads": -1, "filename": "yasi-0.2.1-py3.4.egg", "has_sig": false, "md5_digest": "c5154fed57e95db5aea3f6dcea1052c3", "packagetype": "bdist_egg", "python_version": "3.4", "requires_python": null, "size": 26147, "upload_time": "2016-01-03T23:33:45", "url": "https://files.pythonhosted.org/packages/b7/c6/60f27a87bcbbec0d8b4f4e43a2f541bcb3ed21db6b171ba870f383271242/yasi-0.2.1-py3.4.egg" } ], "1.0.0": [ { "comment_text": "", "digests": { "md5": "909066398784ef081fc963932b69f458", "sha256": "d2b8b03036b69599ad2fe21648bea6956f8d0cf48a1bbbe98930ba40843cfc86" }, "downloads": -1, "filename": "yasi-1.0.0.zip", "has_sig": false, "md5_digest": "909066398784ef081fc963932b69f458", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15479, "upload_time": "2016-01-04T00:33:42", "url": "https://files.pythonhosted.org/packages/c4/fd/17d1e132952cb1a18c023da76ffca7ff9810da51f4ee2944d5619c4aef70/yasi-1.0.0.zip" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "cc484ffe85cdced40559d9d5eb53d804", "sha256": "6ee4fec4a36cbb392d95a6bc008d2b69f7fda5223dd42108abc472e56552e7c3" }, "downloads": -1, "filename": "yasi-1.0.1.zip", "has_sig": false, "md5_digest": "cc484ffe85cdced40559d9d5eb53d804", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 66011, "upload_time": "2016-01-04T12:36:22", "url": "https://files.pythonhosted.org/packages/b2/06/76f396e6fd99266d99c628a6749155f21c616ffa241238070755238377b9/yasi-1.0.1.zip" } ], "1.1.1": [ { "comment_text": "", "digests": { "md5": "32d4a09bf6c53518b09ad79f67dc6f9c", "sha256": "71e8add82519735248a039e890c10303e0b2f465bb7fed0e2b2f27c6472efcfa" }, "downloads": -1, "filename": "yasi-1.1.1.zip", "has_sig": false, "md5_digest": "32d4a09bf6c53518b09ad79f67dc6f9c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 66703, "upload_time": "2016-01-04T15:42:35", "url": "https://files.pythonhosted.org/packages/6e/ab/b5a7fe7ea7abea5b1093905a3316cd1098edbe40e9a4db40174b0aea5a32/yasi-1.1.1.zip" } ], "1.1.2": [ { "comment_text": "", "digests": { "md5": "7bc4ac9c26307c3803522d62d4138319", "sha256": "9d470b43d823f99b6f968a827051163ef8a8c021d374592cf0c3e0609c1c5e6c" }, "downloads": -1, "filename": "yasi-1.1.2.zip", "has_sig": false, "md5_digest": "7bc4ac9c26307c3803522d62d4138319", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 67018, "upload_time": "2016-01-04T17:33:36", "url": "https://files.pythonhosted.org/packages/0e/19/7d4e016ec1b924a045c3d83f74d0077b4facf212b3a2cffac7fba823f958/yasi-1.1.2.zip" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "70c3871366f07bfe6b7ba02729b61e55", "sha256": "e9982db48bb565ce31e23fb74d09c961a0251a9e451e79528c2b9ef3689a18a3" }, "downloads": -1, "filename": "yasi-1.2.0.zip", "has_sig": false, "md5_digest": "70c3871366f07bfe6b7ba02729b61e55", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 71922, "upload_time": "2016-01-09T22:16:53", "url": "https://files.pythonhosted.org/packages/8e/0c/55edd2a18a07cec42ab981e80a557634385fde2bd84fe75ae848b575e0e5/yasi-1.2.0.zip" } ], "1.2.1": [ { "comment_text": "", "digests": { "md5": "6d454a49f348b0fa9160c93017b8d08b", "sha256": "5c712327d83e1a649e9df46f69d0acf0ca8ebffd33b27f9e0ca8c9a563ab9b8a" }, "downloads": -1, "filename": "yasi-1.2.1.zip", "has_sig": false, "md5_digest": "6d454a49f348b0fa9160c93017b8d08b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 74282, "upload_time": "2016-01-22T15:47:35", "url": "https://files.pythonhosted.org/packages/93/0d/42b2296339caff07479b74167cad940db9f2e5f3505c3c30c962c13602cf/yasi-1.2.1.zip" } ], "2.0.0": [ { "comment_text": "", "digests": { "md5": "7d65489efea7292147761ebe84584cbb", "sha256": "2a9718c95c43ddf4824a1b7c5c0dfa390c871b538159c310fed5634f7c11d9fb" }, "downloads": -1, "filename": "yasi-2.0.0.zip", "has_sig": false, "md5_digest": "7d65489efea7292147761ebe84584cbb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 74403, "upload_time": "2016-01-25T10:30:52", "url": "https://files.pythonhosted.org/packages/16/8b/c40b705e4089ab6a3e4399eb9f06a6e9462249b1a711cb83a7df18b179a0/yasi-2.0.0.zip" } ], "2.0.1": [ { "comment_text": "", "digests": { "md5": "a4007bd36b2c65fd5d99fb67e751ae02", "sha256": "fcb3c55e403dd74336c10e3d69dfba07a51be769606e700463f156d8260087e4" }, "downloads": -1, "filename": "yasi-2.0.1.zip", "has_sig": false, "md5_digest": "a4007bd36b2c65fd5d99fb67e751ae02", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 74614, "upload_time": "2016-01-25T22:42:33", "url": "https://files.pythonhosted.org/packages/0f/2d/ba8664ba223fed6a8792611b2647c3586fcc594eb4e9fef203019328c678/yasi-2.0.1.zip" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "a4007bd36b2c65fd5d99fb67e751ae02", "sha256": "fcb3c55e403dd74336c10e3d69dfba07a51be769606e700463f156d8260087e4" }, "downloads": -1, "filename": "yasi-2.0.1.zip", "has_sig": false, "md5_digest": "a4007bd36b2c65fd5d99fb67e751ae02", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 74614, "upload_time": "2016-01-25T22:42:33", "url": "https://files.pythonhosted.org/packages/0f/2d/ba8664ba223fed6a8792611b2647c3586fcc594eb4e9fef203019328c678/yasi-2.0.1.zip" } ] }