├── .dir-locals.el ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE.md └── workflows │ └── test.yml ├── .gitignore ├── .readthedocs.yaml ├── CHANGES.org ├── CONTRIBUTING.md ├── COPYING ├── Eask ├── Makefile ├── README.md ├── doc ├── Makefile ├── build │ └── texinfo │ │ └── evil.texi ├── front.png ├── logo.png ├── logo.svg ├── make.bat ├── requirements.txt └── source │ ├── _ext │ └── elisp.py │ ├── conf.py │ ├── extension.rst │ ├── faq.rst │ ├── hooks.rst │ ├── index.rst │ ├── indices.rst │ ├── internals.rst │ ├── keymaps.rst │ ├── license.rst │ ├── overview.rst │ └── settings.rst ├── evil-command-window.el ├── evil-commands.el ├── evil-common.el ├── evil-core.el ├── evil-development.el ├── evil-digraphs.el ├── evil-ex.el ├── evil-integration.el ├── evil-jumps.el ├── evil-keybindings.el ├── evil-macros.el ├── evil-maps.el ├── evil-repeat.el ├── evil-search.el ├── evil-states.el ├── evil-test-helpers.el ├── evil-tests.el ├── evil-types.el ├── evil-vars.el ├── evil.el └── scripts ├── evil-extract-docstrings ├── evil-release-stable └── evilupdate /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ;; Don't use tabs for el files 2 | ((emacs-lisp-mode . 3 | ((indent-tabs-mode . nil)))) 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.el diff=lisp 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | # Issue type 3 | 4 | 5 | - Bug report 6 | - Enhancement request 7 | - Question 8 | - Other 9 | 10 | # Environment 11 | 12 | Emacs version: 13 | Operating System: 14 | Evil version: 15 | Evil installation type: 16 | Graphical/Terminal: 17 | Tested in a `make emacs` session (see [CONTRIBUTING.md](https://github.com/emacs-evil/evil/blob/master/CONTRIBUTING.md#bug-reports)): 18 | 19 | # Reproduction steps 20 | - Start Emacs 21 | 22 | 23 | # Expected behavior 24 | 25 | 26 | # Actual behavior 27 | 28 | 29 | # Further notes 30 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.ref }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | build: 11 | runs-on: ${{ matrix.os }} 12 | continue-on-error: ${{ matrix.experimental }} 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | os: [ubuntu-latest, macos-latest, windows-latest] 17 | emacs-version: 18 | - 26.3 19 | - 27.2 20 | - 28.2 21 | - 29.4 22 | experimental: [false] 23 | include: 24 | - os: ubuntu-latest 25 | emacs-version: snapshot 26 | experimental: true 27 | - os: macos-latest 28 | emacs-version: snapshot 29 | experimental: true 30 | exclude: 31 | - os: macos-latest 32 | emacs-version: 26.3 33 | - os: macos-latest 34 | emacs-version: 27.2 35 | 36 | steps: 37 | - uses: jcs090218/setup-emacs@master 38 | with: 39 | version: ${{ matrix.emacs-version }} 40 | 41 | - uses: actions/checkout@v4 42 | 43 | - name: Print emacs version 44 | run: | 45 | emacs --version 46 | 47 | - uses: emacs-eask/setup-eask@master 48 | with: 49 | version: 'snapshot' 50 | 51 | - name: Run tests 52 | run: | 53 | make test 54 | 55 | - name: Print results 56 | if: ${{ always() }} 57 | run: | 58 | cat test-results.txt 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.elc 2 | *.cp 3 | *.ky 4 | *.pg 5 | *.tp 6 | .depend 7 | /evil-autoloads.el 8 | /evil-pkg.el 9 | test-results.txt 10 | typescript 11 | 12 | /doc/dir 13 | /doc/*.aux 14 | /doc/*.fn 15 | /doc/*.fns 16 | /doc/*.info 17 | /doc/*.log 18 | /doc/*.toc 19 | /doc/*.vr 20 | /doc/*.vrs 21 | /doc/docstringdb.json 22 | /doc/build/*/ 23 | !/doc/build/texinfo/evil.texi 24 | *.pyc 25 | 26 | /.eask 27 | /dist 28 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-22.04 5 | tools: 6 | python: "3.12" 7 | apt_packages: [emacs-nox] 8 | jobs: 9 | pre_build: 10 | - scripts/evil-extract-docstrings 11 | 12 | sphinx: 13 | configuration: doc/source/conf.py 14 | 15 | python: 16 | install: 17 | - requirements: doc/requirements.txt 18 | -------------------------------------------------------------------------------- /CHANGES.org: -------------------------------------------------------------------------------- 1 | * Changes and New Features in Evil 2 | 3 | ** News in 1.0.7 4 | 5 | * Fix #319. 6 | 7 | ** News in 1.0.6 8 | 9 | * Fix bug induced in emacs trunk due to changed behaviour of 10 | `overriding-terminal-local-map` (fixes #309). 11 | 12 | ** News in 1.0.5 13 | 14 | * Fix bug in `show-paren-mode` due to variable renaming in latest 15 | emacs. 16 | 17 | * Fix bug in isearch module due to variable renaming in latest 18 | emacs. 19 | 20 | ** News in 1.0.4 21 | 22 | * Undo one restriction when argument is read in operator state. 23 | 24 | ** News in 1.0.3 25 | 26 | * Fix `evil-delete-backward-word` at first non-blank in a line. 27 | 28 | ** News in 1.0.2 29 | 30 | * Fix #290. 31 | 32 | ** News in 1.0.1 33 | 34 | *** Improvements 35 | 36 | * An ELPA package built by =make elpa= contains COPYING file. 37 | 38 | * Bind =[tab]= like =\t= in =evil-ex-completion-map=, so that it 39 | cannot be overwritten by a =[tab]= binding in the parent keymap 40 | =minibuffer-local-completion-map=. 41 | 42 | * Improve worst case performance of internal functions 43 | =evil-in-string-p=, =evil-string-beginning= and 44 | =evil-string-end=. This functions are used, e.g., in certain text 45 | objects to detect whether point is within a string. 46 | 47 | * Update authors list. 48 | 49 | *** Fixes 50 | 51 | * The interactive code == is fixed and used correctly in 52 | =evil-ex-set-initial-state=. 53 | 54 | * =evil-ex-global= always generates a single undo-step. 55 | 56 | * Resolved issues: #249, #250, #253 and #257. 57 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Bug reports 2 | 3 | Bug reports and feature requests should be made on the 4 | [issue tracker](https://github.com/emacs-evil/evil/issues) here on github. 5 | 6 | **Before** sending a bug report, please take note of the following comments. 7 | 8 | 1. Please provide a full description of the configuration of your 9 | system. This includes 10 | 11 | - Emacs version, 12 | - Evil version (e.g., the hash in the git repository), 13 | - Whether you use Emacs/Evil in X mode or in terminal mode, 14 | - Whether you use Emacs/Evil in terminal mode with some terminal multiplexer 15 | like **tmux** or **screen** (and see below). 16 | 17 | 2. Test the bug in a clean Emacs environment without any additional 18 | packages loaded (besides Evil itself). You can easily get such an 19 | environment by executing either `make emacs` (for X) or `make 20 | terminal` (for terminal mode) in Evil's source directory. If your 21 | bug is related to some other package, try to load only this package 22 | from the clean environment after using `M-x package-initialize` 23 | first. 24 | 25 | 3. If you've just updated your Evil from the repository, **do not forget to 26 | recompile** Evil by executing `make` in Evil's source directory. 27 | 28 | 4. If possible, try to give a minimal example how to reproduce the error 29 | starting from a fresh Emacs. The minimal example could be some buffer content 30 | and a sequence of key-strokes that show up the error. 31 | 32 | 5. If the bug you want to report is related to the behavior of some commands or 33 | motions, please note the following. One goal of Evil is to get a behavior as 34 | close to **Vim** as possible unless there is a good reason not to do so. The 35 | reason is that many users come from Vim or use both, Vim and Evil, and we 36 | want to keep the number of annoying differences between both as small as 37 | possible, especially in common commands. In case you get an unexpected 38 | behavior, please compare the behavior with plain Vim (i.e., without any 39 | customization), if there's a difference please file the bug with a 40 | description of this difference (and possibly a reference to Vim's 41 | documentation). If you realize that both, Vim and Evil, behave the same but 42 | you want a different behavior, you may make a **feature request** for some 43 | customization option (but the default behavior will probably not be changed 44 | in favor for Vim compatibility). Evil already contains several customization 45 | options and sometimes the desired changes can be achieved as easily as 46 | redefining some key-bindings. 47 | 48 | # Pull Requests 49 | 50 | 1. Please follow the 51 | [Emacs Lisp Style Guide](https://github.com/bbatsov/emacs-lisp-style-guide/) 52 | 2. When in doubt, adhere to the style conventions in the source code, 53 | but don't be afraid of suggesting code enhancements in case you 54 | encounter suboptimal code. 55 | 3. If your pull requests adds a feature or fixes a regression, add 56 | tests covering it to `evil-tests.el`. 57 | -------------------------------------------------------------------------------- /Eask: -------------------------------------------------------------------------------- 1 | (package "evil" 2 | "1.15.0" 3 | "Extensible vi layer") 4 | 5 | (website-url "https://github.com/emacs-evil/evil") 6 | (keywords "emulations") 7 | 8 | (package-file "evil.el") 9 | (files "evil-*.el" '(:exclude "*-tests.el" "*-pkg.el")) 10 | 11 | (script "test" "echo \"Error: no test specified\" && exit 1") 12 | 13 | (source 'gnu) 14 | (source 'melpa) 15 | 16 | (depends-on "emacs" "24.1") 17 | (depends-on "cl-lib") 18 | (depends-on "goto-chg") 19 | (depends-on "nadvice") 20 | 21 | (setq network-security-level 'low) ; see https://github.com/jcs090218/setup-emacs-windows/issues/156#issuecomment-932956432 22 | 23 | (eask-defcommand test 24 | "Basic tests." 25 | (require 'evil-tests) 26 | (evil-tests-initialize nil nil)) 27 | 28 | (eask-defcommand terminal 29 | "Load Evil in a terminal Emacs and run all tests." 30 | (require 'evil-tests) 31 | (evil-tests-initialize nil nil t)) 32 | 33 | (eask-defcommand profiler 34 | "Run all tests with profiler." 35 | (require 'evil-tests) 36 | (evil-mode 1) 37 | (evil-tests-initialize nil t)) 38 | 39 | (eask-defcommand indent 40 | "Re-indent all Evil code." 41 | (setq vc-handled-backends nil) 42 | (dolist (file (eask-package-el-files)) (load file)) 43 | (dolist (buffer (reverse (buffer-list))) 44 | (when (buffer-file-name buffer) 45 | (set-buffer buffer) 46 | (message "Indenting %s" (current-buffer)) 47 | (setq-default indent-tabs-mode nil) 48 | (untabify (point-min) (point-max)) 49 | (indent-region (point-min) (point-max)) 50 | (delete-trailing-whitespace) 51 | (untabify (point-min) (point-max)) 52 | (goto-char (point-min)) 53 | (while (re-search-forward "\\n\\\\{3,\\\\}" nil t) 54 | (replace-match "\\n\\n")) 55 | (when (buffer-modified-p) (save-buffer 0))))) 56 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | EMACS ?= emacs 2 | SED ?= sed 3 | FILES = $(filter-out evil-test-helpers.el evil-tests.el evil-pkg.el,$(wildcard evil*.el)) 4 | VERSION := $(shell $(SED) -n '/^;\+ \+Version: *\(.*\)/{s//\1/p;q}' evil.el) 5 | PROFILER = 6 | TAG = 7 | EASK ?= eask 8 | 9 | ELCFILES = $(FILES:.el=.elc) 10 | 11 | .PHONY: all compile docstrings doc clean tests test emacs term terminal profiler indent elpa version 12 | 13 | # Byte-compile Evil. 14 | all: compile 15 | 16 | compile: 17 | $(EASK) compile 18 | 19 | # Documentation. 20 | docstrings: 21 | @$(EMACS) --script scripts/evil-extract-docstrings 22 | 23 | doc: docstrings 24 | @$(MAKE) -C doc texinfo 25 | 26 | info: doc 27 | @$(MAKE) -C doc info 28 | 29 | # Delete byte-compiled files etc. 30 | clean: 31 | $(EASK) clean all 32 | 33 | # Run tests. 34 | # The TAG variable may specify a test tag or a test name: 35 | # make test TAG=repeat 36 | # This will only run tests pertaining to the repeat system. 37 | test: 38 | $(EASK) run command test 39 | 40 | # Byte-compile Evil and run all tests. 41 | tests: compile 42 | $(EASK) run command test 43 | $(EASK) clean elc 44 | rm -f .depend 45 | 46 | # Load Evil in a fresh instance of Emacs and run all tests. 47 | emacs: 48 | $(EMACS) -Q -L . -l evil-tests.el \ 49 | --eval "(evil-mode 1)" \ 50 | --eval "(evil-tests-initialize '(${TAG}) '(${PROFILER}) t)" 51 | 52 | # Load Evil in a terminal Emacs and run all tests. 53 | term terminal: 54 | $(EASK) run command terminal 55 | 56 | # Run all tests with profiler. 57 | profiler: 58 | $(EASK) run command profiler 59 | 60 | # Re-indent all Evil code. 61 | # Loads Evil into memory in order to indent macros properly. 62 | # Also removes trailing whitespace, tabs and extraneous blank lines. 63 | indent: clean 64 | $(EASK) run command indent 65 | 66 | evil-pkg.el: evil.el 67 | $(EMACS) --batch -l package $^ \ 68 | --eval "(package-generate-description-file (package-buffer-info) \"$@\")" 69 | 70 | # Create an ELPA package. 71 | elpa: evil-pkg.el 72 | $(EASK) package 73 | 74 | # Change the version using make VERSION=x.y.z 75 | version: 76 | @$(EMACS) --script scripts/evilupdate "${VERSION}" 77 | 78 | # Change the version using make VERSION=x.y.z, but do not post to the newsgroup 79 | nversion: 80 | @$(EMACS) --script scripts/evilupdate nonews "${VERSION}" 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![An extensible vi layer for Emacs](https://raw.githubusercontent.com/emacs-evil/evil/master/doc/logo.png) 2 | 3 | [![Build status](https://github.com/emacs-evil/evil/actions/workflows/test.yml/badge.svg)](https://github.com/emacs-evil/evil/actions/workflows/test.yml) 4 | [![MELPA](https://melpa.org/packages/evil-badge.svg)](https://melpa.org/#/evil) 5 | [![MELPA Stable](https://stable.melpa.org/packages/evil-badge.svg)](https://stable.melpa.org/#/evil) 6 | [![NonGNU ELPA](http://elpa.nongnu.org/nongnu/evil.svg)](http://elpa.nongnu.org/nongnu/evil.html) 7 | [![Documentation Status](https://readthedocs.org/projects/evil/badge/?version=latest)](https://evil.readthedocs.io/en/latest/?badge=latest) 8 | [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) 9 | 10 | Evil is an **e**xtensible **vi** **l**ayer 11 | for [Emacs](http://www.gnu.org/software/emacs/). It emulates the main features 12 | of [Vim](http://www.vim.org/), and provides facilities for writing custom 13 | extensions. Also see our page on [EmacsWiki](http://emacswiki.org/emacs/Evil). 14 | 15 | # Installation 16 | 17 | See the 18 | [official documentation](https://evil.readthedocs.io/en/latest/overview.html#installation-via-package-el) 19 | for installation instructions. We recommend using *package.el*. 20 | 21 | As a quickstart, you can add the following code to your Emacs init 22 | file. 23 | 24 | ```elisp 25 | ;; Set up package.el to work with MELPA 26 | (require 'package) 27 | (add-to-list 'package-archives 28 | '("melpa" . "https://melpa.org/packages/")) 29 | (package-initialize) 30 | (package-refresh-contents) 31 | 32 | ;; Download Evil 33 | (unless (package-installed-p 'evil) 34 | (package-install 'evil)) 35 | 36 | ;; Enable Evil 37 | (require 'evil) 38 | (evil-mode 1) 39 | ``` 40 | 41 | ## Dependencies 42 | 43 | * Evil requires Emacs 24.1 or later. 44 | 45 | * Evil requires any of the following for `C-r`: 46 | * `undo-redo` from Emacs 28 47 | * The [undo-tree] package (available via GNU ELPA) 48 | * The [undo-fu] package (available via MELPA and NonGNU ELPA) 49 | 50 | * For the motions `g;` `g,` and for the last-change-register `.`, Evil 51 | requires the [goto-chg.el](https://github.com/emacs-evil/goto-chg) 52 | package (available via MELPA and NonGNU ELPA), which provides the 53 | functions `goto-last-change` and `goto-last-change-reverse`. 54 | 55 | * For Emacs 24.1 and 24.2 Evil also requires 56 | [cl-lib](https://elpa.gnu.org/packages/cl-lib.html). 57 | 58 | # Documentation 59 | 60 | The latest version of the documentation is readable online 61 | [here](https://evil.readthedocs.io/en/latest/index.html). It is also 62 | available as 63 | [PDF](https://evil.readthedocs.io/_/downloads/en/stable/pdf/) and 64 | as [EPUB](https://evil.readthedocs.io/_/downloads/en/stable/epub/). 65 | 66 | # Mailing list 67 | 68 | Evil is discussed at the 69 | [gmane.emacs.vim-emulation](http://lists.ourproject.org/cgi-bin/mailman/listinfo/implementations-list) 70 | mailing list. 71 | 72 | # IRC 73 | 74 | Visit us on `irc.libera.chat #evil-mode`. 75 | 76 | # Contribution 77 | 78 | See 79 | [CONTRIBUTING.md](https://github.com/emacs-evil/evil/blob/master/CONTRIBUTING.md) 80 | for guidelines for issues and pull requests. 81 | 82 | [undo-tree]: https://gitlab.com/tsc25/undo-tree 83 | [undo-fu]: https://codeberg.org/ideasman42/emacs-undo-fu 84 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /doc/front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emacs-evil/evil/682e87fce99f39ea3155f11f87ee56b6e4593304/doc/front.png -------------------------------------------------------------------------------- /doc/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emacs-evil/evil/682e87fce99f39ea3155f11f87ee56b6e4593304/doc/logo.png -------------------------------------------------------------------------------- /doc/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 47 | 49 | 50 | 52 | image/svg+xml 53 | 55 | 56 | 57 | 58 | 59 | 64 | 71 | EVIL 87 | 91 | 97 | 98 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /doc/requirements.txt: -------------------------------------------------------------------------------- 1 | Sphinx==7.3.7 2 | sphinx-rtd-theme==2.0.0 3 | -------------------------------------------------------------------------------- /doc/source/_ext/elisp.py: -------------------------------------------------------------------------------- 1 | import re 2 | from os import path 3 | import json 4 | 5 | from sphinx import addnodes 6 | from sphinx.domains import Domain, ObjType, Index 7 | from sphinx.domains.std import StandardDomain 8 | from sphinx.directives import ObjectDescription 9 | from sphinx.roles import XRefRole 10 | from sphinx.util.nodes import make_refnode 11 | 12 | 13 | with open(path.join(path.dirname(__file__), '..', '..', 'docstringdb.json')) as f: 14 | DATA = json.load(f) 15 | 16 | 17 | re_evilcode = re.compile(r"‘(evil-[^’]*)’") 18 | re_code = re.compile(r"‘([^:][^ ’]*)’") 19 | re_kwd = re.compile(r"‘(:[^’]*)’") 20 | re_item = re.compile(r"([^\n])\n- ") 21 | re_sexp = re.compile(r"\([A-Z \-\.‘’\[\]]+\)|[A-Z\-]+") 22 | re_capitals = re.compile(r"[A-Z\-]+") 23 | re_nonspace = re.compile(r"[^ ]") 24 | re_signature = re.compile(r'\(fn (.*)\)') 25 | 26 | emphasis = [ 27 | 'thing-at-point', 28 | ] 29 | 30 | def emacs_is_local(var): 31 | return DATA[var]['local'] 32 | 33 | def emacs_default_value(var): 34 | default = DATA[var]['default'] 35 | tp = DATA[var]['default-type'] 36 | if tp == 'string': 37 | rep = repr(default)[1:-1] 38 | return f'"{rep}"' 39 | return str(default) 40 | 41 | def process_docstring(docstring, capitals=None): 42 | # Remove explicit signature 43 | docstring = re_signature.sub('', docstring) 44 | 45 | # Add code blocks to indented sections 46 | def blockified_lines(lines): 47 | in_block = False 48 | for line in lines: 49 | try: 50 | indented = next(re_nonspace.finditer(line)).start(0) >= 4 51 | except StopIteration: 52 | indented = None 53 | if indented is True and not in_block: 54 | yield '.. code-block:: elisp' 55 | yield '' 56 | in_block = True 57 | elif indented is False: 58 | in_block = False 59 | yield line 60 | docstring = '\n'.join(blockified_lines(docstring.split('\n'))) 61 | 62 | # Substitute `evil-alpha' with :elisp:ref:`evil-alpha` 63 | docstring = re_evilcode.sub(r':elisp:ref:`\1`', docstring) 64 | 65 | # Substitute `alpha' with ``alpha`` 66 | docstring = re_code.sub(r'``\1``', docstring) 67 | 68 | # Substitute `:alpha' with ``alpha`` 69 | docstring = re_kwd.sub(r'``\1``', docstring) 70 | 71 | # Add empty line between list items 72 | docstring = re_item.sub(r'\1\n\n- ', docstring) 73 | 74 | if capitals is None: 75 | capitals = [] 76 | else: 77 | capitals = list(capitals) 78 | 79 | # Find things that look like sexps 80 | def substitute_sexp(match): 81 | s = match.group(0) 82 | if re_capitals.match(s): 83 | if s in capitals: 84 | return f'*{s}*' 85 | return s 86 | else: 87 | capitals.extend(re_capitals.findall(s)) 88 | return f'``{s}``' 89 | docstring = re_sexp.sub(substitute_sexp, docstring) 90 | 91 | # Italicize some words 92 | for s in emphasis: 93 | docstring = docstring.replace(s, f'*{s}*') 94 | 95 | return docstring 96 | 97 | def emacs_variable_docstring(var): 98 | docstring = DATA[var]['var-docstring'] 99 | return process_docstring(docstring) 100 | 101 | def emacs_function_docstring(var): 102 | docstring = DATA[var]['fn-docstring'] 103 | return process_docstring(docstring, capitals=emacs_argnames(var)) 104 | 105 | def emacs_argnames(var): 106 | arglist = emacs_arglist(var) 107 | return re_capitals.findall(arglist) 108 | 109 | def emacs_arglist(var): 110 | docstring = DATA[var]['fn-docstring'] 111 | match = re_signature.search(docstring) 112 | if match: 113 | return match.group(1) 114 | 115 | arglist = [arg.upper() for arg in DATA[var]['arglist']] 116 | state = None 117 | ret = '' 118 | for arg in arglist: 119 | if arg in ('&REST', '&OPTIONAL'): 120 | if state == '&OPTIONAL': 121 | ret += ']' 122 | state = arg 123 | ret += ' [' 124 | continue 125 | ret += ('' if state in ('&REST', '&OPTIONAL') else ' ') + arg 126 | if state == '&OPTIONAL': 127 | state += '-CONT' 128 | if state is not None and state.startswith('&OPTIONAL'): 129 | ret += ']' 130 | if state == '&REST': 131 | ret += '...]' 132 | return ret 133 | 134 | 135 | class AbstractElisp(ObjectDescription): 136 | 137 | def add_target_and_index(self, name, sig, signode): 138 | anchor = f'elispobj-{sig}' 139 | signode['ids'].append(anchor) 140 | 141 | objs = self.env.domaindata['elisp']['objects'] 142 | objs[sig] = { 143 | 'docname': self.env.docname, 144 | 'anchor': f'elispobj-{sig}', 145 | 'type': self.object_type, 146 | } 147 | 148 | 149 | class AbstractVariable(AbstractElisp): 150 | object_type = 'variable' 151 | 152 | def handle_signature(self, sig, signode): 153 | signode += addnodes.desc_annotation(sig, sig) 154 | return sig 155 | 156 | def run(self): 157 | extra = [] 158 | 159 | default = self.default_value() 160 | if default: 161 | extra.append(f'Default: ``{default}``') 162 | if self.is_buffer_local(): 163 | extra.append('buffer-local') 164 | 165 | self.content.data.extend(['', ', '.join(extra)]) 166 | retval = super().run() 167 | return retval 168 | 169 | 170 | class Variable(AbstractVariable): 171 | required_arguments = 1 172 | optional_arguments = 2 173 | 174 | def default_value(self): 175 | try: 176 | return self.arguments[1] 177 | except IndexError: 178 | return None 179 | 180 | def is_buffer_local(self): 181 | return 'bufloc' in self.arguments[1:] 182 | 183 | 184 | class AutoVariable(AbstractVariable): 185 | required_arguments = 1 186 | 187 | def is_buffer_local(self): 188 | return emacs_is_local(self.arguments[0]) 189 | 190 | def default_value(self): 191 | return emacs_default_value(self.arguments[0]) 192 | 193 | def run(self): 194 | docstring = emacs_variable_docstring(self.arguments[0]) 195 | self.content.data.extend(docstring.split('\n')) 196 | return super().run() 197 | 198 | 199 | class AutoFunction(AbstractElisp): 200 | required_arguments = 1 201 | 202 | @property 203 | def object_type(self): 204 | return 'macro' if DATA[self.arguments[0]]['macrop'] else 'function' 205 | 206 | def handle_signature(self, sig, signode): 207 | args = emacs_arglist(sig) 208 | signode += addnodes.desc_annotation(sig, f'({sig} {args})') 209 | return sig 210 | 211 | def run(self): 212 | docstring = emacs_function_docstring(self.arguments[0]) 213 | self.content.data.extend(docstring.split('\n')) 214 | return super().run() 215 | 216 | 217 | class ElispIndex(Index): 218 | name = 'index' 219 | localname = 'Emacs lisp functions and variables' 220 | shortname = 'Elisp' 221 | 222 | def generate(self, docnames=None): 223 | index = {} 224 | for name, item in self.domain.data['objects'].items(): 225 | if name.startswith('evil-'): 226 | letter = name[5].upper() 227 | else: 228 | letter = name[0].upper() 229 | index.setdefault(letter, []).append(( 230 | name, 231 | 0, 232 | item['docname'], 233 | item['anchor'], 234 | item['type'], 235 | '', 236 | '', 237 | )) 238 | 239 | index = {k: sorted(v, key=lambda k: k[0].lower()) for k, v in index.items()} 240 | index = list(index.items()) 241 | index = sorted(index, key=lambda k: k[0]) 242 | return index, True 243 | 244 | 245 | class Elisp(Domain): 246 | name = 'elisp' 247 | label = 'Emacs lisp' 248 | 249 | object_types = { 250 | 'variable': ObjType('variable', 'variable', 'obj'), 251 | 'autovariable': ObjType('autovariable', 'autovariable', 'obj'), 252 | 'autofunction': ObjType('autofunction', 'autofunction', 'obj'), 253 | } 254 | 255 | directives = { 256 | 'variable': Variable, 257 | 'autovariable': AutoVariable, 258 | 'autofunction': AutoFunction, 259 | } 260 | 261 | roles = { 262 | 'ref': XRefRole(), 263 | } 264 | 265 | initial_data = { 266 | 'objects': {}, 267 | } 268 | 269 | indices = { 270 | ElispIndex, 271 | } 272 | 273 | def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): 274 | obj = self.data['objects'].get(target, None) 275 | if obj is None: 276 | return None 277 | return make_refnode(builder, fromdocname, obj['docname'], obj['anchor'], contnode, obj['anchor']) 278 | 279 | 280 | def setup(app): 281 | app.add_domain(Elisp) 282 | StandardDomain.initial_data['labels']['elispindex'] = ('elisp-index', '', 'Emacs lisp functions and variables') 283 | StandardDomain.initial_data['anonlabels']['elispindex'] = ('elisp-index', '') 284 | 285 | return { 286 | 'version': '0.1', 287 | 'parallel_read_safe': True, 288 | 'parallel_write_safe': True, 289 | } 290 | -------------------------------------------------------------------------------- /doc/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # 16 | 17 | import os, sys 18 | sys.path.append(os.path.abspath("./_ext")) 19 | 20 | 21 | # -- Project information ----------------------------------------------------- 22 | 23 | project = 'Evil' 24 | copyright = '2011-2019, Eivind Fonn, Frank Fischer, Vegard Øye' 25 | author = 'Eivind Fonn, Frank Fischer, Vegard Øye' 26 | 27 | # The full version, including alpha/beta/rc tags 28 | release = '1.15.0' 29 | 30 | master_doc = 'index' 31 | 32 | 33 | latex_elements = { 34 | 'fontpkg': r'\usepackage{palatino} \usepackage{inconsolata}', 35 | 'maketitle': r""" 36 | \newcommand\sphinxbackoftitlepage{{ 37 | Copyright {copyright}. 38 | 39 | \begin{{quote}} 40 | Permission is granted to copy, distribute and/or modify this 41 | document under the terms of the GNU Free Documentation License, 42 | Version 1.3 or any later version published by the Free Software 43 | Foundation; with no Invariant Sections, no Front-Cover Texts, 44 | and no Back-Cover Texts. A copy of the license is included in 45 | the section entitled ``GNU Free Documentation License''. 46 | \end{{quote}} 47 | 48 | The Evil team thanks everyone at gmane.emacs.vim-emulation for 49 | their feedback and contributions. 50 | }} 51 | \sphinxmaketitle 52 | """.format(copyright=copyright), 53 | } 54 | 55 | 56 | texinfo_documents = [ 57 | (master_doc, 'evil', 'Evil documentation', author, 'evil', 58 | 'Extensible vi layer for Emacs', 'Emacs'), 59 | ] 60 | 61 | 62 | # -- General configuration --------------------------------------------------- 63 | 64 | # Add any Sphinx extension module names here, as strings. They can be 65 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 66 | # ones. 67 | extensions = [ 68 | 'elisp', 69 | ] 70 | 71 | # Add any paths that contain templates here, relative to this directory. 72 | templates_path = ['_templates'] 73 | 74 | # List of patterns, relative to source directory, that match files and 75 | # directories to ignore when looking for source files. 76 | # This pattern also affects html_static_path and html_extra_path. 77 | exclude_patterns = [] 78 | 79 | 80 | # -- Options for HTML output ------------------------------------------------- 81 | 82 | # The theme to use for HTML and HTML Help pages. See the documentation for 83 | # a list of builtin themes. 84 | # 85 | html_theme = 'sphinx_rtd_theme' 86 | -------------------------------------------------------------------------------- /doc/source/extension.rst: -------------------------------------------------------------------------------- 1 | Extension 2 | ========= 3 | 4 | The main functionality of Evil is implemented in terms of reusable 5 | macros. Package writers can use these to define new commands. 6 | 7 | 8 | Motions 9 | ------- 10 | 11 | A *motion* is a command which moves the cursor, such as :kbd:`w` or 12 | :kbd:`e`. Motions are defined with the macro 13 | :elisp:ref:`evil-define-motion`. Motions not defined in this way 14 | should be declared with :elisp:ref:`evil-declare-motion`. 15 | 16 | .. elisp:autofunction:: evil-declare-motion 17 | 18 | .. elisp:autofunction:: evil-define-motion 19 | 20 | For example, this is a motion that moves the cursor forward by a 21 | number of characters: 22 | 23 | .. code-block:: elisp 24 | 25 | (evil-define-motion foo-forward (count) 26 | "Move to the right by COUNT characters." 27 | :type inclusive 28 | (forward-char (or count 1))) 29 | 30 | The *type* of a motion determines how it works when used together with 31 | an operator. Inclusive motions include the endpoint in the range 32 | being operated on, while exclusive motions do not. Line motions 33 | extend the whole range to linewise positions, effectively behaving as 34 | if the endpoint were really at the end of the line. Blockwise ranges 35 | behave as a "rectangle" on screen rather than a contiguous range of 36 | characters. 37 | 38 | 39 | Operators 40 | --------- 41 | 42 | An operator is a command that acts on the text moved over by a motion, 43 | such as :kbd:`c` (change), :kbd:`d` (delete) or :kbd:`y` (yank or 44 | copy, not to be confused with "yank" in Emacs terminology which means 45 | *paste*). 46 | 47 | .. elisp:autofunction:: evil-define-operator 48 | 49 | For example, this is an operator that performs ROT13 encryption on the 50 | text under consideration: 51 | 52 | .. code-block:: elisp 53 | 54 | (evil-define-operator evil-rot13 (beg end) 55 | "ROT13 encrypt text." 56 | (rot13-region beg end)) 57 | 58 | Binding this to :kbd:`g?` (where it is by default) will cause a key 59 | sequence such as :kbd:`g?w` to encrypt from the current cursor to the 60 | end of the word. 61 | 62 | 63 | Text objects 64 | ------------ 65 | 66 | Text objects are like motions in that they define a range over which 67 | an operator may act. Unlike motions, text objects can set both a 68 | beginning and an endpoint. In visual state, text objects alter both 69 | ends of the selection. 70 | 71 | Text objects are not directly usable in normal state. Instead, they 72 | are bound in the two keymaps ``evil-inner-text-ojects-map`` and 73 | ``evil-outer-text-objects-map``, which are available in visual and 74 | operator-pending state under the keys :kbd:`i` and :kbd:`a` 75 | respectively. 76 | 77 | .. elisp:autofunction:: evil-define-text-object 78 | 79 | For example, this is a text object which selects the next three 80 | characters after the current location: 81 | 82 | .. code-block:: elisp 83 | 84 | (evil-define-text-object foo (count) 85 | "Select three characters." 86 | (list (point) (+ 3 (point)))) 87 | 88 | For convenience, Evil provides several functions returning a list of 89 | positions which can be used for defining text objects. All of them 90 | follow the convention that a positive *count* selects text after the 91 | current location, while negative *count* selects text before it. 92 | 93 | .. note:: 94 | 95 | The *thingatpt* library is used quite extensively in Evil to define 96 | text objects, and this dependency leaks through in the following 97 | functions. A *thing* in this context is any symbol for which there 98 | is a function called ``forward-THING`` [#thing]_ which moves past a 99 | number of *things*. 100 | 101 | .. elisp:autofunction:: evil-select-inner-object 102 | 103 | .. elisp:autofunction:: evil-select-an-object 104 | 105 | .. elisp:autofunction:: evil-select-paren 106 | 107 | 108 | Range types 109 | ----------- 110 | 111 | A *type* is a transformation acting on a pair of buffer positions. 112 | Evil defines the types ``inclusive``, ``line``, ``block`` and 113 | ``exclusive``, which are used for motion ranges and visual selection. 114 | New types may be defined with the macro *evil-define-type*. 115 | 116 | .. elisp:autofunction:: evil-define-type 117 | 118 | 119 | States 120 | ------ 121 | 122 | States are defined with the macro :elisp:ref:`evil-define-state`, 123 | which takes care to define the necessary hooks, keymaps and variables, 124 | as well as a toggle function ``evil-NAME-state`` and a predicate 125 | function ``evil-NAME-state-p`` for checking whether the state is 126 | active. 127 | 128 | .. elisp:autofunction:: evil-define-state 129 | 130 | For example: 131 | 132 | .. code-block:: elisp 133 | 134 | (evil-define-state test 135 | "Test state." 136 | :tag " " 137 | (message (if (evil-test-state-p) 138 | "Enabling test state." 139 | "Disabling test state."))) 140 | 141 | 142 | .. rubric:: Footnotes 143 | 144 | .. [#thing] There are many more ways that a *thing* can be defined, 145 | but the definition of ``forward-THING`` is perhaps the most 146 | straightforward way to go about it. 147 | -------------------------------------------------------------------------------- /doc/source/faq.rst: -------------------------------------------------------------------------------- 1 | Frequently Asked Questions 2 | ========================== 3 | 4 | Problems with the escape key in the terminal 5 | -------------------------------------------- 6 | 7 | A common problem when using Evil in terminal mode is a certain delay 8 | after pressing the escape key. Even more, when pressing the escape key 9 | followed quickly by another key the command is recognized as 10 | :kbd:`M-` instead of two separate keys: :kbd:`ESC` followed by 11 | :kbd:``. In fact, it is perfectly valid to simulate 12 | :kbd:`M-` by pressing :kbd:`ESC ` quickly (but see below). 13 | 14 | The reason for this is that in terminal mode a key sequence involving 15 | the meta key (or alt key) always generates a so called "escape 16 | sequence", i.e. a sequence of two events sent to Emacs, the first 17 | being :kbd:`ESC` and the second the key pressed simultaneously. The 18 | problem is that pressing the escape key itself also generates the 19 | :kbd:`ESC` event. Thus, if Emacs (and therefore Evil) receives an 20 | :kbd:`ESC` event there is no way to tell whether the escape key has 21 | been pressed (and no further event will arrive) or a :kbd:`M-` 22 | combination has been pressed (and the :kbd:`` event will arrive 23 | soon). In order to distinguish both situations Evil does the 24 | following. After receiving an :kbd:`ESC` event Evil waits for a short 25 | time period (specified by the variable :elisp:ref:`evil-esc-delay` 26 | which defaults to 0.01 seconds) for another event. If no other event 27 | arrives Evil assumes that the plain escape key has been pressed, 28 | otherwise it assumes a :kbd:`M-` combination has been pressed and 29 | combines the :kbd:`ESC` event with the second one. Because a 30 | :kbd:`M-` sequence usually generates both events in very quick 31 | succession, 0.01 seconds are usually enough and the delay is hardly 32 | noticeable by the user. 33 | 34 | If you use a terminal multiplexer like *tmux* or *screen* the 35 | situation may be worse. These multiplexers have exactly the same 36 | problem recognizing :kbd:`M-` sequences and often introduce their 37 | own delay for the :kbd:`ESC` key. There is no way for Evil to 38 | influence this delay. In order to reduce it you must reconfigure your 39 | terminal multiplexer. 40 | 41 | Note that this problem should not arise when using Evil in graphical 42 | mode. The reason is that in this case the escape key itself generates 43 | a different command, namely ``escape`` (a symbol) and hence Evil can 44 | distinguish whether the escape key or a :kbd:`M-` combination has 45 | been pressed. But this also implies that pressing :kbd:`ESC` followed 46 | by cannot be used to simulate :kbd:`M-` in graphical mode! 47 | 48 | 49 | Underscore is not a word character 50 | ---------------------------------- 51 | 52 | An underscore ``_`` is a word character in Vim. This means that word 53 | motions like :kbd:`w` skip over underlines in a sequence of letters as 54 | if it was a letter itself. In contrast, in Evil the underscore is 55 | often a non-word character like operators, e.g. ``+``. 56 | 57 | The reason is that Evil uses Emacs' definition of a word and this 58 | definition does often not include the underscore. In Emacs word 59 | characters are determined by the syntax-class of the buffer. The 60 | syntax-class usually depends on the major-mode of this buffer. This 61 | has the advantage that the definition of a "word" may be adapted to 62 | the particular type of document being edited. Evil uses Emacs' 63 | definition and does not simply use Vim's definition in order to be 64 | consistent with other Emacs functions. For example, word characters 65 | are exactly those characters that are matched by the regular 66 | expression character class ``[:word:]``. 67 | 68 | If you would be satisfied by having the :kbd:`*` and :kbd:`#` searches 69 | use symbols instead of words, this can be achieved by setting the 70 | :elisp:ref:`evil-symbol-word-search` variable to ``t``. 71 | 72 | If you want the underscore to be recognised as word character for other 73 | motions, you can modify its entry in the syntax-table: 74 | 75 | .. code-block:: elisp 76 | 77 | (modify-syntax-entry ?_ "w") 78 | 79 | This gives the underscore the 'word' syntax class. You can use a 80 | mode-hook to modify the syntax-table in all buffers of some mode, 81 | e.g.: 82 | 83 | .. code-block:: elisp 84 | 85 | (add-hook 'c-mode-common-hook 86 | (lambda () (modify-syntax-entry ?_ "w"))) 87 | 88 | This gives the underscore the word syntax-class in all C-like buffers. 89 | 90 | Similarly to Emacs' definition of a word, the definition of a "symbol" is also 91 | dependent on the syntax-class of the buffer, which often includes the 92 | underscore. The default text objects keymap associates kbd::`o` with the symbol 93 | object, making kbd::`cio` a good alternative to Vim's kbd::`ciw`, for example. 94 | The following will swap between the word and symbol objects in the keymap: 95 | 96 | .. code-block:: elisp 97 | 98 | (define-key evil-outer-text-objects-map "w" 'evil-a-symbol) 99 | (define-key evil-inner-text-objects-map "w" 'evil-inner-symbol) 100 | (define-key evil-outer-text-objects-map "o" 'evil-a-word) 101 | (define-key evil-inner-text-objects-map "o" 'evil-inner-word) 102 | 103 | This will not change the motion keys, however. One way to make word motions 104 | operate as symbol motions is to alias the ``evil-word`` *thing* [#thingatpt]_ to 105 | the ``evil-symbol`` thing: 106 | 107 | .. code-block:: elisp 108 | 109 | (defalias 'forward-evil-word 'forward-evil-symbol) 110 | 111 | 112 | .. rubric:: Footnotes 113 | 114 | .. [#thingatpt] Many of Evil's text objects and motions are defined in 115 | terms of the *thingatpt* library, which in this case are defined 116 | entirely in terms of ``forward-THING`` functions. Thus aliasing 117 | one to another should make all motions and text objects implemented 118 | in terms of that *thing* behave the same. 119 | -------------------------------------------------------------------------------- /doc/source/hooks.rst: -------------------------------------------------------------------------------- 1 | Hooks 2 | ===== 3 | 4 | A *hook* is a list of functions that are executed when certain events 5 | happen. Hooks are modified with the Emacs function ``add-hook``. 6 | Evil provides entry and exit hooks for all its states. For example, 7 | when switching from normal state to insert state, all functions in 8 | ``evil-normal-state-exit-hook`` and ``evil-insert-state-entry-hook`` 9 | are executed. 10 | 11 | It is guaranteed that the exit hook will be executed before the entry 12 | hook on all state switches. 13 | 14 | During the hook execution, the variables ``evil-next-state`` and 15 | ``evil-previous-state`` contain information about the states being 16 | switched to and from, respectively. 17 | -------------------------------------------------------------------------------- /doc/source/index.rst: -------------------------------------------------------------------------------- 1 | .. Evil documentation master file, created by 2 | sphinx-quickstart on Thu Dec 12 10:34:49 2019. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Evil 7 | ==== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents 12 | 13 | overview 14 | settings 15 | keymaps 16 | hooks 17 | extension 18 | faq 19 | internals 20 | license 21 | indices 22 | -------------------------------------------------------------------------------- /doc/source/indices.rst: -------------------------------------------------------------------------------- 1 | .. only:: html 2 | 3 | Index 4 | ===== 5 | 6 | - :ref:`elispindex` 7 | -------------------------------------------------------------------------------- /doc/source/internals.rst: -------------------------------------------------------------------------------- 1 | Internals 2 | ========= 3 | 4 | Command properties 5 | ------------------ 6 | 7 | Evil defines *command properties* to store information about commands 8 | [#command]_, such as whether they should be repeated. A command 9 | property is a ``:keyword`` with an associated value, e.g. 10 | ``:repeat nil``. 11 | 12 | .. elisp:autofunction:: evil-add-command-properties 13 | 14 | .. elisp:autofunction:: evil-set-command-properties 15 | 16 | .. elisp:autofunction:: evil-get-command-properties 17 | 18 | .. elisp:autofunction:: evil-get-command-property 19 | 20 | .. elisp:autofunction:: evil-define-command 21 | 22 | 23 | For setting repeat properties, use the following functions: 24 | 25 | .. elisp:autofunction:: evil-declare-repeat 26 | 27 | .. elisp:autofunction:: evil-declare-not-repeat 28 | 29 | .. elisp:autofunction:: evil-declare-change-repeat 30 | 31 | 32 | .. rubric:: Footnotes 33 | 34 | .. [#command] In this context, a *command* may mean any Evil motion, 35 | text object, operator or indeed other Emacs commands, which have 36 | not been defined through the Evil machinery. 37 | -------------------------------------------------------------------------------- /doc/source/keymaps.rst: -------------------------------------------------------------------------------- 1 | .. _chapter-keymaps: 2 | 3 | Keymaps 4 | ======= 5 | 6 | Evil's key bindings are stored in a number of different keymaps. Each 7 | state has a *global keymap*, where the default bindings for that state 8 | are stored. They are named ``evil-normal-state-map``, 9 | ``evil-insert-state-map``, and so on. The bindings in these maps are 10 | visible in all buffers currently in the corresponding state. 11 | 12 | These keymaps function like ordinary Emacs keymaps and may be modified 13 | using the Emacs function ``define-key``: 14 | 15 | .. code-block:: elisp 16 | 17 | (define-key evil-normal-state-map (kbd "w") 'some-function) 18 | 19 | This binds the key :kbd:`w` to the command ``some-function`` in normal 20 | state. The use of ``kbd`` is optional for simple key sequences, like 21 | this one, but recommended in general. 22 | 23 | Most of Evil's bindings are defined in the file ``evil-maps.el``. 24 | 25 | To facilitate shared keybindings between states, some states may 26 | activate keybindings from other states as well. For example, motion 27 | state bindings are visible in normal and visual state, and normal 28 | state bindings are also visible in visual state. 29 | 30 | Each state also has a *buffer-local keymap* which is specific to the 31 | current buffer, and which takes precedence over the global keymap. 32 | These maps are most suitably modified by a mode hook. They are named 33 | ``evil-normal-state-local-map``, ``evil-insert-state-local-map``, and 34 | so on. 35 | 36 | .. code-block:: elisp 37 | 38 | (add-hook 'some-mode-hook 39 | (lambda () 40 | (define-key evil-normal-state-local-map 41 | (kbd "w") 'some-function))) 42 | 43 | For convenience, the functions :elisp:ref:`evil-global-set-key` and 44 | :elisp:ref:`evil-local-set-key` are available for setting global and 45 | local state keys. 46 | 47 | .. elisp:autofunction:: evil-global-set-key 48 | 49 | .. elisp:autofunction:: evil-local-set-key 50 | 51 | The above examples could therefore have been written as follows: 52 | 53 | .. code-block:: elisp 54 | 55 | (evil-global-set-key 'normal (kbd "w") 'some-function) 56 | 57 | (add-hook 'some-mode-hook 58 | (lambda () 59 | (evil-local-set-key 'normal (kbd "w") 'some-function))) 60 | 61 | 62 | evil-define-key 63 | --------------- 64 | 65 | Evil provides the macro :elisp:ref:`evil-define-key` for adding state 66 | bindings to ordinary keymaps. It is quite powerful, and is the 67 | preferred method for fine-tuning bindings to activate in specific 68 | circumstances. 69 | 70 | .. elisp:autofunction:: evil-define-key 71 | 72 | There follows a brief overview of the main functions of this macro. 73 | 74 | - Define a binding in a given state 75 | 76 | .. code-block:: elisp 77 | 78 | (evil-define-key 'state 'global (kbd "key") 'target) 79 | 80 | - Define a binding in a given state in the current buffer 81 | 82 | .. code-block:: elisp 83 | 84 | (evil-define-key 'state 'local (kbd "key") 'target) 85 | 86 | - Define a binding in a given state under the *foo-mode* major mode. 87 | 88 | .. code-block:: elisp 89 | 90 | (evil-define-key 'state foo-mode-map (kbd "key") 'target) 91 | 92 | Note that ``foo-mode-map`` is unquoted, and that this form is safe 93 | before ``foo-mode-map`` is loaded. 94 | 95 | - Define a binding in a given state under the *bar-mode* minor mode. 96 | 97 | .. code-block:: elisp 98 | 99 | (evil-define-key 'state 'bar-mode (kbd "key") 'target) 100 | 101 | Note that ``bar-mode`` is quoted, and that this form is safe before 102 | ``bar-mode`` is loaded. 103 | 104 | 105 | The macro :elisp:ref:`evil-define-key` can be used to augment existing 106 | modes with state bindings, as well as creating packages with custom 107 | bindings. For example, the following will create a minor mode 108 | ``foo-mode`` with normal state bindings for the keys :kbd:`w` and 109 | :kbd:`e`: 110 | 111 | .. code-block:: elisp 112 | 113 | (define-minor-mode foo-mode 114 | "Foo mode." 115 | :keymap (make-sparse-keymap)) 116 | 117 | (evil-define-key 'normal 'foo-mode "w" 'bar) 118 | (evil-define-key 'normal 'foo-mode "e" 'baz) 119 | 120 | This minor mode can then be enabled in any buffers where the custom 121 | bindings are desired: 122 | 123 | .. code-block:: elisp 124 | 125 | (add-hook 'text-mode-hook 'foo-mode) ; enable alongside text-mode 126 | 127 | 128 | Leader keys 129 | ----------- 130 | 131 | Evil supports a simple implementation of Vim's *leader* keys. To bind 132 | a function to a leader key you can use the expression ```` in 133 | a key mapping, e.g. 134 | 135 | .. code-block:: elisp 136 | 137 | (evil-define-key 'normal 'global (kbd "fs") 'save-buffer) 138 | 139 | Likewise, you can use the expression ```` to mimic Vim's 140 | local leader, which is designed for mode-specific key bindings. 141 | 142 | You can use the function :elisp:ref:`evil-set-leader` to designate 143 | which key acts as the leader and the local leader. 144 | 145 | .. elisp:autofunction:: evil-set-leader 146 | -------------------------------------------------------------------------------- /doc/source/license.rst: -------------------------------------------------------------------------------- 1 | The GNU Free Documentation License 2 | ================================== 3 | 4 | Version 1.3, 3 November 2008 5 | 6 | Copyright (c) 2000, 2001, 2002, 2007, 2008 Free Software 7 | Foundation, Inc. http://fsf.org/ 8 | 9 | Everyone is permitted to copy and distribute verbatim copies of 10 | this license document, but changing it is not allowed. 11 | 12 | 13 | 0. PREAMBLE 14 | 15 | The purpose of this License is to make a manual, textbook, or other 16 | functional and useful document *free* in the sense of freedom: to 17 | assure everyone the effective freedom to copy and redistribute it, 18 | with or without modifying it, either commercially or 19 | noncommercially. Secondarily, this License preserves for the 20 | author and publisher a way to get credit for their work, while not 21 | being considered responsible for modifications made by others. 22 | 23 | This License is a kind of "copyleft", which means that derivative 24 | works of the document must themselves be free in the same sense. 25 | It complements the GNU General Public License, which is a copyleft 26 | license designed for free software. 27 | 28 | We have designed this License in order to use it for manuals for 29 | free software, because free software needs free documentation: a 30 | free program should come with manuals providing the same freedoms 31 | that the software does. But this License is not limited to 32 | software manuals; it can be used for any textual work, regardless 33 | of subject matter or whether it is published as a printed book. We 34 | recommend this License principally for works whose purpose is 35 | instruction or reference. 36 | 37 | 1. APPLICABILITY AND DEFINITIONS 38 | 39 | This License applies to any manual or other work, in any medium, 40 | that contains a notice placed by the copyright holder saying it can 41 | be distributed under the terms of this License. Such a notice 42 | grants a world-wide, royalty-free license, unlimited in duration, 43 | to use that work under the conditions stated herein. The 44 | "Document", below, refers to any such manual or work. Any member 45 | of the public is a licensee, and is addressed as "you". You accept 46 | the license if you copy, modify or distribute the work in a way 47 | requiring permission under copyright law. 48 | 49 | A "Modified Version" of the Document means any work containing the 50 | Document or a portion of it, either copied verbatim, or with 51 | modifications and/or translated into another language. 52 | 53 | A "Secondary Section" is a named appendix or a front-matter section 54 | of the Document that deals exclusively with the relationship of the 55 | publishers or authors of the Document to the Document's overall 56 | subject (or to related matters) and contains nothing that could 57 | fall directly within that overall subject. (Thus, if the Document 58 | is in part a textbook of mathematics, a Secondary Section may not 59 | explain any mathematics.) The relationship could be a matter of 60 | historical connection with the subject or with related matters, or 61 | of legal, commercial, philosophical, ethical or political position 62 | regarding them. 63 | 64 | The "Invariant Sections" are certain Secondary Sections whose 65 | titles are designated, as being those of Invariant Sections, in the 66 | notice that says that the Document is released under this License. 67 | If a section does not fit the above definition of Secondary then it 68 | is not allowed to be designated as Invariant. The Document may 69 | contain zero Invariant Sections. If the Document does not identify 70 | any Invariant Sections then there are none. 71 | 72 | The "Cover Texts" are certain short passages of text that are 73 | listed, as Front-Cover Texts or Back-Cover Texts, in the notice 74 | that says that the Document is released under this License. A 75 | Front-Cover Text may be at most 5 words, and a Back-Cover Text may 76 | be at most 25 words. 77 | 78 | A "Transparent" copy of the Document means a machine-readable copy, 79 | represented in a format whose specification is available to the 80 | general public, that is suitable for revising the document 81 | straightforwardly with generic text editors or (for images composed 82 | of pixels) generic paint programs or (for drawings) some widely 83 | available drawing editor, and that is suitable for input to text 84 | formatters or for automatic translation to a variety of formats 85 | suitable for input to text formatters. A copy made in an otherwise 86 | Transparent file format whose markup, or absence of markup, has 87 | been arranged to thwart or discourage subsequent modification by 88 | readers is not Transparent. An image format is not Transparent if 89 | used for any substantial amount of text. A copy that is not 90 | "Transparent" is called "Opaque". 91 | 92 | Examples of suitable formats for Transparent copies include plain 93 | ASCII without markup, Texinfo input format, LaTeX input format, 94 | SGML or XML using a publicly available DTD, and standard-conforming 95 | simple HTML, PostScript or PDF designed for human modification. 96 | Examples of transparent image formats include PNG, XCF and JPG. 97 | Opaque formats include proprietary formats that can be read and 98 | edited only by proprietary word processors, SGML or XML for which 99 | the DTD and/or processing tools are not generally available, and 100 | the machine-generated HTML, PostScript or PDF produced by some word 101 | processors for output purposes only. 102 | 103 | The "Title Page" means, for a printed book, the title page itself, 104 | plus such following pages as are needed to hold, legibly, the 105 | material this License requires to appear in the title page. For 106 | works in formats which do not have any title page as such, "Title 107 | Page" means the text near the most prominent appearance of the 108 | work's title, preceding the beginning of the body of the text. 109 | 110 | The "publisher" means any person or entity that distributes copies 111 | of the Document to the public. 112 | 113 | A section "Entitled XYZ" means a named subunit of the Document 114 | whose title either is precisely XYZ or contains XYZ in parentheses 115 | following text that translates XYZ in another language. (Here XYZ 116 | stands for a specific section name mentioned below, such as 117 | "Acknowledgements", "Dedications", "Endorsements", or "History".) 118 | To "Preserve the Title" of such a section when you modify the 119 | Document means that it remains a section "Entitled XYZ" according 120 | to this definition. 121 | 122 | The Document may include Warranty Disclaimers next to the notice 123 | which states that this License applies to the Document. These 124 | Warranty Disclaimers are considered to be included by reference in 125 | this License, but only as regards disclaiming warranties: any other 126 | implication that these Warranty Disclaimers may have is void and 127 | has no effect on the meaning of this License. 128 | 129 | 2. VERBATIM COPYING 130 | 131 | You may copy and distribute the Document in any medium, either 132 | commercially or noncommercially, provided that this License, the 133 | copyright notices, and the license notice saying this License 134 | applies to the Document are reproduced in all copies, and that you 135 | add no other conditions whatsoever to those of this License. You 136 | may not use technical measures to obstruct or control the reading 137 | or further copying of the copies you make or distribute. However, 138 | you may accept compensation in exchange for copies. If you 139 | distribute a large enough number of copies you must also follow the 140 | conditions in section 3. 141 | 142 | You may also lend copies, under the same conditions stated above, 143 | and you may publicly display copies. 144 | 145 | 3. COPYING IN QUANTITY 146 | 147 | If you publish printed copies (or copies in media that commonly 148 | have printed covers) of the Document, numbering more than 100, and 149 | the Document's license notice requires Cover Texts, you must 150 | enclose the copies in covers that carry, clearly and legibly, all 151 | these Cover Texts: Front-Cover Texts on the front cover, and 152 | Back-Cover Texts on the back cover. Both covers must also clearly 153 | and legibly identify you as the publisher of these copies. The 154 | front cover must present the full title with all words of the title 155 | equally prominent and visible. You may add other material on the 156 | covers in addition. Copying with changes limited to the covers, as 157 | long as they preserve the title of the Document and satisfy these 158 | conditions, can be treated as verbatim copying in other respects. 159 | 160 | If the required texts for either cover are too voluminous to fit 161 | legibly, you should put the first ones listed (as many as fit 162 | reasonably) on the actual cover, and continue the rest onto 163 | adjacent pages. 164 | 165 | If you publish or distribute Opaque copies of the Document 166 | numbering more than 100, you must either include a machine-readable 167 | Transparent copy along with each Opaque copy, or state in or with 168 | each Opaque copy a computer-network location from which the general 169 | network-using public has access to download using public-standard 170 | network protocols a complete Transparent copy of the Document, free 171 | of added material. If you use the latter option, you must take 172 | reasonably prudent steps, when you begin distribution of Opaque 173 | copies in quantity, to ensure that this Transparent copy will 174 | remain thus accessible at the stated location until at least one 175 | year after the last time you distribute an Opaque copy (directly or 176 | through your agents or retailers) of that edition to the public. 177 | 178 | It is requested, but not required, that you contact the authors of 179 | the Document well before redistributing any large number of copies, 180 | to give them a chance to provide you with an updated version of the 181 | Document. 182 | 183 | 4. MODIFICATIONS 184 | 185 | You may copy and distribute a Modified Version of the Document 186 | under the conditions of sections 2 and 3 above, provided that you 187 | release the Modified Version under precisely this License, with the 188 | Modified Version filling the role of the Document, thus licensing 189 | distribution and modification of the Modified Version to whoever 190 | possesses a copy of it. In addition, you must do these things in 191 | the Modified Version: 192 | 193 | A. Use in the Title Page (and on the covers, if any) a title 194 | distinct from that of the Document, and from those of previous 195 | versions (which should, if there were any, be listed in the 196 | History section of the Document). You may use the same title as 197 | a previous version if the original publisher of that version 198 | gives permission. 199 | 200 | B. List on the Title Page, as authors, one or more persons or 201 | entities responsible for authorship of the modifications in the 202 | Modified Version, together with at least five of the principal 203 | authors of the Document (all of its principal authors, if it has 204 | fewer than five), unless they release you from this requirement. 205 | 206 | C. State on the Title page the name of the publisher of the 207 | Modified Version, as the publisher. 208 | 209 | D. Preserve all the copyright notices of the Document. 210 | 211 | E. Add an appropriate copyright notice for your modifications 212 | adjacent to the other copyright notices. 213 | 214 | F. Include, immediately after the copyright notices, a license 215 | notice giving the public permission to use the Modified Version 216 | under the terms of this License, in the form shown in the 217 | Addendum below. 218 | 219 | G. Preserve in that license notice the full lists of Invariant 220 | Sections and required Cover Texts given in the Document's 221 | license notice. 222 | 223 | H. Include an unaltered copy of this License. 224 | 225 | I. Preserve the section Entitled "History", Preserve its Title, and 226 | add to it an item stating at least the title, year, new authors, 227 | and publisher of the Modified Version as given on the Title 228 | Page. If there is no section Entitled "History" in the 229 | Document, create one stating the title, year, authors, and 230 | publisher of the Document as given on its Title Page, then add 231 | an item describing the Modified Version as stated in the 232 | previous sentence. 233 | 234 | J. Preserve the network location, if any, given in the Document for 235 | public access to a Transparent copy of the Document, and 236 | likewise the network locations given in the Document for 237 | previous versions it was based on. These may be placed in the 238 | "History" section. You may omit a network location for a work 239 | that was published at least four years before the Document 240 | itself, or if the original publisher of the version it refers to 241 | gives permission. 242 | 243 | K. For any section Entitled "Acknowledgements" or "Dedications", 244 | Preserve the Title of the section, and preserve in the section 245 | all the substance and tone of each of the contributor 246 | acknowledgements and/or dedications given therein. 247 | 248 | L. Preserve all the Invariant Sections of the Document, unaltered 249 | in their text and in their titles. Section numbers or the 250 | equivalent are not considered part of the section titles. 251 | 252 | M. Delete any section Entitled "Endorsements". Such a section may 253 | not be included in the Modified Version. 254 | 255 | N. Do not retitle any existing section to be Entitled 256 | "Endorsements" or to conflict in title with any Invariant 257 | Section. 258 | 259 | O. Preserve any Warranty Disclaimers. 260 | 261 | If the Modified Version includes new front-matter sections or 262 | appendices that qualify as Secondary Sections and contain no 263 | material copied from the Document, you may at your option designate 264 | some or all of these sections as invariant. To do this, add their 265 | titles to the list of Invariant Sections in the Modified Version's 266 | license notice. These titles must be distinct from any other 267 | section titles. 268 | 269 | You may add a section Entitled "Endorsements", provided it contains 270 | nothing but endorsements of your Modified Version by various 271 | parties---for example, statements of peer review or that the text 272 | has been approved by an organization as the authoritative 273 | definition of a standard. 274 | 275 | You may add a passage of up to five words as a Front-Cover Text, 276 | and a passage of up to 25 words as a Back-Cover Text, to the end of 277 | the list of Cover Texts in the Modified Version. Only one passage 278 | of Front-Cover Text and one of Back-Cover Text may be added by (or 279 | through arrangements made by) any one entity. If the Document 280 | already includes a cover text for the same cover, previously added 281 | by you or by arrangement made by the same entity you are acting on 282 | behalf of, you may not add another; but you may replace the old 283 | one, on explicit permission from the previous publisher that added 284 | the old one. 285 | 286 | The author(s) and publisher(s) of the Document do not by this 287 | License give permission to use their names for publicity for or to 288 | assert or imply endorsement of any Modified Version. 289 | 290 | 5. COMBINING DOCUMENTS 291 | 292 | You may combine the Document with other documents released under 293 | this License, under the terms defined in section 4 above for 294 | modified versions, provided that you include in the combination all 295 | of the Invariant Sections of all of the original documents, 296 | unmodified, and list them all as Invariant Sections of your 297 | combined work in its license notice, and that you preserve all 298 | their Warranty Disclaimers. 299 | 300 | The combined work need only contain one copy of this License, and 301 | multiple identical Invariant Sections may be replaced with a single 302 | copy. If there are multiple Invariant Sections with the same name 303 | but different contents, make the title of each such section unique 304 | by adding at the end of it, in parentheses, the name of the 305 | original author or publisher of that section if known, or else a 306 | unique number. Make the same adjustment to the section titles in 307 | the list of Invariant Sections in the license notice of the 308 | combined work. 309 | 310 | In the combination, you must combine any sections Entitled 311 | "History" in the various original documents, forming one section 312 | Entitled "History"; likewise combine any sections Entitled 313 | "Acknowledgements", and any sections Entitled "Dedications". You 314 | must delete all sections Entitled "Endorsements." 315 | 316 | 6. COLLECTIONS OF DOCUMENTS 317 | 318 | You may make a collection consisting of the Document and other 319 | documents released under this License, and replace the individual 320 | copies of this License in the various documents with a single copy 321 | that is included in the collection, provided that you follow the 322 | rules of this License for verbatim copying of each of the documents 323 | in all other respects. 324 | 325 | You may extract a single document from such a collection, and 326 | distribute it individually under this License, provided you insert 327 | a copy of this License into the extracted document, and follow this 328 | License in all other respects regarding verbatim copying of that 329 | document. 330 | 331 | 7. AGGREGATION WITH INDEPENDENT WORKS 332 | 333 | A compilation of the Document or its derivatives with other 334 | separate and independent documents or works, in or on a volume of a 335 | storage or distribution medium, is called an "aggregate" if the 336 | copyright resulting from the compilation is not used to limit the 337 | legal rights of the compilation's users beyond what the individual 338 | works permit. When the Document is included in an aggregate, this 339 | License does not apply to the other works in the aggregate which 340 | are not themselves derivative works of the Document. 341 | 342 | If the Cover Text requirement of section 3 is applicable to these 343 | copies of the Document, then if the Document is less than one half 344 | of the entire aggregate, the Document's Cover Texts may be placed 345 | on covers that bracket the Document within the aggregate, or the 346 | electronic equivalent of covers if the Document is in electronic 347 | form. Otherwise they must appear on printed covers that bracket 348 | the whole aggregate. 349 | 350 | 8. TRANSLATION 351 | 352 | Translation is considered a kind of modification, so you may 353 | distribute translations of the Document under the terms of 354 | section 4. Replacing Invariant Sections with translations requires 355 | special permission from their copyright holders, but you may 356 | include translations of some or all Invariant Sections in addition 357 | to the original versions of these Invariant Sections. You may 358 | include a translation of this License, and all the license notices 359 | in the Document, and any Warranty Disclaimers, provided that you 360 | also include the original English version of this License and the 361 | original versions of those notices and disclaimers. In case of a 362 | disagreement between the translation and the original version of 363 | this License or a notice or disclaimer, the original version will 364 | prevail. 365 | 366 | If a section in the Document is Entitled "Acknowledgements", 367 | "Dedications", or "History", the requirement (section 4) to 368 | Preserve its Title (section 1) will typically require changing the 369 | actual title. 370 | 371 | 9. TERMINATION 372 | 373 | You may not copy, modify, sublicense, or distribute the Document 374 | except as expressly provided under this License. Any attempt 375 | otherwise to copy, modify, sublicense, or distribute it is void, 376 | and will automatically terminate your rights under this License. 377 | 378 | However, if you cease all violation of this License, then your 379 | license from a particular copyright holder is reinstated (a) 380 | provisionally, unless and until the copyright holder explicitly and 381 | finally terminates your license, and (b) permanently, if the 382 | copyright holder fails to notify you of the violation by some 383 | reasonable means prior to 60 days after the cessation. 384 | 385 | Moreover, your license from a particular copyright holder is 386 | reinstated permanently if the copyright holder notifies you of the 387 | violation by some reasonable means, this is the first time you have 388 | received notice of violation of this License (for any work) from 389 | that copyright holder, and you cure the violation prior to 30 days 390 | after your receipt of the notice. 391 | 392 | Termination of your rights under this section does not terminate 393 | the licenses of parties who have received copies or rights from you 394 | under this License. If your rights have been terminated and not 395 | permanently reinstated, receipt of a copy of some or all of the 396 | same material does not give you any rights to use it. 397 | 398 | 10. FUTURE REVISIONS OF THIS LICENSE 399 | 400 | The Free Software Foundation may publish new, revised versions of 401 | the GNU Free Documentation License from time to time. Such new 402 | versions will be similar in spirit to the present version, but may 403 | differ in detail to address new problems or concerns. See 404 | http://www.gnu.org/copyleft. 405 | 406 | Each version of the License is given a distinguishing version 407 | number. If the Document specifies that a particular numbered 408 | version of this License "or any later version" applies to it, you 409 | have the option of following the terms and conditions either of 410 | that specified version or of any later version that has been 411 | published (not as a draft) by the Free Software Foundation. If the 412 | Document does not specify a version number of this License, you may 413 | choose any version ever published (not as a draft) by the Free 414 | Software Foundation. If the Document specifies that a proxy can 415 | decide which future versions of this License can be used, that 416 | proxy's public statement of acceptance of a version permanently 417 | authorizes you to choose that version for the Document. 418 | 419 | 11. RELICENSING 420 | 421 | "Massive Multiauthor Collaboration Site" (or "MMC Site") means any 422 | World Wide Web server that publishes copyrightable works and also 423 | provides prominent facilities for anybody to edit those works. A 424 | public wiki that anybody can edit is an example of such a server. 425 | A "Massive Multiauthor Collaboration" (or "MMC") contained in the 426 | site means any set of copyrightable works thus published on the MMC 427 | site. 428 | 429 | "CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 430 | license published by Creative Commons Corporation, a not-for-profit 431 | corporation with a principal place of business in San Francisco, 432 | California, as well as future copyleft versions of that license 433 | published by that same organization. 434 | 435 | "Incorporate" means to publish or republish a Document, in whole or 436 | in part, as part of another Document. 437 | 438 | An MMC is "eligible for relicensing" if it is licensed under this 439 | License, and if all works that were first published under this 440 | License somewhere other than this MMC, and subsequently 441 | incorporated in whole or in part into the MMC, (1) had no cover 442 | texts or invariant sections, and (2) were thus incorporated prior 443 | to November 1, 2008. 444 | 445 | The operator of an MMC Site may republish an MMC contained in the 446 | site under CC-BY-SA on the same site at any time before August 1, 447 | 2009, provided the MMC is eligible for relicensing. 448 | -------------------------------------------------------------------------------- /doc/source/overview.rst: -------------------------------------------------------------------------------- 1 | Overview 2 | ======== 3 | 4 | Evil is an extensible vi layer for Emacs. It emulates the main 5 | features of Vim, [#vim]_ turning Emacs into a modal editor. Like Emacs in 6 | general, Evil is extensible in Emacs Lisp. 7 | 8 | 9 | Installation via package.el 10 | --------------------------- 11 | 12 | Evil is available as a package from MELPA stable, MELPA unstable and 13 | NonGNU ELPA. This is the recommended way of installing Evil. 14 | 15 | To set up `package.el` to work with one of the MELPA repositories, you 16 | can follow the instructions on `melpa.org 17 | `_. 18 | 19 | Alternatively you can use NonGNU ELPA. It is part of the default 20 | package archives as of Emacs 28. For older Emacs versions you'll need 21 | to add it yourself: 22 | 23 | .. code-block:: elisp 24 | 25 | (add-to-list 'package-archives 26 | (cons "nongnu" (format "http%s://elpa.nongnu.org/nongnu/" 27 | (if (gnutls-available-p) "s" "")))) 28 | 29 | Once that is done, you can execute the following commands:: 30 | 31 | M-x package-refresh-contents 32 | M-x package-install RET evil RET 33 | 34 | Finally, add the following lines to your Emacs init file: 35 | 36 | .. code-block:: elisp 37 | 38 | (require 'evil) 39 | (evil-mode 1) 40 | 41 | 42 | Manual installation 43 | ------------------- 44 | 45 | First, install `goto-chg` and `cl-lib`. If you have an Emacs version 46 | of 24.3 or newer, you should already have `cl-lib`. 47 | 48 | Evil lives in a git repository. To download Evil, do:: 49 | 50 | git clone --depth 1 https://github.com/emacs-evil/evil.git 51 | 52 | Then add the following lines to your Emacs init file: 53 | 54 | .. code-block:: elisp 55 | 56 | (add-to-list 'load-path "path/to/evil") 57 | (require 'evil) 58 | (evil-mode 1) 59 | 60 | Ensure that your replace ``path/to/evil`` with the actual path to 61 | where you cloned Evil. 62 | 63 | 64 | Modes and states 65 | ---------------- 66 | 67 | The next time Emacs is started, it will come up in *normal state*, 68 | denoted by ```` in the mode line. This is where the main vi 69 | bindings are defined. Note that you can always disable normal state 70 | with :kbd:`C-z`, which switches to an "Emacs state" (denoted by 71 | ````) in which vi keys are completely disabled. Press :kbd:`C-z` 72 | again to switch back to normal state. 73 | 74 | state 75 | Evil uses the term *state* for what is called a "mode" in regular vi 76 | usage, because *modes* are understood in Emacs terms to mean 77 | something else. 78 | 79 | Evil defines a number of states by default: 80 | 81 | normal state (````) 82 | This is the default "resting state" of Evil, in which the main body 83 | of vi bindings are defined. 84 | 85 | insert state (````) 86 | This is the state for insertion of text, where non-modified keys 87 | will insert the corresponding character in the buffer. 88 | 89 | visual state (````) 90 | A state for selecting text regions. Motions are available for 91 | modifying the selected region, and operators are available for 92 | acting on it. 93 | 94 | replace state (````) 95 | A special state mostly similar to insert state, except it replaces 96 | text instead of inserting. 97 | 98 | operator-pending state (````) 99 | A special state entered after launching an operator, but before 100 | specifying the corresponding motion or text object. 101 | 102 | motion state (````) 103 | A special state useful for buffers that are read-only, where motions 104 | are available but editing operations are not. 105 | 106 | Emacs state (````) 107 | A state that as closely as possible mimics default Emacs behaviour, 108 | by eliminating all vi bindings, except for :kbd:`C-z`, to re-enter 109 | normal state. 110 | 111 | 112 | .. rubric:: Footnotes 113 | 114 | .. [#vim] Vim is the most popular version of *vi*, a modal text editor 115 | with many implementations. Vim also adds some functions of its 116 | own, like visual selection and text objects. For more information 117 | see `the official Vim website `_. 118 | -------------------------------------------------------------------------------- /doc/source/settings.rst: -------------------------------------------------------------------------------- 1 | Settings 2 | ======== 3 | 4 | Evil's behaviour can be adjusted by setting some variables. The list 5 | of all available variables and their current values can be inspected 6 | by doing:: 7 | 8 | M-x customize-group RET evil RET 9 | 10 | To change the value of a variable, you can use this interface, or add 11 | a ``setq`` form to your Emacs init file, preferably before Evil is 12 | loaded. [#order]_ 13 | 14 | .. code-block:: elisp 15 | 16 | (setq evil-shift-width 0) 17 | ;; Load Evil 18 | (require 'evil) 19 | 20 | What follows is a non-exhaustive list of the most relevant 21 | customization options. 22 | 23 | 24 | The initial state 25 | ----------------- 26 | 27 | The initial state of a buffer is determined by its major mode. Evil 28 | maintains an association between major modes and their corresponding 29 | states, which is most easily modified using the function 30 | :elisp:ref:`evil-set-initial-state`. 31 | 32 | .. elisp:autofunction:: evil-set-initial-state 33 | 34 | If no state can be found, Evil uses the default initial state. 35 | 36 | .. elisp:autovariable:: evil-default-state 37 | 38 | Alternatively, it is possible to select the initial state based on the 39 | buffer *name* rather than its major mode. This is checked first, so 40 | it takes precedence over the other methods for setting the state. 41 | 42 | .. elisp:autovariable:: evil-buffer-regexps 43 | 44 | 45 | Keybindings and other behaviour 46 | ------------------------------- 47 | 48 | Evil comes with a rich system for modifying its key bindings 49 | :ref:`chapter-keymaps`. For the most common tweaks, the following 50 | variables are available. 51 | 52 | .. elisp:autovariable:: evil-toggle-key 53 | 54 | .. elisp:autovariable:: evil-want-C-i-jump 55 | 56 | .. elisp:autovariable:: evil-want-C-u-delete 57 | 58 | .. elisp:autovariable:: evil-want-C-u-scroll 59 | 60 | .. elisp:autovariable:: evil-want-C-d-scroll 61 | 62 | .. elisp:autovariable:: evil-want-C-w-delete 63 | 64 | .. elisp:autovariable:: evil-want-C-w-in-emacs-state 65 | 66 | .. elisp:autovariable:: evil-want-Y-yank-to-eol 67 | 68 | .. elisp:autovariable:: evil-disable-insert-state-bindings 69 | 70 | 71 | Search 72 | ------ 73 | 74 | .. elisp:autovariable:: evil-search-module 75 | 76 | .. elisp:autovariable:: evil-regexp-search 77 | 78 | .. elisp:autovariable:: evil-search-wrap 79 | 80 | .. elisp:autovariable:: evil-flash-delay 81 | 82 | .. elisp:autovariable:: evil-ex-hl-update-delay 83 | 84 | .. elisp:autovariable:: evil-ex-search-incremental 85 | 86 | 87 | Indentation 88 | ----------- 89 | 90 | .. elisp:autovariable:: evil-auto-indent 91 | 92 | .. elisp:autovariable:: evil-shift-width 93 | 94 | .. elisp:autovariable:: evil-shift-round 95 | 96 | .. elisp:autovariable:: evil-indent-convert-tabs 97 | 98 | 99 | Cursor movement 100 | --------------- 101 | 102 | In standard Emacs terms, the cursor is generally understood to be 103 | located between two characters. In Vim, and therefore also Evil, this 104 | is the case in insert state, but in other states the cursor is 105 | understood to be *on* a character, and that this character is not a 106 | newline. 107 | 108 | Forcing this behaviour in Emacs is the source of some potentially 109 | surprising results (especially for traditional Emacs users---users 110 | used to Vim may find the default behavior to their satisfaction). Many 111 | of them can be tweaked using the following variables. 112 | 113 | .. elisp:autovariable:: evil-repeat-move-cursor 114 | 115 | .. elisp:autovariable:: evil-move-cursor-back 116 | 117 | .. elisp:autovariable:: evil-move-beyond-eol 118 | 119 | .. elisp:autovariable:: evil-v$-excludes-newline 120 | 121 | .. elisp:autovariable:: evil-cross-lines 122 | 123 | .. elisp:autovariable:: evil-respect-visual-line-mode 124 | 125 | .. elisp:autovariable:: evil-track-eol 126 | 127 | .. elisp:autovariable:: evil-start-of-line 128 | 129 | 130 | Cursor display 131 | -------------- 132 | 133 | A state may change the appearance of the cursor. Use the variable 134 | :elisp:ref:`evil-default-cursor` to set the default cursor, and the 135 | variables ``evil-normal-state-cursor``, ``evil-insert-state-cursor`` 136 | etc. to set the cursors for specific states. The acceptable values 137 | for all of them are the same. 138 | 139 | .. elisp:autovariable:: evil-default-cursor 140 | 141 | 142 | Window management 143 | ----------------- 144 | 145 | .. elisp:autovariable:: evil-auto-balance-windows 146 | 147 | .. elisp:autovariable:: evil-split-window-below 148 | 149 | .. elisp:autovariable:: evil-vsplit-window-right 150 | 151 | 152 | Parenthesis highlighting 153 | ------------------------ 154 | 155 | These settings concern the integration between Evil and 156 | ``show-paren-mode``. They take no effect if this mode is not enabled. 157 | 158 | .. elisp:autovariable:: evil-show-paren-range 159 | 160 | .. elisp:autovariable:: evil-highlight-closing-paren-at-point-states 161 | 162 | 163 | Miscellaneous 164 | ------------- 165 | 166 | .. elisp:autovariable:: evil-want-fine-undo 167 | 168 | .. elisp:autovariable:: evil-undo-system 169 | 170 | .. elisp:autovariable:: evil-backspace-join-lines 171 | 172 | .. elisp:autovariable:: evil-kbd-macro-suppress-motion-error 173 | 174 | .. elisp:autovariable:: evil-mode-line-format 175 | 176 | .. elisp:autovariable:: evil-mouse-word 177 | 178 | .. elisp:autovariable:: evil-transient-mouse-selection 179 | 180 | .. elisp:autovariable:: evil-bigword 181 | 182 | .. elisp:autovariable:: evil-esc-delay 183 | 184 | .. elisp:autovariable:: evil-intercept-esc 185 | 186 | .. elisp:autovariable:: evil-kill-on-visual-paste 187 | 188 | .. elisp:autovariable:: evil-echo-state 189 | 190 | .. elisp:autovariable:: evil-complete-all-buffers 191 | 192 | .. elisp:autovariable:: evil-want-empty-ex-last-command 193 | 194 | 195 | .. rubric:: Footnotes 196 | 197 | .. [#order] Strictly speaking, the order only matters if the variable 198 | affects the way Evil is loaded. This is the case with some 199 | variables. 200 | -------------------------------------------------------------------------------- /evil-command-window.el: -------------------------------------------------------------------------------- 1 | ;;; evil-command-window.el --- Evil command-line window -*- lexical-binding: t -*- 2 | ;; Author: Emanuel Evans 3 | ;; Maintainer: Vegard Øye 4 | 5 | ;; Version: 1.15.0 6 | 7 | ;; 8 | ;; This file is NOT part of GNU Emacs. 9 | 10 | ;;; License: 11 | 12 | ;; This file is part of Evil. 13 | ;; 14 | ;; Evil is free software: you can redistribute it and/or modify 15 | ;; it under the terms of the GNU General Public License as published by 16 | ;; the Free Software Foundation, either version 3 of the License, or 17 | ;; (at your option) any later version. 18 | ;; 19 | ;; Evil is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | ;; 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with Evil. If not, see . 26 | 27 | ;;; Commentary: 28 | 29 | ;; This provides an implementation of the Vim command-line window for 30 | ;; editing and repeating past Ex commands and searches. 31 | 32 | ;;; Code: 33 | 34 | (require 'evil-vars) 35 | (require 'evil-common) 36 | (require 'evil-ex) 37 | (require 'evil-search) 38 | 39 | (defvar evil-search-module) 40 | 41 | (defvar evil-command-window-current-buffer nil 42 | "The buffer from which the command-line window was called.") 43 | 44 | (defvar evil-command-window-execute-fn nil 45 | "The command to execute when exiting the command-line window.") 46 | 47 | (defvar evil--command-window-prompt nil 48 | "The key for the command that opened the command-line window (:, /, or ?).") 49 | 50 | (define-derived-mode evil-command-window-mode fundamental-mode "Evil-cmd" 51 | "Major mode for the Evil command-line window." 52 | (add-hook 'after-change-functions #'evil--command-window-draw-prefix nil t) 53 | (auto-fill-mode 0)) 54 | 55 | (defun evil-command-window (history prompt execute-fn) 56 | "Open a command-line window for HISTORY with PROMPT and EXECUTE-FN. 57 | HISTORY should be a list of commands. PROMPT should be the 58 | command-line prompt (one of \":\", \"/\" or \"?\"). EXECUTE-FN should 59 | be a unary function to execute on the result that the user selects. 60 | 61 | If called interactively, edit this minibuffer argument." 62 | (interactive 63 | (list (cons (minibuffer-contents) (minibuffer-history-value)) 64 | (or (minibuffer-prompt) (user-error "Minibuffer is inactive")) 65 | #'evil--command-window-minibuffer-execute)) 66 | (when (derived-mode-p 'evil-command-window-mode) 67 | (user-error "Command-line window is already open")) 68 | (when (evil-ex-p) (evil-ex-teardown)) 69 | (let ((previous-buffer (current-buffer)) 70 | (buffer (get-buffer-create "*Command Line*"))) 71 | (with-current-buffer buffer 72 | (erase-buffer) 73 | (evil-command-window-mode) 74 | (setq-local evil-command-window-current-buffer previous-buffer) 75 | (setq-local evil-command-window-execute-fn execute-fn) 76 | (setq-local evil--command-window-prompt prompt) 77 | (evil--command-window-insert-commands history)) 78 | 79 | (let* ((action 80 | `((display-buffer-reuse-window display-buffer-at-bottom) 81 | ,@(unless (zerop evil-command-window-height) 82 | `((window-height body-lines . ,evil-command-window-height) 83 | (preserve-size nil . t))) 84 | (dedicated . t))) 85 | (window (display-buffer buffer action)) 86 | (delete-window-fun 87 | (lambda (window) 88 | (set-window-parameter window 'delete-window nil) 89 | (delete-window window) 90 | (switch-to-minibuffer)))) 91 | (when (minibufferp) 92 | (set-window-parameter window 'delete-window delete-window-fun)) 93 | (select-window window))) 94 | (goto-char (point-max)) 95 | (unless (bobp) (backward-char) (evil-adjust-cursor))) 96 | 97 | (defun evil--command-window-draw-prefix (beg end _old-len) 98 | "Display `evil--command-window-prompt' as a prefix of the changed lines." 99 | (let ((prefix (propertize evil--command-window-prompt 100 | 'font-lock-face 'minibuffer-prompt))) 101 | (put-text-property beg end 'line-prefix prefix))) 102 | 103 | (defun evil--command-window-insert-commands (history) 104 | "Insert the commands in HISTORY." 105 | (let ((inhibit-modification-hooks t)) 106 | (dolist (cmd (reverse history)) (insert cmd "\n")) 107 | (evil--command-window-draw-prefix (point-min) (point-max) nil))) 108 | 109 | (defun evil-command-window-execute () 110 | "Execute the command on the current line in the appropriate buffer. 111 | The local variable `evil-command-window-execute-fn' determines which 112 | function to execute." 113 | (interactive) 114 | (let ((result (buffer-substring-no-properties 115 | (line-beginning-position) (line-end-position))) 116 | (original-buffer evil-command-window-current-buffer) 117 | (execute-fn evil-command-window-execute-fn)) 118 | (let ((ignore-window-parameters t)) 119 | (ignore-errors (kill-buffer-and-window))) 120 | (unless (buffer-live-p original-buffer) 121 | (user-error "Originating buffer is no longer active")) 122 | (let ((window (get-buffer-window original-buffer))) 123 | (when window (select-window window))) 124 | (with-current-buffer original-buffer (funcall execute-fn result)))) 125 | 126 | (defun evil--command-window-minibuffer-execute (result) 127 | "Terminate this minibuffer argument with RESULT." 128 | (delete-minibuffer-contents) 129 | (insert result) 130 | (exit-minibuffer)) 131 | 132 | (defun evil-command-window-ex (&optional current-command) 133 | "Open a command-line window for editing and executing Ex commands. 134 | If CURRENT-COMMAND is present, it will be inserted under the cursor as 135 | the current command to be edited." 136 | (interactive) 137 | (evil-command-window (cons (or current-command "") evil-ex-history) 138 | ":" 139 | #'evil-command-window-ex-execute)) 140 | 141 | (define-obsolete-function-alias 142 | 'evil-ex-command-window #'evil-command-window "1.15.0" 143 | "Start command window with Ex history and current minibuffer content.") 144 | 145 | (define-obsolete-function-alias 146 | 'evil-ex-search-command-window #'evil-command-window "1.15.0" 147 | "Start command window with search history and current minibuffer content.") 148 | 149 | (defun evil-command-window-ex-execute (result) 150 | "Execute RESULT as an Ex command." 151 | (unless (string-match-p "\\`[ \t\n\r]*\\'" result) 152 | (unless (equal result (car evil-ex-history)) 153 | (push result evil-ex-history)) 154 | (evil-ex-execute result))) 155 | 156 | (defun evil--command-window-search (forward) 157 | "Open a command-line window for searches." 158 | (evil-command-window 159 | (cons "" (cond ((eq evil-search-module 'evil-search) 160 | evil-ex-search-history) 161 | (forward evil-search-forward-history) 162 | (t evil-search-backward-history))) 163 | (evil-search-prompt forward) 164 | (lambda (result) (evil-command-window-search-execute result forward)))) 165 | 166 | (defun evil-command-window-search-forward () 167 | "Open a command-line window for forward searches." 168 | (interactive) 169 | (evil--command-window-search t)) 170 | 171 | (defun evil-command-window-search-backward () 172 | "Open a command-line window for backward searches." 173 | (interactive) 174 | (evil--command-window-search nil)) 175 | 176 | (defun evil-command-window-search-execute (result forward) 177 | "Search for RESULT using FORWARD to determine direction." 178 | (unless (string= result "") 179 | (if (eq evil-search-module 'evil-search) 180 | (progn 181 | (setq evil-ex-search-pattern (evil-ex-make-search-pattern result) 182 | evil-ex-search-direction (if forward 'forward 'backward)) 183 | (unless (equal result (car evil-ex-search-history)) 184 | (push result evil-ex-search-history)) 185 | (evil-ex-search)) 186 | (evil-push-search-history result forward) 187 | (evil-search result forward evil-regexp-search)))) 188 | 189 | (provide 'evil-command-window) 190 | 191 | ;;; evil-command-window.el ends here 192 | -------------------------------------------------------------------------------- /evil-development.el: -------------------------------------------------------------------------------- 1 | ;;; evil-development.el --- Useful features for Evil developers -*- lexical-binding: t -*- 2 | 3 | ;; Author: Justin Burkett 4 | 5 | ;; Version: 1.15.0 6 | 7 | ;; 8 | ;; This file is NOT part of GNU Emacs. 9 | 10 | ;;; License: 11 | 12 | ;; This file is part of Evil. 13 | ;; 14 | ;; Evil is free software: you can redistribute it and/or modify 15 | ;; it under the terms of the GNU General Public License as published by 16 | ;; the Free Software Foundation, either version 3 of the License, or 17 | ;; (at your option) any later version. 18 | ;; 19 | ;; Evil is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | ;; 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with Evil. If not, see . 26 | 27 | ;;; Code: 28 | 29 | ;;; Teach imenu about evil macros 30 | 31 | (with-eval-after-load 'lisp-mode 32 | (when (boundp 'lisp-imenu-generic-expression) 33 | (dolist (macro '("interactive-code" 34 | "type" 35 | "text-object" 36 | "motion" 37 | "command" 38 | "operator")) 39 | (let ((macro-name (format "evil-%s" macro))) 40 | (unless (assoc macro-name lisp-imenu-generic-expression) 41 | (push (list 42 | macro-name 43 | (format "^\\s-*(evil-define-%s\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 44 | macro) 45 | 1) 46 | lisp-imenu-generic-expression)))))) 47 | 48 | (provide 'evil-development) 49 | 50 | ;;; evil-development.el ends here 51 | -------------------------------------------------------------------------------- /evil-integration.el: -------------------------------------------------------------------------------- 1 | ;;; evil-integration.el --- Integrate Evil with other modules -*- lexical-binding: t -*- 2 | 3 | ;; Author: Vegard Øye 4 | ;; Maintainer: Vegard Øye 5 | 6 | ;; Version: 1.15.0 7 | 8 | ;; 9 | ;; This file is NOT part of GNU Emacs. 10 | 11 | ;;; License: 12 | 13 | ;; This file is part of Evil. 14 | ;; 15 | ;; Evil is free software: you can redistribute it and/or modify 16 | ;; it under the terms of the GNU General Public License as published by 17 | ;; the Free Software Foundation, either version 3 of the License, or 18 | ;; (at your option) any later version. 19 | ;; 20 | ;; Evil is distributed in the hope that it will be useful, 21 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | ;; GNU General Public License for more details. 24 | ;; 25 | ;; You should have received a copy of the GNU General Public License 26 | ;; along with Evil. If not, see . 27 | 28 | ;;; Commentary: 29 | 30 | ;; This provides evil integration for various emacs modes. 31 | ;; Additional keybindings (or default state) should go into evil-keybindings.el. 32 | 33 | ;;; Code: 34 | 35 | (require 'evil-maps) 36 | (require 'evil-core) 37 | (require 'evil-macros) 38 | (require 'evil-types) 39 | (require 'evil-repeat) 40 | 41 | ;;; Evilize some commands 42 | 43 | ;; unbound keys should be ignored 44 | (evil-declare-ignore-repeat 'undefined) 45 | 46 | (mapc #'(lambda (cmd) 47 | (evil-set-command-property cmd :keep-visual t) 48 | (evil-declare-not-repeat cmd)) 49 | '(digit-argument 50 | negative-argument 51 | universal-argument 52 | universal-argument-minus 53 | universal-argument-more 54 | universal-argument-other-key)) 55 | (mapc #'evil-declare-not-repeat 56 | '(what-cursor-position)) 57 | (mapc #'evil-declare-change-repeat 58 | '(dabbrev-expand 59 | hippie-expand 60 | quoted-insert)) 61 | (mapc #'evil-declare-abort-repeat 62 | '(balance-windows 63 | eval-expression 64 | execute-extended-command 65 | exit-minibuffer 66 | compile 67 | delete-window 68 | delete-other-windows 69 | find-file-at-point 70 | ffap-other-window 71 | recompile 72 | redo 73 | save-buffer 74 | split-window 75 | split-window-horizontally 76 | split-window-vertically 77 | undo 78 | undo-tree-redo 79 | undo-tree-undo)) 80 | 81 | (evil-set-type #'previous-line 'line) 82 | (evil-set-type #'next-line 'line) 83 | 84 | (dolist (cmd '(keyboard-quit keyboard-escape-quit)) 85 | (evil-set-command-property cmd :suppress-operator t)) 86 | 87 | ;;; Mouse 88 | (evil-declare-insert-at-point-repeat 'mouse-yank-primary) 89 | (evil-declare-insert-at-point-repeat 'mouse-yank-secondary) 90 | 91 | ;;; key-binding 92 | 93 | ;; Calling `keyboard-quit' should cancel repeat 94 | (advice-add 'keyboard-quit :before #'evil-repeat-abort) 95 | 96 | (add-hook 'wdired-mode-hook #'evil-change-to-initial-state) 97 | (advice-add 'wdired-change-to-dired-mode :after 98 | #'evil--change-to-initial-state-with-msg) 99 | (defun evil--change-to-initial-state-with-msg (&rest _) 100 | (evil-change-to-initial-state nil t)) 101 | 102 | ;;; Parentheses 103 | 104 | (evil--advice-add 'show-paren-function :around #'evil--match-paren-in-normal-state) 105 | (defun evil--match-paren-in-normal-state (orig-fun &rest args) 106 | "Match parentheses in Normal state." 107 | (if (eq (not (memq 'not evil-highlight-closing-paren-at-point-states)) 108 | (not (memq evil-state evil-highlight-closing-paren-at-point-states))) 109 | (apply orig-fun args) 110 | (let* ((orig-spdf show-paren-data-function) 111 | (show-paren-data-function 112 | (lambda () 113 | (let ((pos (point)) narrow) 114 | (setq 115 | pos (cl-dotimes (i (1+ (* 2 evil-show-paren-range))) 116 | (setq pos (+ pos (if (cl-evenp i) i (- i)))) 117 | (pcase (syntax-class (syntax-after pos)) 118 | (4 (setq narrow pos) (cl-return pos)) 119 | (5 (cl-return (1+ pos)))))) 120 | (when pos 121 | (save-excursion 122 | (goto-char pos) 123 | (save-restriction 124 | (when narrow (narrow-to-region narrow (point-max))) 125 | (funcall orig-spdf)))))))) 126 | (apply orig-fun args)))) 127 | 128 | ;;; Undo tree 129 | (eval-after-load 'undo-tree 130 | '(with-no-warnings 131 | (evil-ex-define-cmd "undol[ist]" 'undo-tree-visualize) 132 | (evil-ex-define-cmd "ul" 'undo-tree-visualize) 133 | 134 | (define-key undo-tree-visualizer-mode-map 135 | [remap evil-backward-char] 'undo-tree-visualize-switch-branch-left) 136 | (define-key undo-tree-visualizer-mode-map 137 | [remap evil-forward-char] 'undo-tree-visualize-switch-branch-right) 138 | (define-key undo-tree-visualizer-mode-map 139 | [remap evil-next-line] 'undo-tree-visualize-redo) 140 | (define-key undo-tree-visualizer-mode-map 141 | [remap evil-previous-line] 'undo-tree-visualize-undo) 142 | (define-key undo-tree-visualizer-mode-map 143 | [remap evil-ret] 'undo-tree-visualizer-set) 144 | 145 | (define-key undo-tree-visualizer-selection-mode-map 146 | [remap evil-backward-char] 'undo-tree-visualizer-select-left) 147 | (define-key undo-tree-visualizer-selection-mode-map 148 | [remap evil-forward-char] 'undo-tree-visualizer-select-right) 149 | (define-key undo-tree-visualizer-selection-mode-map 150 | [remap evil-next-line] 'undo-tree-visualizer-select-next) 151 | (define-key undo-tree-visualizer-selection-mode-map 152 | [remap evil-previous-line] 'undo-tree-visualizer-select-previous) 153 | (define-key undo-tree-visualizer-selection-mode-map 154 | [remap evil-ret] 'undo-tree-visualizer-set))) 155 | 156 | ;;; Auto-complete 157 | (eval-after-load 'auto-complete 158 | '(progn 159 | (evil-add-command-properties 'auto-complete :repeat 'evil-ac-repeat) 160 | (evil-add-command-properties 'ac-complete :repeat 'evil-ac-repeat) 161 | (evil-add-command-properties 'ac-expand :repeat 'evil-ac-repeat) 162 | (evil-add-command-properties 'ac-next :repeat 'ignore) 163 | (evil-add-command-properties 'ac-previous :repeat 'ignore) 164 | 165 | (defvar evil-ac-prefix-len nil 166 | "The length of the prefix of the current item to be completed.") 167 | 168 | (defvar ac-prefix) 169 | (defun evil-ac-repeat (flag) 170 | "Record the changes for auto-completion." 171 | (cond 172 | ((eq flag 'pre) 173 | (setq evil-ac-prefix-len (length ac-prefix)) 174 | (evil-repeat-start-record-changes)) 175 | ((eq flag 'post) 176 | ;; Add change to remove the prefix 177 | (evil-repeat-record-change (- evil-ac-prefix-len) 178 | "" 179 | evil-ac-prefix-len) 180 | ;; Add change to insert the full completed text 181 | (evil-repeat-record-change 182 | (- evil-ac-prefix-len) 183 | (buffer-substring-no-properties (- evil-repeat-pos 184 | evil-ac-prefix-len) 185 | (point)) 186 | 0) 187 | ;; Finish repeation 188 | (evil-repeat-finish-record-changes)))))) 189 | 190 | ;;; Company 191 | (eval-after-load 'company 192 | '(progn 193 | (mapc #'evil-declare-change-repeat 194 | '(company-complete-mouse 195 | company-complete-number 196 | company-complete-selection 197 | company-complete-common)) 198 | 199 | (mapc #'evil-declare-ignore-repeat 200 | '(company-abort 201 | company-select-next 202 | company-select-previous 203 | company-select-next-or-abort 204 | company-select-previous-or-abort 205 | company-select-mouse 206 | company-show-doc-buffer 207 | company-show-location 208 | company-search-candidates 209 | company-filter-candidates)))) 210 | 211 | ;;; Eval last sexp 212 | (defun evil--preceding-sexp (command &rest args) 213 | "In Normal- or Motion-state, allow last sexp to end at point." 214 | (save-excursion 215 | (or evil-move-beyond-eol 216 | (eolp) 217 | (not (or (evil-normal-state-p) (evil-motion-state-p))) 218 | (forward-char)) 219 | (apply command args))) 220 | (advice-add 'elisp--preceding-sexp :around #'evil--preceding-sexp) 221 | (advice-add 'pp-last-sexp :around #'evil--preceding-sexp) 222 | (advice-add 'lisp-eval-last-sexp :around #'evil--preceding-sexp) 223 | 224 | ;;; Show key 225 | (advice-add 'quail-show-key :around #'evil--in-emacs-state) 226 | (advice-add 'describe-char :around #'evil--in-emacs-state) 227 | (defun evil--in-emacs-state (orig-fun &rest args) 228 | "Temporarily enter Emacs-state and apply ORIG-FUN to ARGS." 229 | (evil-with-state emacs (apply orig-fun args))) 230 | 231 | ;;; ace-jump-mode 232 | (declare-function ace-jump-char-mode "ext:ace-jump-mode") 233 | (declare-function ace-jump-word-mode "ext:ace-jump-mode") 234 | (declare-function ace-jump-line-mode "ext:ace-jump-mode") 235 | (defvar ace-jump-mode-scope) 236 | 237 | (defvar evil-ace-jump-active nil) 238 | 239 | (defmacro evil-enclose-ace-jump-for-motion (&rest body) 240 | "Enclose ace-jump to make it suitable for motions. 241 | This includes restricting `ace-jump-mode' to the current window 242 | in visual and operator state, deactivating visual updates, saving 243 | the mark and entering `recursive-edit'." 244 | (declare (indent defun) 245 | (debug t)) 246 | `(let ((old-mark (mark)) 247 | (ace-jump-mode-scope 248 | (if (and (not (memq evil-state '(visual operator))) 249 | (boundp 'ace-jump-mode-scope)) 250 | ace-jump-mode-scope 251 | 'window))) 252 | (remove-hook 'pre-command-hook #'evil-visual-pre-command t) 253 | (remove-hook 'post-command-hook #'evil-visual-post-command t) 254 | (unwind-protect 255 | (let ((evil-ace-jump-active 'prepare)) 256 | (add-hook 'ace-jump-mode-end-hook 257 | #'evil-ace-jump-exit-recursive-edit) 258 | ,@body 259 | (when evil-ace-jump-active 260 | (setq evil-ace-jump-active t) 261 | (recursive-edit))) 262 | (remove-hook 'post-command-hook 263 | #'evil-ace-jump-exit-recursive-edit) 264 | (remove-hook 'ace-jump-mode-end-hook 265 | #'evil-ace-jump-exit-recursive-edit) 266 | (if (evil-visual-state-p) 267 | (progn 268 | (add-hook 'pre-command-hook #'evil-visual-pre-command nil t) 269 | (add-hook 'post-command-hook #'evil-visual-post-command nil t) 270 | (set-mark old-mark)) 271 | (push-mark old-mark))))) 272 | 273 | (advice-add 'ace-jump-done :after #'evil--after-ace-jump-done) 274 | (defun evil--after-ace-jump-done (&rest _) 275 | (when evil-ace-jump-active 276 | (add-hook 'post-command-hook #'evil-ace-jump-exit-recursive-edit))) 277 | 278 | (defun evil-ace-jump-exit-recursive-edit () 279 | "Exit a recursive edit caused by an evil jump." 280 | (cond 281 | ((eq evil-ace-jump-active 'prepare) 282 | (setq evil-ace-jump-active nil)) 283 | (evil-ace-jump-active 284 | (remove-hook 'post-command-hook #'evil-ace-jump-exit-recursive-edit) 285 | (exit-recursive-edit)))) 286 | 287 | (evil-define-motion evil-ace-jump-char-mode (_count) 288 | "Jump visually directly to a char using ace-jump." 289 | :type inclusive 290 | (evil-without-repeat 291 | (let ((pnt (point)) 292 | (buf (current-buffer))) 293 | (evil-enclose-ace-jump-for-motion 294 | (call-interactively 'ace-jump-char-mode)) 295 | ;; if we jump backwards, motion type is exclusive, analogously 296 | ;; to `evil-find-char-backward' 297 | (when (and (equal buf (current-buffer)) 298 | (< (point) pnt)) 299 | (setq evil-this-type 300 | (cond 301 | ((eq evil-this-type 'exclusive) 'inclusive) 302 | ((eq evil-this-type 'inclusive) 'exclusive))))))) 303 | 304 | (evil-define-motion evil-ace-jump-char-to-mode (_count) 305 | "Jump visually to the char in front of a char using ace-jump." 306 | :type inclusive 307 | (evil-without-repeat 308 | (let ((pnt (point)) 309 | (buf (current-buffer))) 310 | (evil-enclose-ace-jump-for-motion 311 | (call-interactively 'ace-jump-char-mode)) 312 | (if (and (equal buf (current-buffer)) 313 | (< (point) pnt)) 314 | (progn 315 | (or (eobp) (forward-char)) 316 | (setq evil-this-type 317 | (cond 318 | ((eq evil-this-type 'exclusive) 'inclusive) 319 | ((eq evil-this-type 'inclusive) 'exclusive)))) 320 | (backward-char))))) 321 | 322 | (evil-define-motion evil-ace-jump-line-mode (_count) 323 | "Jump visually to the beginning of a line using ace-jump." 324 | :type line 325 | :repeat abort 326 | (evil-without-repeat 327 | (evil-enclose-ace-jump-for-motion 328 | (call-interactively 'ace-jump-line-mode)))) 329 | 330 | (evil-define-motion evil-ace-jump-word-mode (_count) 331 | "Jump visually to the beginning of a word using ace-jump." 332 | :type exclusive 333 | :repeat abort 334 | (evil-without-repeat 335 | (evil-enclose-ace-jump-for-motion 336 | (call-interactively 'ace-jump-word-mode)))) 337 | 338 | (define-key evil-motion-state-map [remap ace-jump-char-mode] #'evil-ace-jump-char-mode) 339 | (define-key evil-motion-state-map [remap ace-jump-line-mode] #'evil-ace-jump-line-mode) 340 | (define-key evil-motion-state-map [remap ace-jump-word-mode] #'evil-ace-jump-word-mode) 341 | 342 | ;;; avy 343 | (declare-function avy-goto-word-or-subword-1 "ext:avy") 344 | (declare-function avy-goto-line "ext:avy") 345 | (declare-function avy-goto-char "ext:avy") 346 | (declare-function avy-goto-char-2 "ext:avy") 347 | (declare-function avy-goto-char-2-above "ext:avy") 348 | (declare-function avy-goto-char-2-below "ext:avy") 349 | (declare-function avy-goto-char-in-line "ext:avy") 350 | (declare-function avy-goto-word-0 "ext:avy") 351 | (declare-function avy-goto-word-1 "ext:avy") 352 | (declare-function avy-goto-word-1-above "ext:avy") 353 | (declare-function avy-goto-word-1-below "ext:avy") 354 | (declare-function avy-goto-subword-0 "ext:avy") 355 | (declare-function avy-goto-subword-1 "ext:avy") 356 | (declare-function avy-goto-char-timer "ext:avy") 357 | (defvar avy-all-windows) 358 | 359 | (defmacro evil-enclose-avy-for-motion (&rest body) 360 | "Enclose avy to make it suitable for motions. 361 | Based on `evil-enclose-ace-jump-for-motion'." 362 | (declare (indent defun) 363 | (debug t)) 364 | `(let ((avy-all-windows 365 | (if (and (not (memq evil-state '(visual operator))) 366 | (boundp 'avy-all-windows)) 367 | avy-all-windows 368 | nil))) 369 | ,@body)) 370 | 371 | (defmacro evil-define-avy-motion (command type) 372 | (declare (indent defun) 373 | (debug t)) 374 | (let ((name (intern (format "evil-%s" command)))) 375 | `(evil-define-motion ,name (_count) 376 | ,(format "Evil motion for `%s'." command) 377 | :type ,type 378 | :jump t 379 | :repeat abort 380 | (evil-without-repeat 381 | (evil-enclose-avy-for-motion 382 | (call-interactively ',command)))))) 383 | 384 | ;; define evil-avy-* motion commands for avy-* commands 385 | (evil-define-avy-motion avy-goto-char inclusive) 386 | (evil-define-avy-motion avy-goto-char-2 inclusive) 387 | (evil-define-avy-motion avy-goto-char-2-above inclusive) 388 | (evil-define-avy-motion avy-goto-char-2-below inclusive) 389 | (evil-define-avy-motion avy-goto-char-in-line inclusive) 390 | (evil-define-avy-motion avy-goto-char-timer inclusive) 391 | (evil-define-avy-motion avy-goto-line line) 392 | (evil-define-avy-motion avy-goto-line-above line) 393 | (evil-define-avy-motion avy-goto-line-below line) 394 | (evil-define-avy-motion avy-goto-subword-0 exclusive) 395 | (evil-define-avy-motion avy-goto-subword-1 exclusive) 396 | (evil-define-avy-motion avy-goto-symbol-1 exclusive) 397 | (evil-define-avy-motion avy-goto-symbol-1-above exclusive) 398 | (evil-define-avy-motion avy-goto-symbol-1-below exclusive) 399 | (evil-define-avy-motion avy-goto-word-0 exclusive) 400 | (evil-define-avy-motion avy-goto-word-1 exclusive) 401 | (evil-define-avy-motion avy-goto-word-1-above exclusive) 402 | (evil-define-avy-motion avy-goto-word-1-below exclusive) 403 | (evil-define-avy-motion avy-goto-word-or-subword-1 exclusive) 404 | 405 | ;; remap avy-* commands to evil-avy-* commands 406 | (dolist (command '(avy-goto-char 407 | avy-goto-char-2 408 | avy-goto-char-2-above 409 | avy-goto-char-2-below 410 | avy-goto-char-in-line 411 | avy-goto-char-timer 412 | avy-goto-line 413 | avy-goto-line-above 414 | avy-goto-line-below 415 | avy-goto-subword-0 416 | avy-goto-subword-1 417 | avy-goto-symbol-1 418 | avy-goto-symbol-1-above 419 | avy-goto-symbol-1-below 420 | avy-goto-word-0 421 | avy-goto-word-1 422 | avy-goto-word-1-above 423 | avy-goto-word-1-below 424 | avy-goto-word-or-subword-1)) 425 | (define-key evil-motion-state-map 426 | (vector 'remap command) (intern-soft (format "evil-%s" command)))) 427 | 428 | ;;; nXhtml/mumamo 429 | ;; ensure that mumamo does not toggle evil through its globalized mode 430 | (eval-after-load 'mumamo 431 | '(with-no-warnings 432 | (push 'evil-mode-cmhh mumamo-change-major-mode-no-nos))) 433 | 434 | ;; visual-line-mode integration 435 | (when evil-respect-visual-line-mode 436 | (evil-define-minor-mode-key 'motion 'visual-line-mode 437 | "j" 'evil-next-visual-line 438 | "gj" 'evil-next-line 439 | "k" 'evil-previous-visual-line 440 | "gk" 'evil-previous-line 441 | "0" 'evil-beginning-of-visual-line 442 | "g0" 'evil-beginning-of-line 443 | "$" 'evil-end-of-visual-line 444 | "g$" 'evil-end-of-line 445 | "V" 'evil-visual-screen-line)) 446 | 447 | ;;; abbrev.el 448 | (defun evil-maybe-expand-abbrev () 449 | (when (and abbrev-mode evil-want-abbrev-expand-on-insert-exit) 450 | (expand-abbrev))) 451 | 452 | (eval-after-load 'abbrev 453 | '(add-hook 'evil-insert-state-exit-hook #'evil-maybe-expand-abbrev)) 454 | 455 | ;;; ElDoc 456 | (eval-after-load 'eldoc 457 | '(when (fboundp 'eldoc-add-command-completions) 458 | (eldoc-add-command-completions "evil-window-"))) 459 | 460 | ;;; XRef 461 | (eval-after-load 'xref 462 | '(progn 463 | (evil-set-command-property 'xref-find-definitions :jump t) 464 | (evil-set-command-property 'xref-find-references :jump t))) 465 | 466 | (provide 'evil-integration) 467 | 468 | ;;; evil-integration.el ends here 469 | -------------------------------------------------------------------------------- /evil-jumps.el: -------------------------------------------------------------------------------- 1 | ;;; evil-jumps.el --- Jump list implementation -*- lexical-binding: t -*- 2 | 3 | ;; Author: Bailey Ling 4 | 5 | ;; Version: 1.15.0 6 | 7 | ;; 8 | ;; This file is NOT part of GNU Emacs. 9 | 10 | ;;; License: 11 | 12 | ;; This file is part of Evil. 13 | ;; 14 | ;; Evil is free software: you can redistribute it and/or modify 15 | ;; it under the terms of the GNU General Public License as published by 16 | ;; the Free Software Foundation, either version 3 of the License, or 17 | ;; (at your option) any later version. 18 | ;; 19 | ;; Evil is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | ;; 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with Evil. If not, see . 26 | 27 | (require 'cl-lib) 28 | (require 'evil-core) 29 | (require 'evil-states) 30 | 31 | ;;; Code: 32 | 33 | (defgroup evil-jumps nil 34 | "Evil jump list configuration options." 35 | :prefix "evil-jumps" 36 | :group 'evil) 37 | 38 | (defcustom evil-jumps-cross-buffers t 39 | "When non-nil, the jump commands can cross borders between buffers. 40 | Otherwise the jump commands act only within the current buffer." 41 | :type 'boolean) 42 | 43 | (defcustom evil-jumps-max-length 100 44 | "The maximum number of jumps to keep track of." 45 | :type 'integer) 46 | 47 | (defcustom evil-jumps-pre-jump-hook nil 48 | "Hooks to run just before jumping to a location in the jump list." 49 | :type 'hook) 50 | 51 | (defcustom evil-jumps-post-jump-hook nil 52 | "Hooks to run just after jumping to a location in the jump list." 53 | :type 'hook) 54 | 55 | (defcustom evil-jumps-ignored-file-patterns '("COMMIT_EDITMSG$" "TAGS$") 56 | "List of regexps to exclude file path from inclusion in the jump list." 57 | :type '(repeat string)) 58 | 59 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 60 | 61 | (defvar savehist-additional-variables) 62 | 63 | (defvar evil--jumps-jumping nil) 64 | 65 | (defvar evil--jumps-jump-command nil 66 | "Set by `evil--jump-backward', used and cleared in the 67 | `post-command-hook' by `evil--jump-handle-buffer-crossing'") 68 | 69 | (eval-when-compile (defvar evil--jumps-debug nil)) 70 | 71 | (defvar evil--jumps-buffer-targets "\\*\\(new\\|scratch\\)\\*" 72 | "Regexp to determine if buffer with `buffer-name' is a valid jump target.") 73 | 74 | (defvar evil--jumps-window-jumps (make-hash-table) 75 | "Hashtable which stores all jumps on a per window basis.") 76 | 77 | (defvar evil-jumps-history nil 78 | "History of `evil-mode' jumps that are persisted with `savehist'.") 79 | 80 | (cl-defstruct evil-jumps-struct 81 | ring 82 | (idx -1) 83 | previous-pos) 84 | 85 | ;; Is inlining this really worth it? 86 | (defsubst evil--jumps-message (format &rest args) 87 | (when (eval-when-compile evil--jumps-debug) 88 | (with-current-buffer (get-buffer-create "*evil-jumps*") 89 | (goto-char (point-max)) 90 | (insert (apply #'format format args) "\n")))) 91 | 92 | (defun evil--jumps-get-current (&optional window) 93 | (unless window (setq window (selected-window))) 94 | (let ((jump-struct (gethash window evil--jumps-window-jumps))) 95 | (unless jump-struct 96 | (setq jump-struct (make-evil-jumps-struct)) 97 | (puthash window jump-struct evil--jumps-window-jumps)) 98 | jump-struct)) 99 | 100 | (defun evil--jumps-get-jumps (struct) 101 | (let ((ring (evil-jumps-struct-ring struct))) 102 | (unless ring 103 | (setq ring (make-ring evil-jumps-max-length)) 104 | (setf (evil-jumps-struct-ring struct) ring)) 105 | ring)) 106 | 107 | (defun evil--jumps-get-window-jump-list () 108 | (let ((struct (evil--jumps-get-current))) 109 | (evil--jumps-get-jumps struct))) 110 | 111 | (defun evil--jumps-savehist-load () 112 | (add-to-list 'savehist-additional-variables 'evil-jumps-history) 113 | (let ((ring (make-ring evil-jumps-max-length))) 114 | (cl-loop for jump in (reverse evil-jumps-history) 115 | do (ring-insert ring jump)) 116 | (setf (evil-jumps-struct-ring (evil--jumps-get-current)) ring)) 117 | (add-hook 'savehist-save-hook #'evil--jumps-savehist-sync) 118 | (remove-hook 'savehist-mode-hook #'evil--jumps-savehist-load)) 119 | 120 | (defun evil--jumps-savehist-sync () 121 | "Update the printable value of window jumps for `savehist'." 122 | (setq evil-jumps-history 123 | (delq nil (mapcar #'(lambda (jump) 124 | (let* ((mark (car jump)) 125 | (pos (if (markerp mark) 126 | (marker-position mark) 127 | mark)) 128 | (file-name (cadr jump))) 129 | (when (and (not (file-remote-p file-name)) 130 | (file-exists-p file-name) 131 | pos) 132 | (list pos file-name)))) 133 | (ring-elements (evil--jumps-get-window-jump-list)))))) 134 | 135 | (defun evil--jumps-current-file-name () 136 | "Get the current buffer file name for `evil--jumps-push'." 137 | (or buffer-file-name 138 | (when (derived-mode-p 'dired-mode) default-directory))) 139 | 140 | (defun evil--jumps-jump (idx shift) 141 | (let ((target-list (evil--jumps-get-window-jump-list))) 142 | (evil--jumps-message "jumping from %s by %s" idx shift) 143 | (evil--jumps-message "target list = %s" target-list) 144 | (setq idx (+ idx shift)) 145 | (let ((current-file-name (or (evil--jumps-current-file-name) (buffer-name))) 146 | (size (ring-length target-list))) 147 | (unless evil-jumps-cross-buffers 148 | ;; skip jump marks pointing to other buffers 149 | (while (and (< idx size) (>= idx 0) 150 | (not (string= current-file-name (cadr (ring-ref target-list idx))))) 151 | (setq idx (+ idx shift)))) 152 | (when (and (< idx size) (>= idx 0)) 153 | ;; actual jump 154 | (run-hooks 'evil-jumps-pre-jump-hook) 155 | (let* ((place (ring-ref target-list idx)) 156 | (pos (car place)) 157 | (file-name (cadr place))) 158 | (setq evil--jumps-jumping t) 159 | (unless (string= current-file-name file-name) 160 | (if (string-match-p evil--jumps-buffer-targets file-name) 161 | (switch-to-buffer file-name) 162 | (find-file file-name))) 163 | (setq evil--jumps-jumping nil) 164 | (goto-char pos) 165 | (setf (evil-jumps-struct-idx (evil--jumps-get-current)) idx) 166 | (run-hooks 'evil-jumps-post-jump-hook)))))) 167 | 168 | (defun evil--jumps-push () 169 | "Push the current cursor/file position to the jump list." 170 | (let ((target-list (evil--jumps-get-window-jump-list)) 171 | (file-name (evil--jumps-current-file-name)) 172 | (buffer-name (buffer-name)) 173 | (current-pos (point-marker)) 174 | (first-pos nil) 175 | (first-file-name nil) 176 | (excluded nil)) 177 | (when (and (not file-name) 178 | (string-match-p evil--jumps-buffer-targets buffer-name)) 179 | (setq file-name buffer-name)) 180 | (when file-name 181 | (dolist (pattern evil-jumps-ignored-file-patterns) 182 | (when (string-match-p pattern file-name) 183 | (setq excluded t))) 184 | (unless excluded 185 | (unless (ring-empty-p target-list) 186 | (setq first-pos (car (ring-ref target-list 0))) 187 | (setq first-file-name (car (cdr (ring-ref target-list 0))))) 188 | (unless (and (equal first-pos current-pos) 189 | (equal first-file-name file-name)) 190 | (evil--jumps-message "pushing %s on %s" current-pos file-name) 191 | (ring-insert target-list `(,current-pos ,file-name))))) 192 | (evil--jumps-message "%s %s" 193 | (selected-window) 194 | (and (not (ring-empty-p target-list)) 195 | (ring-ref target-list 0))))) 196 | 197 | (evil-define-command evil-show-jumps () 198 | "Display the contents of the jump list." 199 | :repeat nil 200 | (evil-with-view-list 201 | :name "evil-jumps" 202 | :mode "Evil Jump List" 203 | :format [("Jump" 5 nil) 204 | ("Marker" 8 nil) 205 | ("File/text" 1000 t)] 206 | :entries (let* ((jumps (evil--jumps-savehist-sync)) 207 | (count 0)) 208 | (cl-loop for jump in jumps 209 | collect `(nil [,(number-to-string (cl-incf count)) 210 | ,(number-to-string (car jump)) 211 | (,(cadr jump))]))) 212 | :select-action #'evil--show-jumps-select-action)) 213 | 214 | (defun evil--show-jumps-select-action (jump) 215 | (let ((position (string-to-number (elt jump 1))) 216 | (file (car (elt jump 2)))) 217 | (kill-buffer) 218 | (switch-to-buffer (find-file file)) 219 | (goto-char position))) 220 | 221 | (defun evil-set-jump (&optional pos) 222 | "Set jump point at POS. 223 | POS defaults to point." 224 | (save-excursion 225 | (when (markerp pos) 226 | (set-buffer (marker-buffer pos))) 227 | 228 | (unless (or (region-active-p) (evil-visual-state-p)) 229 | (push-mark pos t)) 230 | 231 | (unless evil--jumps-jumping 232 | ;; clear out intermediary jumps when a new one is set 233 | (let* ((struct (evil--jumps-get-current)) 234 | (target-list (evil--jumps-get-jumps struct)) 235 | (idx (evil-jumps-struct-idx struct))) 236 | (cl-loop repeat idx 237 | do (ring-remove target-list)) 238 | (setf (evil-jumps-struct-idx struct) -1)) 239 | (when pos 240 | (goto-char pos)) 241 | (evil--jumps-push)))) 242 | (put 'evil-set-jump 'permanent-local-hook t) 243 | 244 | (defun evil--jump-backward (count) 245 | (setq evil--jumps-jump-command t) 246 | (let ((count (or count 1))) 247 | (evil-motion-loop (nil count) 248 | (let* ((struct (evil--jumps-get-current)) 249 | (idx (evil-jumps-struct-idx struct))) 250 | (evil--jumps-message "jumping back %s" idx) 251 | (when (= idx -1) 252 | (setq idx 0) 253 | (setf (evil-jumps-struct-idx struct) 0) 254 | (evil--jumps-push)) 255 | (evil--jumps-jump idx 1))))) 256 | 257 | (defun evil--jump-forward (count) 258 | (setq evil--jumps-jump-command t) 259 | (let ((count (or count 1))) 260 | (evil-motion-loop (nil count) 261 | (let* ((struct (evil--jumps-get-current)) 262 | (idx (evil-jumps-struct-idx struct))) 263 | (when (= idx -1) 264 | (setq idx 0) 265 | (setf (evil-jumps-struct-idx struct) 0) 266 | (evil--jumps-push)) 267 | (evil--jumps-jump idx -1))))) 268 | 269 | (defun evil--jumps-window-configuration-hook (&rest _args) 270 | (let* ((window-list (window-list-1 nil nil t)) 271 | (existing-window (selected-window)) 272 | (new-window (previous-window))) 273 | (when (and (not (eq existing-window new-window)) 274 | (> (length window-list) 1)) 275 | (let* ((target-jump-struct (evil--jumps-get-current new-window))) 276 | (if (not (ring-empty-p (evil--jumps-get-jumps target-jump-struct))) 277 | (evil--jumps-message "target window %s already has %s jumps" new-window 278 | (ring-length (evil--jumps-get-jumps target-jump-struct))) 279 | (evil--jumps-message "new target window detected; copying %s to %s" existing-window new-window) 280 | (let* ((source-jump-struct (evil--jumps-get-current existing-window)) 281 | (source-list (evil--jumps-get-jumps source-jump-struct))) 282 | (when (= (ring-length (evil--jumps-get-jumps target-jump-struct)) 0) 283 | (setf (evil-jumps-struct-previous-pos target-jump-struct) (evil-jumps-struct-previous-pos source-jump-struct)) 284 | (setf (evil-jumps-struct-idx target-jump-struct) (evil-jumps-struct-idx source-jump-struct)) 285 | (setf (evil-jumps-struct-ring target-jump-struct) (ring-copy source-list))))))) 286 | ;; delete obsolete windows 287 | (maphash (lambda (key _val) 288 | (unless (member key window-list) 289 | (evil--jumps-message "removing %s" key) 290 | (remhash key evil--jumps-window-jumps))) 291 | evil--jumps-window-jumps))) 292 | (put 'evil--jumps-window-configuration-hook 'permanent-local-hook t) 293 | 294 | (defun evil--jump-hook (&optional command) 295 | "`pre-command-hook' for evil-jumps. 296 | Set jump point if COMMAND has a non-nil `:jump' property. Otherwise, 297 | save the current position in case the command being executed will 298 | change the current buffer." 299 | (setq command (or command this-command)) 300 | (if (evil-get-command-property command :jump) 301 | (evil-set-jump) 302 | (setf (evil-jumps-struct-previous-pos (evil--jumps-get-current)) 303 | (point-marker)))) 304 | (put 'evil--jump-hook 'permanent-local-hook t) 305 | 306 | (defun evil--jump-handle-buffer-crossing () 307 | (let ((jump-command evil--jumps-jump-command)) 308 | (setq evil--jumps-jump-command nil) 309 | (dolist (frame (frame-list)) 310 | (dolist (window (window-list frame)) 311 | (let* ((struct (evil--jumps-get-current window)) 312 | (previous-pos (evil-jumps-struct-previous-pos struct))) 313 | (when previous-pos 314 | (setf (evil-jumps-struct-previous-pos struct) nil) 315 | (if (and 316 | ;; `evil-jump-backward' and 'evil-jump-forward' need 317 | ;; to be handled specially. When jumping backward 318 | ;; multiple times, calling `evil-set-jump' is always 319 | ;; wrong: If you jump back twice and we call 320 | ;; `evil-set-jump' after the second time, we clear 321 | ;; the forward jump list and `evil--jump-forward' 322 | ;; won't work. 323 | 324 | ;; The first time you jump backward, setting a jump 325 | ;; point is sometimes correct. But we don't do it 326 | ;; here because this function is called after 327 | ;; `evil--jump-backward' has updated our position in 328 | ;; the jump list so, again, `evil-set-jump' would 329 | ;; break `evil--jump-forward'. 330 | (not jump-command) 331 | (let ((previous-buffer (marker-buffer previous-pos))) 332 | (and previous-buffer 333 | (not (eq previous-buffer (window-buffer window)))))) 334 | (evil-set-jump previous-pos) 335 | (set-marker previous-pos nil)))))))) 336 | (put 'evil--jump-handle-buffer-crossing 'permanent-local-hook t) 337 | 338 | (if (bound-and-true-p savehist-loaded) 339 | (evil--jumps-savehist-load) 340 | (add-hook 'savehist-mode-hook #'evil--jumps-savehist-load)) 341 | 342 | (defun evil--jumps-install-or-uninstall () 343 | (if evil-local-mode 344 | (progn 345 | (add-hook 'pre-command-hook #'evil--jump-hook nil t) 346 | (add-hook 'post-command-hook #'evil--jump-handle-buffer-crossing nil t) 347 | (add-hook 'next-error-hook #'evil-set-jump nil t) 348 | (add-hook 'window-configuration-change-hook #'evil--jumps-window-configuration-hook nil t)) 349 | (remove-hook 'pre-command-hook #'evil--jump-hook t) 350 | (remove-hook 'post-command-hook #'evil--jump-handle-buffer-crossing t) 351 | (remove-hook 'next-error-hook #'evil-set-jump t) 352 | (remove-hook 'window-configuration-change-hook #'evil--jumps-window-configuration-hook t))) 353 | 354 | (add-hook 'evil-local-mode-hook #'evil--jumps-install-or-uninstall) 355 | 356 | (provide 'evil-jumps) 357 | 358 | ;;; evil-jumps.el ends here 359 | -------------------------------------------------------------------------------- /evil-keybindings.el: -------------------------------------------------------------------------------- 1 | ;;; evil-keybindings.el --- Add some Evil keybindings to other modules -*- lexical-binding: t -*- 2 | 3 | ;; Author: Vegard Øye 4 | ;; Maintainer: Vegard Øye 5 | 6 | ;; Version: 1.15.0 7 | 8 | ;; 9 | ;; This file is NOT part of GNU Emacs. 10 | 11 | ;;; License: 12 | 13 | ;; This file is part of Evil. 14 | ;; 15 | ;; Evil is free software: you can redistribute it and/or modify 16 | ;; it under the terms of the GNU General Public License as published by 17 | ;; the Free Software Foundation, either version 3 of the License, or 18 | ;; (at your option) any later version. 19 | ;; 20 | ;; Evil is distributed in the hope that it will be useful, 21 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | ;; GNU General Public License for more details. 24 | ;; 25 | ;; You should have received a copy of the GNU General Public License 26 | ;; along with Evil. If not, see . 27 | 28 | ;;; Commentary: 29 | 30 | ;; This provides a set of keybindings for other emacs modes. This also includes 31 | ;; setting up the initial evil state of those other modes. 32 | 33 | ;;; Code: 34 | 35 | (require 'evil-maps) 36 | (require 'evil-core) 37 | (require 'evil-macros) 38 | (require 'evil-types) 39 | (require 'evil-repeat) 40 | 41 | ;; etags-select 42 | ;; FIXME: probably etags-select should be recomended in docs 43 | (eval-after-load 'etags-select 44 | '(progn 45 | (define-key evil-motion-state-map "g]" 'etags-select-find-tag-at-point))) 46 | 47 | ;;; Buffer-menu 48 | 49 | (evil-add-hjkl-bindings Buffer-menu-mode-map 'motion) 50 | 51 | ;; dictionary.el 52 | 53 | (evil-add-hjkl-bindings dictionary-mode-map 'motion 54 | "?" 'dictionary-help ; "h" 55 | "C-o" 'dictionary-previous) ; "l" 56 | 57 | ;;; Dired 58 | 59 | (eval-after-load 'dired 60 | '(progn 61 | ;; use the standard Dired bindings as a base 62 | (defvar dired-mode-map) 63 | (evil-make-overriding-map dired-mode-map 'normal) 64 | (evil-add-hjkl-bindings dired-mode-map 'normal 65 | "J" 'dired-goto-file ; "j" 66 | "K" 'dired-do-kill-lines ; "k" 67 | "r" 'dired-do-redisplay ; "l" 68 | ;; ":d", ":v", ":s", ":e" 69 | ";" (lookup-key dired-mode-map ":")))) 70 | 71 | ;;; ERT 72 | 73 | (evil-add-hjkl-bindings ert-results-mode-map 'motion) 74 | 75 | ;;; Info 76 | 77 | (evil-add-hjkl-bindings Info-mode-map 'motion 78 | "0" 'evil-beginning-of-line 79 | (kbd "\M-h") 'Info-help ; "h" 80 | "\C-t" 'Info-history-back ; "l" 81 | "\C-o" 'Info-history-back 82 | " " 'Info-scroll-up 83 | "\C-]" 'Info-follow-nearest-node 84 | (kbd "DEL") 'Info-scroll-down) 85 | 86 | ;;; Speedbar 87 | 88 | (evil-add-hjkl-bindings speedbar-mode-map 'motion 89 | "h" 'backward-char 90 | "j" 'speedbar-next 91 | "k" 'speedbar-prev 92 | "l" 'forward-char 93 | "i" 'speedbar-item-info 94 | "r" 'speedbar-refresh 95 | "u" 'speedbar-up-directory 96 | "o" 'speedbar-toggle-line-expansion 97 | (kbd "RET") 'speedbar-edit-line) 98 | 99 | ;; Ibuffer 100 | (eval-after-load 'ibuffer 101 | '(progn 102 | (defvar ibuffer-mode-map) 103 | (evil-make-overriding-map ibuffer-mode-map 'normal) 104 | (evil-define-key 'normal ibuffer-mode-map 105 | "j" 'evil-next-line 106 | "k" 'evil-previous-line 107 | (kbd "RET") 'ibuffer-visit-buffer))) 108 | 109 | ;;; ag.el 110 | (eval-after-load 'ag 111 | '(progn 112 | (defvar ag-mode-map) 113 | (add-to-list 'evil-motion-state-modes 'ag-mode) 114 | (evil-add-hjkl-bindings ag-mode-map 'motion))) 115 | 116 | ;;; ELP 117 | 118 | (advice-add 'elp-results :after #'evil--set-motion-state) 119 | (defun evil--set-motion-state (&rest _) 120 | (evil-motion-state)) 121 | 122 | (provide 'evil-keybindings) 123 | 124 | ;;; evil-keybindings.el ends here 125 | -------------------------------------------------------------------------------- /evil-repeat.el: -------------------------------------------------------------------------------- 1 | ;;; evil-repeat.el --- Repeat system -*- lexical-binding: t -*- 2 | 3 | ;; Author: Frank Fischer 4 | ;; Maintainer: Vegard Øye 5 | 6 | ;; Version: 1.15.0 7 | 8 | ;; 9 | ;; This file is NOT part of GNU Emacs. 10 | 11 | ;;; License: 12 | 13 | ;; This file is part of Evil. 14 | ;; 15 | ;; Evil is free software: you can redistribute it and/or modify 16 | ;; it under the terms of the GNU General Public License as published by 17 | ;; the Free Software Foundation, either version 3 of the License, or 18 | ;; (at your option) any later version. 19 | ;; 20 | ;; Evil is distributed in the hope that it will be useful, 21 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | ;; GNU General Public License for more details. 24 | ;; 25 | ;; You should have received a copy of the GNU General Public License 26 | ;; along with Evil. If not, see . 27 | 28 | ;;; Commentary: 29 | 30 | ;; A repeat begins when leaving Normal state; it ends when re-entering 31 | ;; Normal state. The diagram below shows possible routes between 32 | ;; Normal state (N), Insert state (I), Visual state (V), 33 | ;; Operator-Pending state (O) and Replace state (R). (Emacs state 34 | ;; is an exception: nothing is repeated in that state.) 35 | ;; ___ 36 | ;; / \ 37 | ;; | R | 38 | ;; \___/ 39 | ;; ^ | 40 | ;; | | 41 | ;; ___ |___V ___ 42 | ;; / \ <------- / \ -------> / \ 43 | ;; | V | | N | | O | 44 | ;; \___/ -------> \___/ <------- \___/ 45 | ;; | | ^ | 46 | ;; | | | | 47 | ;; | V___| | 48 | ;; | / \ | 49 | ;; +--------> | I | <--------+ 50 | ;; \___/ 51 | ;; 52 | ;; The recording of a repeat is started in one of two cases: Either a 53 | ;; command is about to be executed (in pre-command-hook) or normal 54 | ;; state is exited. The recording is stopped whenever a command has 55 | ;; been completed and evil is in normal state afterwards. Therefore, 56 | ;; a non-inserting command in normal-state is recorded as a single 57 | ;; repeat unit. In contrast, if the command leaves normal state and 58 | ;; starts insert-state, all commands that are executed until 59 | ;; insert-state is left and normal state is reactivated are recorded 60 | ;; together in one repeat unit. In other words, a repeat unit consists 61 | ;; of all commands that are executed starting and ending in normal 62 | ;; state. 63 | ;; 64 | ;; Not all commands are recorded. There are several commands that are 65 | ;; completely ignored and other commands that even abort the currently 66 | ;; active recording, e.g., commands that switch buffer. 67 | ;; 68 | ;; During recording the repeat information is appended to the variable 69 | ;; `evil-repeat-info', which is cleared when the recording 70 | ;; starts. This accumulated repeat information is put into the 71 | ;; `evil-repeat-ring' when the recording is finished. The dot command, 72 | ;; `\[evil-repeat]' (`evil-repeat') replays the most recent entry in 73 | ;; the ring, preceeding repeats can be replayed using 74 | ;; `\[evil-repeat-pop]' (`evil-repeat-pop'). 75 | ;; 76 | ;; Repeat information can be stored in almost arbitrary form. How the 77 | ;; repeat information for each single command is recorded is 78 | ;; determined by the :repeat property of the command. This property 79 | ;; has the following interpretation: 80 | ;; 81 | ;; t record commands by storing the key-sequence that invoked it 82 | ;; nil ignore this command completely 83 | ;; ignore synonym to nil 84 | ;; motion command is recorded by storing the key-sequence but only in 85 | ;; insert state, otherwise it is ignored. 86 | ;; abort stop recording of repeat information immediately 87 | ;; change record commands by storing buffer changes 88 | ;; SYMBOL if SYMBOL is contained as key in `evil-repeat-types' call 89 | ;; the corresponding (function-)value, otherwise call the 90 | ;; function associated with SYMBOL. In both cases the 91 | ;; function should take exactly one argument which is either 92 | ;; `pre', `pre-read-key-sequence' or `post' specifying on 93 | ;; whether the function is called before or after the 94 | ;; execution of the command. 95 | ;; 96 | ;; Therefore, using a certain SYMBOL one can write specific repeation 97 | ;; functions for each command. 98 | ;; 99 | ;; Each value of ring `evil-repeat-info', i.e., each single repeat 100 | ;; information must be one of the following two possibilities: 101 | ;; If element is a sequence, it is regarded as a key-sequence to 102 | ;; be repeated. Otherwise the element must be a list 103 | ;; (FUNCTION PARAMS ...) which will be called using 104 | ;; (apply FUNCTION PARAMS) whenever this repeat is being executed. 105 | ;; 106 | ;; A user supplied repeat function can use the functions 107 | ;; `evil-record-repeat' to append further repeat-information of the 108 | ;; form described above to `evil-repeat-info'. See the implementation 109 | ;; of `evil-repeat-keystrokes' and `evil-repeat-changes' for examples. 110 | ;; 111 | ;; The repeat information is executed with `evil-execute-repeat-info', 112 | ;; which passes key-sequence elements to `execute-kbd-macro' and 113 | ;; executes other elements as defined above. A special version is 114 | ;; `evil-execute-repeat-info-with-count'. This function works as 115 | ;; `evil-execute-repeat-info', but replaces the count of the first 116 | ;; command. This is done by parsing the key-sequence, ignoring all 117 | ;; calls to `digit-prefix-argument' and `negative-argument', and 118 | ;; prepending the count as a string to the vector of the remaining 119 | ;; key-sequence. 120 | 121 | ;;; Code: 122 | 123 | (require 'evil-states) 124 | 125 | (defmacro evil-without-repeat (&rest body) 126 | (declare (indent defun) 127 | (debug t)) 128 | `(let ((pre-command-hook (remq 'evil-repeat-pre-hook pre-command-hook)) 129 | (post-command-hook (remq 'evil-repeat-post-hook post-command-hook))) 130 | ,@body 131 | (evil-repeat-abort))) 132 | 133 | (defsubst evil-repeat-recording-p () 134 | "Return non-nil if a recording is in progress." 135 | (eq evil-recording-repeat t)) 136 | 137 | (defun evil-repeat-start () 138 | "Start recording a new repeat into `evil-repeat-info'." 139 | (evil-repeat-reset t) 140 | (evil-repeat-record-buffer) 141 | (when (evil-visual-state-p) 142 | (let* ((range (evil-visual-range)) 143 | (beg (evil-range-beginning range)) 144 | (end (max 1 (1- (evil-range-end range)))) 145 | (nfwdlines (evil-count-lines beg end))) 146 | (evil-repeat-record 147 | (cond 148 | ((eq evil-visual-selection 'char) 149 | (list #'evil-repeat-visual-char 150 | nfwdlines 151 | (- end 152 | (if (zerop nfwdlines) 153 | beg 154 | (save-excursion 155 | (goto-char end) 156 | (line-beginning-position)))))) 157 | ((eq evil-visual-selection 'line) 158 | (list #'evil-repeat-visual-line nfwdlines)) 159 | ((eq evil-visual-selection 'block) 160 | (list #'evil-repeat-visual-block 161 | nfwdlines 162 | (abs (- (evil-column beg) (evil-column end)))))))))) 163 | 164 | (defun evil-repeat-stop () 165 | "Stop recording a repeat. 166 | Update `evil-repeat-ring' with the accumulated changes 167 | in `evil-repeat-info' and clear variables." 168 | (unwind-protect 169 | (when (evil-repeat-recording-p) 170 | (setq evil-repeat-info (evil-normalize-repeat-info evil-repeat-info)) 171 | (when (and evil-repeat-info evil-repeat-ring) 172 | (ring-insert evil-repeat-ring evil-repeat-info))) 173 | (evil-repeat-reset nil))) 174 | 175 | (defun evil-repeat-abort () 176 | "Abort current repeation." 177 | (evil-repeat-reset 'abort)) 178 | 179 | (defun evil-repeat-reset (flag) 180 | "Clear all repeat recording variables. 181 | Set `evil-recording-repeat' to FLAG." 182 | (setq evil-recording-repeat flag 183 | evil-repeat-info nil 184 | evil-repeat-buffer nil)) 185 | 186 | (defsubst evil-repeat-record-position (&optional pos) 187 | "Set `evil-repeat-pos' to POS or point." 188 | (setq evil-repeat-pos (or pos (point)))) 189 | 190 | (defun evil-repeat-record-buffer () 191 | "Set `evil-repeat-buffer' to the current buffer." 192 | (unless (minibufferp) 193 | (setq evil-repeat-buffer (current-buffer)))) 194 | 195 | (defmacro evil-save-repeat-info (&rest body) 196 | "Execute BODY, protecting the values of repeat variables." 197 | (declare (indent defun) 198 | (debug t)) 199 | `(let (evil-repeat-ring 200 | evil-recording-repeat 201 | evil-recording-current-command 202 | evil-repeat-info 203 | evil-repeat-changes 204 | evil-repeat-pos 205 | evil-repeat-keys 206 | evil-repeat-buffer 207 | this-command 208 | last-command) 209 | ,@body)) 210 | 211 | (defun evil-repeat-different-buffer-p (&optional strict) 212 | "Whether the buffer has changed in a repeat. 213 | If STRICT is non-nil, returns t if the previous buffer 214 | is unknown; otherwise returns t only if the previous 215 | buffer is known and different from the current buffer." 216 | (and (or (buffer-live-p evil-repeat-buffer) strict) 217 | (not (minibufferp)) 218 | (not (eq (current-buffer) evil-repeat-buffer)))) 219 | 220 | (defvar evil-repeat-types 221 | '((t . evil-repeat-keystrokes) 222 | (change . evil-repeat-changes) 223 | (motion . evil-repeat-motion) 224 | (insert-at-point . evil-repeat-insert-at-point) 225 | (ignore . nil)) 226 | "Alist of defined repeat-types.") 227 | 228 | (defun evil--repeat-type (command) 229 | "Return the :repeat property of COMMAND." 230 | (when (functionp command) ; ignore keyboard macros 231 | (let* ((type (evil-get-command-property command :repeat t)) 232 | (repeat-type (assq type evil-repeat-types))) 233 | (if repeat-type (cdr repeat-type) type)))) 234 | 235 | (defun evil-repeat-type (command &optional default) 236 | "Return the :repeat property of COMMAND. 237 | If COMMAND doesn't have this property, return DEFAULT." 238 | (declare (obsolete evil--repeat-type "1.15.0")) 239 | (when (functionp command) ; ignore keyboard macros 240 | (let* ((type (evil-get-command-property command :repeat default)) 241 | (repeat-type (assq type evil-repeat-types))) 242 | (if repeat-type (cdr repeat-type) type)))) 243 | 244 | (defun evil-repeat-force-abort-p (repeat-type) 245 | "Whether the current command should abort the recording of repeat information. 246 | Return non-nil if so." 247 | (or (evil-repeat-different-buffer-p) ; ... buffer changed 248 | (eq repeat-type 'abort) ; ... explicitly forced 249 | (eq evil-recording-repeat 'abort) ; ... already aborted 250 | (evil-emacs-state-p) ; ... in Emacs state 251 | (and (evil-mouse-events-p ; ... mouse events 252 | (this-command-keys-vector)) 253 | (null repeat-type)) 254 | (minibufferp))) ; ... minibuffer activated 255 | 256 | (defun evil-repeat-record (info) 257 | "Append INFO to `evil-repeat-info'." 258 | (when (evil-repeat-recording-p) 259 | (setq evil-repeat-info (nconc evil-repeat-info (list info))))) 260 | 261 | ;; called from `pre-command-hook' 262 | (defun evil-repeat-pre-hook () 263 | "Prepare the current command for recording the repeation." 264 | (when evil-local-mode 265 | (let ((repeat-type (evil--repeat-type this-command))) 266 | (cond 267 | ;; abort the repeat 268 | ((evil-repeat-force-abort-p repeat-type) 269 | ;; We mark the current record as being aborted, because there 270 | ;; may be further pre-hooks following before the post-hook is 271 | ;; called. 272 | (evil-repeat-abort)) 273 | ;; ignore those commands completely 274 | ((or (null repeat-type) 275 | (evil-mouse-events-p (this-command-keys-vector)))) 276 | ;; record command 277 | (t 278 | ;; In normal-state or visual state, each command is a single 279 | ;; repeation, therefore start a new repeation. 280 | (when (or (evil-normal-state-p) 281 | (evil-visual-state-p)) 282 | (evil-repeat-start)) 283 | (setq evil-recording-current-command t) 284 | (funcall repeat-type 'pre)))))) 285 | (put 'evil-repeat-pre-hook 'permanent-local-hook t) 286 | 287 | ;; called from `post-command-hook' 288 | (defun evil-repeat-post-hook () 289 | "Finish recording of repeat-information for the current-command." 290 | (when (and evil-local-mode evil-recording-repeat) 291 | (let ((repeat-type (evil--repeat-type this-command))) 292 | (cond 293 | ;; abort the repeat 294 | ((evil-repeat-force-abort-p repeat-type) 295 | ;; The command has been aborted but is complete, so just reset 296 | ;; the recording state. 297 | (evil-repeat-reset nil)) 298 | ;; ignore if command should not be recorded or the current 299 | ;; command is not being recorded 300 | ((or (null repeat-type) 301 | (not evil-recording-current-command))) 302 | ;; record command 303 | (t 304 | (funcall repeat-type 'post) 305 | ;; In normal state, the repeat sequence is complete, so record it. 306 | (when (evil-normal-state-p) 307 | (evil-repeat-stop))))) 308 | ;; done with recording the current command 309 | (setq evil-recording-current-command nil))) 310 | (put 'evil-repeat-post-hook 'permanent-local-hook t) 311 | 312 | (defun evil-clear-command-keys () 313 | "Clear `this-command-keys' and all information about the current command keys. 314 | Calling this function prevents further recording of the keys that 315 | invoked the current command" 316 | (clear-this-command-keys t) 317 | (setq evil-repeat-keys "")) 318 | 319 | (defun evil-this-command-keys (&optional post-cmd) 320 | "Version of `this-command-keys' with finer control over prefix args." 321 | (vconcat 322 | (let ((arg (if post-cmd current-prefix-arg prefix-arg))) 323 | (and (numberp arg) 324 | ;; Only add prefix if no repeat info recorded yet 325 | (null evil-repeat-info) 326 | (number-to-string arg))) 327 | (this-single-command-keys))) 328 | 329 | (defun evil-repeat-keystrokes (flag) 330 | "Repeation recording function for commands that are repeated by keystrokes." 331 | (cond 332 | ((eq flag 'pre) 333 | (when evil-this-register 334 | (evil-repeat-record 335 | `(set evil-this-register ,evil-this-register))) 336 | (setq evil-repeat-keys (evil-this-command-keys))) 337 | ((memq flag '(post pre-read-key-sequence)) 338 | (evil-repeat-record (if (zerop (length (evil-this-command-keys t))) 339 | evil-repeat-keys 340 | (evil-this-command-keys t))) 341 | ;; erase commands keys to prevent double recording 342 | (evil-clear-command-keys)))) 343 | 344 | (defun evil-repeat-motion (flag) 345 | "Repetition for motions. 346 | Motions are recorded by keystroke but only in Insert state." 347 | (when (memq evil-state '(insert replace)) 348 | (evil-repeat-keystrokes flag))) 349 | 350 | (defun evil-repeat-changes (flag) 351 | "Repeation recording function for commands that are repeated by buffer changes." 352 | (cond 353 | ((eq flag 'pre) 354 | (add-hook 'after-change-functions #'evil-repeat-change-hook nil t) 355 | (evil-repeat-start-record-changes)) 356 | ((eq flag 'post) 357 | (remove-hook 'after-change-functions #'evil-repeat-change-hook t) 358 | (evil-repeat-finish-record-changes)))) 359 | 360 | ;; called from the `after-change-functions' hook 361 | (defun evil-repeat-change-hook (beg end length) 362 | "Record change information for current command." 363 | (let ((repeat-type (evil--repeat-type this-command))) 364 | (when (and (evil-repeat-recording-p) 365 | (eq repeat-type 'evil-repeat-changes) 366 | (not (evil-emacs-state-p)) 367 | (not (evil-repeat-different-buffer-p t)) 368 | evil-state) 369 | (unless (evil-repeat-recording-p) 370 | (evil-repeat-start)) 371 | (evil-repeat-record-change (- beg evil-repeat-pos) 372 | (buffer-substring beg end) 373 | length)))) 374 | (put 'evil-repeat-change-hook 'permanent-local-hook t) 375 | 376 | (defun evil-repeat-record-change (relpos ins ndel) 377 | "Record the current buffer changes during a repeat. 378 | If CHANGE is specified, it is added to `evil-repeat-changes'." 379 | (when (evil-repeat-recording-p) 380 | (push (list relpos ins ndel) evil-repeat-changes))) 381 | 382 | (defun evil-repeat-start-record-changes () 383 | "Start the recording of a new set of buffer changes." 384 | (setq evil-repeat-changes nil) 385 | (evil-repeat-record-position)) 386 | 387 | (defun evil-repeat-finish-record-changes () 388 | "Finish the recording of buffer changes and record them as repeat." 389 | (when (evil-repeat-recording-p) 390 | (evil-repeat-record `(evil-execute-change 391 | ,(nreverse evil-repeat-changes) 392 | ,(- (point) evil-repeat-pos))) 393 | (setq evil-repeat-changes nil))) 394 | 395 | (defun evil-repeat-insert-at-point (flag) 396 | "Repeation recording function for commands that insert text in region. 397 | For example `mouse-yank-primary'. This records text insertion when a command 398 | inserts some text in a buffer between (point) and (mark)." 399 | (cond 400 | ((eq flag 'pre) 401 | (add-hook 'after-change-functions #'evil-repeat-insert-at-point-hook nil t)) 402 | ((eq flag 'post) 403 | (remove-hook 'after-change-functions #'evil-repeat-insert-at-point-hook t)))) 404 | 405 | (defun evil-repeat-insert-at-point-hook (beg end _length) 406 | (let ((repeat-type (evil--repeat-type this-command))) 407 | (when (and (evil-repeat-recording-p) 408 | (eq repeat-type 'evil-repeat-insert-at-point) 409 | (not (evil-emacs-state-p)) 410 | (not (evil-repeat-different-buffer-p t)) 411 | evil-state) 412 | (setq evil-repeat-pos beg) 413 | (evil-repeat-record (list 'insert (buffer-substring beg end)))))) 414 | (put 'evil-repeat-insert-at-point-hook 'permanent-local-hook t) 415 | 416 | (defun evil-normalize-repeat-info (repeat-info) 417 | "Concatenate consecutive arrays in REPEAT-INFO. 418 | Return a single array." 419 | (let* ((result (cons nil nil)) 420 | (result-last result) 421 | cur cur-last) 422 | (dolist (rep repeat-info) 423 | (cond 424 | ((null rep)) 425 | ((arrayp rep) 426 | (setq rep (listify-key-sequence rep)) 427 | (cond 428 | (cur 429 | (setcdr cur-last (cons rep nil)) 430 | (setq cur-last (cdr cur-last))) 431 | (t (setq cur (cons rep nil) 432 | cur-last cur)))) 433 | (t 434 | (when cur 435 | (setcdr result-last (cons (apply #'vconcat cur) nil)) 436 | (setq result-last (cdr result-last) 437 | cur nil)) 438 | (setcdr result-last (cons rep nil)) 439 | (setq result-last (cdr result-last))))) 440 | (when cur 441 | (setcdr result-last (cons (apply #'vconcat cur) nil))) 442 | (cdr result))) 443 | 444 | (defun evil-repeat-visual-char (nfwdlines nfwdchars) 445 | "Restore a character visual selection. 446 | If the selection is in a single line, the restored visual 447 | selection covers the same number of characters. If the selection 448 | covers several lines, the restored selection covers the same 449 | number of lines and the same number of characters in the last 450 | line as the original selection." 451 | (evil-visual-char) 452 | (when (> nfwdlines 0) 453 | (forward-line nfwdlines)) 454 | (forward-char nfwdchars)) 455 | 456 | (defun evil-repeat-visual-line (nfwdlines) 457 | "Restore a character visual selection. 458 | If the selection is in a single line, the restored visual 459 | selection covers the same number of characters. If the selection 460 | covers several lines, the restored selection covers the same 461 | number of lines and the same number of characters in the last 462 | line as the original selection." 463 | (evil-visual-line) 464 | (forward-line nfwdlines)) 465 | 466 | (defun evil-repeat-visual-block (nfwdlines nfwdchars) 467 | "Restore a character visual selection. 468 | If the selection is in a single line, the restored visual 469 | selection covers the same number of characters. If the selection 470 | covers several lines, the restored selection covers the same 471 | number of lines and the same number of characters in the last 472 | line as the original selection." 473 | (evil-visual-block) 474 | (let ((col (current-column))) 475 | (forward-line nfwdlines) 476 | (move-to-column (+ col nfwdchars) t))) 477 | 478 | (defun evil-execute-change (changes rel-point) 479 | "Execute as list of changes. 480 | 481 | CHANGES is a list of triples (REL-BEG INSERT-TEXT NDEL). 482 | REL-BEG is the relative position (to point) where the change 483 | takes place. INSERT-TEXT is the text to be inserted at that 484 | position and NDEL the number of characters to be deleted at that 485 | position before insertion. 486 | 487 | REL-POINT is the relative position to point before the changed 488 | where point should be placed after all changes." 489 | (evil-save-repeat-info 490 | (let ((point (point))) 491 | (dolist (change changes) 492 | (goto-char (+ point (nth 0 change))) 493 | (delete-char (nth 2 change)) 494 | (insert (nth 1 change))) 495 | (goto-char (+ point rel-point))))) 496 | 497 | (defun evil-execute-repeat-info (repeat-info) 498 | "Execute a repeat-information REPEAT-INFO." 499 | (evil-save-repeat-info 500 | (dolist (rep repeat-info) 501 | (cond 502 | ((or (arrayp rep) (stringp rep)) 503 | (let ((input-method current-input-method) 504 | (evil-input-method nil)) 505 | (deactivate-input-method) 506 | (unwind-protect 507 | (execute-kbd-macro rep) 508 | (activate-input-method input-method)))) 509 | ((consp rep) 510 | (when (and (= 3 (length rep)) 511 | (eq (nth 0 rep) 'set) 512 | (eq (nth 1 rep) 'evil-this-register) 513 | (>= (nth 2 rep) ?0) 514 | (< (nth 2 rep) ?9)) 515 | (setcar (nthcdr 2 rep) (1+ (nth 2 rep)))) 516 | (apply (car rep) (cdr rep))) 517 | (t (error "Unexpected repeat-info: %S" rep)))))) 518 | 519 | ;; TODO: currently we prepend the replacing count before the 520 | ;; key-sequence that calls the command. Can we use direct 521 | ;; modification of prefix-arg instead? Does it work in 522 | ;; conjunction with `execute-kbd-macro'? 523 | (defun evil-execute-repeat-info-with-count (count repeat-info) 524 | "Repeat the repeat-information REPEAT-INFO with the count of 525 | the first command replaced by COUNT. The count is replaced if 526 | and only if COUNT is non-nil." 527 | (evil-save-repeat-info 528 | (cond 529 | ;; do nothing (zero repeating) 530 | ((and count (zerop count))) 531 | ;; replace count 532 | (count 533 | (let ((evil-repeat-count count) 534 | done) 535 | (while (and repeat-info 536 | (arrayp (car repeat-info)) 537 | (not done)) 538 | (let* ((count-and-cmd (evil-extract-count (pop repeat-info)))) 539 | (push (vconcat (number-to-string count) 540 | (nth 2 count-and-cmd) 541 | (nth 3 count-and-cmd)) 542 | repeat-info) 543 | (setq done t))) 544 | (evil-execute-repeat-info repeat-info))) 545 | ;; repeat with original count 546 | (t (evil-execute-repeat-info repeat-info))))) 547 | 548 | ;; Keep the compiler happy - this is a buffer local var 549 | (defvar evil--execute-normal-return-state) 550 | 551 | (evil-define-command evil-repeat (count &optional save-point) 552 | "Repeat the last editing command with count replaced by COUNT. 553 | If SAVE-POINT is non-nil, do not move point." 554 | :repeat ignore 555 | :suppress-operator t 556 | (interactive (list current-prefix-arg 557 | (not evil-repeat-move-cursor))) 558 | (cond 559 | ((null evil-repeat-ring) 560 | (error "Already executing repeat")) 561 | (save-point 562 | (save-excursion 563 | (evil-repeat count))) 564 | (t 565 | (unwind-protect 566 | (let ((evil-last-find-temp evil-last-find) 567 | (confirm-kill-emacs t) 568 | (kill-buffer-hook 569 | (cons #'(lambda () 570 | (user-error "Cannot delete buffer in repeat command")) 571 | kill-buffer-hook)) 572 | (undo-pointer buffer-undo-list)) 573 | (evil-with-single-undo 574 | (setq evil-last-repeat (list (point) count undo-pointer)) 575 | (evil-execute-repeat-info-with-count 576 | count (ring-ref evil-repeat-ring 0)) 577 | (setq evil-last-find evil-last-find-temp))) 578 | (if (eq 'evil-execute-in-normal-state last-command) 579 | (evil-change-state evil--execute-normal-return-state) 580 | (evil-normal-state)))))) 581 | 582 | ;; TODO: the same issue concerning disabled undos as for `evil-paste-pop' 583 | (evil-define-command evil-repeat-pop (count &optional save-point) 584 | "Replace the just repeated command with a previously executed command. 585 | Only allowed after `evil-repeat', `evil-repeat-pop' or 586 | `evil-repeat-pop-next'. Uses the same repeat count that 587 | was used for the first repeat. 588 | 589 | The COUNT argument inserts the COUNT-th previous kill. 590 | If COUNT is negative, this is a more recent kill." 591 | :repeat nil 592 | :suppress-operator t 593 | (interactive (list (prefix-numeric-value current-prefix-arg) 594 | (not evil-repeat-move-cursor))) 595 | (cond 596 | ((not (and (eq last-command #'evil-repeat) 597 | evil-last-repeat)) 598 | (user-error "Previous command was not evil-repeat: %s" last-command)) 599 | (save-point 600 | (save-excursion 601 | (evil-repeat-pop count))) 602 | (t 603 | (unless (eq buffer-undo-list (nth 2 evil-last-repeat)) 604 | (evil-undo-pop)) 605 | (goto-char (car evil-last-repeat)) 606 | ;; rotate the repeat-ring 607 | (while (> count 0) 608 | (when evil-repeat-ring 609 | (ring-insert-at-beginning evil-repeat-ring 610 | (ring-remove evil-repeat-ring 0))) 611 | (setq count (1- count))) 612 | (while (< count 0) 613 | (when evil-repeat-ring 614 | (ring-insert evil-repeat-ring 615 | (ring-remove evil-repeat-ring))) 616 | (setq count (1+ count))) 617 | (setq this-command #'evil-repeat) 618 | (evil-repeat (cadr evil-last-repeat))))) 619 | 620 | (evil-define-command evil-repeat-pop-next (count &optional save-point) 621 | "Same as `evil-repeat-pop', but with negative COUNT." 622 | :repeat nil 623 | :suppress-operator t 624 | (interactive (list (prefix-numeric-value current-prefix-arg) 625 | (not evil-repeat-move-cursor))) 626 | (evil-repeat-pop (- count) save-point)) 627 | 628 | (defun evil--read-key-sequence-advice (&rest _) 629 | "Record `this-command-keys' before it is overwritten." 630 | (when (and (evil-repeat-recording-p) 631 | evil-recording-current-command) 632 | (let ((repeat-type (evil--repeat-type this-command))) 633 | (when (functionp repeat-type) 634 | (funcall repeat-type 'pre-read-key-sequence))))) 635 | 636 | (advice-add 'read-key-sequence :before #'evil--read-key-sequence-advice) 637 | (advice-add 'read-key-sequence-vector :before #'evil--read-key-sequence-advice) 638 | 639 | (provide 'evil-repeat) 640 | 641 | ;;; evil-repeat.el ends here 642 | -------------------------------------------------------------------------------- /evil-test-helpers.el: -------------------------------------------------------------------------------- 1 | ;;; evil-test-helpers.el --- unit test helpers for Evil -*- coding: utf-8; lexical-binding: t -*- 2 | 3 | ;; Author: Vegard Øye 4 | ;; Maintainer: Vegard Øye 5 | ;; Package-Requires: ((evil "1.15.0")) 6 | ;; Version: 1.15.0 7 | 8 | ;; This file is NOT part of GNU Emacs. 9 | 10 | ;;; License: 11 | 12 | ;; This file is part of Evil. 13 | ;; 14 | ;; Evil is free software: you can redistribute it and/or modify 15 | ;; it under the terms of the GNU General Public License as published by 16 | ;; the Free Software Foundation, either version 3 of the License, or 17 | ;; (at your option) any later version. 18 | ;; 19 | ;; Evil is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | ;; 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with Evil. If not, see . 26 | 27 | ;;; Commentary: 28 | 29 | ;; This file contains helper functions for writing tests for 30 | ;; evil-mode. These helpers can also be used by other packages which 31 | ;; extend evil-mode. 32 | 33 | ;; To write a test use `evil-test-buffer': 34 | 35 | ;; (require 'evil-test-helpers) 36 | ;; 37 | ;; (ert-deftest evil-test () 38 | ;; :tags '(evil) 39 | ;; (evil-test-buffer 40 | ;; "[T]his creates a test buffer." ; cursor on "T" 41 | ;; ("w") ; key sequence 42 | ;; "This [c]reates a test buffer."))) ; cursor moved to "c" 43 | ;; 44 | ;; The initial state, the cursor syntax, etc., can be changed 45 | ;; with keyword arguments. See the documentation string of 46 | ;; `evil-test-buffer' for more details. 47 | ;; 48 | ;; This file is NOT part of Evil itself. 49 | 50 | (require 'elp) 51 | (require 'ert) 52 | (require 'evil) 53 | 54 | ;;; Code: 55 | 56 | (when (fboundp 'font-lock-add-keywords) 57 | (font-lock-add-keywords 'emacs-lisp-mode 58 | '(("(\\(evil-test-buffer\\)\\>" 59 | 1 font-lock-keyword-face)))) 60 | 61 | (defvar evil-test-point nil 62 | "Marker for point.") 63 | (make-variable-buffer-local 'evil-test-point) 64 | (defvar evil-test-visual-start nil 65 | "Marker for Visual beginning.") 66 | (make-variable-buffer-local 'evil-test-visual-start) 67 | (defvar evil-test-visual-end nil 68 | "Marker for Visual end.") 69 | (make-variable-buffer-local 'evil-test-visual-end) 70 | 71 | (defvaralias 'evil-test-select-enable-clipboard 72 | (if (boundp 'select-enable-clipboard) 73 | 'select-enable-clipboard 74 | 'x-select-enable-clipboard)) 75 | 76 | (defmacro evil-test-buffer (&rest body) 77 | "Execute FORMS in a temporary buffer. 78 | The following optional keywords specify the buffer's properties: 79 | 80 | :state STATE The initial state, defaults to `normal'. 81 | :visual SELECTION The Visual selection, defaults to `char'. 82 | :point-start STRING String for matching beginning of point, 83 | defaults to \"[\". 84 | :point-end STRING String for matching end of point, 85 | defaults to \"]\". 86 | :visual-start STRING String for matching beginning of 87 | Visual selection, defaults to \"<\". 88 | :visual-end STRING String for matching end of 89 | Visual selection, defaults to \">\". 90 | 91 | Then follows one or more forms. If the first form is a string, 92 | it is taken to be a buffer description as passed to 93 | `evil-test-buffer-from-string', and initializes the buffer. 94 | Subsequent string forms validate the buffer. 95 | 96 | If a form is a list of strings or vectors, it is taken to be a 97 | key sequence and is passed to `execute-kbd-macro'. If the form 98 | is \(file FILENAME CONTENTS), then the test fails unless the 99 | contents of FILENAME equal CONTENTS. If the form is \(error 100 | SYMBOL ...) then the test fails unless an error of type SYMBOL is 101 | raised. Remaining forms are evaluated as-is. 102 | 103 | \(fn [[KEY VALUE]...] FORMS...)" 104 | (declare (indent defun)) 105 | (let ((state 'normal) 106 | arg key point-start point-end string 107 | visual visual-start visual-end) 108 | ;; collect keywords 109 | (while (keywordp (car-safe body)) 110 | (setq key (pop body) 111 | arg (pop body)) 112 | (cond 113 | ((eq key :point-start) 114 | (setq point-start (or arg ""))) 115 | ((eq key :point-end) 116 | (setq point-end (or arg ""))) 117 | ((eq key :state) 118 | (setq state arg)) 119 | ((eq key :visual) 120 | (setq visual arg)) 121 | ((eq key :visual-start) 122 | (setq visual-start (or arg ""))) 123 | ((eq key :visual-end) 124 | (setq visual-end (or arg ""))))) 125 | ;; collect buffer initialization 126 | (when (stringp (car-safe body)) 127 | (setq string (pop body))) 128 | ;; macro expansion 129 | `(let ((buffer (evil-test-buffer-from-string 130 | ,string ',state 131 | ,point-start ,point-end 132 | ',visual ,visual-start ,visual-end)) 133 | (kill-ring kill-ring) 134 | (kill-ring-yank-pointer kill-ring-yank-pointer) 135 | evil-test-select-enable-clipboard 136 | message-log-max) 137 | (unwind-protect 138 | (save-window-excursion 139 | (with-current-buffer buffer 140 | ;; necessary for keyboard macros to work 141 | (switch-to-buffer-other-window (current-buffer)) 142 | (buffer-enable-undo) 143 | ;; parse remaining forms 144 | ,@(mapcar 145 | #'(lambda (form) 146 | (let (error-symbol) 147 | (when (and (listp form) 148 | (eq (car-safe form) 'error)) 149 | (setq error-symbol (car-safe (cdr-safe form)) 150 | form (cdr-safe (cdr-safe form)))) 151 | (let ((result 152 | (cond 153 | ((stringp form) 154 | `(evil-test-buffer-string 155 | ,form 156 | ',point-start ',point-end 157 | ',visual-start ',visual-end)) 158 | ((eq (car-safe form) 'file) 159 | `(evil-test-file-contents ,(cadr form) 160 | ,(car (cddr form)))) 161 | ((or (stringp (car-safe form)) 162 | (vectorp (car-safe form)) 163 | (memq (car-safe (car-safe form)) 164 | '(kbd vconcat))) 165 | ;; we need to execute everything as a single 166 | ;; sequence for command loop hooks to work 167 | `(execute-kbd-macro 168 | (apply #'vconcat 169 | (mapcar #'listify-key-sequence 170 | (list ,@form))))) 171 | ((memq (car-safe form) '(kbd vconcat)) 172 | `(execute-kbd-macro ,form)) 173 | (t form)))) 174 | (if error-symbol 175 | `(should-error ,result :type ',error-symbol) 176 | result)))) 177 | body))) 178 | (when (buffer-name buffer) (kill-buffer buffer)))))) 179 | 180 | (defmacro evil-test-selection (string &optional end-string 181 | before-predicate after-predicate) 182 | "Verify that the Visual selection contains STRING." 183 | (declare (indent defun)) 184 | `(progn 185 | (save-excursion 186 | (goto-char (or evil-visual-beginning (region-beginning))) 187 | (evil-test-text nil (or ,string ,end-string) ,before-predicate)) 188 | (save-excursion 189 | (goto-char (or evil-visual-end (region-end))) 190 | (evil-test-text (or ,end-string ,string) nil nil ,after-predicate)))) 191 | 192 | (defun evil-test-buffer-string (string &optional 193 | point-start point-end 194 | visual-start visual-end) 195 | "Validate the current buffer according to STRING. 196 | If STRING contains an occurrence of POINT-START immediately 197 | followed by POINT-END, that position is compared against point. 198 | If STRING contains an occurrence of VISUAL-START followed by 199 | VISUAL-END, those positions are compared against the Visual selection. 200 | POINT-START and POINT-END default to [ and ]. 201 | VISUAL-START and VISUAL-END default to < and >." 202 | (let ((actual-buffer (current-buffer)) 203 | (marker-buffer (evil-test-marker-buffer-from-string 204 | string 205 | point-start point-end 206 | visual-start visual-end)) 207 | before-point after-point string selection) 208 | (unwind-protect 209 | (with-current-buffer marker-buffer 210 | (setq string (buffer-string)) 211 | (when evil-test-point 212 | (setq before-point (buffer-substring (point-min) evil-test-point) 213 | after-point (buffer-substring evil-test-point (point-max)))) 214 | (when (and evil-test-visual-start evil-test-visual-end) 215 | (setq selection (buffer-substring 216 | evil-test-visual-start evil-test-visual-end))) 217 | (with-current-buffer actual-buffer 218 | (if (or before-point after-point) 219 | (evil-test-text before-point after-point) 220 | ;; if the cursor isn't specified, just test the whole buffer 221 | (save-excursion 222 | (goto-char (point-min)) 223 | (evil-test-text nil string #'bobp #'eobp))) 224 | (when selection 225 | (evil-test-selection selection)))) 226 | (kill-buffer marker-buffer)))) 227 | 228 | (defun evil-test-buffer-from-string (string &optional 229 | state 230 | point-start point-end 231 | visual visual-start visual-end) 232 | "Create a new buffer according to STRING. 233 | If STRING contains an occurrence of POINT-START immediately 234 | followed by POINT-END, then point is moved to that position. 235 | If STRING contains an occurrence of VISUAL-START followed by 236 | VISUAL-END, then a Visual selection is created with those boundaries. 237 | POINT-START and POINT-END default to [ and ]. 238 | VISUAL-START and VISUAL-END default to < and >. 239 | STATE is the initial state; it defaults to `normal'. 240 | VISUAL is the Visual selection: it defaults to `char'." 241 | (let ((type (evil-visual-type (or visual 'char))) 242 | (buffer (evil-test-marker-buffer-from-string 243 | string point-start point-end 244 | visual-start visual-end))) 245 | (with-current-buffer buffer 246 | (prog1 buffer 247 | (evil-change-state state) 248 | ;; let the buffer change its major mode without disabling Evil 249 | (add-hook 'after-change-major-mode-hook #'evil-initialize) 250 | (when (and (markerp evil-test-visual-start) 251 | (markerp evil-test-visual-end)) 252 | (evil-visual-select 253 | evil-test-visual-start evil-test-visual-end type) 254 | (when evil-test-point 255 | (goto-char evil-test-point) 256 | (evil-visual-refresh) 257 | (unless (and (= evil-visual-beginning 258 | evil-test-visual-start) 259 | (= evil-visual-end 260 | evil-test-visual-end)) 261 | (evil-visual-select 262 | evil-test-visual-start evil-test-visual-end type -1) 263 | (goto-char evil-test-point) 264 | (evil-visual-refresh)))) 265 | (when (markerp evil-test-point) 266 | (goto-char evil-test-point)))))) 267 | 268 | (defun evil-test-marker-buffer-from-string (string &optional 269 | point-start point-end 270 | visual-start visual-end) 271 | "Create a new marker buffer according to STRING. 272 | If STRING contains an occurrence of POINT-START immediately 273 | followed by POINT-END, that position is stored in the 274 | buffer-local variable `evil-test-point'. Similarly, 275 | if STRING contains an occurrence of VISUAL-START followed by 276 | VISUAL-END, those positions are stored in the variables 277 | `evil-test-visual-beginning' and `evil-test-visual-end'. 278 | POINT-START and POINT-END default to [ and ]. 279 | VISUAL-START and VISUAL-END default to < and >." 280 | (let ((string (or string "")) 281 | (point-start (regexp-quote 282 | (if (characterp point-start) 283 | (string point-start) 284 | (or point-start "[")))) 285 | (point-end (regexp-quote 286 | (if (characterp point-end) 287 | (string point-end) 288 | (or point-end "]")))) 289 | (visual-start (regexp-quote 290 | (if (characterp visual-start) 291 | (string visual-start) 292 | (or visual-start "<")))) 293 | (visual-end (regexp-quote 294 | (if (characterp visual-end) 295 | (string visual-end) 296 | (or visual-end ">"))))) 297 | (with-current-buffer (generate-new-buffer " *test*") 298 | (prog1 (current-buffer) 299 | (save-excursion 300 | (insert string)) 301 | (save-excursion 302 | (when (> (length point-start) 0) 303 | (if (> (length point-end) 0) 304 | (when (re-search-forward 305 | (format "\\(%s\\)[^%s]?\\(%s\\)" 306 | point-start point-end point-end) nil t) 307 | (goto-char (match-beginning 0)) 308 | (delete-region (match-beginning 2) (match-end 2)) 309 | (delete-region (match-beginning 1) (match-end 1)) 310 | (setq evil-test-point 311 | (move-marker (make-marker) (point)))) 312 | (when (re-search-forward point-start nil t) 313 | (goto-char (match-beginning 0)) 314 | (delete-region (match-beginning 0) (match-end 0)) 315 | (setq evil-test-point 316 | (move-marker (make-marker) (point))))))) 317 | (save-excursion 318 | (when (and (> (length visual-start) 0) 319 | (> (length visual-end) 0)) 320 | (when (re-search-forward visual-start nil t) 321 | (goto-char (match-beginning 0)) 322 | (delete-region (match-beginning 0) (match-end 0)) 323 | (setq evil-test-visual-start 324 | (move-marker (make-marker) (point)))) 325 | (when (re-search-forward visual-end nil t) 326 | (goto-char (match-beginning 0)) 327 | (delete-region (match-beginning 0) (match-end 0)) 328 | (setq evil-test-visual-end 329 | (move-marker (make-marker) (point)))))))))) 330 | 331 | (defun evil-test-text (before after &optional before-predicate after-predicate) 332 | "Verify the text around point. 333 | BEFORE is the expected text before point, and AFTER is 334 | the text after point. BEFORE-PREDICATE is a predicate function 335 | to execute at the beginning of the text, and AFTER-PREDICATE 336 | is executed at the end." 337 | (when before 338 | (if (functionp before) 339 | (setq before-predicate before 340 | before nil) 341 | (should (string= (buffer-substring 342 | (max (point-min) (- (point) (length before))) 343 | (point)) 344 | before)))) 345 | (when after 346 | (if (functionp after) 347 | (setq after-predicate after 348 | after nil) 349 | (should (string= (buffer-substring 350 | (point) 351 | (min (point-max) (+ (point) (length after)))) 352 | after)))) 353 | (when before-predicate 354 | (ert-info ((format "Expect `%s' at the beginning" before-predicate)) 355 | (save-excursion 356 | (backward-char (length before)) 357 | (should (funcall before-predicate))))) 358 | (when after-predicate 359 | (ert-info ((format "Expect `%s' at the end" after-predicate)) 360 | (save-excursion 361 | (forward-char (length after)) 362 | (should (funcall after-predicate)))))) 363 | 364 | (defmacro evil-test-region (string &optional end-string 365 | before-predicate after-predicate) 366 | "Verify that the region contains STRING." 367 | (declare (indent defun)) 368 | `(progn 369 | (save-excursion 370 | (goto-char (region-beginning)) 371 | (evil-test-text nil (or ,string ,end-string) ,before-predicate)) 372 | (save-excursion 373 | (goto-char (region-end)) 374 | (evil-test-text (or ,end-string ,string) nil nil ,after-predicate)))) 375 | 376 | (defmacro evil-test-overlay (overlay string &optional end-string 377 | before-predicate after-predicate) 378 | "Verify that OVERLAY contains STRING." 379 | (declare (indent defun)) 380 | `(progn 381 | (save-excursion 382 | (goto-char (overlay-start ,overlay)) 383 | (evil-test-text nil (or ,string ,end-string) ,before-predicate)) 384 | (save-excursion 385 | (goto-char (overlay-end ,overlay)) 386 | (evil-test-text (or ,end-string ,string) nil nil ,after-predicate)))) 387 | 388 | (defmacro evil-with-temp-file (file-var content &rest body) 389 | "Create a temp file with CONTENT and bind its name to FILE-VAR within BODY. 390 | FILE-VAR must be a symbol which contains the name of the 391 | temporary file within the macro body. CONTENT is either a string 392 | to be used as the content of the temporary file or a form to be 393 | executed with the temporary file's buffer as \(current-buffer), 394 | see `with-temp-file'. BODY contains the forms to be executed 395 | while the temporary file exists. The temporary file is deleted at 396 | the end of the execution of BODY." 397 | (declare (indent 2) 398 | (debug (symbolp form body))) 399 | `(let ((,file-var (make-temp-file "evil-test"))) 400 | (with-temp-file ,file-var 401 | ,(if (stringp content) 402 | `(insert ,content) 403 | content)) 404 | ,@body 405 | (delete-file ,file-var))) 406 | 407 | (defun evil-test-file-contents (name contents) 408 | "Ensure that the contents of file with NAME equal CONTENTS." 409 | (with-temp-buffer 410 | (insert-file-contents name) 411 | (should (string= (buffer-string) 412 | contents)))) 413 | 414 | (provide 'evil-test-helpers) 415 | 416 | ;;; evil-test-helpers.el ends here 417 | -------------------------------------------------------------------------------- /evil-types.el: -------------------------------------------------------------------------------- 1 | ;;; evil-types.el --- Type system -*- lexical-binding: t -*- 2 | 3 | ;; Author: Vegard Øye 4 | ;; Maintainer: Vegard Øye 5 | 6 | ;; Version: 1.15.0 7 | 8 | ;; 9 | ;; This file is NOT part of GNU Emacs. 10 | 11 | ;;; License: 12 | 13 | ;; This file is part of Evil. 14 | ;; 15 | ;; Evil is free software: you can redistribute it and/or modify 16 | ;; it under the terms of the GNU General Public License as published by 17 | ;; the Free Software Foundation, either version 3 of the License, or 18 | ;; (at your option) any later version. 19 | ;; 20 | ;; Evil is distributed in the hope that it will be useful, 21 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | ;; GNU General Public License for more details. 24 | ;; 25 | ;; You should have received a copy of the GNU General Public License 26 | ;; along with Evil. If not, see . 27 | 28 | ;;; Commentary: 29 | 30 | ;; A type defines a transformation on a pair of buffer positions. 31 | ;; Types are used by Visual state (character/line/block selection) 32 | ;; and Operator-Pending state (character/line/block motions). 33 | ;; 34 | ;; The basic transformation is "expansion". For example, the `line' 35 | ;; type "expands" a pair of positions to whole lines by moving the 36 | ;; first position to the beginning of the line and the last position 37 | ;; to the end of the line. That expanded selection is what the rest 38 | ;; of Emacs sees and acts on. 39 | ;; 40 | ;; An optional transformation is "contraction", which is the opposite 41 | ;; of expansion. If the transformation is one-to-one, expansion 42 | ;; followed by contraction always returns the original range. 43 | ;; (The `line' type is not one-to-one, as it may expand multiple 44 | ;; positions to the same lines.) 45 | ;; 46 | ;; Another optional transformation is "normalization", which takes 47 | ;; two unexpanded positions and adjusts them before expansion. 48 | ;; This is useful for cleaning up "invalid" positions. 49 | ;; 50 | ;; Types are defined at the end of this file using the macro 51 | ;; `evil-define-type'. 52 | 53 | (require 'evil-common) 54 | (require 'evil-macros) 55 | 56 | ;;; Code: 57 | 58 | ;;; Type definitions 59 | 60 | (evil-define-type exclusive 61 | "Return the positions unchanged, with some exceptions. 62 | If the end position is at the beginning of a line, then: 63 | 64 | * If the beginning position is at or before the first non-blank 65 | character on the line, return `line' (expanded). 66 | 67 | * Otherwise, move the end position to the end of the previous 68 | line and return `inclusive' (expanded)." 69 | :normalize (lambda (beg end) 70 | (cond 71 | ((progn 72 | (goto-char end) 73 | (and (/= beg end) (bolp))) 74 | (setq end (max beg (1- end))) 75 | (cond 76 | ((progn 77 | (goto-char beg) 78 | (looking-back "^[ \f\t\v]*" (line-beginning-position))) 79 | (evil-expand beg end 'line)) 80 | (t 81 | (unless evil-cross-lines 82 | (setq end (max beg (1- end)))) 83 | (evil-expand beg end 'inclusive)))) 84 | (t 85 | (evil-range beg end)))) 86 | :string (lambda (beg end) 87 | (let ((width (- end beg))) 88 | (format "%s character%s" width 89 | (if (= width 1) "" "s"))))) 90 | 91 | (evil-define-type inclusive 92 | "Include the character under point. 93 | Handling for `evil-want-visual-char-semi-exclusive' is deprecated, 94 | and will be removed in a future version." 95 | :expand (lambda (beg end) 96 | (if (and (with-no-warnings evil-want-visual-char-semi-exclusive) 97 | (evil-visual-state-p) 98 | (< beg end) 99 | (save-excursion 100 | (goto-char end) 101 | (or (bolp) (eolp)))) 102 | (evil-range beg end 'exclusive) 103 | (evil-range beg (1+ end)))) 104 | :contract (lambda (beg end) 105 | (evil-range beg (max beg (1- end)))) 106 | :normalize (lambda (beg end) 107 | (evil-range beg (if (eq (char-after end) ?\n) 108 | (max beg (1- end)) end))) 109 | :string (lambda (beg end) 110 | (let ((width (- end beg))) 111 | (format "%s character%s" width 112 | (if (= width 1) "" "s"))))) 113 | 114 | (evil-define-type line 115 | "Include whole lines." 116 | :one-to-one nil 117 | :expand (lambda (beg end) 118 | (evil-range 119 | (progn 120 | (goto-char beg) 121 | ;; move to beginning of line as displayed 122 | (evil-move-beginning-of-line) 123 | (point)) 124 | (progn 125 | (goto-char end) 126 | ;; move to the end of line as displayed 127 | (evil-move-end-of-line) 128 | (line-beginning-position 2)))) 129 | :contract (lambda (beg end) 130 | (evil-range beg (max beg (1- end)))) 131 | :string (lambda (beg end) 132 | (let ((height (count-lines beg end))) 133 | (format "%s line%s" height 134 | (if (= height 1) "" "s"))))) 135 | 136 | (evil-define-type screen-line 137 | "Include whole lines, being aware of `visual-line-mode' 138 | when `evil-respect-visual-line-mode' is non-nil." 139 | :one-to-one nil 140 | :expand (lambda (beg end) 141 | (if (not (and evil-respect-visual-line-mode visual-line-mode)) 142 | (evil-line-expand beg end) 143 | (evil-range 144 | (progn 145 | (goto-char beg) 146 | (save-excursion 147 | (beginning-of-visual-line))) 148 | (progn 149 | (goto-char end) 150 | (save-excursion 151 | ;; `beginning-of-visual-line' reverts to the beginning of the 152 | ;; last visual line if the end of the last line is the end of 153 | ;; the buffer. This would prevent selecting the last screen 154 | ;; line. 155 | (if (= (line-beginning-position 2) (point-max)) 156 | (point-max) 157 | (beginning-of-visual-line 2))))))) 158 | :contract (lambda (beg end) 159 | (evil-range beg (max beg (1- end)))) 160 | :string (lambda (beg end) 161 | (let ((height (count-screen-lines beg end))) 162 | (format "%s screen line%s" height 163 | (if (= height 1) "" "s"))))) 164 | 165 | (evil-define-type block 166 | "Like `inclusive', but for rectangles: 167 | the last column is included." 168 | :expand (lambda (beg end &rest properties) 169 | (let ((beg-col (evil-column beg)) 170 | (end-col (evil-column end)) 171 | (corner (plist-get properties :corner))) 172 | ;; Since blocks are implemented as a pair of buffer 173 | ;; positions, expansion is restricted to what the buffer 174 | ;; allows. In the case of a one-column block, there are 175 | ;; two ways to expand it (either move the upper corner 176 | ;; beyond the lower corner, or the lower beyond the 177 | ;; upper), so try out both possibilities when 178 | ;; encountering the end of the line. 179 | (cond 180 | ((= beg-col end-col) 181 | (goto-char end) 182 | (cond 183 | ((eolp) 184 | (goto-char beg) 185 | (if (eolp) 186 | (evil-range beg end) 187 | (evil-range (1+ beg) end))) 188 | ((memq corner '(lower-right upper-right right)) 189 | (evil-range (1+ beg) end)) 190 | (t 191 | (evil-range beg (1+ end))))) 192 | ((< beg-col end-col) 193 | (goto-char end) 194 | (if (eolp) 195 | (evil-range beg end) 196 | (evil-range beg (1+ end)))) 197 | (t 198 | (goto-char beg) 199 | (if (eolp) 200 | (evil-range beg end) 201 | (evil-range (1+ beg) end)))))) 202 | :contract (lambda (beg end) 203 | (let ((beg-col (evil-column beg)) 204 | (end-col (evil-column end))) 205 | (if (> beg-col end-col) 206 | (evil-range (1- beg) end) 207 | (evil-range beg (max beg (1- end)))))) 208 | :string (lambda (beg end) 209 | (let ((height (count-lines 210 | beg 211 | (progn 212 | (goto-char end) 213 | (if (and (bolp) (not (eobp))) 214 | (1+ end) 215 | end)))) 216 | (width (abs (- (evil-column beg) 217 | (evil-column end))))) 218 | (format "%s row%s and %s column%s" 219 | height 220 | (if (= height 1) "" "s") 221 | width 222 | (if (= width 1) "" "s")))) 223 | :rotate (lambda (beg end &rest properties) 224 | "Rotate block according to :corner property. 225 | :corner can be one of `upper-left',``upper-right', `lower-left' 226 | and `lower-right'." 227 | (let ((left (evil-column beg)) 228 | (right (evil-column end)) 229 | (corner (or (plist-get properties :corner) 230 | 'upper-left))) 231 | (evil-sort left right) 232 | (goto-char beg) 233 | (if (memq corner '(upper-right lower-left)) 234 | (move-to-column right) 235 | (move-to-column left)) 236 | (setq beg (point)) 237 | (goto-char end) 238 | (if (memq corner '(upper-right lower-left)) 239 | (move-to-column left) 240 | (move-to-column right)) 241 | (setq end (point)) 242 | (setq properties (plist-put properties 243 | :corner corner)) 244 | (apply #'evil-range beg end properties)))) 245 | 246 | (evil-define-type rectangle 247 | "Like `exclusive', but for rectangles: 248 | the last column is excluded." 249 | :expand (lambda (beg end) 250 | ;; select at least one column 251 | (if (= (evil-column beg) (evil-column end)) 252 | (evil-expand beg end 'block) 253 | (evil-range beg end 'block)))) 254 | 255 | ;;; Standard interactive codes 256 | 257 | (evil-define-interactive-code "*" 258 | "Signal error if the buffer is read-only." 259 | (when buffer-read-only 260 | (signal 'buffer-read-only nil))) 261 | 262 | (evil-define-interactive-code "b" (prompt) 263 | "Name of existing buffer." 264 | (list (read-buffer prompt (current-buffer) t))) 265 | 266 | (evil-define-interactive-code "c" 267 | "Read character." 268 | (list (read-char))) 269 | 270 | (evil-define-interactive-code "p" 271 | "Prefix argument converted to number." 272 | (list (prefix-numeric-value current-prefix-arg))) 273 | 274 | (evil-define-interactive-code "P" 275 | "Prefix argument in raw form." 276 | (list current-prefix-arg)) 277 | 278 | ;;; Custom interactive codes 279 | 280 | (evil-define-interactive-code "" 281 | "Prefix argument converted to number, possibly multiplied by evil--window-digit." 282 | (let ((prefix-num (prefix-numeric-value current-prefix-arg))) 283 | (if evil--window-digit 284 | (list (* evil--window-digit prefix-num)) 285 | (list prefix-num)))) 286 | 287 | (evil-define-interactive-code "" 288 | "Count." 289 | (list (when current-prefix-arg 290 | (prefix-numeric-value current-prefix-arg)))) 291 | 292 | (evil-define-interactive-code "" 293 | "Count, but only in visual state. 294 | This should be used by an operator taking a count. In normal 295 | state the count should not be handled by the operator but by the 296 | motion that defines the operator's range. In visual state the 297 | range is specified by the visual region and the count is not used 298 | at all. Thus in the case the operator may use the count 299 | directly." 300 | (list (when (and (evil-visual-state-p) current-prefix-arg) 301 | (prefix-numeric-value 302 | current-prefix-arg)))) 303 | 304 | (evil-define-interactive-code "" 305 | "Prefix argument converted to number, or nil possibly multiplied by 306 | evil--window-digit." 307 | (let ((prefix-num (prefix-numeric-value current-prefix-arg))) 308 | (list 309 | (cond (evil--window-digit (* evil--window-digit prefix-num)) 310 | (current-prefix-arg prefix-num))))) 311 | 312 | (evil-define-interactive-code "" 313 | "Character read through `evil-read-key'." 314 | (list 315 | (if (evil-operator-state-p) 316 | (evil-without-restriction (evil-read-key)) 317 | (evil-read-key)))) 318 | 319 | (evil-define-interactive-code "" 320 | "Untyped motion range (BEG END)." 321 | (evil-operator-range)) 322 | 323 | (evil-define-interactive-code "" 324 | "Typed motion range (BEG END TYPE)." 325 | (evil-operator-range t)) 326 | 327 | (evil-define-interactive-code "" 328 | "Typed motion range of visual range (BEG END TYPE). 329 | If visual state is inactive then those values are nil." 330 | (if (evil-visual-state-p) 331 | (let ((range (evil-visual-range))) 332 | (list (car range) 333 | (cadr range) 334 | (evil-type range))) 335 | (list nil nil nil))) 336 | 337 | (evil-define-interactive-code "" 338 | "Current register." 339 | (list evil-this-register)) 340 | 341 | (evil-define-interactive-code "" 342 | "Current yank-handler." 343 | (list (evil-yank-handler))) 344 | 345 | (evil-define-interactive-code "" 346 | "Ex argument." 347 | :ex-arg t 348 | (list (when evil-called-from-ex-p evil-ex-argument))) 349 | 350 | (evil-define-interactive-code "" () 351 | "Prefix argument or ex-arg, converted to number" 352 | (list (cond 353 | (current-prefix-arg (prefix-numeric-value current-prefix-arg)) 354 | (evil-ex-argument (string-to-number evil-ex-argument)) 355 | (evil-called-from-ex-p nil) 356 | (t 1)))) 357 | 358 | (evil-define-interactive-code "" 359 | "Ex file argument." 360 | :ex-arg file 361 | (list (when evil-called-from-ex-p (evil-ex-file-arg)))) 362 | 363 | (evil-define-interactive-code "" 364 | "Ex buffer argument." 365 | :ex-arg buffer 366 | (list evil-ex-argument)) 367 | 368 | (evil-define-interactive-code "" 369 | "Ex shell command argument." 370 | :ex-arg shell 371 | (list evil-ex-argument)) 372 | 373 | (evil-define-interactive-code "" 374 | "Ex file or shell command argument." 375 | :ex-arg file-or-shell 376 | (list evil-ex-argument)) 377 | 378 | (evil-define-interactive-code "" 379 | "Ex symbolic argument." 380 | :ex-arg sym 381 | (list (and evil-ex-argument (intern evil-ex-argument)))) 382 | 383 | (evil-define-interactive-code "" 384 | "Ex line number." 385 | (list 386 | (when evil-called-from-ex-p 387 | (let ((expr (evil-ex-parse (or evil-ex-argument "")))) 388 | (if (eq (car expr) 'evil-goto-line) 389 | (save-excursion (goto-char evil-ex-point) 390 | (eval (cadr expr) t)) 391 | (user-error "Invalid address")))))) 392 | 393 | (evil-define-interactive-code "" 394 | "Ex bang argument." 395 | :ex-bang t 396 | (list evil-ex-bang)) 397 | 398 | (evil-define-interactive-code "" 399 | "Ex delimited argument." 400 | (when evil-called-from-ex-p 401 | (evil-delimited-arguments (or evil-ex-argument "")))) 402 | 403 | (evil-define-interactive-code "" 404 | "Ex global argument." 405 | (when evil-called-from-ex-p 406 | (evil-ex-parse-global (or evil-ex-argument "")))) 407 | 408 | (evil-define-interactive-code "" 409 | "Ex substitution argument." 410 | :ex-arg substitution 411 | (when evil-called-from-ex-p 412 | (evil-ex-get-substitute-info (or evil-ex-argument "") t))) 413 | 414 | (evil-define-interactive-code "" 415 | "Ex register and count argument, both optional. 416 | Can be used for commands such as :delete [REGISTER] [COUNT] where the 417 | command can be called with either zero, one or two arguments. With one 418 | argument, if it is numeric, it is treated as a COUNT, otherwise, as a 419 | REGISTER." 420 | (when evil-called-from-ex-p 421 | (evil-ex-get-optional-register-and-count evil-ex-argument))) 422 | 423 | (defun evil-ex-get-optional-register-and-count (string) 424 | "Parse STRING as an ex arg with both optional REGISTER and COUNT. 425 | Return a list (REGISTER COUNT)." 426 | (let* ((split-args (split-string (or string ""))) 427 | (arg-count (length split-args)) 428 | (arg0 (car split-args)) 429 | (arg1 (cadr split-args)) 430 | (number-regex "^-?[1-9][0-9]*$") 431 | (register nil) 432 | (count nil)) 433 | (cond 434 | ;; :command REGISTER or :command COUNT 435 | ((= arg-count 1) 436 | (if (string-match-p number-regex arg0) 437 | (setq count arg0) 438 | (setq register arg0))) 439 | ;; :command REGISTER COUNT 440 | ((eq arg-count 2) 441 | (setq register arg0 442 | count arg1)) 443 | ;; more than 2 args aren't allowed 444 | ((> arg-count 2) 445 | (user-error "Invalid use"))) 446 | 447 | ;; if register is given, check it's valid 448 | (when register 449 | (unless (= (length register) 1) 450 | (user-error "Invalid register")) 451 | (setq register (string-to-char register))) 452 | 453 | ;; if count is given, check it's valid 454 | (when count 455 | (unless (string-match-p number-regex count) 456 | (user-error "Invalid count")) 457 | (setq count (string-to-number count)) 458 | (unless (> count 0) 459 | (user-error "Invalid count"))) 460 | 461 | (list register count))) 462 | 463 | (provide 'evil-types) 464 | 465 | ;;; evil-types.el ends here 466 | -------------------------------------------------------------------------------- /evil.el: -------------------------------------------------------------------------------- 1 | ;;; evil.el --- Extensible vi layer -*- lexical-binding: t; -*- 2 | 3 | ;; The following list of authors was kept up to date until the beginning of 4 | ;; 2017, when evil moved under new maintainers. For authors since then, please 5 | ;; consult the git logs. 6 | 7 | ;; Alessandro Piras 8 | ;; Alexander Baier 9 | ;; Antono Vasiljev 10 | ;; Bailey Ling 11 | ;; Barry O'Reilly 12 | ;; Christoph Lange 13 | ;; Daniel Reiter 14 | ;; Eivind Fonn 15 | ;; Emanuel Evans 16 | ;; Eric Siegel 17 | ;; Eugene Yaremenko 18 | ;; Frank Fischer 19 | ;; Frank Terbeck 20 | ;; Gordon Gustafson 21 | ;; Herbert Jones 22 | ;; Jonas Bernoulli 23 | ;; Jonathan Claggett 24 | ;; José A. Romero L. 25 | ;; Justin Burkett 26 | ;; Lars Andersen 27 | ;; Lintaro Ina 28 | ;; Lukasz Wrzosek 29 | ;; Marian Schubert 30 | ;; Matthew Malcomson <> 31 | ;; Michael Markert 32 | ;; Mike Gerwitz 33 | ;; Nikolai Weibull 34 | ;; phaebz 35 | ;; ralesi 36 | ;; Rodrigo Setti 37 | ;; Sanel Zukan 38 | ;; Sarah Brofeldt 39 | ;; Simon Hafner 40 | ;; Stefan Wehr 41 | ;; Sune Simonsen 42 | ;; Thomas Hisch 43 | ;; Tim Harper 44 | ;; Tom Willemse 45 | ;; Trevor Murphy 46 | ;; Ulrich Müller 47 | ;; Vasilij Schneidermann 48 | ;; Vegard Øye 49 | ;; Winfred Lu 50 | ;; Wolfgang Jenkner 51 | ;; Xiao Hanyu 52 | ;; York Zhao 53 | 54 | ;; The following line is included for NonGNU ELPA's build script: 55 | ;; Maintainer: Tom Dalziel 56 | 57 | ;; Maintainers: The emacs-evil team. 58 | ;; To get in touch, please use the bug tracker or the 59 | ;; mailing list (see below). 60 | ;; Created: 2011-03-01 61 | ;; Version: 1.15.0 62 | ;; Package-Requires: ((emacs "24.1") (cl-lib "0.5") (goto-chg "1.6") (nadvice "0.3")) 63 | ;; Keywords: emulations 64 | ;; URL: https://github.com/emacs-evil/evil 65 | ;; Repository: https://github.com/emacs-evil/evil.git 66 | ;; EmacsWiki: http://www.emacswiki.org/emacs/Evil 67 | ;; Bug tracker: https://github.com/emacs-evil/evil/issues 68 | ;; If you have bug reports, suggestions or patches, please 69 | ;; create an issue at the bug tracker (open for everyone). 70 | ;; Other discussions (tips, extensions) go to the mailing list. 71 | ;; Mailing list: 72 | ;; Subscribe: http://tinyurl.com/implementations-list 73 | ;; Newsgroup: nntp://news.gmane.org/gmane.emacs.vim-emulation 74 | ;; Archives: http://dir.gmane.org/gmane.emacs.vim-emulation 75 | ;; You don't have to subscribe to post; we usually reply 76 | ;; within a few days and CC our replies back to you. 77 | ;; 78 | ;; This file is NOT part of GNU Emacs. 79 | 80 | ;;; License: 81 | 82 | ;; This file is part of Evil. 83 | ;; 84 | ;; Evil is free software: you can redistribute it and/or modify 85 | ;; it under the terms of the GNU General Public License as published by 86 | ;; the Free Software Foundation, either version 3 of the License, or 87 | ;; (at your option) any later version. 88 | ;; 89 | ;; Evil is distributed in the hope that it will be useful, 90 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 91 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 92 | ;; GNU General Public License for more details. 93 | ;; 94 | ;; You should have received a copy of the GNU General Public License 95 | ;; along with Evil. If not, see . 96 | 97 | ;;; Commentary: 98 | 99 | ;; Evil is an extensible vi layer for Emacs. It emulates the main 100 | ;; features of Vim, and provides facilities for writing custom 101 | ;; extensions. 102 | ;; 103 | ;; Evil lives in a Git repository. To obtain Evil, do 104 | ;; 105 | ;; git clone git://github.com/emacs-evil/evil.git 106 | ;; 107 | ;; Move Evil to ~/.emacs.d/evil (or somewhere else in the `load-path'). 108 | ;; Then add the following lines to ~/.emacs: 109 | ;; 110 | ;; (add-to-list 'load-path "~/.emacs.d/evil") 111 | ;; (require 'evil) 112 | ;; (evil-mode 1) 113 | ;; 114 | ;; Evil requires undo-redo (Emacs 28), undo-fu or undo-tree for redo 115 | ;; functionality. Otherwise, Evil uses regular Emacs undo. 116 | ;; 117 | ;; https://codeberg.org/ideasman42/emacs-undo-fu 118 | ;; https://melpa.org/#/undo-fu 119 | ;; https://gitlab.com/tsc25/undo-tree 120 | ;; https://elpa.gnu.org/packages/undo-tree.html 121 | ;; 122 | ;; Evil requires `goto-last-change' and `goto-last-change-reverse' 123 | ;; function for the corresponding motions g; g, as well as the 124 | ;; last-change-register `.'. One package providing these functions is 125 | ;; goto-chg.el: 126 | ;; 127 | ;; https://github.com/emacs-evil/goto-chg 128 | ;; https://melpa.org/#/goto-chg 129 | ;; https://elpa.nongnu.org/nongnu/goto-chg.html 130 | ;; 131 | ;; Without this package the corresponding motions will raise an error. 132 | 133 | ;;; Code: 134 | 135 | (require 'evil-vars) 136 | (require 'evil-common) 137 | (require 'evil-core) 138 | (require 'evil-states) 139 | (require 'evil-repeat) 140 | (require 'evil-macros) 141 | (require 'evil-search) 142 | (require 'evil-ex) 143 | (require 'evil-types) 144 | (require 'evil-commands) 145 | (require 'evil-jumps) 146 | (require 'evil-maps) 147 | 148 | (when evil-want-integration 149 | (require 'evil-integration)) 150 | 151 | (when evil-want-keybinding 152 | (require 'evil-keybindings)) 153 | 154 | (run-hooks 'evil-after-load-hook) 155 | 156 | (provide 'evil) 157 | 158 | ;;; evil.el ends here 159 | -------------------------------------------------------------------------------- /scripts/evil-extract-docstrings: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S emacs --script 2 | 3 | (setq cur-path (file-name-directory load-file-name)) 4 | 5 | (add-to-list 'load-path (expand-file-name ".." cur-path)) 6 | (require 'evil) 7 | (require 'evil-digraphs) 8 | (require 'json) 9 | (require 'help) 10 | 11 | (defun mark-command-keys (string) 12 | "Mark key bindings in STRING with the \":kbd:\" Sphinx role." 13 | (when string 14 | (cl-loop 15 | for prev = 0 then pos until (>= prev (length string)) 16 | for pos = (next-single-property-change prev 'face string (length string)) 17 | concat 18 | (let ((s (substring string prev pos))) 19 | (if (eq (get-text-property prev 'face string) 'help-key-binding) 20 | (format ":kbd:`%s`" s) 21 | s))))) 22 | 23 | (let (vars) 24 | (mapatoms 25 | (lambda (sym) 26 | (when (string-prefix-p "evil-" (symbol-name sym)) 27 | (let ((default (eval (car (get sym 'standard-value))))) 28 | (push `(,sym (default . ,(cond 29 | ((consp default) (format "%S" default)) 30 | ((symbolp default) (symbol-name default)) 31 | (t default))) 32 | (local . ,(local-variable-if-set-p sym)) 33 | (default-type . ,(type-of default)) 34 | (var-docstring . ,(mark-command-keys (documentation-property sym 'variable-documentation))) 35 | (fn-docstring . ,(ignore-errors (mark-command-keys (documentation sym)))) 36 | (arglist . ,(help-function-arglist sym)) 37 | (functionp . ,(functionp sym)) 38 | (macrop . ,(macrop sym))) 39 | vars))))) 40 | (with-temp-file (expand-file-name "../doc/docstringdb.json" cur-path) 41 | (insert (json-encode vars)))) 42 | -------------------------------------------------------------------------------- /scripts/evil-release-stable: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # Copyright (c) 2015 Frank Fischer 4 | # 5 | # This program is free software: you can redistribute it and/or 6 | # modify it under the terms of the GNU General Public License as 7 | # published by the Free Software Foundation, either version 3 of the 8 | # License, or (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | 18 | 19 | # This script releases a new (minor) stable release given that some 20 | # new commits on the stable branch since the last tag exist. 21 | 22 | Dir.chdir File.dirname(__FILE__) 23 | 24 | def die(msg = "Failed") 25 | STDERR.puts msg 26 | exit 1 27 | end 28 | 29 | def run(cmd) 30 | system(cmd) or die(cmd) 31 | end 32 | 33 | run 'hg pull' 34 | run 'hg update -r stable' 35 | 36 | tag = `hg tags`.split("\n").select{|line| line =~ /^\d+\.\d+\.\d+/}.map do |line| 37 | tag, rev = line.split 38 | major, minor, tiny = tag.split(/\./).map(&:to_i) 39 | [major, minor, tiny, rev[/\d+/].to_i] 40 | end.max 41 | 42 | tag or die 'No tagged revision found' 43 | 44 | stable = `hg log -r 'branch(stable) and not file("../.hgtags") and not ..tag("re:\\d+\\.\\d+\\.\\d+")' | wc -l`.to_i != 0 45 | 46 | if stable 47 | new_tag = "#{tag[0]}.#{tag[1]}.#{tag[2]+1}" 48 | run "make -C .. nversion VERSION='#{new_tag}'" 49 | run "hg commit -m 'update version to #{new_tag}'" 50 | run "hg tag -m 'version #{new_tag}' -r stable #{new_tag}" 51 | run "hg push -r stable" 52 | end 53 | -------------------------------------------------------------------------------- /scripts/evilupdate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/emacs --script 2 | ;;; evilupate.el -- Publishing script for Evil 3 | 4 | ;;; Header: 5 | 6 | ;; This file is not part of Emacs 7 | 8 | ;; Author: Frank Fischer 9 | ;; Maintainer: Frank Fischer 10 | ;; Version: 1.0 11 | ;; Package-Requires: ((emacs "24.3") (s "1.9.0") (f "0.17.2") yaoddmuse) 12 | 13 | ;; The contents of this file are subject to the GPL License, Version 3.0. 14 | 15 | ;; Copyright (C) 2015, 2016, Frank Fischer 16 | 17 | ;; This program is free software: you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version 21 | 22 | ;; This program is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with this program. If not, see . 29 | 30 | ;;; Commentary: 31 | 32 | ;; This is a small script to update Evil's version at certain places: 33 | ;; 34 | ;; - topic of the IRC channel #evil-mode in irc.libera.chat 35 | ;; - EmacsWiki page 36 | ;; - header of all source files 37 | ;; - the ELPA package file 38 | ;; 39 | ;; The script should be invoked with the new version string 40 | ;; 41 | ;; evil-update.el 1.2.3 42 | ;; 43 | 44 | ;;; Code: 45 | 46 | (package-initialize) 47 | 48 | (require 'f) 49 | (require 'erc) 50 | (require 'yaoddmuse) 51 | 52 | (defconst evilupdate-irc-nick "lyrobot") 53 | (defconst evilupdate-irc-channel "#evil-mode") 54 | (defconst evilupdate-irc-topic 55 | "Evil = Extensible vi layer for Emacs | Current version: VERSION | https://github.com/emacs-evil/evil | If you don't get an answer here, please use the mailing-list implementations-list@lists.ourproject.org") 56 | (defconst evilupdate-wiki-page "Evil") 57 | (defvar evilupdate-version "1.0.0") 58 | (defvar evilupdate-done nil) 59 | 60 | (defun evilupdate-wait () 61 | "Wait until `evilupdate-done' is set to t." 62 | (while (not evilupdate-done) 63 | (sleep-for 1)) 64 | (setq evilupdate-done nil)) 65 | 66 | (defun evilupdate-done () 67 | "Set `evilupdate-done' to t to stop the corresponding `evilupdate-wait'." 68 | (setq evilupdate-done t)) 69 | 70 | (defun evilupdate-update-irc () 71 | "Update the topic of the IRC channel." 72 | (let ((erc-nick evilupdate-irc-nick) 73 | (erc-autojoin-channels-alist nil) 74 | (auth-sources nil)) 75 | (erc-tls :server "irc.libera.chat" :port "6697" :nick evilupdate-irc-nick) 76 | (add-hook 'erc-join-hook 77 | (lambda () 78 | (let (case-fold-search) 79 | (erc-set-topic (replace-regexp-in-string "VERSION" 80 | evilupdate-version 81 | evilupdate-irc-topic 82 | nil t))) 83 | (erc-quit-server "") 84 | (sleep-for 5) 85 | (evilupdate-done))) 86 | (erc-join-channel evilupdate-irc-channel) 87 | (evilupdate-wait))) 88 | 89 | (defun evilupdate-wiki-trace (page-buffer-name) 90 | "Callback for updating the EmacsWiki page in buffer PAGE-BUFFER-NAME." 91 | (with-current-buffer page-buffer-name 92 | (goto-char (point-min)) 93 | (when (re-search-forward "Current stable version: \\*\\*\\([^*]*\\)\\*\\*") 94 | (goto-char (match-beginning 1)) 95 | (delete-region (match-beginning 1) (match-end 1)) 96 | (insert evilupdate-version) 97 | (yaoddmuse-post-buffer (current-buffer) evilupdate-version nil) 98 | (evilupdate-done)))) 99 | 100 | (unless (require 'nadvice nil t) 101 | (defadvice yaoddmuse-display-page (around evilupdate activate) 102 | (evilupdate-wiki-trace (ad-get-arg 0)))) 103 | 104 | (defun evilupdate-update-emacswiki () 105 | "Update the version information on the EmacsWiki page." 106 | (setq yaoddmuse-wikis 107 | '(("EmacsWiki" "https://www.emacswiki.org/emacs" utf-8 "uihnscuskc=1;"))) 108 | (when (featurep 'nadvice) 109 | (advice-add 'yaoddmuse-display-page :after 'evilupdate-wiki-trace)) 110 | (yaoddmuse-edit "EmacsWiki" evilupdate-wiki-page t) 111 | (evilupdate-wait)) 112 | 113 | (defun evilupdate-update-regexp (file regexp) 114 | "Update version tag in FILE. 115 | The version tag is defined by the REGEXP, in particular by the first 116 | match group." 117 | (find-file file) 118 | (goto-char (point-min)) 119 | (when (re-search-forward regexp nil t) 120 | (goto-char (match-beginning 1)) 121 | (delete-region (match-beginning 1) (match-end 1)) 122 | (insert evilupdate-version) 123 | (save-buffer))) 124 | 125 | (defun evilupdate-update-files () 126 | "Replace version comments in all source files." 127 | (dolist (file (f-glob "*.el")) 128 | (evilupdate-update-regexp file ";;\\s-*Version:\\s-*\\([^\n]+\\)"))) 129 | 130 | (defun evilupdate-update-pkg () 131 | "Replace version in package file." 132 | (evilupdate-update-regexp "evil-pkg.el" "\"evil\"[ \t\n\r]*\"\\([^\"]+\\)\"")) 133 | 134 | (defun evilupdate-update-var () 135 | "Replace version in `evil-version' variable." 136 | (evilupdate-update-regexp 137 | "evil-vars.el" 138 | "t \"\\([^\"]*\\)\"[) \n\r\t]*\"The current version of Evil")) 139 | 140 | (defun evilupdate-update-news () 141 | "Send an posting to the mailing list." 142 | (shell-command (concat "thunderbird -compose \"newsgroups=gmane.emacs.vim-emulation,preselectid=id2,subject='[ANN] Evil version " evilupdate-version " released',body='" 143 | "Evil version " evilupdate-version " has been released. 144 | 145 | The stable version can be installed from MELPA stable [1] and NonGNU ELPA [2]. 146 | The latest development version is available from MELPA [3]. 147 | 148 | The Evil developers. 149 | 150 | [1] http://stable.melpa.org 151 | [2] https://elpa.nongnu.org/nongnu/evil.html 152 | [3] http://melpa.org 153 | '\""))) 154 | 155 | (defun evilupdate-update (version nonews) 156 | "Update Evil to VERSION. 157 | If NONEWS is non-nil do not post a message to the newsgroup." 158 | (setq evilupdate-cnt 0) 159 | (setq evilupdate-version version) 160 | (evilupdate-update-emacswiki) 161 | (evilupdate-update-irc) 162 | (evilupdate-update-files) 163 | (evilupdate-update-pkg) 164 | (evilupdate-update-var) 165 | (unless nonews (evilupdate-update-news))) 166 | 167 | (cond 168 | ((= (length argv) 2) 169 | (unless (equal (car argv) "nonews") 170 | (user-error "Usage: evilupdate.el [-n] VERSION")) 171 | (evilupdate-update (cadr argv) t)) 172 | ((= (length argv) 1) 173 | (evilupdate-update (cadr argv))) 174 | (t 175 | (user-error "Usage: evilupdate.el [-n] VERSION"))) 176 | 177 | ;;; evilupdate.el ends here 178 | --------------------------------------------------------------------------------