{"id":13593075,"url":"https://github.com/hlissner/evil-snipe","last_synced_at":"2025-10-06T00:50:47.516Z","repository":{"id":24220699,"uuid":"27612830","full_name":"hlissner/evil-snipe","owner":"hlissner","description":"2-char searching ala vim-sneak \u0026 vim-seek, for evil-mode","archived":false,"fork":false,"pushed_at":"2023-08-21T16:03:11.000Z","size":645,"stargazers_count":342,"open_issues_count":17,"forks_count":26,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-29T21:04:15.794Z","etag":null,"topics":["emacs","emacs-packages","evil","vim-sneak"],"latest_commit_sha":null,"homepage":"","language":"Emacs Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hlissner.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2014-12-05T22:24:03.000Z","updated_at":"2025-03-11T15:35:33.000Z","dependencies_parsed_at":"2024-01-14T10:01:37.348Z","dependency_job_id":"84a456be-bc37-4483-b2dc-15540d022fe0","html_url":"https://github.com/hlissner/evil-snipe","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hlissner%2Fevil-snipe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hlissner%2Fevil-snipe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hlissner%2Fevil-snipe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hlissner%2Fevil-snipe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hlissner","download_url":"https://codeload.github.com/hlissner/evil-snipe/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247406088,"owners_count":20933803,"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":["emacs","emacs-packages","evil","vim-sneak"],"created_at":"2024-08-01T16:01:16.340Z","updated_at":"2025-10-06T00:50:42.484Z","avatar_url":"https://github.com/hlissner.png","language":"Emacs Lisp","funding_links":[],"categories":["Emacs Lisp"],"sub_categories":[],"readme":"[![Made with Doom Emacs](https://img.shields.io/badge/Made_with-Doom_Emacs-blueviolet.svg?style=flat-square\u0026logo=GNU%20Emacs\u0026logoColor=white)](https://github.com/hlissner/doom-emacs)\n![Release tag](https://img.shields.io/github/tag/hlissner/evil-snipe.svg?label=release\u0026style=flat-square)\n[![MELPA](http://melpa.org/packages/evil-snipe-badge.svg?style=flat-square)](http://melpa.org/#/evil-snipe)\n![Build status](https://img.shields.io/github/workflow/status/hlissner/evil-snipe/CI/master?style=flat-square)\n\n# evil-snipe\n\n![Sniper!](../screenshots/cover.jpg)\n\nEvil-snipe emulates [vim-seek](https://github.com/goldfeld/vim-seek) and/or\n[vim-sneak](https://github.com/justinmk/vim-sneak) in\n[evil-mode](https://gitorious.org/evil/pages/Home).\n\nIt provides 2-character motions for quickly (and more accurately) jumping around\ntext, compared to evil's built-in f/F/t/T motions, incrementally highlighting\ncandidate targets as you type.\n\n## Install\n\nEvil-snipe is available on MELPA.\n\n`M-x package-install evil-snipe`\n\n```emacs-lisp\n(require 'evil-snipe)\n```\n\n`evil-snipe` comes with two global modes: `evil-snipe-mode` and\n`evil-snipe-override-mode`, and two local modes: `evil-snipe-local-mode` and\n`evil-snipe-override-local-mode`.\n\nYou can either a) enable one or both globally:\n\n```elisp\n(evil-snipe-mode +1)\n(evil-snipe-override-mode +1)\n\n;; and disable in specific modes\n(push 'python-mode evil-snipe-disabled-modes)\n\n;; or disable it manually\n(add-hook 'python-mode-hook #'turn-off-evil-snipe-mode)\n(add-hook 'python-mode-hook #'turn-off-evil-snipe-override-mode)\n```\n\nOr b) enable one or both locally, where you need it:\n\n```elisp\n(add-hook 'python-mode-hook 'turn-on-evil-snipe-mode)\n(add-hook 'python-mode-hook 'turn-on-evil-snipe-override-local-mode)\n```\n\n## Usage\n\nBy default, snipe only binds \u003ckbd\u003es\u003c/kbd\u003e (forward)/\u003ckbd\u003eS\u003c/kbd\u003e (backward) to\n`evil-snipe-s` and `evil-snipe-S`, respectively. In operator mode, snipe is\nbound to \u003ckbd\u003ez\u003c/kbd\u003e/\u003ckbd\u003eZ\u003c/kbd\u003e and \u003ckbd\u003ex\u003c/kbd\u003e/\u003ckbd\u003eX\u003c/kbd\u003e (exclusive).\n\nThe last snipe can be repeated with \u003ckbd\u003es\u003c/kbd\u003e/\u003ckbd\u003eS\u003c/kbd\u003e after a successful snipe\n(or with \u003ckbd\u003es\u003c/kbd\u003e+\u003ckbd\u003eRET\u003c/kbd\u003e).\n\nEvil-snipe can override evil-mode's native motions with 1-char sniping:\n\n```elisp\n;; Globally\n(evil-snipe-override-mode 1)\n\n;; Or locally\n(add-hook 'ruby-mode-hook 'evil-snipe-override-local-mode)\n```\n\nThe benefit of this is:\n\n* Incremental highlighting\n* You can repeat searches with \u003ckbd\u003ef\u003c/kbd\u003e, \u003ckbd\u003eF\u003c/kbd\u003e, \u003ckbd\u003et\u003c/kbd\u003e and\n\u003ckbd\u003eT\u003c/kbd\u003e (ala [Clever-F](https://github.com/rhysd/clever-f.vim))\n* \u003ckbd\u003e;\u003c/kbd\u003e and \u003ckbd\u003e,\u003c/kbd\u003e are available for repeating searches (and won't\n  interfere with the original maps; they take effect only after a successful snipe)\n* A more streamlined experience in general\n\n## Customization\n\n### Search scope\n\nThese three variables determine the scope of snipes (and the incremental\nhighlighter):\n\n* `evil-snipe-scope` (default: `line`)\n* `evil-snipe-repeat-scope` (default: `whole-line`) Scope while _repeating_\n  searches with `evil-snipe-repeat` or `evil-snipe-repeat-reverse`.\n* `evil-snipe-spillover-scope` (default: `nil`) Scope to expand to when a snipe\n  fails. Only useful if set to a broader scope than `evil-snipe-scope`.\n\nThese are the possible settings:\n\nValue            | Description\n-----------------|------------------------------------------------------------\n'line            | rest of the current line after cursor (`vim-seek` behavior)\n'buffer          | rest of the buffer after cursor (`vim-sneak` behavior)\n'visible         | the rest of the _visible_ buffer after cursor\n'whole-line      | same as `'line`, but highlights on either side of cursor\n'whole-buffer    | same as `'buffer`, but highlights *all* matches in buffer\n'whole-visible   | same as `'visible`, but highlights *all* visible matches in buffer\n\n### Character aliases\n\nSpecific characters can be aliased to regex patterns by modifying `evil-snipe-aliases`.\n\n#### Examples\n\n* To map \u003ckbd\u003e[\u003c/kbd\u003e to any opening parentheses or bracket **in all modes**:\n\n  ```elisp\n  (push '(?\\[ \"[[{(]\") evil-snipe-aliases)\n  ```\n\n  Therefore, \u003ckbd\u003es\u003c/kbd\u003e\u003ckbd\u003ea\u003c/kbd\u003e\u003ckbd\u003e[\u003c/kbd\u003e will match `a[`, `a{` or `a(`\n\n* To map \u003ckbd\u003e:\u003c/kbd\u003e to a python function (but only in `python-mode`):\n\n  ```elisp\n  (add-hook 'python-mode-hook\n    (lambda ()\n      (make-variable-buffer-local 'evil-snipe-aliases)\n      (push '(?: \"def .+:\") evil-snipe-aliases)))\n  ```\n\n### Faces\n\n* `evil-snipe-first-match-face`: The first highlighted match.\n* `evil-snipe-matches-face`: The rest of the highlighted matches.\n\n### Sniping in visual mode\n\nTo avoid binding conflicts, evil-snipe has no visual mode bindings. You can add\nthem with:\n\n```elisp\n(evil-define-key 'visual evil-snipe-local-mode-map \"z\" 'evil-snipe-s)\n(evil-define-key 'visual evil-snipe-local-mode-map \"Z\" 'evil-snipe-S)\n```\n\n### Integration into avy/evil-easymotion\n\nThis will allow you to quickly hop into avy/evil-easymotion right after a snipe.\n\n```elisp\n(define-key evil-snipe-parent-transient-map (kbd \"C-;\")\n  (evilem-create 'evil-snipe-repeat\n                 :bind ((evil-snipe-scope 'buffer)\n                        (evil-snipe-enable-highlight)\n                        (evil-snipe-enable-incremental-highlight))))\n```\n\n(Thanks to [PythonNut](https://github.com/PythonNut) for this.\n[More info here](https://github.com/hlissner/evil-snipe/issues/25#issuecomment-208068419))\n\n## Conflicts with other plugins\n\nIt seems `evil-snipe-override-mode` causes problems in Magit buffers, to fix this:\n\n`(add-hook 'magit-mode-hook 'turn-off-evil-snipe-override-mode)`\n\n## Appendix\n\n### Other settings\n\n* `evil-snipe-enable-highlight` (default: `t`) Highlight first match.\n* `evil-snipe-enable-incremental-highlight` (default: `t`) Incrementally highlight all\n  matches in scope.\n* `evil-snipe-override-evil-repeat-keys` (default: `t`) Whether or not evil-snipe will\n  override evil's default \u003ckbd\u003e;\u003c/kbd\u003e and \u003ckbd\u003e,\u003c/kbd\u003e mappings with snipe's (when\n  `evil-snipe-override-mode` is on).\n* `evil-snipe-repeat-keys` (default `t`) If non-nil, pressing \u003ckbd\u003es\u003c/kbd\u003e/\u003ckbd\u003eS\u003c/kbd\u003e\n  after a search will repeat it. If `evil-snipe-override-evil` is non-nil, this applies\n  to f/F/t/T as well.\n* `evil-snipe-show-prompt` (default `t`) Whether or not to show the \"N\u003e\" prompt.\n* `evil-snipe-smart-case` (default `nil`) If non-nil, searches will be case-insenstive\n  unless your search contains a capital letter.\n* `evil-snipe-auto-scroll` (default `nil`) If non-nil, the window will scroll to follow\n  the cursor.\n* `evil-snipe-auto-disable-substitute` (default: `t`) Whether or not evil's\n  default substitute mappings (s/S) are unset. They can sometimes interfere with\n  snipe. Must be set _before_ evil-snipe is loaded.\n* `evil-snipe-skip-leading-whitespace` (default `t`) If non-nil, sniping will skip over\n  leading whitespace when you search for whitespace.\n* `evil-snipe-tab-increment` (default `nil`) If non-nil, pressing TAB in the snipe\n  prompt will increase the size of the snipe buffer.\n* `evil-snipe-use-vim-sneak-bindings` (default `nil`) If non-nil, evil-snipe\n  binds z/Z to exclusive sniping in operator state, but leaves the x/X bindings\n  free. This mirrors the default bindings of vim-sneak, and frees up cx/cX to be\n  used by [evil-exchange](https://github.com/Dewdrops/evil-exchange).\n\n### Functions\n\n* `evil-snipe-mode` / `evil-snipe-local-mode`\n* `evil-snipe-override-mode` / `evil-snipe-override-local-mode`\n* `evil-snipe-repeat` / `evil-snipe-repeat-reverse`\n* `evil-snipe-s` / `evil-snipe-S`: inclusive 2-char sniping\n* `evil-snipe-x` / `evil-snipe-X`: exclusive 2-char sniping\n* `evil-snipe-f` / `evil-snipe-F`: inclusive 1-char sniping\n* `evil-snipe-t` / `evil-snipe-T`: exclusive 1-char sniping\n\n### Default keybindings\n\n```elisp\n(evil-define-key '(normal motion) evil-snipe-local-mode-map\n  \"s\" 'evil-snipe-s\n  \"S\" 'evil-snipe-S)\n\n(evil-define-key 'operator evil-snipe-local-mode-map\n  \"z\" 'evil-snipe-s\n  \"Z\" 'evil-snipe-S\n  \"x\" 'evil-snipe-x\n  \"X\" 'evil-snipe-X)\n\n(evil-define-key 'motion evil-snipe-override-local-mode-map\n  \"f\" 'evil-snipe-f\n  \"F\" 'evil-snipe-F\n  \"t\" 'evil-snipe-t\n  \"T\" 'evil-snipe-T)\n\n(when evil-snipe-override-evil-repeat-keys\n  (evil-define-key 'motion map\n    \";\" 'evil-snipe-repeat\n    \",\" 'evil-snipe-repeat-reverse))\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhlissner%2Fevil-snipe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhlissner%2Fevil-snipe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhlissner%2Fevil-snipe/lists"}