{"id":28571729,"url":"https://github.com/andre0991/vilpy","last_synced_at":"2025-06-10T19:30:24.658Z","repository":{"id":50621606,"uuid":"354353468","full_name":"Andre0991/vilpy","owner":"Andre0991","description":"Modal-like structural editing","archived":false,"fork":false,"pushed_at":"2023-11-22T01:00:09.000Z","size":716,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2023-11-22T15:53:56.455Z","etag":null,"topics":["clojure","lisp","paredit"],"latest_commit_sha":null,"homepage":"","language":"Emacs Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Andre0991.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-04-03T17:31:10.000Z","updated_at":"2023-11-22T15:53:56.456Z","dependencies_parsed_at":"2023-11-21T15:49:20.283Z","dependency_job_id":null,"html_url":"https://github.com/Andre0991/vilpy","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Andre0991%2Fvilpy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Andre0991%2Fvilpy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Andre0991%2Fvilpy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Andre0991%2Fvilpy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Andre0991","download_url":"https://codeload.github.com/Andre0991/vilpy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Andre0991%2Fvilpy/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259136856,"owners_count":22810553,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","lisp","paredit"],"created_at":"2025-06-10T19:30:20.267Z","updated_at":"2025-06-10T19:30:24.613Z","avatar_url":"https://github.com/Andre0991.png","language":"Emacs Lisp","funding_links":[],"categories":[],"sub_categories":[],"readme":"# vilpy\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"imgs/torta-holandesa.jpg\"\n   alt=\"vilpy logo\"/\u003e\n\u003c/p\u003e\n\n\u003e creamy \u0026 even shorter lisp editing\n\n`vilpy` is a vi-like `paredit`.\nIt is modal in the sense that when the point is exactly before or after a paren, keys run commands rather than inserting text. For more details, see [documentation](#documentation).\n\n`vilpy` is a stripped-down fork of the excellent [lispy](https://github.com/abo-abo/lispy).\nThink of it as a `lispy-core`, which is lighter, but no less sweet.\n`vilpy` keybindings are vimmier and it is considerably smaller (no refactoring and debugging features, fewer dependencies).\nFor more differences with `lispy`, please consult the [alternatives](#alternatives) section.\n\nI prefer forking the original code because (1) the author is happy with the current approach of bundling everything in the same package, and that's perfectly fine ([issue](https://github.com/abo-abo/lispy/issues/74)) and (2) `lispy` is critical for getting things done in my job, but the Clojure-specific parts are not important for me and they do interfere with some projects.\n\n## Supported languages \u0026 compatibility with other modes\nThe navigation features are tested with emacs-lisp and Clojure, but they are likely to work with other lisps.\n\nemacs-lisp and Clojure (`cider` and `inf-clojure`) also support evaluation, describing the symbol at point and indentation.\nThese features can be added to other languages by setting the proper handlers in the variable `vilpy--handlers-alist` (see the customization section).\n\n`vilpy` defines its own keybindings that might conflict with `parinfer`, `paredit` and other structural editing modes.\n\n## Installation\n`vilpy` must be installed manually as of now.\n\nNote that `vilpy` requires [`avy`](https://github.com/abo-abo/avy).\nYou might need to install it as well.\n\n### Vanilla\n\n``` emacs-lisp\n;; replace `vilpy-load-path` by the directory that has `vilpy.el`\n(let ((vilpy-path \"~/path/to/vilpy\"))\n  (add-to-list 'load-path vilpy-path)\n  (require 'vilpy))\n(add-hook 'emacs-lisp-mode-hook (lambda () (vilpy-mode 1)))\n(add-hook 'clojure-mode-hook (lambda () (vilpy-mode 1)))\n; if using the treesitter version of clojure-mode:\n(add-hook 'clojure-ts-mode-hook (lambda () (vilpy-mode 1)))\n\n;; recommended settings for `evil` users\n;; those are the default keybindings, but they are overriden by `evil`\n(evil-define-key 'insert 'vilpy-mode-map (kbd \"C-k\") 'vilpy-kill)\n(evil-define-key 'insert 'vilpy-mode-map (kbd \"C-d\") 'vilpy-delete)\n```\n\n### `use-package`\n\n``` emacs-lisp\n(use-package vilpy\n  :load-path\n  \"~/path/to/vilpy/\"\n  :hook\n  ((emacs-lisp-mode clojure-mode clojure-ts-mode) . vilpy-mode))\n```\n\n## Documentation\n\nYou can find workflow examples in [usage](/docs/usage.md).\n\nFor a complete list of commands, see the [function reference](/docs/reference.md).\n\n## Customization\nThis section presents some common ways that `vilpy` can be configured.\n\nThere is also the [wiki](https://github.com/Andre0991/vilpy/wiki), with additional configuration examples and tips.\n\n### Adding support to other modes\n\nBy default, `vilpy` supports Emacs Lisp and Clojure.\nThese are the official supported modes because I use them everyday and the test suite ensures that their syntax is well handled by `vilpy`.\nThat said, you can easily use `vilpy` with other languages (presumably lisps) and it should work without major issues.\n\nFor example, for using `vilpy` with [sly](https://github.com/joaotavora/sly), customize `vilpy--handlers-alist` like this:\n\n```emacs-lisp\n(add-to-list 'vilpy--handlers-alist\n\t     '(:sly . ((:decider-fn . (lambda () (bound-and-true-p sly-mode)))\n\t\t       (:eval-last-sexp . sly-eval-last-expression)\n\t\t       (:eval-defun . sly-eval-defun)\n\t\t       (:eval-region . sly-eval-region)\n\t\t       (:eval-buffer . sly-eval-buffer)\n\t\t       (:describe-symbol . sly-describe-symbol))))\n```\n\n### Keybindings\n#### Single-key bindings\nUse `vilpy-define-key` for overriding a default binding.\n\nFor calling `my-function` with the key `H`, use\n\n``` emacs-lisp\n(vilpy-define-key vilpy-mode-map \"H\" 'apt-vilpy-describe)\n```\n\n#### Multi-key bindings\nYou may wish to override keybinding that reads two characters - for example, `wo`, which goes to the other window.\n\nThere is no way to do that without modifying the whole prefix (`w`, in this example).\n\nThat said, you can simply copy the current function that lists those bindings to your init file and modify it as you wish - and there is nothing wrong with that.\n\nFor doing that, please consult `vilpy-mode-map-special` and check which function is called for the prefix you are going to change. Then, copy it to your configuration, as exemplified below.\n\n``` emacs-lisp\n(defun vilpy-window-actions ()\n  (interactive)\n  (cl-case (read-char-from-minibuffer \"Actions:\\n\no: Select other window.\nh: Select left window.\n\\n\")\n    (?o (other-window 1))\n    (?h (windmove-left))\n    (t (vilpy--complain-unrecognized-key))))\n    \n(vilpy-define-key map \"w\" 'vilpy-window-actions)\n```\n\n#### Overriding behavior\nYou may want to override some default behavior based on some conditions.\nFor example, suppose you want to change `H`, which is originally bound to `vilpy-foo`, to `my-function`, but only if `inf-clojure-minor-mode` is enabled.\n\nYou would use this:\n\n``` emacs-lisp\n(defun my-override-vilpy-describe ()\n  (interactive)\n  (if (bound-and-true-p inf-clojure-minor-mode)\n      (call-interactively 'my-function)\n    (call-interactively 'vilpy-foo)))\n\n(vilpy-define-key vilpy-mode-map \"H\" 'my-override-vilpy-describe)\n```\n\n## Alternatives\n### [`lispy`](https://github.com/abo-abo/lispy/)\n`vilpy` has some important differences from its big brother.\n\nIn particular, it attempts to respect the following design goals:\n- **Be vimmier**: the default keybindings resemble vim more than `lispy` (note that if you do not know vim, it's okay. `lispy` keybindings are arguably not super emacs-y either, so either way you would have to invest some time in learning some keys.)\n- **Reduce the feature set to navigation and evaluation functions**. We don't need debugging and tags features. Refactoring commands can be leveraged from other packages. This makes `vilypy` easier to maintain and understand.\n- **Have a reduced, but reliable set of commands that works well with all supported languages.** The original `lispy` has some nice refactoring tools, but they mostly works for Emacs Lisp. This adds confusion for people trying to use it, as it is not always clear if some command will work for a given language.\n- **Rely on fewer external dependencies**. This also makes `vilpy` easier to maintain. Currently, its only dependency is `avy`, which is essential for navigation commands.\n- **Drop support for non-lisps languages**. While the prospect of using `vilpy` in other languages is interesting, this is not very well tested and not a priority. That said, you can always invoke `vilpy-mode` manually and see what happens.\n- **Be less magic**. For example, in the original `lispy`, the function for evaluating the last sexp also uses `setq` when evaluating `defvars`. `vilpy` does not try to guess your intent. `vilpy` is intentionally dumber.\n- **Do not inject language-specific code**. For example, `lispy` loads `le-clojure.clj` when you use `cider` for providing some features such as getting bindings from `let` when evaluating forms. This relies on injecting dependencies to `cider` and will not work on some project setups (see https://github.com/abo-abo/lispy/issues/552). `vilpy` simple uses `cider-eval*` functions.\n\nThat said, `lispy` has more features, including debugging and refactoring capabilities and support more languages. If you want a more featureful package, go for it.\n\n### [`lispyville`](https://github.com/noctuid/lispyville)\n\n`lispyville` is a layer on top of `lispy` that adapts some `evil` commands for working consistently with `lispy`.\nPersonally, I never felt the need for `lispyville` when using `evil`: using vim commands while in normal mode and `lispy` commands in insert mode worked fine for me.\nI found `lispyville` quite difficult to grasp, and I simply got used to the raw `lispy` commands, avoiding this extra indirection for `lispy` commands.\n\nThat said, it's clear that `lispyville` is useful for lots of people., so would be great if it worked with `vilpy`.\nI believe this should not be too difficult: maybe simply forking it and renaming `lispy` to `vilpy` and fixing some renamed functions will do it.\nAnother simpler possibility is aliasing `vilpy` functions to their `lispy` counterparts.\nHowever, I do not have the motivation for experimenting with this now.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandre0991%2Fvilpy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandre0991%2Fvilpy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandre0991%2Fvilpy/lists"}