pax_global_header00006660000000000000000000000064136070332320014511gustar00rootroot0000000000000052 comment=5b690258fcfc47ca1fed25f17e04356edc713925 evil-1.12.17/000077500000000000000000000000001360703323200126215ustar00rootroot00000000000000evil-1.12.17/.dir-locals.el000066400000000000000000000001231360703323200152460ustar00rootroot00000000000000;; Don't use tabs for el files ((emacs-lisp-mode . ((indent-tabs-mode . nil)))) evil-1.12.17/.gitattributes000066400000000000000000000000171360703323200155120ustar00rootroot00000000000000*.el diff=lisp evil-1.12.17/.github/000077500000000000000000000000001360703323200141615ustar00rootroot00000000000000evil-1.12.17/.github/ISSUE_TEMPLATE.md000066400000000000000000000017611360703323200166730ustar00rootroot00000000000000 # Issue type - Bug report - Enhancement request - Question - Other # Environment Emacs version: Operating System: Evil version: Evil installation type: Graphical/Terminal: Tested in a `make emacs` session (see [CONTRIBUTING.md](https://github.com/emacs-evil/evil/blob/master/CONTRIBUTING.md#bug-reports)): # Reproduction steps - Start Emacs # Expected behavior # Actual behavior # Further notes evil-1.12.17/.gitignore000066400000000000000000000001771360703323200146160ustar00rootroot00000000000000*.elc *.aux *.cp *.fn *.fns *.info *.ky *.log *.pg *.toc *.tp *.vr *.vrs .depend evil-autoloads.el test-results.txt typescript evil-1.12.17/.travis.yml000066400000000000000000000007401360703323200147330ustar00rootroot00000000000000language: nix os: - linux env: - EMACS_CI=emacs-24-5 - EMACS_CI=emacs-25-3 - EMACS_CI=emacs-26-3 - EMACS_CI=emacs-snapshot matrix: allow_failures: - env: EMACS_CI=emacs-snapshot install: - bash <(curl https://raw.githubusercontent.com/purcell/nix-emacs-ci/master/travis-install) script: - emacs --version - script -eqc 'make test' > /dev/null after_script: - cat test-results.txt notifications: email: on_success: never on_failure: always evil-1.12.17/CHANGES.org000066400000000000000000000025221360703323200144030ustar00rootroot00000000000000* Changes and New Features in Evil ** News in 1.0.7 * Fix #319. ** News in 1.0.6 * Fix bug induced in emacs trunk due to changed behaviour of `overriding-terminal-local-map` (fixes #309). ** News in 1.0.5 * Fix bug in `show-paren-mode` due to variable renaming in latest emacs. * Fix bug in isearch module due to variable renaming in latest emacs. ** News in 1.0.4 * Undo one restriction when argument is read in operator state. ** News in 1.0.3 * Fix `evil-delete-backward-word` at first non-blank in a line. ** News in 1.0.2 * Fix #290. ** News in 1.0.1 *** Improvements * An ELPA package built by =make elpa= contains COPYING file. * Bind =[tab]= like =\t= in =evil-ex-completion-map=, so that it cannot be overwritten by a =[tab]= binding in the parent keymap =minibuffer-local-completion-map=. * Improve worst case performance of internal functions =evil-in-string-p=, =evil-string-beginning= and =evil-string-end=. This functions are used, e.g., in certain text objects to detect whether point is within a string. * Update authors list. *** Fixes * The interactive code == is fixed and used correctly in =evil-ex-set-initial-state=. * =evil-ex-global= always generates a single undo-step. * Resolved issues: #249, #250, #253 and #257. evil-1.12.17/CONTRIBUTING.md000066400000000000000000000054521360703323200150600ustar00rootroot00000000000000# Bug reports Bug reports and feature requests should be made on the [issue tracker](https://github.com/emacs-evil/evil/issues) here on github. **Before** sending a bug report, please take note of the following comments. 1. Please provide a full description of the configuration of your system. This includes - Emacs version, - Evil version (e.g., the hash in the git repository), - Whether you use Emacs/Evil in X mode or in terminal mode, - Whether you use Emacs/Evil in terminal mode with some terminal multiplexer like **tmux** or **screen** (and see below). 2. Test the bug in a clean Emacs environment without any additional packages loaded (besides Evil itself). You can easily get such an environment by executing either `make emacs` (for X) or `make terminal` (for terminal mode) in Evil's source directory. If your bug is related to some other package, try to load only this package from the clean environment after using `M-x package-initialize` first. 3. If you've just updated your Evil from the repository, **do not forget to recompile** Evil by executing `make` in Evil's source directory. 4. If possible, try to give a minimal example how to reproduce the error starting from a fresh Emacs. The minimal example could be some buffer content and a sequence of key-strokes that show up the error. 5. If the bug you want to report is related to the behavior of some commands or motions, please note the following. One goal of Evil is to get a behavior as close to **Vim** as possible unless there is a good reason not to do so. The reason is that many users come from Vim or use both, Vim and Evil, and we want to keep the number of annoying differences between both as small as possible, especially in common commands. In case you get an unexpected behavior, please compare the behavior with plain Vim (i.e., without any customization), if there's a difference please file the bug with a description of this difference (and possibly a reference to Vim's documentation). If you realize that both, Vim and Evil, behave the same but you want a different behavior, you may make a **feature request** for some customization option (but the default behavior will probably not be changed in favor for Vim compatibility). Evil already contains several customization options and sometimes the desired changes can be achieved as easily as redefining some key-bindings. # Pull Requests 1. Please follow the [Emacs Lisp Style Guide](https://github.com/bbatsov/emacs-lisp-style-guide/) 2. When in doubt, adhere to the style conventions in the source code, but don't be afraid of suggesting code enhancements in case you encounter suboptimal code. 3. If your pull requests adds a feature or fixes a regression, add tests covering it to `evil-tests.el`. evil-1.12.17/COPYING000066400000000000000000001045131360703323200136600ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . evil-1.12.17/Cask000066400000000000000000000002221360703323200134210ustar00rootroot00000000000000(package "evil" "1.12.17" "Extensible Vi layer for Emacs.") (files "*.el") ;; (depends-on "goto-chg" "0.6.3") ;; (depends-on "undo-tree" "1.6") evil-1.12.17/Makefile000066400000000000000000000071001360703323200142570ustar00rootroot00000000000000SHELL = /bin/sh EMACS ?= emacs FILES = $(filter-out evil-test-helpers.el evil-tests.el evil-pkg.el,$(wildcard evil*.el)) VERSION := $(shell sed -ne '/define-package/,$$p' evil-pkg.el | sed -ne '/^\s*"[[:digit:]]\+\(\.[[:digit:]]\+\)*"\s*$$/ s/^.*"\(.*\)".*$$/\1/p') ELPAPKG = evil-$(VERSION) PROFILER = DOC = doc TAG = LIBS = -L lib ELCFILES = $(FILES:.el=.elc) .PHONY: all compile compile-batch info pdf clean tests test emacs term terminal profiler indent elpa version # Byte-compile Evil. all: compile compile: $(ELCFILES) .depend: $(FILES) @echo Compute dependencies @rm -f .depend @for f in $(FILES); do \ sed -n "s/ *(require '\(evil-[^)]*\).*)/$${f}c: \1.elc/p" $$f >> .depend;\ done -include .depend $(ELCFILES): %.elc: %.el $(EMACS) --batch -Q -L . $(LIBS) -f batch-byte-compile $< # Byte-compile all files in one batch. This is faster than # compiling each file in isolation, but also less stringent. compile-batch: clean $(EMACS) --batch -Q -L . $(LIBS) -f batch-byte-compile ${FILES} # Documentation. doc: info pdf info: clean cd $(DOC) && makeinfo evil.texi pdf: clean cd $(DOC) && texi2pdf evil.texi # Delete byte-compiled files etc. clean: rm -f *~ rm -f \#*\# rm -f *.elc rm -f .depend cd $(DOC) && rm -f *.aux *.cp *.fn *.fns *.info *.ky *.log *.pg *.toc *.tp *.vr *.vrs # Run tests. # The TAG variable may specify a test tag or a test name: # make test TAG=repeat # This will only run tests pertaining to the repeat system. test: $(EMACS) -nw -Q -L . $(LIBS) -l evil-tests.el \ --eval "(evil-tests-initialize '(${TAG}) '(${PROFILER}))" # Byte-compile Evil and run all tests. tests: compile $(EMACS) -nw -Q -L . $(LIBS) -l evil-tests.el \ --eval "(evil-tests-initialize '(${TAG}) '(${PROFILER}))" rm -f *.elc .depend # Load Evil in a fresh instance of Emacs and run all tests. emacs: $(EMACS) -Q -L . $(LIBS) -l goto-chg.el -l evil-tests.el \ --eval "(evil-mode 1)" \ --eval "(evil-tests-initialize '(${TAG}) '(${PROFILER}) t)" # Load Evil in a terminal Emacs and run all tests. term: terminal terminal: $(EMACS) -nw -Q -L . $(LIBS) -l goto-chg.el -l evil-tests.el \ --eval "(evil-mode 1)" \ --eval "(evil-tests-initialize '(${TAG}) '(${PROFILER}) t)" # Run all tests with profiler. profiler: $(EMACS) --batch -Q -L . $(LIBS) -l goto-chg.el -l evil-tests.el \ --eval "(evil-tests-initialize '(${TAG}) (or '(${PROFILER}) t))" # Re-indent all Evil code. # Loads Evil into memory in order to indent macros properly. # Also removes trailing whitespace, tabs and extraneous blank lines. indent: clean $(EMACS) --batch --eval '(setq vc-handled-backends nil)' ${FILES} evil-tests.el -Q -L . $(LIBS) -l evil-tests.el \ --eval "(dolist (buffer (reverse (buffer-list))) \ (when (buffer-file-name buffer) \ (set-buffer buffer) \ (message \"Indenting %s\" (current-buffer)) \ (setq-default indent-tabs-mode nil) \ (untabify (point-min) (point-max)) \ (indent-region (point-min) (point-max)) \ (delete-trailing-whitespace) \ (untabify (point-min) (point-max)) \ (goto-char (point-min)) \ (while (re-search-forward \"\\n\\\\{3,\\\\}\" nil t) \ (replace-match \"\\n\\n\")) \ (when (buffer-modified-p) (save-buffer 0))))" # Create an ELPA package. elpa: @echo "Creating ELPA package $(ELPAPKG).tar" @rm -rf ${ELPAPKG} @mkdir ${ELPAPKG} @cp $(FILES) COPYING evil-pkg.el ${ELPAPKG} @tar cf ${ELPAPKG}.tar ${ELPAPKG} @rm -rf ${ELPAPKG} # Change the version using make VERSION=x.y.z version: @$(EMACS) --script scripts/evilupdate "${VERSION}" # Change the version using make VERSION=x.y.z, but do not post to the newsgroup nversion: @$(EMACS) --script scripts/evilupdate nonews "${VERSION}" evil-1.12.17/README.md000066400000000000000000000130031360703323200140750ustar00rootroot00000000000000![An extensible vi layer for Emacs](https://raw.githubusercontent.com/emacs-evil/evil/master/doc/logo.png) [![Build Status](https://travis-ci.org/emacs-evil/evil.svg?branch=master)](https://travis-ci.org/emacs-evil/evil) [![MELPA](https://melpa.org/packages/evil-badge.svg)](https://melpa.org/#/evil) [![MELPA Stable](https://stable.melpa.org/packages/evil-badge.svg)](https://stable.melpa.org/#/evil) [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) Evil is an **e**xtensible **vi** **l**ayer for [Emacs](http://www.gnu.org/software/emacs/). It emulates the main features of [Vim](http://www.vim.org/), and provides facilities for writing custom extensions. Also see our page on [EmacsWiki](http://emacswiki.org/emacs/Evil). # Download Evil lives in a git repository. To download Evil, do ``` git clone --depth 1 https://github.com/emacs-evil/evil ~/.emacs.d/evil ``` # Install After the download step, add the following lines to `~/.emacs`: ```elisp (add-to-list 'load-path "~/.emacs.d/evil") (require 'evil) (evil-mode 1) ``` ## Dependencies * Evil requires [undo-tree.el](http://www.emacswiki.org/emacs/UndoTree) in the `load-path` for linear undo and undo branches. * For the motions `g;` `g,` and for the last-change-register `.`, Evil requires the [goto-chg.el](https://github.com/emacs-evil/goto-chg) package, which provides the functions `goto-last-change` and `goto-last-change-reverse`. # Documentation A brief [PDF manual](https://raw.githubusercontent.com/emacs-evil/evil/master/doc/evil.pdf) is available. # Mailing list Evil is discussed at the [gmane.emacs.vim-emulation](http://lists.ourproject.org/cgi-bin/mailman/listinfo/implementations-list) mailing list. # IRC Visit us on `irc.freenode.net #evil-mode`. # Contribution See [CONTRIBUTING.md](https://github.com/emacs-evil/evil/blob/master/CONTRIBUTING.md) for guidelines for issues and pull requests. # FAQ ## Problems with the **Escape** key in terminal mode A common problem when using Evil in terminal mode is a certain delay after pressing the Escape key. Even more, when pressing the Escape key followed quickly by another key the command is recognized as M- instead of two separate command ESC followed by . In fact, it is perfectly valid to simulate M- by pressing ESC quickly (but see below). The reason for this is that in terminal mode a key sequence involving the Meta-key (or Alt-key) always generates a so called "escape sequence", i.e., a sequence of two events sent to Emacs, the first being ESC the second the key pressed simultaneously. The problem is that pressing the Escape-key itself also generates the ESC event. Thus, if Emacs (and therefore Evil) receives an ESC event there is no way to tell whether the Escape key has been pressed (and no further event will arrive) or a M- combination has been pressed (and the event will arrive soon). In order to distinguish both situations Evil does the following. After receiving an ESC event Evil waits for a short time period (specified by the variable `evil-esc-delay` which defaults to 0.01 seconds) for another event. If no other event arrives Evil assumes that the plain Escape key has been pressed, otherwise it assumes a M- combination has been pressed and combines the ESC event with the second one. Because a M- sequence usually generates both events in very quick succession, 0.01 seconds are usually enough and the delay is hardly noticeable by the user. But if you use a terminal multiplexer like **tmux** or **screen** the situation may be worse. Those multiplexers have exactly the same problem recognizing M- sequences and often introduce their own delay for the ESC key. There is no way for evil to influence this delay. In order to reduce it you must reconfigure your terminal multiplexer. Note that this problem should not arise when using Evil in X mode. The reason is that in this case the Escape key itself generates a different command, namely 'escape (a symbol) and hence Evil can distinguish whether the Escape key or a M- combination has been pressed. But this also implies that pressing ESC followed by cannot be used to simulate M- in X mode! ## Underscore "_" is not a word character An underscore "_" is a word character in Vim. This means that word-motions like `w` skip over underlines in a sequence of letters as if it was a letter itself. In contrast, in Evil the underscore is often a non-word character like operators, e.g. `+`. The reason is that Evil uses Emacs' definition of a word and this definition does often not include the underscore. In Emacs word characters are determined by the syntax-class of the buffer. The syntax-class usually depends on the major-mode of this buffer. This has the advantage that the definition of a "word" may be adapted to the particular type of document being edited. Evil uses Emacs' definition and does not simply use Vim's definition in order to be consistent with other Emacs functions. For example, word characters are exactly those characters that are matched by the regular expression character class `[:word:]`. If you want the underscore to be recognised as word character, you can modify its entry in the syntax-table: ```elisp (modify-syntax-entry ?_ "w") ``` This gives the underscore the word syntax-class. You can use a mode-hook to modify the syntax-table in all buffers of some mode, e.g.: ```elisp (add-hook 'c-mode-common-hook #'(lambda () (modify-syntax-entry ?_ "w"))) ``` This gives the underscore the word syntax-class in all C-like buffers. evil-1.12.17/doc/000077500000000000000000000000001360703323200133665ustar00rootroot00000000000000evil-1.12.17/doc/evil.pdf000066400000000000000000007417541360703323200150420ustar00rootroot00000000000000%PDF-1.4 % 1 0 obj << /Length 587 /Filter /FlateDecode >> stream xmTM@+z&?tBL$d4*.<_fW_wիrc;`GUOV&ʮ[v6W7TvbuYt/N.5=S> stream xmTM@+z&?tBL0d4*.<̿~UfW_uvc;Z̫MfG} I]/ޭmޯo⣩0^'^x]fkn{EK{*ʇupg6;ލ$4;gZ8, M[TPRJGeWxmE7 "/7j;{Yʋ"1tm|oirI ɑc׺>[TқEnn#bBSEV嶭mzsg)gR133w xAb;aGL6K&0+}&"?(Ҧa/ c,!-f3*Ix {asIC%hS7}H=ŤIY(jŧ Z4{SO5Z ekxvKǬ@2a> stream xmSn0+$z"aKU^CvF^p=!94gB˥0pދ s#P~k@hZ+vQڦ(A,Rf5Ħq8>K_X NH3$Ǟ{<0*5c~Pʯ5W42^!0^#rqxƘE3x z)cgl1BҰ?Xq!NAWA*d1)iȧΰО 9璆NVfkVaUJ?%͚5ػbTW=ј52f&p2pjV^cHMcVYxLS7E=1j g endstream endobj 6 0 obj << /Length 264 /Filter /FlateDecode >> stream x}=o w~#rX+CJVԊv5`QBx"W ;"݉zdet7[2$,tzٿo]4 J-o̶%7{,s?ySD;j[ YȭѠ_q!Ĺш-|imuګNnοZ~Ȕ:+"ƨ`ԎǴyWE8q&Oy0i{(r<ozzzf9 endstream endobj 5 0 obj << /Type /Page /Contents 6 0 R /Resources 4 0 R /MediaBox [0 0 612 792] /Parent 9 0 R >> endobj 4 0 obj << /Font << /F72 7 0 R /F51 8 0 R >> /ProcSet [ /PDF /Text ] >> endobj 12 0 obj << /Length 741 /Filter /FlateDecode >> stream xuTKo0 W;'vZv0 J"ԏVߏ"6-2)#E~(#?U"*UZFA{AJYS)%'ޗ&,7wv51V7=4p}hJٝ!V%3b̂K 2E{26m:3.v,}q"6iBɉ̹Ur5=l;/8e)Wת$\78%\h`w'dF ʔgi#Iĥfs3އ]ZTa3vdf|'tAS]yUT]J J 9g:Rm`4c]l{gI]xjbsS4@ g(q,TQ $KlۻG%maj/ lpb_8sHIW#<b//:B߱0{EWPaiPqvNq> endobj 10 0 obj << /Font << /F51 8 0 R /F60 13 0 R >> /ProcSet [ /PDF /Text ] >> endobj 34 0 obj << /Length 1294 /Filter /FlateDecode >> stream xr6~ J-w4mzud 7e#1n)8_/$Q)RLH"Yi^A7f0[^f fyϫŇg?.<j#8 R*saQY.$W7jQ`NҼ F}{.f*0aJ*AI . ޶CRay$B=Naܼ."!= Fʢ̓b(~HO2FH)bIW!ڪJ A[V~2]+?%aLbyMYG 2+Ɛ%qog@bWAzge`κ,L3/6ng:dR `|ap ) `w'&sɃx1bFJH0X uX\b 'k9/o=6RN*^p` sƸLJ9.;.^a9UVM @#*Ā)dҧ$ '2),)(EW_/KcV0ꏋ̕MQ5le.pS8 h ǤT#;K#q4jsDܧzVm'&H!P=I)Sj1}}IyX%h3fӛ҆}li9:1 ׏ۭD'3*i]m6?{Q1 N-P;$>We~$:ۜqF"4wi| K$cؔxٍK8 ;& ڽnn j{Q}1JfLpoڝ;e7>`VtןG1Zm*:tTS u+D ‰^'2}] dž endstream endobj 33 0 obj << /Type /Page /Contents 34 0 R /Resources 32 0 R /MediaBox [0 0 612 792] /Parent 9 0 R /Annots [ 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R ] >> endobj 14 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [441.93 643.088 450 653.051] /A << /S /GoTo /D (1) >> >> endobj 15 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [444.545 626.65 450 634.226] /A << /S /GoTo /D (1) >> >> endobj 16 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [444.545 613.499 450 621.075] /A << /S /GoTo /D (1) >> >> endobj 17 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [441.93 581.619 450 594.371] /A << /S /GoTo /D (2) >> >> endobj 18 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [444.545 567.97 450 575.546] /A << /S /GoTo /D (3) >> >> endobj 19 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [444.545 554.819 450 562.395] /A << /S /GoTo /D (3) >> >> endobj 20 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [441.93 522.939 450 535.572] /A << /S /GoTo /D (4) >> >> endobj 21 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [444.545 506.866 450 516.866] /A << /S /GoTo /D (5) >> >> endobj 22 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [441.93 480.199 450 490.162] /A << /S /GoTo /D (6) >> >> endobj 23 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [441.93 447.821 450 457.664] /A << /S /GoTo /D (7) >> >> endobj 24 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [444.545 431.382 450 438.837] /A << /S /GoTo /D (7) >> >> endobj 25 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [444.545 416.111 450 425.686] /A << /S /GoTo /D (7) >> >> endobj 26 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [444.545 402.96 450 412.657] /A << /S /GoTo /D (8) >> >> endobj 27 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [444.545 389.809 450 399.385] /A << /S /GoTo /D (9) >> >> endobj 28 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [439.091 378.78 450 386.234] /A << /S /GoTo /D (10) >> >> endobj 29 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [433.861 349.689 450 359.651] /A << /S /GoTo /D (11) >> >> endobj 30 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [439.091 331.129 450 340.826] /A << /S /GoTo /D (11) >> >> endobj 31 0 obj << /Type /Annot /Subtype /Link /Border [0 0 0] /Rect [433.861 288.219 450 297.465] /A << /S /GoTo /D (12) >> >> endobj 35 0 obj << /D [33 0 R /XYZ 90 720 null] >> endobj 32 0 obj << /Font << /F51 8 0 R /F72 7 0 R /F97 36 0 R /F59 37 0 R /F52 38 0 R >> /ProcSet [ /PDF /Text ] >> endobj 51 0 obj << /S /GoTo /D (Overview) >> endobj 54 0 obj (Overview) endobj 55 0 obj << /S /GoTo /D (Installation) >> endobj 58 0 obj (Installation) endobj 59 0 obj << /S /GoTo /D (Modes and states) >> endobj 62 0 obj (Modes and states) endobj 63 0 obj << /S /GoTo /D (Settings) >> endobj 66 0 obj (Settings) endobj 67 0 obj << /S /GoTo /D (The cursor) >> endobj 70 0 obj (The cursor) endobj 71 0 obj << /S /GoTo /D (The initial state) >> endobj 74 0 obj (The initial state) endobj 75 0 obj << /S /GoTo /D (Keymaps) >> endobj 78 0 obj (Keymaps) endobj 79 0 obj << /S /GoTo /D (evil-define-key) >> endobj 82 0 obj (evil-define-key) endobj 83 0 obj << /S /GoTo /D (Hooks) >> endobj 86 0 obj (Hooks) endobj 87 0 obj << /S /GoTo /D (Macros) >> endobj 90 0 obj (Macros) endobj 91 0 obj << /S /GoTo /D (Motions) >> endobj 94 0 obj (Motions) endobj 95 0 obj << /S /GoTo /D (Operators) >> endobj 98 0 obj (Operators) endobj 99 0 obj << /S /GoTo /D (Text objects) >> endobj 102 0 obj (Text objects) endobj 103 0 obj << /S /GoTo /D (Types) >> endobj 106 0 obj (Types) endobj 107 0 obj << /S /GoTo /D (States) >> endobj 110 0 obj (States) endobj 111 0 obj << /S /GoTo /D (Other internals) >> endobj 114 0 obj (Other internals) endobj 115 0 obj << /S /GoTo /D (Command properties) >> endobj 118 0 obj (Command properties) endobj 119 0 obj << /S /GoTo /D (GNU Free Documentation License) >> endobj 122 0 obj (GNU Free Documentation License) endobj 127 0 obj << /Length 2290 /Filter /FlateDecode >> stream xڕXo6_aKe`͈ (pW=4ݶ{}l_p{烒eGf p>~3\'yHHqXW>]H?Zj\Pa.wSwໍ]( r:_,r< 7wfZ/h/IBBI{u,2Y\D+엑OGUsfJ^uS_oݗK|CMe֝X4 >LJێ8ك5|x<2椹b5jW?"/Dd2[d$$,dkTLA >0)oZ=Qxj("=ڶ|Zܫp.m#"Qr "|H|ޔ`|ԯCli8 3[0I4P{2oe 3 Z`]6!Ю./ui/-W}u%A fKH),@A;if2Rml[MY0vtJ+"Is5u*BKɉ>:eW}*]] zv5ߝ\$Jk;z~/8³ˁ/|x a7H$2̲fշ ;T4F$ۖɡH@(G.I׸vc; ,p~0fm*8gr$qONU )BUjU#D ofj=e5,ƲQ2Qoʮpi] ["OxT8 $1sJd Rop{>mo7 %A #(6Qd-/ v[ j%Bh2Qlx4 ަuӓa=ws\KvN"GjjnXC(h'1c Q1VTSac[Jn@ ܻkͰC׶ جeG5;^6 < ً-\GF_fNQ },&߭ĖEI pkTia 934CXʽqNp|=TTw}L$y]XlP|-] EQ=ٳocȡTն-=Vyk B7gq &WᴨG3~ogs4jWydjr|5U2}$ 4)ffLwf`Ty{UMZS<ӹ zQ| aT;~s*q @"cØ0*`=<\OvQR,sE`\Ss  pz@^ضn@l0X_ 3ޘ 7nGqսR(c]~Ҭ7˰* /_c4\XDCl +ش_:nᎷ6cu}F Ph=Jeio3υ[*ɞi7fȭ'8Ak+δ_ﺾhN $IN[aozhۍ+-^D(NRf&*ǖ, ǖ1W$$̂YF 9_< u>̰g״==4$TJ`9hv6r׼4L˒Z^fSŢ?' |z#y1<>OB~-\@vlq "X.u3?M/d9$St̥b/ʕ 8.Hw(RKö00\"=M-TcTT@> endobj 123 0 obj << /Type /Annot /Border [0 0 0] /Rect [104.944 88.518 194.383 98.979] /Subtype /Link /A << /S /URI /URI (http://www.vim.org/) >> >> endobj 124 0 obj << /Type /Annot /Border [0 0 0] /Rect [104.944 76.152 288.528 88.518] /Subtype /Link /A << /S /URI /URI (http://www.emacswiki.org/emacs/UndoTree) >> >> endobj 39 0 obj << /D [126 0 R /XYZ 90 720 null] >> endobj 52 0 obj << /D [126 0 R /XYZ 90 720 null] >> endobj 56 0 obj << /D [126 0 R /XYZ 90 628.813 null] >> endobj 60 0 obj << /D [126 0 R /XYZ 90 477.173 null] >> endobj 125 0 obj << /Font << /F51 8 0 R /F72 7 0 R /F4 128 0 R /F52 38 0 R /F55 129 0 R /F58 130 0 R /F2 131 0 R /F35 132 0 R /F31 133 0 R >> /ProcSet [ /PDF /Text ] >> endobj 136 0 obj << /Length 2199 /Filter /FlateDecode >> stream xڭY[o8~ϯ[e bś.bE`g3Xr-70}h) IR|e,e*-W뽻„p05eQgpE>{mv]C)e Ct躲m7RiOW~#-IpƉ( %NR(bXN ܼI<iP~˺q5mW0@ԧӔwMѲykr4Ekuٛ}ނl mtDd\VehpiED"JF:ȿa+e~ѻKPޖ/ۦh_?,hR &l_YCa3ec΋y*d`Mu[sv VzEƏz _#andNJ12SLuJ!zCf넬VR/[ħ,TN]SzMaWg1YU|%lj;Wb%2uRo:W*BT G#k,ZmrՅ2ԛ$>i0z&{5OFK\Mu_P7([/ &P(A?,#v49kQ+DP4Enjѥ\#JTx4m-{"vF(benJ8eHhUlhsܥvL +쐱ɪCl$za#הC1m< d3  1ߐPUtE9,;òʋjj"eX&4&ƈerC6$73,QCa vv?tch:j >#EƤT%!wv"3I Yz2>DK#; q%hW' 4TTi<DY,^[Cr|2VKty췕Y@V* Ԡ,G-[S$ɤ/z9 ,~,4r/e4S:TĄ|W4Ů0]bI9\H:m1T2PG3 ؇USq(=1+#]nkzdn#>g/6 VeWNZ F7zXЏޚݴ=UJ$P7mYino5Xk}53R%45^u+`+waU0<.b H(Q="1<~|JL]Ɛ<--O/tGpCCcmi/GC.r'1 wq_'yP*:fGO!Douxr _)yfLˤBbwP~GŚ9G+'|A'NׇTRg~ vY zF¦^9Dhk#.@{Scgacmu8^FZrmlÎፓ9T'5 M*Yc0= Aۍ ^[ڶ@` 4 %QϨs<3uCMsۤscy2nژO׾x#F#ֲ6Tb jz:>G\ͥ XPp K-M{FGءTTo݅rT}57JG&ܧᩱU֖g\p K;; endstream endobj 135 0 obj << /Type /Page /Contents 136 0 R /Resources 134 0 R /MediaBox [0 0 612 792] /Parent 9 0 R >> endobj 40 0 obj << /D [135 0 R /XYZ 90 720 null] >> endobj 64 0 obj << /D [135 0 R /XYZ 90 720 null] >> endobj 134 0 obj << /Font << /F51 8 0 R /F72 7 0 R /F58 130 0 R /F52 38 0 R /F4 128 0 R /F2 131 0 R /F31 133 0 R >> /ProcSet [ /PDF /Text ] >> endobj 139 0 obj << /Length 1547 /Filter /FlateDecode >> stream xڵXo6_a20q")Jb֢:`[}i X,yHQu9wGY|Y*%q6["Q£/W?Q|##g1z1x5PJ0U޶m^^7YůW#%$x 8Mjd12&<?3:7~FpM8gZ/\ eF"ao"5e K[#f"c,Ew@p {%$O|Tn-Ok1]V`4 4IȀ%!! +y9Sy24k|JD,d.b ODx8~Hll6x, !m͒SR,kB(Up.lVuUg Pw=HTGVe NNRļ?D2g y`i>E\A'T1!q|O4 D(і#-͐d%Cu}mAIhɔg>S_ we:M y \,KRn9U"< 4V]TzH\3.4]MkZKÝAhU^V ;CVZ4=)Ԧ\Ypp!T]Ȉ\>(2Q (*s\݂ `EdeUE6._(.˟j.+V0\MPS QNN)9<*zM[J}7v1`o,sڊ> &CIL` @ܧgTRMWڼ*Q u{9!ap(- $6%&Y8LT,G46Kt s- t(H}HoGŝQ`5QcfP>tgI)0Ł#SX8$w/&}J :LrȠ`!E%& q9~|Ya)Oڅ^D(UK#poE_dҡ9xQ"dTzAנWGC^eMy-ذ4tk}WdrfŮҫ-<1hiz(]BLël]MaIGQ# 1< ql~8xS*([,*ڄ}`7C0$oߢÓg ,ChHyF)> 79|8~clR!f[u+jg> endobj 41 0 obj << /D [138 0 R /XYZ 90 720 null] >> endobj 68 0 obj << /D [138 0 R /XYZ 90 595.408 null] >> endobj 72 0 obj << /D [138 0 R /XYZ 90 183.87 null] >> endobj 137 0 obj << /Font << /F51 8 0 R /F52 38 0 R /F58 130 0 R /F72 7 0 R /F55 129 0 R >> /ProcSet [ /PDF /Text ] >> endobj 142 0 obj << /Length 1170 /Filter /FlateDecode >> stream xڽXYo6~X%JyLm"/Ir\` ֮}JdM ; g曃30G7YQLTDnhL8ab| ~>Sg0] !cO0bY&y /_n3Xo)D_]JQm@mV4mݻdq|جSXG@DS9 ,& ߻~k3B]"b|Lbg{Ck9 Ø3hJdLН hC]Z9j;/`~iAP]^Itq *;&:j+`6 pG6;>$n*{yW4މ|1.CYC YjwK yQIx^'Dq8֛7H\%o $ٺ3Imi@}t.Nd1%"DW7Uj~,;e[lEh:Rb2JɞR^Wݠ-,٦LDzӽ\BQ2E޸E}#HfF1W8 q'~~h3zW/# J2i_.w} S`sts 5P?kn]8ll 5R8hcUɴVuɍ(o/'g;AW5vȭ44q}R)*aÐ]aڨ uU=f0u5q i1. 79O]v;,>@x{]ͣ0Buǩ5ٛ:o;Iymj&ܯGTi+7̊oqwܶMrKpnqU6җz+_뉙 ^<2VO8̲Mv=7^aqM< endstream endobj 141 0 obj << /Type /Page /Contents 142 0 R /Resources 140 0 R /MediaBox [0 0 612 792] /Parent 143 0 R >> endobj 42 0 obj << /D [141 0 R /XYZ 90 720 null] >> endobj 76 0 obj << /D [141 0 R /XYZ 90 720 null] >> endobj 140 0 obj << /Font << /F51 8 0 R /F72 7 0 R /F55 129 0 R /F52 38 0 R /F58 130 0 R >> /ProcSet [ /PDF /Text ] >> endobj 146 0 obj << /Length 1366 /Filter /FlateDecode >> stream xڝWKo6WD"#Hm|]`K!q_,hRy|Hb]_%~pEB|˃ ")b4,Eձ2Gn !K2fE!y$?V^ݯF?A_"؂ E|$i.E ]2eOt`f)ޖŽ07O! l7n ¥#P6^9n,4Hytl͒eݹ~=54[L$tJӔЄ<\O8OulfWl6cb4^zwT1$sX<@ tcarя)aJ )Iw"-H1k-f𐳄> endobj 43 0 obj << /D [145 0 R /XYZ 90 720 null] >> endobj 80 0 obj << /D [145 0 R /XYZ 90 720 null] >> endobj 144 0 obj << /Font << /F51 8 0 R /F72 7 0 R /F93 147 0 R /F52 38 0 R /F55 129 0 R /F58 130 0 R >> /ProcSet [ /PDF /Text ] >> endobj 150 0 obj << /Length 830 /Filter /FlateDecode >> stream xڽo0W6f foԩ4JpN;HBdM5`_=;Kg{(t#GF<,̈7] Ps%qӷ2@QˇIS? nǟGu(E-vI#8"dN1M% Kڤ̈0sٰ q`jLJ>wleZ5M2?SvBN8]o&3UҎILJqZ8lu9 E3$TvR]VS|ҭbڀ:}็I#d1EJ_0'|e }@eUAy+xY{E4zBAnRlm]-+L:]yJ8NqP$oU~W <PȺpP#Y^NA$8(_-c) tm۵&aKq pT ~oP5h)D8#đU G ˪[0\g0:Sʆaד ~&v9gsJ/ mn>.w,b| 6Q٢ipW):H݌vl%4į {ˀۣFa)! xr}[u٘P`׌~y \tIց\qnR֮6:wV[y&{؜ L vEx]V>tiqi|wb+&b 3 zCeV^_gJ endstream endobj 149 0 obj << /Type /Page /Contents 150 0 R /Resources 148 0 R /MediaBox [0 0 612 792] /Parent 143 0 R >> endobj 44 0 obj << /D [149 0 R /XYZ 90 720 null] >> endobj 84 0 obj << /D [149 0 R /XYZ 90 720 null] >> endobj 148 0 obj << /Font << /F51 8 0 R /F72 7 0 R /F55 129 0 R /F52 38 0 R >> /ProcSet [ /PDF /Text ] >> endobj 153 0 obj << /Length 2584 /Filter /FlateDecode >> stream xڭZ[۸~ϯKd bśH[ Mjl-<=Й Z )<7~ЛS(Ήf{zWՇwr #ݾϒЂЛxo٧Cu~s3q !նX+47qw?NH^)^0 UQ)<#r\,i掇S܃xLE\"k[et>֧0/< nݻW}}cVO`h ,j艹vmtPO΍FP ^~rvSx+8jK.J .WkPWO#cJ`H-nڋDjPAY vӡ;SOo/d6\O byJQ2PnD36(6!ZbJhƃ5;UNzdz؂Nao:n1ZpRL}39Y(A7y9p`m '{#.na8t'!4_:$f^8_ kwh"qH?C.z1@^9_u. 2|/uH ]Om5Ba_a7:"S*{iaIa݂ex' km a[\`/F^ؼ F ywFnf@A\{1e\(SN]e98>T<j鋒pY~tvqŜV:̊ w5@5샻<㨇ս]-$Rǻpw 1`FceS5xtK!՘tަ"k&uC4h,t:#x:a\Ao4}k?r QI-oڃoL(_4K+  ǦMol Z­}jϜ@n!$ F8 if]vJlvա$+WPwn8A@!oBBY (\N164U0ڼf×^D9xQ|cFNW WJbZt-p jv׬ N;sI:O<3JkkʄZ٠k޵q4ç{S#2;s!S531Sb2t|n&#"GK8 qNI6RWItgꗔXdL$ ƳtcͅCZ6Jk+뗷yJ׽la"jnu2T5_2Mdt]T!p1C9i{{r(Yz;v<F7{v/筛nU_mI~Hu2]gIŚ||V7(KQEA^m?)7kl(gDsQO]+qY3gCw~/{wK>׼5(Z2g9c!TL2(.)CK]C6!Yv]nL7=FF*aEx *%B2Dzt {b4{й9<=*~Ԫ]<$ (<<Ͼ\&BOYݢH E"fǴ0@jz@ޮ0r--(LY|Go)M~ ;0^H)X7)4 (ܴ)r>7_b Q۰^(yZr1$iw2:j.yY{")^tNg>ԦXwZ[•+`+@Ϸ&bC߈]6kk()MkPajB\PЕ)o6s8uE)D$>. OSיǺ DEg_{ħNWݸS QAX+v-S2kn :j*-jѾP9yi]WFҿW joJp:7uXEV endstream endobj 152 0 obj << /Type /Page /Contents 153 0 R /Resources 151 0 R /MediaBox [0 0 612 792] /Parent 143 0 R >> endobj 45 0 obj << /D [152 0 R /XYZ 90 720 null] >> endobj 88 0 obj << /D [152 0 R /XYZ 90 720 null] >> endobj 92 0 obj << /D [152 0 R /XYZ 90 631.47 null] >> endobj 96 0 obj << /D [152 0 R /XYZ 90 188.761 null] >> endobj 151 0 obj << /Font << /F51 8 0 R /F72 7 0 R /F55 129 0 R /F58 130 0 R /F52 38 0 R /F56 154 0 R >> /ProcSet [ /PDF /Text ] >> endobj 157 0 obj << /Length 2553 /Filter /FlateDecode >> stream xڭYKo6ϯ0rXqŧCY EK [mk-5$=b( 0নXA~URJV){uwP܏r 4_K~PfΥt+껡a/7ϛF H [fUKE4ݮsQ?6vjOۡ(NT1^ kt ߽'O 7 ~vOlۧkQ$a~|*/~9(4oU&t(D3vPث|K5ɈBfpkg;zs6Mc'vS]dUXnT6y.lOXdK0cʅ&u@.>]Wё8~ؑn+ߥ2O^NWL?M/`vI'hH3Uj?Ia~'"<Й oi~anL0(ٶٖ_S4^BzVRˀ"]2&b3 .ڲPo3[F4hUٕAkUw\lp3#s. Nņ/nBV&U ۮ#p!-i ښj)͖b0r/ߗ oяm>oCтDÐ+BޤMjXЌ@iN /qSVFŵA=e$"ƣJpn")qR ڱ=X O8XpW.4@ך"?Lch'uv>ѳuQq4hm;;%s~drYeAǦ jqLO]:s;>O*;P)#A?8XwI;0UU=m^k >t1RlfnX(OCy30[ sP% 931[kpzSh/t8HEh"z%ebХ5ET\,jjA<JB{`@%"F򡟸@B[I 214, `Τ\՝7p~8z7 l=6r0&˧]梊]WQ;©`Ҽ?H5V bMv(mm0sŴ†X.+0U!u 4MaUD˷OX:;'3|,ByfZ4@;!\HNB(i^HF}a]ax-:bœqp*rj97!G-$׶j /[hbf86HD5M3oK֞֞wq .MhXtD@ʊ=vlG(.FJEQwdsG;2F_p1FLفn&{S$yW>;9>^ A?Vڑ)/>] F* qy{ɜQ%f]* @@'wY5q2 U|_]ą$*&T$`@H}mHؔHXefٲzu .=be$,ZZ߯s§A|૜ SGlWo8 !Z,Ocg= gƢ+ꅯ ,T::*O}!UH&˴)6ǖ"nu^T)Cu2fCC_ߺF :}؞C=6 ^=t# Ͻ *Ed\9wxx꼋WxfZ{]qɲ+. /xu9x?}i'ҎRL(޼`+ؑ=Q+f.݀a)k DA:ȯV~ۇ 4dMo R endstream endobj 156 0 obj << /Type /Page /Contents 157 0 R /Resources 155 0 R /MediaBox [0 0 612 792] /Parent 143 0 R >> endobj 46 0 obj << /D [156 0 R /XYZ 90 720 null] >> endobj 100 0 obj << /D [156 0 R /XYZ 90 258.95 null] >> endobj 155 0 obj << /Font << /F51 8 0 R /F55 129 0 R /F52 38 0 R /F58 130 0 R /F72 7 0 R /F56 154 0 R >> /ProcSet [ /PDF /Text ] >> endobj 160 0 obj << /Length 2574 /Filter /FlateDecode >> stream xZKoܺWY44bŇH)]ݶ@ t\lHIP(slI. 뼾UU])YUz?⮕€t5ׯ~sίxʬW׷%W$NS=R)eۥJ_ЏЗLݯyo 9pトA8/Xq ŸTtwX~j7yE0/vY>v΅)ͩL”Ks[72g*_)7!6kܯ9)<]*JNߢ<^u fyzKauV( <4j큁/YɸIqyԊy`O=aJ"U$pN`.7o)qcYKmY:n~F'kʵUz->L[Z,i-1,2ePH#’+J!nn))ՌWIjFuUQOWUO5n!^J1=źA4y4th9x@uPuw~QeS̛gPuwqT a`a5TYCHapZ pЊ~K ,+K&/WTQW{KPjH[޲bFh,4Ӆ>∬Yجv\cx2")ojJc-}fs HhnM_9˭ ͸p|;9D#<- JbЗD ,ņ'G+:S.qÕ;+@Rd3nTpj^I& /hbMڸH'>BN '9MѤ[ahtwfdV4FC ,-?0]<0k+* S # kzhkzthXB Z!@.vb 0_0Ӓ_ -PE2^29"+@#Ш4'Hʻ'@&A& 2*) *7.wOxʪmiF!b ∥248Ŏh!.<;dB "uDMK4:AaD2L/aY.>j])EaV `yVGK[„ZOw)/se bܯ뻴kZ(}܁fn?З;P9 djERCk--ׁ{cP{| TݴnFN]^Nm_^&#@b[AĦӢLs0g"ċ t/AXĬ7!) >SsFU*V`8C;P{R`U3{*|_r,Uޝj0G,h&r亰$/ds|&?Pkr!t:ARtFd* TZ "A"p³&u4MA,/r8,E=ǃS&pl_T> 9U@6뀞z x*mNҕc۽:) &ުIV\yzD Nߺ@<<pP\p<ۦKI`s*:4  mѕ1ۣRNfE l#AZ6wǞt;7G3J;ݞp|^odo")ݸqSݸ6T80ilڙmi?mb` +$3fKaY-> endobj 47 0 obj << /D [159 0 R /XYZ 90 720 null] >> endobj 104 0 obj << /D [159 0 R /XYZ 90 235.448 null] >> endobj 158 0 obj << /Font << /F51 8 0 R /F52 38 0 R /F58 130 0 R /F55 129 0 R /F61 161 0 R /F72 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 164 0 obj << /Length 1914 /Filter /FlateDecode >> stream xڽXK6ϯ(2.`^~4 d - wݰ]3ɟ)JVeEmIEKG#elWH*U7[}Q i Û|g*;<[N//d}*L>UJ'ǡa-Jx7_sP%^k"BM8/YKŸTñ說>Nx ȗ֌xHlLjrɸ&-:OnqjgEL.483#N{"ӂsݝ̉o?g\Z}c @D3݆yf@ɜڜ9Y VCh*1pbdO1--y \zV|m'hbʓeS& pE+ƅ unb8,:[ѕdDWׁq'߸ڎ8z׬q0{ܮ[?P"jmʚ\ĝ3ˍ7~ߊ<EJπE9bDQ%'T {+Z%SG)`ڠeI>~fsc)d5OSSt5 @%+#J9l*JVt]Tn+ ~h ^HQ;M6",覂{7y`0d!bB$W&/0{Z`nPI|5j +oFtѸ^I&3Thtfݐ%HL$ݢ[*g ,#hx2b0:^,_s70]8ƫxg*/aZYr3 0&[%,9\$&7HDR4`tE>;jPl<+TKJfqcmxV,g0Gi',!Z|.Ht,*@T-eE*'Q>չL~ju>[ N9Sy 'NlfЈSaC/C9Ls36ƇKG<1Z,Yzˈn\7ZuhƱ^\^UXBE˵~vЩc94ckO%!6Uul>skfK (R6r g̋2 iq_G `(`IKZ9a5=sj.@vԅdY^RYɋLAS_#˦ (%>b%ܱB2fqXcgc+@NsQ~=kf4TD.X8V'{e9EM%+{zr-׮(dȥpD PZ&JNz%4z|X 3/`ܵXVFct*Ƥ6z<':m8qc>tXl@G-X|GDH]? ¹ZCػ{udta=gƇ{b4(3L^ Yg]b|ѹQ}5S?T3<_Iy<단W|,ge!6^@UqמBBtWӹ֓9.wn\aZS^|Fd%C lK&Wfgg:l>J}-Rs>_qX$WMEC4zzҹ|ys;y+-]8ey ݒtƩri&ߪSԼTtႵ kWbhT2/Κ|Z*SQU%6y(8o9ŽڻNhWP5BN૰UQ5{#W*8-d/[3^W ˝1WW=b cC endstream endobj 163 0 obj << /Type /Page /Contents 164 0 R /Resources 162 0 R /MediaBox [0 0 612 792] /Parent 165 0 R >> endobj 48 0 obj << /D [163 0 R /XYZ 90 720 null] >> endobj 108 0 obj << /D [163 0 R /XYZ 90 494.317 null] >> endobj 162 0 obj << /Font << /F51 8 0 R /F52 38 0 R /F58 130 0 R /F55 129 0 R /F72 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 168 0 obj << /Length 1246 /Filter /FlateDecode >> stream xXMo8W+~SuaomU,H$'ߡMGD䛙7oT"?ȳ.VY`a‚dˋ߿(`ͳ-SeN>m޵I* *ITk:uIʵ0\uy9YV?_7PΔ i+)}I4'_#&TH= p rjU a>5E]zEF\SQet?2&i:ݥ3ʤæhCjYi.FAoZê^7C=ƟkcI=]+Ӥۯ|RaqχH_ r-hf e:uo·8c/; ]ITK>#G'U"bOYR'Zni9JqCon拮k+kҤ%r!2b.`GqGJḃ6E 2f_+Ⱦ^>ьm9eool^x$;U endstream endobj 167 0 obj << /Type /Page /Contents 168 0 R /Resources 166 0 R /MediaBox [0 0 612 792] /Parent 165 0 R >> endobj 49 0 obj << /D [167 0 R /XYZ 90 720 null] >> endobj 112 0 obj << /D [167 0 R /XYZ 90 720 null] >> endobj 116 0 obj << /D [167 0 R /XYZ 90 660.224 null] >> endobj 166 0 obj << /Font << /F51 8 0 R /F72 7 0 R /F55 129 0 R /F58 130 0 R /F52 38 0 R /F61 161 0 R /F56 154 0 R >> /ProcSet [ /PDF /Text ] >> endobj 172 0 obj << /Length 2833 /Filter /FlateDecode >> stream xڅYYܸ~%j`Zuxm/&zx`#(x}ꢤ "ţu|Q72ɓ$,:핒 |ԍ2*~C}tl"0mmoIw?OF|iýwLȃjuc +7* cX^ea+yNyfiJ0y w5RٺdafpGnө[Lo_/~? s@muc[e /D",nvIfeLQli/̹]g-GBӛ7{( 깮W+s=DY*vLʹo&/ӭ }QdGqh#0Pern/[ixG;:x<\lR}A^ A7M7مC68"ӗn׷'0&F134nTг:'D-r )SB'vHqG[bl (pI ME=L4lHA/xL1/Nb@|Ͻ@^A])i4cK/ҡǖb9udi<$#Sm6VXP-_o~<`/lvvg3 ΁fb^o[ʻZ戝SoY[2}R ="bj<>6ֱ8Ӟj4+rԤr<P V{=L#zxfb'p`MO A tl7XOZQ8[|%@=."y '@:t9v~-_9)WU4padHH{*ܙ,MBwN5𻬻ζe.m{8N FApaOMAW pz8 `AK>;` uYZP#|K 5Szw ;Jk6]p!-$2BN$H93b8B,_"jn= k̉}0a4?@`sx>_BC]O~2?` įǨ?-Z(H"B٭G=8${/z]?~\˙!U3:8yr}'!,SgdK{@ccxp ^sXQX9m@@ob '~:cH8;X9`@Ok "p- p RG%[z@#=ɊО(R.ҽaE<"lBH?rx`I]<%+Y;͕ T |fep{rs pk뺰z AlfTDq|t10O1{\{oa+풢dQFAaGIPm:hPO,*5J5RR١+!s\}xp(޷l[KuasgsO-lvhk UPhBcdH貼,4.TpOŏnK閯^6> endobj 169 0 obj << /Type /Annot /Border [0 0 0] /Rect [118.8 628.168 204.708 638.168] /Subtype /Link /A << /S /URI /URI (http://fsf.org/) >> >> endobj 50 0 obj << /D [171 0 R /XYZ 90 720 null] >> endobj 120 0 obj << /D [171 0 R /XYZ 90 720 null] >> endobj 170 0 obj << /Font << /F51 8 0 R /F72 7 0 R /F60 13 0 R /F52 38 0 R /F55 129 0 R >> /ProcSet [ /PDF /Text ] >> endobj 175 0 obj << /Length 2925 /Filter /FlateDecode >> stream xڅYYs9~ϯpeUys$$hw2X5} ޔ  Pr_r/Y6]͖Eo/&D0PZm\$tfb]^;>&2U_M,ݧ00^-gQc-F75-XDE\]aWت%d1OQ]g7 a?8S ILld3Jې ,v*Z Td c`NZTu8uu; _ZE3mQWiV nZV`d$ǩ lf]f%Iqt'a1(m붕T4# awc UvXS}M;?6Ud#ZXE೩bD@ ayfh>QB)bk+ۘ=n v=;"ؿ\-٥C@8Hj^Fm x޳%wH -VŐ-]G ΖQ>LF|ZX"'}%1dò qzۘCyD 0Iݓ|`ݻJFXtBw)6KR)ʥwp4x:J)6}jw5QM1vRfUl]|TXu IvZege9ΘRj%EQhi 09;rȧf4u8eR][ s34#{aji(nJ!I5IYIX \ ʆDٲI;q? EaNڢr۞D?69˳pw9<ɤS)##JāǤArY)C%.ۋ3+& b0&EEZ#o' _< &xo3<%|aI^1Q_oM<y@yE^OHaBPg %ںt?GeJ)bF^.su׉ӑg\bV|a&Mx;ww7]: qZ(q߷ h`84ԾBYKi0iJ }]ZwMb5 &^~>,dIewooFVUd>P$Roe +1zR[+-Kпz ΰb}31hh4GkD EmВ[rU 'NÈ܃2)jm#)/D0ko~s%`z"隧%URj2NpFTC'ʴ2{=P$*K»?>]RC3Mhd}G]*S_B1," |vqT?ҋ0g:&|eNsQ\5V ?u b *sGq*!ƚ+߱å+4ѤuH`g^$0kmºPIf)S(pw=}H7" \'M@S׎0{V ΢=z_i0E;IkHIrMF#XgUe$R p<8G1hp_DhAZtxom{@hCH@E՟dWYhU>]բZ'DPD_ 3Y_ ؜juX$KXxZpڂތ4ޝ˖3<,{c.ю:頦X$ mw2W3gdgg\ > endobj 176 0 obj << /D [174 0 R /XYZ 90 720 null] >> endobj 173 0 obj << /Font << /F51 8 0 R >> /ProcSet [ /PDF /Text ] >> endobj 179 0 obj << /Length 2909 /Filter /FlateDecode >> stream xڅYK۸W-*KK"7ۛLjTƩresЈ1Ej>u7HhYnE7!"ɒd[Myz*HGBxo_]t",O⾺O|y`۪zI$x|~46OZц,(moi0ZK]v ( Jo{Wo<yCE>OQ3>IM4ʂɤ̴yPheaB߼vClݝ&:ub8p>P"#N]X,}DOb tBH0W)k(c}zThϩ㈐o+( u' =c%efO4#SݯwC!v#JIIbYs[6f& +ʚWM߻lG5=E X?4>J9Z Qm/ yqpd רy66$Au,inŰc(9?!竳g}q<(%Ex&[+Ic ?ּ q,Kj^=@St"s\`c#+S39զD {}.c=HrO5ِE~I0/)+O .$ςRWt}D)<1e3B!Eő,Jn>&GÕ- |(]WI ) Y,*-j'_/k2BәK )kYyΖےjg?t \݇z33^LZvyxW@*wyYIi|Bڎ3j~!ʴ5Dɟ Қt5Z;ء]8-i;u8:fClH6=/yNzNzC)#j-^Tw/$JXl7WdӠ#- UKx @d놥n{CL9'I+xLM7Cf(K)Hb0H?HO3+{RipfZŔ'\tiVuE{L]s o&W? vy~io#|eһ|)aDpgh]K%(gp I꾵Fw/gAe <`Tm~p'5rj9YPT gRLd8 R2_O0g8䄝 endstream endobj 178 0 obj << /Type /Page /Contents 179 0 R /Resources 177 0 R /MediaBox [0 0 612 792] /Parent 165 0 R >> endobj 180 0 obj << /D [178 0 R /XYZ 90 720 null] >> endobj 177 0 obj << /Font << /F51 8 0 R >> /ProcSet [ /PDF /Text ] >> endobj 183 0 obj << /Length 2522 /Filter /FlateDecode >> stream xڅYYs~ׯ`%*7٤lٖ*1N<;5K>} 0Xb˵{{z6ME"o/_RÀ37߽O?~<4wnkm{w?{wyJqn W;0zTo``a?O_#BzÛ4A,"VIX=stTt Ugh.4~v8K<+gXǔ&=ZiP= >A’Өp6g\_fVn{aO/[}~%a]NW|$Q68@[=IG{PHpN<^2DT(?R)-WK#tFskאnhfzܒQY+Տ L@yfq)vIIs%=ccg?+2}=hiݡh:7v  =<.GՠD*U".Vf$t4hQ MER6}' ;`YFZ:2Q_w컨 IjHEbxp[e/\j TaҌCdz6vƟg=*+5`bhLl>-{'0vn{{Fdלrt]{7|d^ ٰȣI1x#s8b7I㵸w"Mj|B)80yp"(4:Rp~ 2e+c௏r/GyW 4`|!а>06An@ALCjN+Zw\$Yk{P=Y@6JµE}՞kT"h>D3ڶfSV*{At+N|*+/۵uAIg8I :k?0HEѝ bwrql, )Air -1K i:w\ś2,qӛ4315P$$h-. 19t}bcxY0Pj? 4QFicPv71Hhq/3a%5~TZjTs]BdNC#SH\a҅nzG5HNPMRI|t@Cqǰ%)[.VwT~d r JA Mv5܄:o8b+CGiJ$Q06#:D8!bTl;etPHSoB8ņw azsH 65OYʝ켕k\,Ĕe/Nb J54tգJtQ8UAtv2(3\Iw3%9-;'Ŀ޲\ԒO(0[^$`a9'4B7frDj^8?T'X.I5u϶U yA gWUTGfnrdbPU56?.$혓璌aAtkXc.܂X3yӣ!M Y 6hb ~x™? zgy+l/,oHy0.|EC|9,\L0Z_G;*R4{1VղK -} dn1}:[U_zY =K0PŗeXHק}}JDY}  01cĬ!o`P&/@eSEFB%䁥Ƣ,Z-=N~y%.-Eǿ0$觞A?`yw5$ |%%`ޡYh }wHoA endstream endobj 182 0 obj << /Type /Page /Contents 183 0 R /Resources 181 0 R /MediaBox [0 0 612 792] /Parent 165 0 R >> endobj 184 0 obj << /D [182 0 R /XYZ 90 720 null] >> endobj 181 0 obj << /Font << /F51 8 0 R >> /ProcSet [ /PDF /Text ] >> endobj 187 0 obj << /Length 2573 /Filter /FlateDecode >> stream xڅYIsϯp%T➜f}qjlF/T&Z$p۩hO@4~+~U_aʣj{z ] %LX:3>nk\*jsYlʫzry*bOwlDEyR\Â'U-+^MoU M։$mJ׿8 X%WI0ct;2{A1ێ[n@ht)#t5u[J"U2o,Tº?fOvjLA/pexr Ij=Sat]S,5pm>++AE(S! S4*ም/5Y?0_nZE^k3Ԥ|]ٺ橅F#w՞;}7R[B>pJp=4|_X nwѱ`# Gbop.NZxt>k^ Ldvh5hQ?zvM4tc 5ԳE ؒE:NAx)<6' \7vcwnBVz2?| NPKUMۅ `CjsѶ^1oGqD\?4e+Zݯ(@#޷ ˜%yCu)"h \穷|آLd#X b\pp>t`/jd/=܉+L}Ȼh])n i=`+BGbaDDp@vpgIy_ۀ?)!@;4u?phڏPOE0̯|h(ayFW7;fQUCF܉*O&NCH#@é/5X[F 5As)O -Hh3u dI<`6Y9󉆳d`'F`hI6%ڰAJ"$R#)⸓9 :PԄ!e7ܢgXK|s5|,b kXJACg([).3). `z#dB% IٚOon~c?~nV-(T Aid֌uc_Zf֨*-L,bWv̂ 76S4AI{%#?''2GrpE(-b*) Df&\TԔTmma##78.\%!:.kV vrjLE)D%`"Q'n hk0B~pʠ3% {c,v́JymvEP*BJې&A =61I Ij߳pe6wD>|_yɎ _ʼ#eMB0,8.e5nHؘTBߔLJ aQl}Pi/yy=He9ㆌJ Wl0}DTۄIȶzB O: ͠0ʧ{FM*B=O0B\)AQ>]pωgUB i1ryc!-cvl S&c;۷/67wߙW)x".1# x4g=)qF=-D:gܒ#O,xON/ѴgKCWcY+a'emNx7~:sҘ\`S!{aKQ)u}aiٌ;ÑԱI1-o$mq<[ډ5_~b*~'=VY/3yr/: #5_0aؼd,hl=LV;Ah@phaH엳4GB䙽b/ Žt.88_h`X`k8^˝a=;%ihgx}S8ۇa\m SC_ٛũVO endstream endobj 186 0 obj << /Type /Page /Contents 187 0 R /Resources 185 0 R /MediaBox [0 0 612 792] /Parent 189 0 R >> endobj 188 0 obj << /D [186 0 R /XYZ 90 720 null] >> endobj 185 0 obj << /Font << /F51 8 0 R >> /ProcSet [ /PDF /Text ] >> endobj 193 0 obj << /Length 2769 /Filter /FlateDecode >> stream xڍYIsW|fD[<%3Jer r6" <<o0]TE$WUZ^loB~}I.'[˯YtWUXEtu}x\]e|_]&I\4uU՚{7L(4z՛)F" *VYz0㟨?!"/ӫ(IYjuape޿}*`}Er qޯ}z3 |eWy]Wa1haiat[ 37虧bzDŽZ[m, meĺeGeUy@H{/5 D\E`CR? 3 g$v{"uqr7& o+îq5'1P6Q$ڨ- -̖ hl#dndݩM֢gM<G'Ҏm'keRL?3Eo@殔 C =ǂi4_ 4JbMs@Qrp8=MSXEcA6V-kiybIl+ IojÓQ&?ge eJJY\$@&ML]Jqz5hU(g 0DJ<;܃7LZc{'cOvfd7HLn.Zlceˎ=H0|Az[H eq| UA cF;ǔ~ZuݫFc2l9i8y22ﻆe=9/gxC2@~q3/I>6Z4)wӵ@ebTx8#ikn{`W0J7g<;$ U~pk4n)hR 6'3k&/\!! Va^jTɰ&ěػmwq{sL S%Z#?\|\JNLz %9()((DLdwZB|σ lW1vl{L½Rr>B5Xbn|huUyA 6cYiܳ2G99M*M"6-|f% F,I U2:Fu}C6 RKv[5*.| d,Eu-'9r vI:x 7@?,;)T,kmbH'4:q4x~AoIv'w QDDI~`*`n~9+tO*4t9OvJufϱVf)HbEd}V%"~_a%囐kVgd2q2\xW3Wv=TuR}Ǟ;݈rid4t**H %>^٥ ^g͆cLNT\Rw, @ C>d7<۸cba@?%S JG|KˀQ.3 7n(",2@1<-NM,O7q k{oRY.ҋV J6 _MzŗcP\#;D(rrQ/>I*l]NzHK75䉃|Cy(Dq4'2YʁJL#k\j%!/`CpKe r0=z /[ Z!РE!sYRp= AVv=beCX`XmJPɑDzz,IBB xvH{aC% $eZ^~;ל3ì0[ ] 6z?+|:K ם:mj!̡a%2 _Th։ܽk1AoDYjndԫ3"heafQm;p?J TV,ߠ2$ ։k3Y5p,' (a404SdEY`KB 7^[y'C.xbXLMHΎ0P?0Bcj Ց 'NwhH<1^(=bạ)8M\E;{I4}GTQUTMU-c2oqD7H[z'Foq)`)GEģ̣XVSj$}y._NrlA2# v4I#=WF^ CU endstream endobj 192 0 obj << /Type /Page /Contents 193 0 R /Resources 191 0 R /MediaBox [0 0 612 792] /Parent 189 0 R >> endobj 194 0 obj << /D [192 0 R /XYZ 90 720 null] >> endobj 191 0 obj << /Font << /F51 8 0 R >> /ProcSet [ /PDF /Text ] >> endobj 197 0 obj << /Length 2240 /Filter /FlateDecode >> stream xڅX[o~_a(@숺oiN'EYt@KtL,ě3Jb "p ->E/0\Q(|~ xˇۏXXl]/p^R^aD_? >^g*E7!akMM[~Ӆ;`i$Ȯ|˨a?r(Y$YaD׀e/?=6~yM/y\TrKМ&QB2@ZxͶǻtuٚ."HKdyaSnG+:(KATIqA=d1*^ ԽM-42u HN!c,I`b6* y9 CoO~6Kҧlae5f2#,wp %Sh@x0-.d$YsNrwM6&.r%,| K<ՀRckyl#ʟ+֙Un?=Pwy=3֊'u\?14TKϽ{<ִŅƨ{LJ݄{_LUIk_39Mm0'@Z{K< 9կ;j%M98Yu #Hbe ne̐^|cL@)iɀ 0 D@8#6so-@4P=x_]+1鍐R84 ~H|r{h$kL Qdr/x$uJ=*DXC)_N`2qmJ Ku ,,z&puN?oCdɨu ݷ 6)~X;tjx.AVs*"ȹ `_8Cw-y@J憵j- yA—1,+[([(&~@lr[rpy8sc]B~.K% %^3v5RVP<.CMi26^%sdx; E$AT_x`*U x\EoysN+i?" o$_$HBWdڼ[4?^ éxNY)N'L:%q7l -QY)`.} N50:L _1'#ϸK)fIrC:^8Z#ND'{87ca*Ma7 q@UV%4KJ><1(4ZYd=mV(q/b |?ECi~({FbFZB M{N$1㚮ijthB lě _1`l =@LNL^ 4a~C$,NomF)8/M9+[iTY endstream endobj 196 0 obj << /Type /Page /Contents 197 0 R /Resources 195 0 R /MediaBox [0 0 612 792] /Parent 189 0 R /Annots [ 190 0 R ] >> endobj 190 0 obj << /Type /Annot /Border [0 0 0] /Rect [130.994 626.119 291.356 636.119] /Subtype /Link /A << /S /URI /URI (http://www.gnu.org/copyleft/) >> >> endobj 198 0 obj << /D [196 0 R /XYZ 90 720 null] >> endobj 195 0 obj << /Font << /F51 8 0 R /F52 38 0 R >> /ProcSet [ /PDF /Text ] >> endobj 201 0 obj << /Length 1332 /Filter /FlateDecode >> stream xڍWYo6~X%ZH;NAn,qBl :p8fY!Lb{ W `XL8ޯ..ٌEaelZOUn7_4Pu_ !Dp?Ņ n 1 EU6$.T#Kb,ta5 \rĆϘ !NeȄ6||ĝ,\k!*-d  !=0]CG%jafX ;-8e!޵y*w}Oln6s">qXtĺɑz(yn*cω0;e=&XEe7 u-ɾs !Du5ӵ*Ϻ~3* ~؜A5@X [:k|m4t6hr?w9fiű4L:7 п[qO'IQq{8ػA:ߪ3&,!˽d|`|" ejm]BL">4ymUI:~KZ"xP[SދnzqC'(TM/5Z@E1\ŭ}-r_d8A0zڣrzJ?#|#?>MoRsnxP1W)o4kS \<`WL.ݧ3DCH4Hj+jhDyL:IGwQBa;aIA lK>0Qt_@H־ :ݞk2 cQ_q~%{}(lԧ]Q ju$0e3R岗9Wq 0RkRh H=00xnR$%!mx $O⤄,L@I 4JxHiS 5GcB(tW 5e-*0?\-EGc7j.)yPCôw gQT0&"?" $NۣCmph`w\ueck%2ֆ <^+bT/v(5=VKD7$F[]8QQZJO#兎\&*USR w&ZChj|D)Yb:}&9QժA'b/(c8XD|e5^7$YOh?Ea#?ב endstream endobj 200 0 obj << /Type /Page /Contents 201 0 R /Resources 199 0 R /MediaBox [0 0 612 792] /Parent 189 0 R >> endobj 202 0 obj << /D [200 0 R /XYZ 90 720 null] >> endobj 199 0 obj << /Font << /F51 8 0 R /F72 7 0 R /F31 133 0 R /F58 130 0 R >> /ProcSet [ /PDF /Text ] >> endobj 203 0 obj [777.8 277.8 388.9 388.9 500 777.8 277.8 333.3 277.8 500 500 500 500 500 500 500 500 500 500 500 277.8 277.8 305.6 777.8 472.2 472.2 777.8 755.6 711.1 722.2 766.7 655.6 627.8 786.1 783.3 397.2 516.7 783.3 600 950 783.3 750 683.3 750 759.7 555.6 694.4 769.4 755.6 1033.3 755.6 755.6 611.1 280 544.4 280 500 277.8 277.8 486.1 555.6 444.4 555.6 466.7 305.6 500 555.6 277.8 305.6 527.8 277.8 833.3 555.6 500 555.6 527.8 427.8 394.4 390.3] endobj 204 0 obj [388.9 388.9] endobj 205 0 obj [514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6] endobj 206 0 obj [525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525] endobj 207 0 obj [285.5 314 542.4 285.5 856.5 571 513.9 571 542.4 402 405.4 399.7 571 542.4] endobj 208 0 obj [599.5 571 571 856.5 856.5 285.5 314 513.9 513.9 513.9 513.9 513.9 770.7 456.8 513.9 742.3 799.4 513.9 927.8 1042 799.4 285.5 285.5 513.9 856.5 513.9 856.5 799.4 285.5 399.7 399.7 513.9 799.4 285.5 342.6 285.5 513.9 513.9 513.9 513.9 513.9 513.9 513.9 513.9 513.9 513.9 513.9 285.5 285.5 285.5 799.4 485.3 485.3 799.4 770.7 727.9 742.3 785 699.4 670.8 806.5 770.7 371 528.1 799.2 642.3 942 770.7 799.4 699.4 799.4 756.5 571 742.3 770.7 770.7 1056.2 770.7 770.7 628.1 285.5 513.9 285.5 513.9 285.5 285.5 513.9 571 456.8 571 457.2 314 513.9 571 285.5 314 542.4 285.5 856.5 571 513.9 571 542.4 402 405.4 399.7 571 542.4 742.3 542.4 542.4] endobj 209 0 obj [525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525] endobj 210 0 obj [583.3 555.6 555.6 833.3 833.3 277.8 305.6 500 500 500 500 500 808.6 444.4 500 722.2 777.8 500 902.8 1013.9 777.8 277.8 277.8 500 833.3 500 833.3 777.8 277.8 388.9 388.9 500 777.8 277.8 333.3 277.8 500 500 500 500 500 500 500 500 500 500 500 277.8 277.8 277.8 777.8 472.2 472.2 777.8 750 708.3 722.2 763.9 680.6 652.8 784.7 750 361.1 513.9 777.8 625 916.7 750 777.8 680.6 777.8 736.1 555.6 722.2 750 750 1027.8 750 750 611.1 277.8 500 277.8 500 277.8 277.8 500 555.6 444.4 555.6 444.4 305.6 500 555.6 277.8 305.6 527.8 277.8 833.3 555.6 500 555.6 527.8 391.7 394.4 388.9 555.6 527.8 722.2 527.8 527.8] endobj 211 0 obj [569.5 569.5] endobj 212 0 obj [525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525] endobj 213 0 obj [277.8] endobj 214 0 obj [272] endobj 215 0 obj [1000] endobj 216 0 obj [583.3 555.6 555.6 833.3 833.3 277.8 305.6 500 500 500 500 500 750 444.4 500 722.2 777.8 500 902.8 1013.9 777.8 277.8 277.8 500 833.3 500 833.3 777.8 277.8 388.9 388.9 500 777.8 277.8 333.3 277.8 500 500 500 500 500 500 500 500 500 500 500 277.8 277.8 277.8 777.8 472.2 472.2 777.8 750 708.3 722.2 763.9 680.6 652.8 784.7 750 361.1 513.9 777.8 625 916.7 750 777.8 680.6 777.8 736.1 555.6 722.2 750 750 1027.8 750 750 611.1 277.8 500 277.8 500 277.8 277.8 500 555.6 444.4 555.6 444.4 305.6 500 555.6 277.8 305.6 527.8 277.8 833.3 555.6 500 555.6 527.8 391.7 394.4 388.9 555.6 527.8 722.2 527.8 527.8 444.4 500 1000] endobj 217 0 obj [875 312.5 342.6 581 937.5 562.5 937.5 875 312.5 437.5 437.5 562.5 875 312.5 375 312.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 312.5 312.5 342.6 875 531.3 531.3 875 849.5 799.8 812.5 862.3 738.4 707.2 884.3 879.6 419 581 880.8 675.9 1067.1 879.6 844.9 768.5 844.9 839.1 625 782.4 864.6 849.5 1162 849.5 849.5 687.5 312.5 581 312.5 562.5 312.5 312.5 546.9 625 500 625 513.3 343.7 562.5 625 312.5 343.7 593.7 312.5 937.5 625 562.5 625 593.7 459.5 443.8 437.5 625 593.7 812.5 593.7 593.7] endobj 218 0 obj << /Length1 1540 /Length2 7612 /Length3 0 /Length 8623 /Filter /FlateDecode >> stream xڍTl7,ҍ 1 FCBBBCQ@ZJCny<A0Ӌ~?RM0#  xXp2\e(?o B_7F/Qs`Go(kD/M <n:r[sUyB5a(_a&ѡ ~N\ѝS*" Hk'(,ЍG#aP? G QhBo$$FN^Ic `h' zh_? @@P 3ItA;P'B0=H n<[|<ƶj3vI!=˩\bOܲ" v]nX}VÕEj0UP\e>]5g_:fUlg71\sʞfC'V><#~7eP4ΖcǀMӓtt$nKɛs;_v-65g0dWn}Kd @HCS%۞谜#ʡ7%%3n_gu,d%0>DUU<grz-u\qPl5olvEj6 ˷);8ԶnV- x"0؋)KxWf{ܐ4Fï/ӭe?PI6%n?|˱j⇹#hS۔@kh[Fh:Yp( VWP!{-[˼S+ G,ulGAf,Y^npObFc!j$FLD_iecۅ [.͝*x ڂj=QL7ZڇW)m6> pc5ӉE_=_"Yhح6> 49"y<^iɪ^ zX]^>(Oýoi*:Y*fm86lMY\{!³k9[e$;ǛsG1ϰW{ 2\GH!&xJpjBg.탨3mPvE0_+9@~~Ahx`b?Jq<+̏~)32YcQ?7g}0QǠ?sʵTH/p o^0GU%Z:)?#v9^尚y5Vi@e.[^M`am$ܵW?S3+E.tzpEm"[v7mر3&Я)Fa/5ZVϩ\k(^J $]RAL+>xT9n>zAۚBOy`qnL|{CMbf}jRD;Vrb_@AQ&\Oe[F-^p\ݘZRaz!F9|݉DEҭ w-l,~ymj#vp?Giᄃ61qዴ/=s,G>'meM|a;O%yF#(7(a=2QVPT͗pm `xE#>~4R{Dm%n=sDA߮'}ZE`+qyWO!w7SZ?>|4P>]J/%+Ŵ0{ Qaζ7"\??) GfNNU3g/*hY9 4uy!YD<-Xx}1DB;x00PžׅYz,v(tfuh8Lc5UCx'r)9Gr`݌rhz\A'͜ȀB6گ_j̻''[/%wBZh\m3MD*Kr? pop&.6/a 2ufznz<;{޶o$>fb_ ttizJ (g;1{fBl$2YCY3|22~Kp3UFr11mGȈW~iQi#=[[D@F;0jyg ^*B|fT߂-%-m2 ƜRةi4`ĩgRtEE/S5D7T?w$_|x)"|/JErL#058qm"doI(;iHNzT=Ku#]2>sl0L%#K܎wvq,(\D&Hv "pg?veB\r'@}?]B#gTfYbY'j_w_*ts{$ӽY EkRqNj֔u?|' ZkRwֱΨꆟcW8_7 S(Pjus)puzR2ƞɛ;AWR1BC;1|,1@VyL[ sWե!UfU,Xi]Sh1jRz4}cΚTzxu\,0_d{*=tS+ѨE/YDPWܟ %1bd1Af>٘|3/. NKj\Ar[ R>[g''>^IAW|MW/p@լ{4{숫,N,ud$=- !4H8=x\)&ݲR:[pCAC:3LF{. ]'%i}D7Xt쓳"ZۿB#[O5J ]7nbMQԅ2ERD}c"K=H[I]zeb4ztx_|徱kFN8Y1Ʃk&d*ƴ:ܻbV햮4SΎd"E+دddn9t\sXtn-KXM"~ሣI4]Zjh$y0ӍѪ3BvZetF &Fs.u:u _"QYTO U Wcaj/bUONqŸ` {\t?cd[;{usˇ$nJơyUB>BǠ8ct;onBL>.R\wU~*N;Zi,$hܫ|8waxERX{yJ>pfܺsňWz2}=fGcİ= ?ݷ&K:=@%O]l(W W^[?+* nj|<`4Wҹr27dJRӉ`G/OwY "K<6d\Ct{&JXoiה;@k:سfQfxFVel)ϰ0+Q/".s)g 1fW|<:x%b6~oOZ6bBDN$>]BnP`IǛ[mMWe]:ޟLo1«sΨ>}m/y ylpjZK('ePٖ3JUK % gKH;6N!wDʭf3a JK0-s$+{9.ۗQ\Z$}-$1]}2 M59/\*i0N%{@qkpy82Lʁ-R(`[`}jPV }Oge#4ߐ;5Ŭ5VxMKKR|{ytX_qʧz&daNz S& j\HdsoIt^2I˚[ACD1#ޏ="EZkSN}ʅ2KXDS7Y\L]QērI1GJKRwK?*{^>3 慧2Rƪi37+jcX xYy=c1~y&X5k>%k*ZZ5j%=6̧?.B/qvᐰsZRb.+>ׅÙOy? bо+GI3[^R5x! ~N\?)˩8V);o6޴&ibOΝ^Ja_=”e$/j6Wvg# z[t5D᳑8[> Sy+$Doogd{C [P.gBߪ91rK|E\B?_v|J+J47WB 8>m9RE>-)8c(5{Lֻ9ouXKgfL>&il'tX&ta;%C' kԥNnXuQ6*|+Ö!cݤ+9X)53K/ѬؙX,Yő:ُN*o hTfkD@ޠ!9).ݞlN:,m.hyGaj{U6p1aPóϭH.j鿆I9Ľ}Wsn}dc?}4%{369=~kkRk҇?0]x'ʑLtȬ.Ȓ fTHIQ.M?3_/k ŹB:G 1qɖEmU~<&62Z}@#߱ Stn G)=$`鄎89 >~Yv"ywe$q/̄7$³N[*B:IB_p>RÐ$)eRE4a].k6ʛ+I:<|""l `;'@ ؾk™2ƴg1ֶɌD^9kfSƶC4gtwޥ|CYlN4?ј;m7qBEDբw@ЈVa)U&icW }Y|רǢLT*`Ev9l;8t=81^5/D"}!&0+k+kut;~7^}gozD/?Ű*pw}n"Gzշty4Yt\1# -i3/}&)$[-$iµ3 %r@N"s{AbM4Dٻd$Y~ai?kޭX6\ ;#""^wLvDism}iPg+*L^ig endstream endobj 219 0 obj << /Type /FontDescriptor /FontName /AJOFCV+CMB10 /Flags 4 /FontBBox [-62 -250 1011 750] /Ascent 694 /CapHeight 686 /Descent -194 /ItalicAngle 0 /StemV 108 /XHeight 444 /CharSet (/a/ampersand/e/i/l/n/o/p/r/s/t) /FontFile 218 0 R >> endobj 220 0 obj << /Length1 2191 /Length2 15307 /Length3 0 /Length 16607 /Filter /FlateDecode >> stream xڍT%z 45ٞmOζmd۶'sj_"#RP41X;13re4,̰dd*fa@f6e"@wCYk%`fd=7@lfHX`ɄmlLL#Ґ A;@ dofMAV eC35utf`pqqZ9؛S\MJ 3e ojdS3)m] ddmg(KmA2-037ܿ df3hffm06d]i@k 6@g%ҁ1AE9ڛ::;Yő0m6Y;:U=n _4lT@"yl\jhW7[J{3W61' 3tcEhMJ!!W `cxov?*]㟈6x8{3(}6T g adc4|vE][zVfnxg'ېykA X_#BM,F313W鿖?Sxnif Rq0112Z?*[z?M)jmhc1@7Xcfcx00[8yma(;A/ѿA0A\"5 3Ab0HA v]z.g/by'` t0= `PޓAIޓ{R"w#k` Fe`@c3?z6Npx71|'a?;b-ߙXLu;`_nM{ymqw#dgH\ ?H3rӔ:ws'{?ޟGS{?Nq|o?{. ?1w:ۿ%0 +vyƐ'м6Z ,ٞz*Dz}$owI#ȫ;_V_=NZ?&(={)M.MaN ѩ||Th"˶sDTE{pw(9_. R:CW4Gc9M HMz4w{75F(GuRࡵ8VЍCq:6M!t,Q\#Qh߁c!Z->.Eڙ1T&9TFͮ(yeσuP^vGo3 "䜠>COlB})\g[B&xW.'|;j9'*>'Ӓya"/fB9] wU,w;.X{G>".l'Ncb9cRj/IKqAa,O^B1B(T{\VkPEhoieR7/c,mxwèj,aqicR|7YtFE78x }BCԡWbNOJ:HŁhg_Hm/W"|ZW^%VcuiNAAj~BY5uRoto.'hU%TͩH'6T67x8\.ȟ1aĕ=y39X #Vg>Ҍa T qZ CAYaZCn亇溸/sHdz 1_ewW\sa?mVt{o6F] SFd̥ϯp\-_rWԘi5AF V»Rl\uݛ#Vx~ \T C{UD&}MRVغd8綂a,HDf:8s\#W3h[lC'J.ܢ,#u R664Kx jQ&d9]tdʌeK湱ܚx tx#wI2CKZ߇,ooQیҘǹ&DC^Q94X<IQ ' `D<h~!H'@B;ߛ3Oͯ| W@b6^u%k(if vzfUDKt15xd1 oF*:uORx ş}f@ uWbP3k}"XmJoa *c5ʘO^DtdQ$.3oċ^tBHv14'00w 꽭[*dq5i98FS֒Q&|Y=EڍlpA+ZIft / 2o1w$]Q2 YZ3^o~gTdX2KHk~ۛJz*z[OVRY[%&+f,:״?]"c׳S l e.kQ{CH惊67dK~zC,u+BŹC\X Ę>p({a[Q_+|=Q!͞5S8s,cQgF{Sխ0N`; Xh_%0 AI<;iRz"Us@cM2!f&{".CJlTO0~*M7̕j8qr3WH>dB+W?IiCpmSV%2'琲eBŪR5mCWL k[يs#bdY Lm#54VM-Cƴī ,yUg/}>%*=%U{[ d488͕Q=ƫym=Xq3!}vsk!=Ň:ox80'9&2kĿ^hW$\[ ok[(dī=ұhUi !)16M`X,;ɿI>wBwHў_FF " r6ĻVI :%:_ vI:b q﹢y3lЄTO9*Jvw$iu\@bl5"r|W&rT$H:S{pTUEeULQɫQۇы`d2:ǰY]X+ sk4GPގxw/܃9O}Np)Γ1Ipޯ-t緺mGpT? έ,4!f iZ /2ËwK;uGDUmYӱm y6Mg]4z ?=LG.F¦ӏꔽf~IM;7o-cygx )͘REp)Kɬ}Oo#QւxR`R&+Xw{#`;g !7C^-!b^pbZ5q8ee𓸋׮e Ŏ5톹$\8~NJzM* ⼷LipϺBDXrRw ý){ ;dJ~[Dvs9 W吜U2ә ϩ!ArzEN4o % ppFXʟ.+z+U]nE}.Nbx \Pv^n<;se'Ww?2sh%Ss3/[;yݐ4 BAtpr1 cЎ°"|zh|uHy Te9{DN}d4=DIXD<%:EdYR9f*xhѯ _nvnUoDGTƗsIPі.{M;m5'+a+/ZE{ub5bR<3%0J-WY~qD`@]h%M\wDU-urk#Ϡ!}ΆGtdN&%X,~+pG-MT핍QVNI.!. }RL1g;B93ITskjY8gE=}X_{yBRuov#7=ĉD4ysr L"g9:qo>D0i1 =Wi>vu 7k궓P䗢!#i~oEo0UYδa\HFue[y2n_d{gܞōZne؉jm7hwm{0 dEh<~Wֺ1}2(C )-^PK1}2OgJl0!,u*i2*ͅXOnthJ>T:tll~n=b>u’eGI# W|xCu怐J/]VOw<>*ߋa֧GbJ/H8Feg=5ACYnU \0Ec,:IL6kyX/k%cICkš.D}KRo27P p|+7"_S''sZ;IA27E$,Uęy߭]|JC[ľS="dLPP"h&#bH?- [SrhPدi??ű p~*pqrGq]I:ɴ%0G+5max_%І#7AMғg"4ܓOE aq_7/Hoof͡ti0/;sDz8~'².o`Z0F"4Xp\h3 oCkj/|wU 8L.B (߼p\IfpP`DɰPϑЬx(T~8\B|;4)bh |HzR8l}Pgnj2 RjNRu:$,ގg'pɏpxbʍT~?Jѓ=M\Rg15xo-p܋椏̚\MF|Q,c&9&Tj1_i<3($m*ma%TU)@ xM9Sǰ̻_' r݊B7#u[)O͜?LֶW/ucX3Pa:Ґczwޣf-?v T5]4 v uvQYuj'.\q Zg9=W-&pd1G㒀{^Z7u0Ws|Fm_%fI7KK4Tdkr _AP}ea=вo2"AgSF6VUQXX##$.Oͷ۠j(|97Y2Inc": Wte˙ ]^Jܭ]<{R[ wsy,XT*8JנxX[&]RwBrB 9fɑ/* R'GW@ 9 !X6j+8=I7.Kٶ}ͦj%Ǜ{lrZ0a .DWH+"iQ<&*M$n\Y^D_H}U')(k^'{*#~(E$ _j|?ةގAS@@&, 9j| 8](%/k<R~+94TMd_4e{-@{rk ]`̵{|ܳS Ov|t ¾)(ʄ02Y+dhu}hOVUa^8- Ɩ2T]"Tfi0GGqƉ6=?nf2yf[I\J,whXoIS!vhp#! ˬP# tB>"eR~=Gf_is֠1"C4쓚n8j ]QtQREI=݉>fg!øXڠ4\2vu B '%r STyB@ kyWU&Dd8ȯ'&cZwF=5lm~j7:pg2hq1Rq9Bi{i4I$dܠ^.фb^94Q3.J%W"$iJEj߁{\d4_#;&IDQGOLm.QzQr\a%Lw@ CjgUM(G_o5Y=Ӹwӗƺ!yS~8u?` bl[oG$*t- ;%~ԷT?æеa͆ul겣 q L(d-B|%!nT;/ lJYQm\dPa|퇈"!M]%-b;i@`$y!3du;{jU/4BNJAF^{5;H`3pNNg㣕#;N3?.b 2r$LvN4%o'%dMX1y^[ۭLšHV֝P}wVV 4=g`l|Zx09%[Ljᢏ-ԅ+jE~ǟ9+p`"IB% s}-bt]Z~}0mB/~WOCH|#Rfs8]"jyǽ*:_o,ؐSx2Q3MK-u:amYLg>*%[@+U^əř}꺴fKٻk"_|d7Iz,7`Ņ8k]jJ# kfnYBh8C"OЛ2YӭxS5w ǛfY/,aj&Al,j- bCMFNbA6D'OITHF st/oK#,kg%'!7+̎{]Eٍ]b_щHbuQu]/^EqNHXVmQWhcL ؓV?N!Udsrd:]а XKR![4iv1.A){ON;^yn^RnUI#ۙ'Wn? tz's%?^r|67{ y჏׬p%@9+3 0_gOHPKy3$69E/m5U-lp2dNir- %(?U:K( X3ߋhs(9F[ l5|`9䋬+xeS?SBv[wi/ife]b#=o[ Џ0SY 1-  Xd.WkR" mp+J)K. -ݫ?ONkm=" FUqj2R^E[8Sl[ƨmOjnGaF_h Me.V%>*իX*-q-?3~] Bes> |Cp1vW`:p[kq𓧶(144=$A4W˲siMByszF} Ljv, "O;좂=_I[d)dL1R["L&˕sᛮ97BgpE`ׂ"fxz|y!\䦉Uk۵<Е(֘l8sI#S>`#Z9nǜp2#ɪG]A:+C@]/[6euGlsš-7;`ZsO.Ԣ!w+86 >ݜ8'oz~2@0?< =ta6в@zx FvsO5olGWDb.Hl(fTn4X&eQ!XZ|µe 1fϻme}vu@%E?AOP(J˳ /Dv8,y >=`w.|npw'P8ɱ!c_/0A{*Frf@7h?ع\RڹM;9;HJu ]toV=)ñپM9J[tyŌ@*)]AHW_]o(ҬO"I%uq]ZMwJgY*Vcj~C!w0˭rdXM dP0֐E2?#H8ڀx1eFgX3t-Ir0M:J k%V Ι.yDSq\LHe^) :&JTt~LGQ Z?}|[iO"Qb&ݎ% ~o }? j`49`? ͟ KE<#)$::j,5浈2XH4+rUT?-do߃&s❮|$L>U55u3leb6p/@Esjs%ɳ}|"Iȥ>5WP28R]"&[I=Ew|u\A3ȫ79C7Ɗjpt 0V@A$ʕo;>3.me<&ǂ2+w'I`ɯm6@F78Ϣʞ7Qm1%mGJ.599ѕOOU9Jۋ Rye7+^N,7fblk.MAQC(UO|m\|,?+#p^җ}X$tj&&}16v{a_YN\?ybMmUo?i0eϰlmg@rwXܘ3S-Y.#LϏY=15(s;ȓO:@i.. sQ!1h\{Z)cW HөB_U;7լ _ L >*#:SMx %1^2° LjSgA5SЌkgHZǡk}U$5ZaS+q9i|}3mp=+xjJg;9kʤͥ8|^dD3XVn:xDi'D;B##ɗ7* (io>|"e#cÿvUfQ379SɈ}ek<_)ʷImr6.:X炲ul2~utgPa8DX:d{Ȉן$#0c 1Ef4f~L*H@V>:η)XEpalH1.OҌgw8*OB8$tv-sRp1i-%@ ǿcsXhr {=IM!ˢ=F`ӗuQTHaeURH! C$Y=YNDKj8ʍ29>'J/5p~1y#xuDDt %F$Ktu/>ZU%>OQL &?D&!u7/k}`G*8ŨE%d;ZTNnY% ba## }s{#CJH*~ն1xS1RJ)F 2B>1|;0=0iDzsw"aU;1N`oA6L/%- )%ֲ5PM:@%*!쭲 H )-mQΟU]7Lw`3zkf.u}Bu5-BEoi6^%\/ҳ*%y_M5ĺ{ak1~i[ea.i%2zes--<+^O1(zH='-v 5mv C*L"mO`F#Lpshf,5x\hʦŻ G#~:) d%aRWx=T`7|7qZFn*0 M\SpɢunΫ5oa(gL8) ĺŅ5WI 5g"1H6W&[?_UMjD\mj̤K>_N/.hӺ9I_N/B+[&үuc)Eh;P\/ gwKaM"oηv >W ~iX5LLGL1#(fMhsS~8R)QkO8,$$ Ln7ﭓ34•+|/: .4y8LuAG]%Z0 U ]՞>*jŠ~ф0,A,5?aIs 5aZdjJMtڴԝ6A&(@rnI&v /^="H(*Ql բeW]َZ{A`O1V=(2 /!?'CP6Ō&3$wR .jϨ=mU #(ϰtFzօNFg7D*!Х֜& VpkjꆊdQ7q zP'lzf|lDwwDd)`=oI?`ynp [x’J;C}l+$ ~&bs]L58nxopl2#  -TWEE0=8-M񏐸biJy!-|MkJgAֺ5VLhtfJv.%W1格yx [^>q l* $&sq:4sc(O67{Y%mK5!jK""SΦ$P^Ql'0O8VA~/|4,kdzZ&t:wQ먎e&yͦp̉{O:}B t36/m@r0[fV1b;":`ץW& -tc\M-{nYOEDfY: =<UsT ݶ>Ntj/<7q` %)#gld1,uOR1TS&k)"N2=٪&}B%YПVm.Bb0>=$o}tT+DF)VH/k ؘj#SY,#NWdju Ldt^Qhegzۯï<UJVCh40LyQVo L.ہ^ͧ0]4eϯω_H{ˌiý 41l;Nп J9`X ̬ MdMPvaoQ1{ 5"4syp-܃W4贎giqň5!AiH>Ox,X*F i iA jߊ\gGcډAs7Q>lt_8VAʲ w|^0ղFLl5 h^ K*,H3(Nr UC5HS}$5gxЄ;` endstream endobj 221 0 obj << /Type /FontDescriptor /FontName /FQEBNF+CMBX12 /Flags 4 /FontBBox [-53 -251 1139 750] /Ascent 694 /CapHeight 686 /Descent -194 /ItalicAngle 0 /StemV 109 /XHeight 444 /CharSet (/A/C/D/E/F/G/H/I/K/L/M/N/O/Oslash/S/T/U/V/a/b/c/colon/d/e/f/five/four/g/h/i/j/k/l/m/n/o/one/p/period/quoteleft/quoteright/r/s/seven/six/t/three/two/u/v/w/x/y) /FontFile 220 0 R >> endobj 222 0 obj << /Length1 1420 /Length2 5888 /Length3 0 /Length 6851 /Filter /FlateDecode >> stream xڍwT6 "UJDPHWB $$"HoJM{ RR(|{=~<7׌La(; d`f o;"PH@b($Pd7e@ to #Tx `@} xUQho GoݺyW8PA@!H>w%TB\((G ~9G-#*)qŊ0 7#c<0O@+5/0EA ,g],aqs'?ϡ`?gRLR ` $;I00/EE(!HGa?-) E_{ T6ة&JSxeHl+P}J\biV3.}v;>˵\u\k\v|8'hX&\)tqFuP)Myi}TqS'ՠ$S&f>]r>>Zbέ+v[|pO(^]CMb&ҏbt;MFMXw@a5Ď#Nz J*&756EثpLCh+=59]7EmO0 x~/bmBy- C+o hbk| ȭ27wv2/qYp۝l.S(?y8@Ѱmx!+d{uWk'Xn6x^>r:+Nҥ/u`A%vm͙: m1v^z ڂZ&}`Lud5m #{ǀ>ٰL]$;kHvNRe 179.!xkPQoZJyǏso܏OhPHب/m01̜ G/~G2N2K#Hڼk[qYtJ7:^^fͺH/oģkvs2Y5$ i'%en,{0]>¿Lq;O R`<:٭q뱓Zh7(ߍɇo77}shǹefוǚ.֒pWPgTF`wlL܈GS>vf/[C?~- κ_p|~^A1qj,C꫉g jy MѲK%0ncDPiRSIW2ubNI[Zx;.>6j YQ-|ꊚ_ =AO_}qdPdVM n EA _PjWD_Drt7+sON]$.ׅ ?^0C r068.f$I3dIajd9> +(@ޏأ"! Q݊ {CJ˹wK%9%Gكg JɽGJ?PV ݱlAsM@͵zm OzS3a.fZ}ȑ3.yOl2Lf$*Dkך Xiʎo5KbK7+Շ"־VS`AT彽B.'7ӯh ]sB;(w N_SkL_@^QlɶX{z\kŌO`Hyo-8ke*O,>*i]۳C~{wE^h p`c9%* I:3|f973<,#:Ly6zFqW T+VM[4S I{\\..egچZvFȦ3)Yq6OCKr>,̮&nk:V,t$n$J~b>R?|azLX1zgBy{ۅޅ淸\$[ _?Qu*2Ě1݊Vo&.4tJxM[^e"My_pNtdjO8b<dVdw:"mYJ;Հ(pRXW'ŧ:&t[WjmO=rHLE} g"R׫kY rR8pK׬sH"MaNi;c6p:K8Bs7JQQݒt^zjoڕS#vq3E}ɴZSO~8̭ȜF<{;4K9X3GYEruG0IiKkA%+1d #<*ϨE#c?40'hg ݥ@X@@nozK5D|17Saz=΅'uVF*(nh 8똚IyLG [ŷj3 ʧҮɽO6Y46|~&VU͢K ruu)Ju(.9ɈR_![8̼WXއń8h4Sy@GϺg'.DQ2(y6c ¼{vNKS_+V4Q y?޵t1LI%{SW">)Ъ0CУpbB_p4qLm:CAixԟkhŸ _+'+͛ 2\x@^NUdn~7K+M6+3TvqJW4EB)i7Y BF}u\`2i}Gsf2]uO/p5 FU > \' xfuCm/6v~FX*)ŽW_<1l=[0+ho**3U.W?h$G8 )rOZ/cڟX>qJ)Zruiًlם`I9soT;~ˋ U95 푊-={,<Rq{}ڽkAT\2ٵK#"%03zQx0 Qib`Seib9COo{3X17ׯg" ue}̚%҅vz\l5F@漹[z.T^howѴ|~x%Cl:MaiFUU `<~ln@Kx#`/}zh,E7:~nxţN`t(ZZ [<,ylN8#kCLh+ $ʆ9ռ3'!i-n1>Tat$UҮ5ywJM59ZI#1,g^rCfHh؏٥㪏.FU1bbm2]Ŭg YkZϊ#hpw1ۗ.sΞ+gd DcQX@m~c-^6|zL]`.ۍDc/rѨ8)!veM⢑boC+'>_]katTm1:; .ٟ=̬eN,[(:񶀉\z,IȔcu5-֍IP1e3NťЦB7R>Goٺ3 Y;9B~wn6S3bO*6Z{N]x]t?SUEM#IgsvLs}uw3H0WTH޲.8-[|ǹuw/Ȉxִҥ%D9}ۯJh"쎒2s/rX…djN?xiAD8-QZ/JJt{kWjE^p5(?FUyw+tI8d|y–n)E6 tB)#VBYܣ^O{C&e9O )ÜTC?=!z뭖8NjYds=. r)@m@[މ@|!=":Yfhn>e%Uo_?>%'!HF? Q{Q' 2 lzksh,4]vL'k=9[oy^]'ɯNW<4ml<^zC g!yjv>V'Ŧ|M1wT 쎖b=/^92ե9],1arg6lfizTr({Be,&>xI+\գ# ޭ3#'}CRo0f# =.I.7pthr9i,zˑsn",fI1t\`,Z;]iq%gz00b] {_M d3@^4Oi8')F{`9#2SڦIݴpwe6Hu=l۵rA$_PpjsdcVK[cߟ68HdI_4II))hDCf3l|a~jIrF&4}dx7Qթt4t*/~rs0{~GyKƉK!ɰ шs c5 YWt<")ɔE S0AX2NzmR9^e&@[b7?H+[9DH=$9vr{jCA[ _ 5*)EPFVҒ&? pj"tǣV6:Oyx IYܯV8MZuup?l}Wvkp%K|,}^=;<)~N%;n|k$?~uY RQ~&̃gwJ*z)[8U(A1r_-c'MP9D,1c/*`X̣ 3O{,xȷDS*⦑ pp,2]cSYIZz} {|ػ|{k(HY;Bsi&S6CM endstream endobj 223 0 obj << /Type /FontDescriptor /FontName /CUJHND+CMMI10 /Flags 4 /FontBBox [-32 -250 1048 750] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle -14 /StemV 72 /XHeight 431 /CharSet (/period) /FontFile 222 0 R >> endobj 224 0 obj << /Length1 1420 /Length2 5888 /Length3 0 /Length 6852 /Filter /FlateDecode >> stream xڍuTk-("DAJД7iRwA$$AH 7{"M84A(H^Dz|?߽kݻV̞g? '!"mSEp !i}mmu0PHHD@HHi80X$%100S@m4 lA i!!@4F vAB@ 4 pG;cpG Tta0 !`= Ap*%]]]X4.tE@qA?)u?@#;`Ź10 aPX|3 ݁Z@]G7X7r Y @`;"a@]U-FAX4>Fڃm_GU`8 œ07Bg#wGد Ӏy#ma'00oP$(?no? h.('K h?_#TS12C?A%%Г_Ł Ws:*l:Yo&.gon GBbB{ ~S}"Ug{_q߀#v@ڻA/6"~o6 tv:_E/t~o?tA8ⷘ=Cc?_<,!wrg;k?m~} b@0v%Ā Ban4@q 7$P?4g (-? G@ }W Y:T1LO,VRkQr13P]? 7ϱGl#7M 1zLPx! UcwnJh54Vifz1g6Z;90",Q'MSZN1=EmG0REQYjéB*O5 Y hsi-دڥ!b7rRhcl!gPiUѐA+= Zp{!J|~P4 Kz10ɂPgq];W%ʺet%5I#ce8ZhgXY46Uo돁<>[TW_t%Ƌ NϤJ$`mEy ZF!H3Ү `B/I8(+/YX6Y']u-ʣ7|{dѡbmu}F^ ]mޤf=QR;k;ל(szH2=te+asbhGKU>Xz|ߴs Ur0ot,XّHT3Jp)+3Yu-̖!^bJO"R0^'(dX"6zLhf,A6Kբ1s˒i7}g+< 8(dMǬM0:&j92%b<.` s Ff/cW2OLr.% %t7wd :6J>זI.EK6Oa(iGeKwJ-cThvk0z 3a(.zYbyIuE#K-ç+=U'e0LI5M?}h2 qvzjK Xp+N?kEsr Ҥ>nZ=I >amҏtk&* `cD+Y׆r$qO'OHt/8&K. ^m1vT5/Yky_IZޖdŤB1O$$Fypq|GoW̑ XZf}Xs`g\Ʃ~㙄󦦚s=O*jinXl;Da<&srRףD!uyNtdAZۆt - J-Ğ)FDEҩ8<}ɛUD>OR7nlx*:]Lj&ɇq_Upq ԭKGO-k,pBt_PrdQ[d؎j'|TBzPmH.j6r8 P>[OʥNn|C- ʃ K=NsWI{Z>yBHAXO5$Ci!{wyg1ߦ-?V3vv'MkH Tй;бMj={'s`{k#RlsWs7`1mBpX'z{4DtB^Yz㧘c*ZZHc :Ah (fvOGnP%$V*xp$IM g{_A-كu; -McG}TOUzG=& w0e4C\J9.t vZشfPh7N:] h 1 07sג.芩/KYh놮[ Y(\^3)rɸB眂&C}rRЇg j8N6BhbV}&ߺ{ ܯ'\،#I̞PJ?׆aN_ .X.)Sh~!˴BbՌ= L_l.A`qΗkRP6t6T|%.y}D_1ڞ0Wz)hæk[} &yA2EJriQUvGcԟH :a:uF; gxqex DPNnZe˄ ޝǑ<9^ڡС[0۞#FӯpA*N҈o#"4xP+k%ikbT=ޏ,I8N 0f录:-BQb ņ!:$M,n :DSYgR~^` Es]\ —nn"1o-""ȟ( xs)1%=Ͽ( b/:=a[FCo#I#͹hڠWkn!Xʞ=vS7@fRi&Gbجg^TٰB9q#U=Ɍmb0zn%1Ɖ{V?0Ad7 ԖӒJ)nO?ӠDBIpW/{l)vpee;r]P|>8#4(v#x@ N7K{q>\O$5(#mH9Lt(Βsh2F$d®Vٕx}I cZabyMWpӳ![d`IJUΪo2aʩ^$ `͢kOmeLѶ-1ڙnbM@nK6+!n&!et%Ww] <=9~%VzNvbܼ+mydƆ˫wy&9o|VGrgmN&!Z&${均)oXMtxKcd-Tw<tM%vW,lb ARC8(NW CӺD,|Xa`k|@2p3Aʘogo›GZJ9eD׌K6SYi.V: t.^ ?bdgm'%6ZxyrX`I=s:.K;i| K1CQTY7SbBUBaz;ESM WIftU& OvMh/\/of/ᵁ)O } bt\zA/J`Īa81y[-,UL%:T^ʿ “JQ%LlCci;^b> &qW"RC@SzֶG.YUOZ*Bvy+"}֊_VLr+NfC6LZ'[4VS<-?f $Ω@.SW (-o$X],eP^lě**]s7&amQ"L| ~ ~is^׭Pޜi>ڑ7cNY~FIZY՘' f5iv,/zּ/˾W>+$hg0rmJA=\D'.gǀ R<?.RW|o떰5 KJ8$8\> )]d6' |} FU"AMַIT(&*K%f\Odm y@ GXD! Qc>IEWPLskc-Ҿ7Y[+n>uy6n ' Su,gI].#u/}e_.d@$Z?l8<,%Tw[+q endstream endobj 225 0 obj << /Type /FontDescriptor /FontName /GPANTX+CMMI12 /Flags 4 /FontBBox [-31 -250 1026 750] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle -14 /StemV 65 /XHeight 431 /CharSet (/period) /FontFile 224 0 R >> endobj 226 0 obj << /Length1 2700 /Length2 23079 /Length3 0 /Length 24579 /Filter /FlateDecode >> stream xڌP\ i,8Kp!Hvfd-ଭk9Pi2[9[e@,lIe v6' 5Zn$IvN;'GW ?Cg7@tGtvq@gI`e t4w(lMgK; ?!lA VV///sGwg7z&ty ;ek\ev@'w NДW6Vۀ Oo,W ;--]̝|lv@ 0weh 74s0 #0Oynv. ww;_% # 􋟔vֿ'`mde+Vm';W?&`o fcc]@oK[_|\)8E쬁?H~@`eg Xm윐~Gclc^VN>/ p1s9쿖06%U3坬ng-9z38wFll_/{+_B2|1|pOYhe sy;8F;w;o윀jv^6f|p/wRߔNV`f=qjk,N \^ DyD#o `R?U_`U7F\VE7sQ\#0E_ ή`nLO7F`zoiF`z:o\ ~#o<--_+ko9_8忈Xpq8:NkX%hgs9|{ֿ!8w_w^__nD~Xff8? `W' ?jp1.`.௲v1دV^ppWg?9~+=?1vp[tqz1 npw'ߺ=イYN jl݀l&o /?1<z̼X?norH@Sko#xZ"8[ W}'bMgwkx@OLYuOXڔ[ {;ld1݌47c4PYKl_'5twlW>4\;nYšmJE䧒 wڱFES9p f3oI28Fw~k}˴8  Ii$f,n* BeJ^b`HӈqjocNJ*nxeFSl | $kXn鰶O&^yL5v=ֺ.`Hv0[$#Jl mk(F [jʿ`ZL{5 9x dgc3">?P^wҶ69eʣb=,S,=.'MmZuj`Th Z9.TRy/UllEQ=ˉNvGnR }gr(Za9o4USec o7-($<>j ?l>y1KQ+( EIt| }{QݪzG:}gҴA'].D&&CQWw#@;6!|v30]lOm/⪴գ! JVNW"#GrbW/3 bd+܍W^] CRJFi <$fMx;}&زI>;Wej =yu^f Ħ4Ij9aUk?+Y`绫%F @%4]~py(uƺg䦉.cXdfm(d?}:׌| vVIFF7  eg+GH}jwر!d[%)PVWg+dzi @Sք"˒"A?}쀢ylf+)"Z"mD*ۤNrCY#sޚa;p?殗@qhEoA*srG7G|jvfBԞN#_VE?ZޮdiD7ߏv_=:iz&Pe[I6,̌rx+YMTl9nIU]=w8SߏQwZ_Y0v.ZT>{H8 Ա!%Y!܆/HdP+9qk^x3N~̔/GE7"dP;㷥@KaVvā+lP>:pkН(/w\fOex0|ߝj}ݕJ&͑#@#N)ĺ#T{]")z X7؎LGmNI.!""Oc9[ nT BEgedSd]՟q>[{/ʳc=ˆЎe/|Gce!b9ܗRt*Tat$>JY[#`9 ^):m-hmy ]Ҫת3}Soj8{y]r}`w@61cX!-Pv棩5'ܪ/0׬W? JIJzaU~Pfp [.B .WiDCŪPeQ\cj+! =6^Y{PʱxLk ~@`Sё`1Qnqd:izhޜKP Uhn8}o\|yn R/{̳7ܒPOeY^~*y%4 s6DN<> dT.ՆUߋxF$Ypȥ٭ߞ]ie V$jh7?hI)+.W0 raݴ b(/@qe1Ӝh 矨 m{(RIJy] 7dL+pLdnHQO͖%UQ;dJp홨nLB#4jT)~D`H92t+H{ӿ>wTG=\!@jK]=T mF4PA_Qm$~i{ʶq@"קZ4:s{3d@$T=8NOQnuuJA Re1¢yvdSSƩҷ\+7n/':\^8B36 _9AF $óD`}cPtJÆ焼fn㮖bEvuў7_b5$LH4$zטfgTs+U¬,:~\^G#}~Z|y٧C)]⠾u&*8բ]!|~y ⛾iy}s9'R$ ӫ#N6էM ,SRL( iͫLߙ~;(rX"kD]%.4$}{D}}];AxMZk-B+ҚPi:6o8P{?֢m:J4 rPdOp&#vNnŌKj2穱w499K'HշY]Ty!u]s+rIkM\tv]}{ 'LO<:'G2EHgY ]xD&,1?$oL ~ i6dd[ϼǜ/[<=&HxO7&\;(~yu.=N9+_J>2c '{) iSdal2gurłC MR%[2if br4IB/-'0@O'> bMΞKrqrMIWygI!?gޮZp&nR'aZ+Oj?<54w׽3A%k;Q{A~Ofz_#Y=r&nC3:xj}VV4;U(LxkǹXB9~g Wo,#u!k.>A4Q.͎9/q;@yT}w~~VE]s=9p)N2Tx|9xP5YFIڦJ9Eeuk#wO t]6S9d(~N@"M5{O"u WcoYV j743Xc8CZz[^e(%Ǹc]boKEXTldIVF.߫fKT xȪ>GYPVE>w Vˀq&!sGWKnNy h+avk)Qmy'ԫn@y%cp+ȷ[ےSJm`kv~j\f 0r=ߓ<N  gf)jLG3>hʑh !̼N/#sR" %0<by=owNuaS"ߧ91U:^$`ň40+=B*jPw%,w/9-C<̳ pŖLg wEڈ-66[?zd ua=,7A=0@ܼpqw~"y87mIǘй:=E2 >~WGeLo_y)"4X9@=WۅAǡ7^F 0XǺ(5yI+`OQIh&PKw75#`-` _'lSxVkjc\įPJ~):M9#g#4ĸS&3̈́ص 6ހ7L$y <'&bO/kk%2\;֑ROM=`H-Vx53TJ^'AhśIʑ84][hBhdTv QwϋzX m:g7e{2K2!{ EFB<@I:Jp'&Ӭ: {hn6 ݜ1A &/vFU*rSWcdZbs2x*/zlUBeͶk3p\M2R YjM4aǙIÝ Tq$!*oi|;n8[&@?s} 4Mx C_&+=#lDt#$Яc/2] ;YgD7pʩcK&zh>?Zm(>'/3A)5+{ʂ%([x^wgT&x$EhYcP;% _w𐀼nZM iǖNq3gq35V s O FK5G AOp6{in?q*+~ )xv2)C"^Ԇ&|Vk"ݡ'@ (jxCVxҼ$qQ$k;fOkeyĢXn WvGnJܭK߷@ -YPJ^Ȍ5*8k4p>E0L0[3\!^"Kڍ۽W361$}17&ہWIz\-ӏ%7kOF9zF:7y ~V.^a$vvdn ~N<ƗjǸo-Z.*EѷϺ<%,V? wgM+v+$AKC3ͬ;9C#rlHd҂KHRaT'dZpگm{| %8՝6l q%iP{ ׂVCRr1PVDVFmH3=IWhN#I"?=;A\K"og6sPUN'ېePXbu@Tq$Blb(>ftM G9Et/`%izHqPYLH73Gx7)jANHQ *~%#K{k HM;GLz2Q8U@f2d]nk<[;Qx&I33!j(}"~ xlGQoT$_W7  }[ӵ:mRh\F?#Zr)q'b`Ivhd兒yҺF>3s?:=!:}X-bRoxL>t7L-І=\‰/c~cD2~kYmae~s̐ߩ}LgM9k·PhIHT+ <%1U_vH(ChLjX>KD Nh-J}\MBi֖">V u1F6p#AK_]Co!{c6zzIP| o ?6DOr:dYp[:ѰձiHgtUE)"|35Sx%7ɣbQXxP ʈM0w1pD?:0U1yd+6RrgAw:?U156nXW9选xȠxօ1}{?I73-1]BDp#B;3$w< oC4?߹n'̻zk#ޖo'8%I?˝)CϽ1ԳS1hf`V;ɃI]Q(`hA(f[uBO ?>Vl2VJU"$*WUEdMHOZD*UR.0/4ǼQεg,L͂넓9 )3R'x` !a!>e%bd/X3< *+X\k8 S,!xT eu{X0AzkrWD'ΔSDb?z:Ci\+ީ8#D1~>in2]ؼqCRhH`t[iQvH ,'@30ZR:k1!~Y z EŜ#7Kz2|jI&*S<"3N㦈K`tƼYay}}K^s@1QS+u&3Vsry09HNk=ᚣÀ``fVne,=]& H|eI^86ĚoWXen2 h K['2Vۏߓ$S&Lh w{*BȎO2oUi1-0eU2زYf9##UT) ]-]͊s%Aj㋩Cv(d4d8Iʚv?PV Uڟgb<- 5= e!iV)1TyK-]OtE;tɬET>M(q'<%1֔KD hJRx|r d.Ofue i5qZ o !1#@S_";I *v*a6rB.Y0B«0 ϠzQ28+s'! g\Ӟ d${Ċ-.*{qJX_ؼiD.ՙ>5F7nu>8^4?(Gu5W~ O^sY\1 $vB[hV}X?_GE/bf$TdzwYh")O}smS2gbOyQ$|pvNE#&5.I4|i>~ :@v,"zjt[4vMmg @G) 5|f9S9?r; VlèerKSdRoJ5S&BMh,RNcReۮqqJFʹ䋯a&xҹRjz7diya*M~,6q5ÈTڨN~{Xy+a`S̈ZUkg um v&dGI>\$d1M[ĵp*="]suԇ <M)A_V+H(($;std3F #k`<;EÞ=y.ǧ]q?pC4\`ǽЩ )>gdڄ!aT])W܀ fײ2~!nmVM\V(>~è(#2eɍBq3 +9VLmhO=TZ.}B"cޑ٘SKU*M(a;7_V;-zd|[!X5hY8MKNe-= @B~bCCLnǞ[&jQQ۾>}TSx=&8/rפ:)],Biv~r# Y? dhI8Vx ~LjLjH[NaBLn-NiQA^싒o?5V'h8^3nwXkȰk~WPt.Wh!ʇ#+U彐0:k|EYB|h/"C}m8VӺF'9LAj!M}Z+LwM Xc&G+3.~A)پH~[ؙ̄f5}ݡ6 !RkX Pߊ'fA_tVA. o&gDHi7< [SG6X1rQpAtW! hn/cjH"TΊX}:J4Ҫ]( %6KIn:WuYTg4@vz(B@ٶq'Xoګ~ݻʴ'`Jy"ghI"ѻF#CR;"G*qll>4߈-8)/?mw0J7ՎNyNG |0~*.~@8Wh{u{7ĕeey)7qˏsə(diEI8~H~|}y&.cAi> CrwjǺm?PGPQ\1G;H3/J\* Xy50LIj9w\dO{ 8<ɬEHL tHNGMa`_s [c25Ѭ"4OQ N5*+OGCy=i J^p}~т{ ^̙vi.g[h%-k#Z?&n23%bBS/w͋/;Y g$vFhѻbZ4|# ~+*cu'fYh^`ٙX"P{@fZt]HsnU'@}ɉ$@5-Z@? kCmy7֋ٽdGMgjvb2jzlugJ uu$KFGF7m=ưH_E݌XL6)[ .8!_./|ڴƽb)MpM7t2w ɦ6"q)^<줿$EdFR+i[-BZ2/hi$~?h}C>Q 53_ %h?ziOE=N[G;)> *'U,=L\ kWo ϳJKe>P( -kS a׿ά74o#,]sJ'Ug{)>%DʐG}̮$PP,h&f3^e#MAy 9Ws'"l2@ E89Afcg6J 16%q89Gt(38*^V)~.jM&S)Q1wE$ vQQh$AL332!<5S dy2%7>"Sь مdMCƘ7nO"䁈'DZ>EH${' Vu)ž!RVXQj^eQOEeJGk9;ݜSl_=VF[: ױ b^ =)qÿzb4·,]l3%[dg: _+3Vݜ)Z˃±|:o4HUCV:JC83 H_.cC[ R6aTX wQXUj/MVz- e=ԯe So"4+k=R/a),c?"g U+}xy˪';Az{]'9mmb2]қrvXjb~[њ,8K&9 z2˟6;E#,ݔGJaZhPKTڵBSX}1meaa{*7zsއ<Rt)!xK5=JfD.Cnv!ۼk㿣ɾ[ GRsXKߕ^YaJMn[<]#;Cf1V/堉#\J!LA):^8(?Nzx:}bᬵ)醕{w/1s{>ُbҝςuRLޚZ.񾴱ZUzPqf;m_n̒6 EzӐE˗wc2!v!KfN]YPgr58feTl0 F,‚>Muߏn==lHz枛R#3e%7ج9J6-t:WP#T7.&FIt=zigͷu8y fu@dY[ K yy3~LA-­'5Ctn52f=|:=A_x>Gy ֤ǧ?2X)VS8R\˖-i kC F{i\ka2~0ĽzR(ڏiiٙ9aLq맪wM*A5E-t>Ap2(t5:?#6G24wLbyh8:[1b\Zɫ\[!|.bFs[ɩ|!BhnKtʣ;ӊ7)>iܟ[&8w7e-[w--ީ/M*-~X̟'OxmW݊옏$vaVE@4Ua1!g222NPQn@[r^hDo0.k| 'a@E>CKo|SF5T@GxEm NYJͅrBdؗQU%zj\Sy A`k]#]X%}*lZJOyɗJs܁jg:ZXv:-BW/2ͱf^廝pܖ}3$D> |#ttqHM˪gyUUF_3/(ghW!8ynsQ7vQW' βZ99'q{p831׀:u % n yp }Aر8tK:tc;\csyh.8זCKa+jߵwRKtsE؛y%6Ca#0_m 7Cpr-39~] z8Y9%iJ1t|f_CPj;Jb0էdZ|&s ]_î,24ZZow4{ .Yס؅?2⚠)k'1=ϠQaYgOH)RՕo7?iȨoyUԛ$eawurKĨMK-j^]2SY_k.}qTE1ɩ 1hmV9OE+]^^%L)3  Y!p l[bHYuԖeP> Et|n|hSP<68-!{a_:"1F}6w"`IO,m/%U5ܣ׮NPHJCZj"}ŜJ@'45oH sDR6WE'&dMkH/2MIU\5L5\H#f/yp2,Ȕ0C\.]oCrB߀d(A 9k:$e&u![9Z&)5d\Ȏw`BFp<_!-Pu v/ҭ h} l2l)NKϒR: X?ݱ|߳i(*lAbc &3fl]B7C~bD6V.$XWB^1I3MD¢,dk{D83P:Rwl8|8ˆ7E6TdՋ84b.'#&0{OPS2q&)3j'C+D'Cq2rD}ƀkY@5f;J<xFDnpi _!V9NE?iS[A}wP}K4ZWb(q8G,o75ɼOѦN!ׅ&G!ߨ߶QnN\Y\POTa@Rԑ?0cvm`GgD:YIOl)&ʤpSBt-bT't>`De1Xٴf]*s7VRt fwt# C~cL'b hUITg"Xk7G=af mfv\鼒],HIxb:O&2a]{[B`wML"!pi"J"b0X+0EFXkJ{&86%ooJUpnXrVW6Փgch!!ႭW|xp+vckX"S+YoB~~#"/yv%Ȇ̯_pB=-L[< >m( 2f}L:DbhzmG! {Q,=ߛM_ nS?4v=ihpI]G/\ƿjCGK! 3cgSS@2.h"? &9&4rP1]S :}YllOSbQx-T0+Kgk:rk.uZuMd ^UC,*ϺΒ;Xw< \M9zzg&L؉dlejV|W"ǵXO=QsUX"2)Fɾt5&5Z{< 9|.s]J^IERa3Q=,I|keM^|9 nqݽGmY4^?|Q!Z ,)+H( ~ 3YTLA]: 'xS[~b/((Thz=Io 3m['f~ tz]8{e w܌aue5 (WU gfJƶ#-ʏŁ= 7Y.1b7 Jf7d'Nhrc , Y]vߐ]mPNGKTjX (ʿb~tpuz}28Th8{}-zڃ E+:Ls/\D~=/BZdn`p^yLP]]+p+l!`W~M;L`t0qz~2MHwW`.8g N LN:onThퟋmٟWt;GY{RuYhHee^~7} 2Qg`djpGy"qe2&i//`}H,xGlgں$q& ]4YP 0)YW UmJ-ʝ dJg ƺSNƋQœ#KaPlH\imG8.*MDT~q8-D'Tʅ,bPɻ%ŚٸKI=֡0=]{-"=dHΡJ%Ǫ#'*PV@5"`(Z&Ufg|OrK\+`>& [;wHYR>îZBd& ch/UP끥܂B)jJ;QA6=}w}o$˾=ȼ>[o.Gqbю._ .蕋6k|9;n-ЉhJyyʵi84t΍"[/{Փ!_<{mtR~Uv1,SlYG Xgޞ2avMӹٱ0[wjpn0qY3Uq,bR~wZ59/z׮ACeϣƔRb U>):NS<GY f"& S2![64|9Qr +TY$-^ƨǻID% JN y#<˾:S]@^ʽquF^:Rv'͛qlf-@qWpTF’`0󩖐[#$&O̢A;Fݛmo qf_<ϧ{!bYC}^F+ۋ-Au~<𩔏Jdd(ɺ%:k ڵk~SΘWƥ5-`VWPi{ᶗ^ 2%-)#p/ljH*BO~Vy.X.b 6 &;'(F;XK\$ 6Wv;ʷJN/ydAb\Kh3`¯ghK#+ %2GBS/xžߔWJm߸;՞ۨڛK'm:{)&W' AR6DcgC|I $`*53LjZe3iH#Li* NpD3U  9tq".D!t5y8Puaa]O .?(UzlKt:Ext4h*I>J/wTfGP7~BgDN3*qUX@rw7O$yJ>XN`,V҂C3pkzz5H&I')*{SF*1VHk;=_gkלɹwThF+B#+(؝:[XXF3>)]܄:L*/E9l8W"]0kEɥQEٸvt#5K%= 9/NWv5 3T.1 kivU(z4(^nٞ)w5Jw^nKYR_Eor0N&%eFGwT|)>$rcK:!>Jli9St !OR23K(kh\dw;g5>%a,ѨɃɎO:i}Fr9+MLi*`>STU@S>vfy58efҮ]}%PoNBͲU'ik`<8ojRdi13un"TiJɮ"Ѩ::Ĭߝhz\GX-zPBT f;E?.Fq%?ky ƞ'ͦrq }ZC2X:.'R^It$w{c_ȹn ©2liHX^8hm,l4 c%_~R'Q(+C04zR1 pӔy ρ0gǨbGخ<7r:o0 رKP^dDKژo mVˏP! 2T񍛷8a5vS5KuU6boRRB?%2AjYq\YI;K.%I22]>z=6Cr 껀 tNfno,_or DnN&UyO0!ܶtj&#Kd8X[^Ymfl/{V)9EU6?DAy4z۽BW2;%''Yҧ 3@>ז?:K7y }v0ώKJyZYk9!C,SEw芬/1cBbA>kgU0ܨER5 _W>%D `o袦e7k<ť RN[{ 0:ĬXZt:Qa~W'y2'K?n5ݺ#k3]*%I⇝` K|?mhl/Pi cLT SxXun_KY0q|3Q09 Tٍë=8Xe^]^ĭEQpy/!A8nq#H >OD`ةUq1ԛ/5Z7҅W~G<-Ҟw 6uW[zpβ\0<zG:14xWvy;%XfJI[!?xj@h(=sE,FMN.dmjb;c?sI{||JsC~rb|+̷]m. 3Cy&G H@.:֞P Wܼm.wW9 `Lm `f!glƒZ%N:Qxn[4M/Υ}REf26*Cx.pQя(ݷlĖzW)o:x0XMvewC0фr`s\W)$S;jLFѺ>4@]3%o"(*]a\ v$Y=[׈*Aֺ ftv7sB|']Hd=#cU;K1Ccl-C:;x-5T?#^jD*HI'iv+}?`xe {pyH&OܗZs[V R$f>)sL>џ* O;z^} .-sM;Fa?_/U<c^%:!FwkuKT&tRX{4-p;soqv#O~b[e/2j h :bwn?].4`E.JtR! {5)o6  n$s`'xshd+Y$;sNCJnlNgBy&qOD&a.k LxX%PϿdc MN3xIډ>qfkTEu `IyhX8%jmiP0JW+ ur_6bB7T$ild&b6B]I8ܭooFHHaIr pLoaT3͡gԎ,}%$03q7_gvr>^ i+ xK_$qx3Q+ ^(a %Q]Ek Ԓ|J!k/4p~_ R+6ցAH:AY}DS%w_Fv`ȂI o,ŕUiY/d|$֞X "O[ qƔ/B(xaybN>huI`vjVa=:d=bUo]i}~kla(# `<ш̌Ry MfĞ"i+dTJ_2 ݒو>dxh࣭݋zLVn8Gq?q6/>..͍X09eZaud K?#HaRF07qqe' 'o/}-i -0BS v ȏ(4e!(YU4QArL~-@?Z`i&c:JXCuxٙv4\s0 Vk4Q.a<RGt{[u 7ȡfEAJ(G%AjowMOy:0d>\tPyQ :cȅ/y_+6s4 Cd|Vnfzs6;R kA)YjTN4v1@ETǰ~v݃r?O2Hw9@*({/هBH!=nI>̦\;FQ iZпb妬v%)䄍wUA~v{'ɻZH܉3Vgg%Tb0UXYEP'BlU5r\ ݥ8zpN(ⓐc׿1F_uZjOXq2 á?bIQ^0X9qіd* endstream endobj 227 0 obj << /Type /FontDescriptor /FontName /NYRYBF+CMR10 /Flags 4 /FontBBox [-40 -250 1009 750] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle 0 /StemV 69 /XHeight 431 /CharSet (/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/Oslash/P/Q/R/S/T/U/V/W/X/Y/Z/a/b/bracketleft/bracketright/c/colon/comma/d/e/eight/emdash/endash/f/ff/fi/five/fl/four/g/h/hyphen/i/j/k/l/m/n/nine/o/one/p/parenleft/parenright/period/q/quotedblleft/quotedblright/quoteleft/quoteright/r/s/semicolon/seven/six/slash/t/three/two/u/v/w/x/y/z/zero) /FontFile 226 0 R >> endobj 228 0 obj << /Length1 1395 /Length2 6090 /Length3 0 /Length 7032 /Filter /FlateDecode >> stream xڍVT컧$F42 tl1r4J  Ҋ( RJJ()W{νgl}~{TT D1PDK~~3FQrͮCx:w3@>@"-`_hPpu(7_ AbU:`@p A( G+ @S4 ++)Abhu_\! L 4sEx6E;c8@(o| kMu s^G`,a_<῍_j|8O'p8o/qo 0,@ɎWÝ wxA_Oxn9Q.HJK\7Mh NT\(*.B @!YZ#(dA9@_0|"wC4p?Ka/C7?meV(b,~# @%6;!|iB񛡂rޚ s@( ~`?&8~]RC;9q)i KR@Np߼Ph,> tFc)) _2-/o"Kp?@nu{ua (E(n sLC&";bsAiIC`_y ,1Ÿ$>dd 09vJu7JЙWpwV]|R/(+g"DR+P-W9C+ӧ2j]^ ʮ={sڗ[q[k-jۘZuH3yC(q_ *=&ŨH]xJ"kWQsDdg6®AbF8ݵlZ' "k")+Jaޟ𤠔-bRsRs3rS$wĥ9l&X?K=0eLPJ! }I]vA$o%|؎ >l2EkO>bw8̈r)dR'=m{|C[VMF |[H>IP{tϩ|ԝ&%2T٬M|$rJ;F s!-dXFu9NׂGCg]\h[-j2v}ÿ{CyL6kiW骹rtIh Y&0{6# ҷvifB5^L0wXYu\'cӠzH%%MuRFP'~fz'>t|Dn797]b4I:֙#@_㌠ԛ4B(zYs:I!l~W ]˹iYBuSqEiuԽ~v_S&&}SF$ED #ߌ6+Lb62ի^O*8ɫEJ56|2 $o*3#Ƅ8aC㳚nš yu=:'gj<ޞ<NXAtڭrHr8ž^_x9ӵ-yQ$7IT. >6 dWʞ?O}V mA=xAʧ<E7hWtuƸ5Ӭ4tHex|"\dn:EZ9~NܦΩSX>`">6E9#aIr<ŏ;4Zm {d_= Fx@NCx޵)msFi4ANvbkmۘؗi_*h%ku+alJi :Y?uf cT`39y}YW_?|W: U͸$,T ʮ?,pjUDOXt=0]P"a8":#Ȱ殪MyHF^0\?ד)~Hkr5$U>YH'i:2 ::7J_Q*y 윪G"M 1, $[܊cV5wfeF X#z=Ghls}Ix ĕC3^ԙ?KŽgj6oSچ'8wV9R1&sjk#dY) ? 8[t1s 7dc*DM]%?]rkJ:U+V& =mwЉNwEyZ)&/8m.®d4.q(zn^WY)5Jt'\ZxV{y#[E\MHiM;I }žO$䧗F~?a&}d^2^0'<휘hlN~-Ez xOHb,9}'[/Cvs^\ /jBl0V6c v,mFN:`r9 ^gC-86XNI3=k*bWEa2+=25k{L~\hbQ7zW(6>z~L )@y.qO"? cż[}6hހ`y.&2%ћ7jNJ[iӥ&iNu폥dܪQ֜!Fɯi4-Y KTi>0NcqDUϊۘȃ͸W&J_?k{]Vty2zfv !>mF9z}7w%ikU_DhEHI~a7<ӞJ@] *g$c'Ad籨k|YՔ+L6mî- {&ϗ>3-$j AfQafQ ݋Z xtHpgg~AIRvM;;-Syq߶ G눱SVmw3 uj#}Z5gm>5kWpdյUUj{@ pL׊Oc62hT ۵۷Biwt]iiOF+ uXhl$lai7%1؅Gy) ) WI|\@2EIp>d^j\Ml+8\^, 5_Ϳ5tPO! ιh37<#D}is§@O ϖEBfi FM2qpw'{ep\#pZ`G@T"0+'c3 Mɔ(g藥XvTr9 ا$Y-% f~Ga?@CT a(p).qGq%4#[ 3kE6aWكTӄ|WPr=EJp ~ZV XKAֆM=?ׯQhUJi49~RrH Ƙq٧ d8QR%=3=rU@Yֳy#IT:|Յ]تS0nv3!5nMN:[- eǠ{JsTi+.cRH"۬lFE}gZS}ĻSm)7QzsBL 0Y۬ngwX`mnjӍt`XnYWyRW+nXpIj9K 1fr.sT#ȪSJ$ (ie ǖDG69K*YYm_lF-ENCZPuj&ltW[@&uVXZ/c#"*¸|#8r {ւmߒE7;,oTw;㨊rQW^YPT?@4'AfTW>bΎxcUv\pmehTH<>ْdk#fVC =gqI[?֦ѝvcw%rm.RAF"Y;Yo $:A󰯒Sz/C)$Uٕ j7n{7zg+ؑO1EO2I2s?/Pzʷv-i)0M C)L7nZ]e2e =՗W_}C,n%(& 6Լ7-;LHCTA>gdg&%ed?xnB`w%tZ3u?%0LS=ɷ٘~7FsGQ v{ wmUh:n00& Ln_љyAPuٗBtjp:V$,e3V,mWH]6>{goϹ$5BVFw"-HT]W;-!w?x.}Yl&{}=Z K.9҉\B {>gkrQv6̛wrp鮉d`-}\\d4JJśv3ѱ?&pxK3ܚ$x o>[j^ F)pw ;~Y !;\w_%. HHF3zT)LE&Qvq-.a@Gͭdm$%:2O;__*m'?oCamޢ#gy߄1LŹ e.SP \<\s-34Zu:>cra6S +/l5zX8@ _å|6Y$"AL*yoRZv} n-Q`~mԓҗT*!4_iA.^ʜ ڰ[o j}I\TĮʾ UdBǑv/{"G 'ϧ}ynxFeb| ^k)Whu([/&\ޛ"hvp6&UpEܹ!~|l֔m3BwX0RTѷ'vY1x䷋F@LRb޺P,ұh CDF&||Cg;_ #a endstream endobj 229 0 obj << /Type /FontDescriptor /FontName /FYGEPU+CMR7 /Flags 4 /FontBBox [-27 -250 1122 750] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle 0 /StemV 79 /XHeight 431 /CharSet (/one/two) /FontFile 228 0 R >> endobj 230 0 obj << /Length1 1905 /Length2 13348 /Length3 0 /Length 14527 /Filter /FlateDecode >> stream xڍPX.ݽqw'{ph]Cpwwwwww ݝwĊ*B&vF@q;[gzf&27\\dag#C&ja&gg v09x9y,LL6sZv@'Xr;{G 3s,>ܜtlƆ9CgsGFcCkBP;;021819S,@'+] Ob Us *vn@hbkt|H쁶e@_ `ja (28; mM04v7t5640pC߿9;Z;;18YX0,fk"bgcuv>Q Gǭ{0V+[;7[Φ&P0qgTppJC `gbbf@wcs?zT2!`Aca r2t]>^T7efX;fGMwp|aN~53cX9@/49F[;=#0!q2X*#6߈ `4qF?tvt-acCbch `MJ@?-?XX~а?~iQ?Gsc1v99~l_ҿp4?h8~ ),4?hx ǩ]??7݁ư+vƟ,:k&4RVFJ r|JE^\%z:kk K_2OgMLOMz403N$O sZ䥽QԍCMv:>C%|,UZ>[D@Np̒QciW:ɼDO+kAw$Qi׏Dscw ot>M> H۳4$%p0.9  W;6MwzuVKxVوoj?!EƞOf"* 8\߹oL ;p~1!=0%Κ `8m*Wi~>S-P_ftAm9hfJ)rT~ov"yYճ[+1= !&UAP@@'c O=|,&ړ<|WF^%ѠpgQ5?[:ZC$*$Ӡc=eA@RS'\?ݛZ&#Ir7\ 3g2wr@L=i0mҪ_#`]}^nXSaI-U׬zDRĶ ʵea)| (^ý}"pTOd6<ᔣ>s%hz:^f;tM\[A]|MRSsNd1&GKJsܕ9W=Ai6W\ 6eE;\HCQeDOcg:E6V}'E >ilGnaC ו‹cDDх_~6*$gwhj"o#IRO/ ;#N$K/$&sS \Vc~pwJ"-)V3tĈnofr3=S=׬gK Br]D\@?"%QKGFII\nSh3_{PNK026p>_E6r*x]EfL̹#dfئ4z󾱘bWߚ!m,eK33_.`GnKNRXi(q#ȏ#9AQ~j8u1C'%C[ZtK 7|ʣ3E}fsdyu+h%3Rv5=OZRѺ*, .685]/ztQ.V1ݪkcW_1nmE/yM[y>Q6VY,VܥeU%U/8#ֽvwd$-L[9TIvGG,2}MCtGgJDLx`t0^66|f/O+~p(luQșZqd鈢ݬ Lw}T1@ubxc[MZOwWUXlIOHZɌqߢ/x_X9sRrflW\e頳PIU|-`?ɕύVx^9E*Uk~xBuUdґwt󵞍pv[S6۫wE]ŏt)6Źzym˽k@0_[P|@+ؼQd-(>Y07joDS}]⏻aVGocs)oXK*V DP',M7Kzv/pRy+VTH*ݲ%7I;@_nǐo5cU F ; ˞f߾ F^F(rP\O~Zّ{ެQ\m6["ȄÁ "Im8/9xhrSvH6Pe( $Wiԙ]‹oy-%ʆKqce1J0OUgO*… ӢF0FM4aI 0-(g)v9a *œo[vPO%^GV(տΪ<쨔%ɘҖjuYHOA\D]M]- )ۙQl]|kdQ$!QYw`3%Fh!=.ow?tg=m*ꭿ.crXֹ}TZ' ~k‘91$Sk`XYȌWi۸ڛݞck3m'kn ]u܆Ȫ?c +Qs;M(a9 t|9Ix¯B$]|)Y?]'e+;S"#* 7@JCq7CMPhwH 2746=qkTjM mqF:Qysb-Mt4$urd\o'`qbQu$\"~$g|=O=խzh9D`I s~ v#lB\ݰRk;3^L_G?%QDhѺpq–1F'p~,'Vϴb?ԫ8Q3E ?I~4Ht5V4+қ#Fs]8Y&᭮cT$̺[V>d8}—+9myQ<#"slo"k#~Hv*sP!l Y1 _Z;TD%'.*.WVs1!CUV ^}AE`;f7,1֖d9T#}GT}[ vuSpzDn^0])U2R8z?B]~ J:$0 ҏx,#<|" þK 9X1hF{cG[s%dpOYMx`\^6"j-[TGhoX7zk) bh/~s!go۟N}}HA2_=ȧr$ͶfD^ vo1 6N+$md nFVMc̘@ $OZjh#q8 \=ܙgNcotn}{zگ )~DD8Nl^2/ΖvD'ԏ :F>9w3נ0Xh$Az=&47 ]orCQnS_K[;)ew2 Rq,S(u j )dtSpxƄek\zc- CzD"2 ߤ\:C`iIt,"È 3~ qT&4Mm uQe,/v:,-%FTS׫T>q~z;TaWIثhPħ97HҒH:򫟬U/uc% >6aԐy.ߪvt3>"cX&pEM5}&kDnA% c)kv޹؏#M!蠕h+zcxZ1ܱEx*,نZ "ȵ(&T$A >&+C+T=,AP!kRi÷z,P0ΧN%E/9[[բ$7e rr'>B[!l}\E–q3VM%S?uw\#;7i8ӑPչDUx9Q`nn|AlYV)L4\{e:6Ɨ* "jQmPA*U?z"i-T,pXCK˧, O›Ne=&LIt;zLj8_qK3``k؛~=HyM }cJY|Y'BcWunSiz, 7r\-O4{,X?ʍ+)ZUQ K7")]_ѫ%`_m ۊj$>o}F$3P@E3MW9VECȈsj-UAf"߬bjW{;jFB)蛐"o;֣_7ApGA ~1ƨ( F] BYhV_QtUycZwq)9R$tqr (-:u4#Uk .W c@7NkJfy64j|%姸.64+Jp]V>ůԟJ9LgQSspw\_$J*YW`CV }kQ-&˦Fu|rnH27Lruos> s(k}h1PǽHBϊ7%Kg4ǯ$kHMytLBU?hQux߯6ΊQV1XٲpJMb܇ q?7yF펓u?Yk沖ATҤ)Rwyx?!d<YbJơ&UyТ_yE!(o#eWع-{&D+b$<*mzOCatiݽz5g#$=&>́C:Hwh yQA~]ڷce`` ZQPZ`)%Yv%SI|+1  >$MO[[2%mXg@#1u*vደO$R>u:ŸIGHWq 52\6,Q~= jM6wŸyK?BKo[vbq õdSʶS' 4"+CmJإ0s˲xcU0Mc"R2=cB8ύ*p$;з/0;B+lʕFA =n<mnjZ~#X^F}i1+d KSMBQvrq z,\Q?*/}+4)K wʉ!exw9Enj$~M:.H,"~V]`'{Gt0%Ε>O; L6?)ѫ0%2'7MPV7p3y˝^?}{T1LJ 1 CS3qY5)׎2w (OITdž]uDea0GiA*}9vMG'k߿A%e(wN$VN=y]:yrʩa>]VBڊ;r&X̍v`P ԿRa2: 'C 1`< dDlU"Uj^\uZd@%೬BgRm_bpIW]NE u|Ns2\9?% 7h9c;%T_{ ~Ե5`GEjt-mo%tV v4YS:`HCY!1Vj-;<f3ŘpL.z\F)xeɊ]_6d-  O^h|FgLDu%@'wzq3\0" 6t5fY ;NwTILHMQ.F$yT<x `W *L&a.WB8HU?Žsc2v(A$bi{F|UgG,)=:E^-gm@eFyU n]/YsZ>g?vef6>풕[l~@ؖ6 V%fC3i[0+4 ,%uw[ty(s U8NF)*Fr#\ >OH93C~(Lͧ"wr0zKi)Uo'{WW%.+8J=zLlElu ftO,D%afJ4>DQJiXRH| k,}s*8 y6 JIWf6fTX +g+ka]m.?﫡'VgIysiH]W_ʓ*K̂_wMp&Q -SQ4!:|SC@׾8Nr>YF0z$1&%taI oq 4b=g] n}w P-]קJҍfNksmN51v_8\LGdTNP/o$C?̂jx`pu*RÆ"G&(d| {\oΝcN/,Co*#:Eg䡶tc Ut=V.S4¸|y D7z3iwLG~eqʒ}DLrh;?M)U z?DI fřY}1ܩ/u=f"Bp[>yxb^Пt5a g,8iſșX͠s vd0_Qs\Csbz%W=qJ"ܯxmH\A0_p臝QT*jgO?Տ:>҃]tyc%. ߕ|YYZw`y L?ĺ4"=Bx E"ݵ)S!7d>$눲M) E|!FRT]UJ-zC~R\ zVsb=-`GP.slKK4%z^:˧on7QeցF.Ny JS)Ut_:'mմ$ t^,hKQxn^w8Q8pJ{X҅]F{[Ʈ^ yWf2 {/iݗ 1[ZKM$mԎsJ#(*v79b ~#Iyȴ _{*¼Q LR4.I8sף ~#OԆ/xTL>@ҎEFPY[k(TMNo';{b}j75Z\>OvalVZdrC==m<54p!1iq#alSOd׊>а91a.%'U48¼Tf(| (%#j8x.ȏ--~HDMO0֥[x mr!N3?Fu .x6W$ϰ_Spd,7rw6qU2RR:]e">b!-=Y?1]SCN/r5* 07hgcag[ǯ:@|j^dLDe% l;f (Wk:s d>-l$+}.V(Zo[UkLzgW^ZR/IfO^cHH C 3bSI]}ah.Zf{ ",-.dĊC=4rAN96mRD6<9KZ9Vl5)ݺ߾?~\H"QV=H09[7v@?-HI&jS6=6nNh)gņ^*Cz_:53czԪ7 ^= P7(\2/Ab[gTfM3pU{±(Gp7RhC 6QZsi['\Xz~^$d@2$Qp E( VDKOONY#3s=%X#"kν u^1-鞳"F/7|";Yɦh6nE鎩wȕfM%8q@{=r;u4K3._US D b2r% fv]SP+ w1@H*3XflUWx#y) R>8F7 G+Pcŷ}yT7]xF -Qs?w<2z$Rzh6ұfHx5M,J ں'6V\ٱnb J[7Cl&rQqjԱK\YKis@`+`{5LrgŢn{@(q+ DS4+U 0-q{riku Ez[چhP^4Ȯr|P| Yn>8;}Uv,nS^Tjx=|0vE{Юj: itB.eLFٰ0^fQ~54U 6Ha: j! \g'k2žޏWhI߱1ELNP5Pf*/ dqZzp\}Eru:?B $E:O bG$Pد0G&?z%x料ے̳ku}=J4aFڨC$AЈIOUl8SKg")A?TENs|iQt?kN QȊCF9yз!ß 7h'fBL[jtq:H4&04t<̋i<$7%݄p_SyNZSDdK/W3%/6b)ȑ7w:Jp0lOQ5|N2' 2DM_YMf~ZA.#]cg,lc7W՝(f xP u`rCJ ގӒ HݏpզNBX]QS\b F;9הHjxa ɂr%O+D?5,z[%\[sf do־W sUhL/0b(LAW ୐摒 bNpʞK 0f$k*UC|_ Z-\5HqkŰsI"GnBaBUkbX 4]qZS5=AQ54D(~1/mCu SȕM2 9>^^M+hXv597Oz=GқːC)xS%Ȏ`6$e{xdn$f;FQ'^>z˙4KD@G<p֑yXfMJ *~g7];\" 2YbKV\?U>a5~.xԑE7>tmVwKE endstream endobj 231 0 obj << /Type /FontDescriptor /FontName /POQFGH+CMR9 /Flags 4 /FontBBox [-39 -250 1036 750] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle 0 /StemV 74 /XHeight 431 /CharSet (/E/F/S/T/V/a/b/c/colon/comma/d/e/f/ff/g/h/i/j/k/l/m/n/o/p/period/quoteleft/quoteright/r/s/t/u/v/w/x/y) /FontFile 230 0 R >> endobj 232 0 obj << /Length1 1807 /Length2 11974 /Length3 0 /Length 13105 /Filter /FlateDecode >> stream xڍPk d݂; 0 k4w.sn}UT֧~gTIAl :102DUXl̬j 'k刔@Gؖ QӛLPl qX8yYx<6;Č\@yF H) sw[8#ڄE;@219Ym2YT& prebruue4qd; \AN#h d )j )TfNF@du|sq5:޲Tv@ˀXYlv621ٺlf k @QB͉`dk#dmdf7u#2s4q992:0o,nk* :9"O 4y;wwke v72ٚUg[3PZ7e@'3337hX0@/[ _c~1GQ-nߓ KSQdv\b.4d.+/uT^g3ib(244¢ׂHZ W~?HFI~Q-SO 2;&sYK w%H;zRJlZYދ3- ov~T2=)i:y?Yp@:84!5"8辦a=_5Q0+AMx\A N1bPA-2m_vT^m2=$\j_ ⅗v[~+ 3 Įתi 'Hh @Gb,3Gy~܈qhWg>z&F@{| (Q87Ah3Lxi0PH)wh*zv4".aV-st6?U"T *(HbԶ. OO,n&HYesyZ0$}k&¿֔=PH> MۍE[ IܮȾ'O;5=Akȫ'vR-bzxr1kosfj3KcfӺ jq-6P$uL1|SM Rj5\wz4A`įz øHy6ZIQs+/>1ikWAK5ѥF*p>#|k˗`}A꡾Ђp.($W߁JDuyMzby8K Tc4 N;gIْ\[r8zčMܡC`)]Qn3t5I9fS)O%StaXǒofSbƥIKFZc#mV{˭C#^tGNYGG1GGsya7j0uSZ\+JY/}k<{:J21ų KV6 'NעԸz3դOUτ{$>$ Oak˴1-dϡOV' UxwN]3,. 3&O=4N u'W_+q K"I*E,# 51X/WR'̟hO_zONH:3ڑJrU~)@%@i@i  B$L;+* ڪfق_.x;LJHz(BBjAnhR_7loܔn\d>E=0i~W E"yH)W7=\'T;$jEi5#9>_(h`;0[7ñLKGRK8TQUr[w7KЩ*$+mVT16wfR_w֥\ e BoTO?n Iȝ\O \Ct@hLa7 h7$S L W,ZL6R6Tsd+pYT-΋zNE) XҒu^Աr>0Zm{OYc;cao{0ET"% ǔ[j#*R`4oV8[1uRxanmw*% 6(<4sl쳄_x~>XIFǪt!-S!Ck>qGa` V:BLcbFDEm)?Е`o lJg&gR25-0Z|5g~l["K4q8uZ9O6iKd|9l$_`9L[zI^̨hd^v6?o?uA)Di(ejܺP]'[~n%ΗrOR֯c> N48~[2ܘ |ߟkvUcsn.9n1I(tc(Ƥ]FV,eLUiEl xyf/=^Y&R ٽ/bk~'gZa|'[3w$ټ&_'+s}J9^+[7=ݱLJ3m9gJC<'a&V/LYК/t adboѹvamZYsIh0*GҺFZgeXUa;,h覿pz>9Yܘ)Nŕ_xqAsԐVH:+@ .~ P`ŊS""r\}֡.PÚ[P] =֪v۠%{1:AO[Q/+Ltw7sv[= #s(/ ;׻:Miu;Q.Wtu'\Z[( fBR0AʹڽF5aSi=%f(\{&:sEoM}$"̟ƿGH}o_x~`~@'6k-O@9vrtZN"6b=}h)ȡ_>ѭޟLx:LC `-|fF0 ?nÚ,PMo3.?Fa<(xC?Qw3(a"jN,4c ,"R뇓*Osc\0'Ş }t ޽F2!ĵq)H%|)l*֐𙷹bFW}dE+ƼT>eV눰*pAycyޙam̢k^rxMey cujUǢAЬl/[>͖ 9q6L_A.le-0_dIgn/fmIwv)8ěǝ$ְ U7!^-a|ggծh w69V'>#tɿ7? LnҖkxH*\S55u0rp YÊ5>cՇ*gBף&;Y~e/iuj}Z(t$GS-( 1T['eҬH>\W &0Z7IMӟNߠhwNA>[H'`FA}><ef]t@8M=@:=Nh|6],qݡGYCm\c.N[H 6F8Q!!*uiz-^ie .$Oj^쑅zTa8hym =}5acb)æ2:>+UpchZ'l$3Ug Ѕ8UL_$|cz#ʡ q՚9aWke{9\îhzb:4":t^{/4]=Hht|@|R@ZY#{?o6vقvEa̐砰`mj_`a/|wmֲcQF xب iՂH;)~ yI6*SE7tzU_zvBaby 6:Eޗ_ 0Sd/gMtې"V:i>e\ΐz}_}v v ȱJXLv57QnMϗy%iFX6c"CxG"ٌPTrqt//lzkb-,>'aw. fHMha gpǓ5~p:|j)XU$( :`PQ'XأW/$\-qN$#@6W.s sk+$q` }qH8.aAö7x*$i9&Mb"P*nh[2vlSV@"vJq{N|Ǒ1JCUو56=J* #bE$le7V ǟ\K?).eɢQ+6C.YYpƤԇJy\-vqܞhxO7-~˜p#b(klb õvUiWns_*Y1Dܜ\57zuW*ա8 ]\9yxp0ά0/)Sp1{ıՋGIKFPi$E?W+C .)IimNV$U>vШ7y]iGPz@V" vuRqF lׅDZ68Fw3 `8=˼GHj @k˟Dpt< rJf<0_ҩ87Φk}296Za ic0* , Μ(~%"A ʦ&A8_&ܞ9F\};'a=B+X{)%BQ1\Q9dq(N@ OwrUQvd?g$^4?9O3u5AZ*5yYrjeoe=ۇ@h6ᝫPgvDј$SaagSc d]E.' tL]X>>Z;lB!_w|u~}=$ ,"e/Ǟ? A,YgO~GLra/p7$T0 }L]o/l;sbb9<}Vӌ#kaY I<Ŧk9EΠ;L7#*gqh2D;߂i~y82F!KS򤌅YƷ>FH18*3]˹؊=GC&KxJM4szo~2NgnQI"RVK I.iu^Qs$ժ#6t5ᱬ@Bf1atA,[ L SI"6B*/3|N3f N֚0..p{ߵqpƴd辶%6a޹liv9n6:7 `ឱu+@,e˖ZkFB^‰ mk^(0pNK 1cjkX".T(!<6W!R* ) }l^=!!@ŀlDyι0^'O0WX̬yjqk 9L lP}b([]¸GTphk|Gg{Ů_g u}-rns3s~*\ptn̬ηncNSOv)jHOtJCmY#y?RK)S)a,MFP_?[aEysbyC%GJwX|z;w1'?cmW8Ĩ8- lٜP cd" ͷ*#q&Z3kSELS'kS8{~MpM }; + ? mQBbO1 +Zl.o}NNopJ\I]]JtdJ+oN^`' >2 ;; ~ c*$\wf|#k7UunA-y)J*ʭeTs7WDq/ĥ-no#|}{ŴP41p59oU (.΢+@\[=5/QX() FbZ%tpmyz8-r>Iӻ Hɏxڷ);B'gRk.U'x񗾨OœBa#rYnWW@xnQmYqqۗYLFہ"6Bq& BG[4/UIL(BDcsOG[ ى+(=,uNm序"8YPUBe<(p؍?lj(Z,KP[][RԵ]+$Wd<={ie, Ho,O_PXnP pXr" [U]?I 75"kjC>%G=1&RS529ͧyQn.XZ8A&r`z'kL}Qx@m6Gn>ZٖM8jǏfnLNG,-i߇؝{ S½>Pgb&b[|OEϾ!4]r-a>X;ud)AVSI>,>t9<[㉸E0~ojaBR al:V?qNuTyo:XQo $g ,!ޓaH}d.}!Sޒ^nZUjU>pHϧ[+=Е^p@;NZ'ڍn@M RGDEBgO{ĵ8N;I]ޡiv3EJB0}i]>'j5G%S/<0~4]SI?̾p Xա˛`(X%{Kd`0F^cBȥsK#\EZCI#EOlشf - QvLH7-Zl]SsT0T Sv2*"U/HDk_.Eei.c{ o]KW/Dt pG[`<M[-y'UZHޖ̝k^8,}.X0Z*g37ӽyh37 Cթ\"4JOfUˌ=yvt0Sz[,?c0S_c)BBe1DZ0Ѓ$ T\luA֯U4œTLKB6&D`զHEQjD0;KvQZ%*ٯ͍L¯GVrtW~YC3KYO%[1MPyY]w\b_)mcBڃUy엣ZGd O@ 9k0VzT{oՓT {7 5OEᱞ>/ڧFJw5rj*cekJ&,jFs&čYiH 8 Iv yKqYgXD#kn2";J endstream endobj 233 0 obj << /Type /FontDescriptor /FontName /BMYQUM+CMSL10 /Flags 4 /FontBBox [-62 -250 1123 750] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle -9 /StemV 79 /XHeight 431 /CharSet (/N/a/b/c/d/e/f/ff/g/h/hyphen/i/j/k/l/m/n/o/p/period/r/s/t/u/v/w/x/y) /FontFile 232 0 R >> endobj 234 0 obj << /Length1 1405 /Length2 6172 /Length3 0 /Length 7125 /Filter /FlateDecode >> stream xڍuTT{.J4RCtwJ#C0#%-! !tH !CZB;ݻֽkg{}p14P 8J@X(P3ѕ@ ') &Ezp堂P*CnaQ vD e 'F^$*$)+ Pr"a`B9C1 7  G{ "N_` "}O};72AN3! ½0p h <κzO??࿂A`007(@]W 7/&0N+@y0'Di0]VCTP8ʋTaH(vߓu#|?# q !dyzCT`T$蜠(8@=P?_Fj  9B1?$h/BzCoDXQ NOv[  X1' fY/ )41?6ee- ! 1I4ii A?Q Hƀi8|]Ae(շ7~gԽ~y~3( -rzPZ(Jp'̊ H IVüa~P! vGOS "`??8a lҁ]1/̼~N$DI0H0߯ (L1@0P - K|~*F"1 3-"<L!.mgJL#"b71ȝM+X;_yqjAt[x'C7S߆(սm/]o5N+{Q8ĉnq8/=dΦW{܍;d8# q RRd8J95JZ^#,Y">cÖnxlgntKұst1|O =n q2Q`Z=e^FSҍK/T/{9Yzܚ&ڵc;Lq^7z^tQF\%2br ?cj# U\^0gTXmh>I@' ٣!$k<CqrtAKc:uJ3?3\hklk@vG7YXFW[EQַ  ">/݌=v'$?˜Tzg7C7nřu'{?XivW2tRڌXI#dYt\#Y,Wz5@ʑz@EP+Yv/Pl*Io+yUkX)D̙,V?:q;ҴM&5ftB]H*Z=“yIؙ:՛K5NU@'<[êyGVqK]Ŷ7% &B9I3<i"fPw=JV\kn76ѫ&RtȹK6&yjEL^#v{K'_UV= \">-ϽK> ݗ'NU:wC,D'҄c9Nd^j&1;-ǧ~+5<.F_ĺ,㔘Бm J `GK7Bܹ<_;|. wM^6iN|Ɇ_vG#CjaMeڒƸ,/!vh&Hc `6#G& 5%<*_sҳz"Y#/Y\ N,`vIb?p >Leb[b+V7w$8 j & /pE1'UolfZ}y>&=j8iwj*{-qؠ'Ϧ߭$7>0uI$cҝV(ĽϺ=u%{PX3&{/e}jcfr$]=S.qfJIDNfjoDKJp;_2+a)&dE3KԾ!)kxn٪Xui f ӮM7Љ jB[%o>]Q ]{dh;Dt1me?H|#\E:yA Ɇ]W8~Pl-/pJfLJZ߬)}cUE9:)',YPeKVVvHS]lBոoUG4 vbS#xBjCz.Ig;/"46_ 2]Jd1Ϩ*Ɠ `>y-ԸKiHUܨqr!1+V+ZdPOԔTr-Wo Q9:1\ 3;C"#" F۰>1}sǯVJ}ūNȚ$Z-jԿPQh%[lN#]n]$m~Jpލg,!dW鼭\IE>-}M#ٝŪb"VHɐh ['l֤-7FPftO4 ~[v7_9M|D/   #"*t9.Կ@'5 zָVӬ`~ʫB֚8_8pEb*!n;iGA/s]<hKQ"_o0c.kg³s.@ѲS½>eĕMݱ$Vf)22ϢT',?+sE W?5fn/X7qwrULy_l;{5 KQ+O-ԕN;;W'P&D:9cE h2VFė Zظx3Vz#%jݙtzY`c3;xNfͶǯW+{dw6Rϊȉb@}愸tNvX JkFEYiLFR4՜7rjQ6ٕ0Zd2<9BT/e#~ſ.kD.dW1/P4p.ykMm̔I^ICIk'ıO%=n|Z!Q"re:en8eʑ*zfz:KM'pZC\x]CٸgJph)5#70=wQ0t%Bd"PY[s*%S>pqV#'Ea1ijML24nJ;mdC<m{P&>(ﻕS|t`)DZ5$W+z7u{0PeQF̜67!*t=[Vj yFYmjAҚYYu ŀn,aw>sNZH׷'fGyo; Ӷ[^1Iж}KYlhi.P@K7<ӓCdCIve2tF-lR4\<.<9mjH jRz̕X"?*va?a[=Fr>$̷6w _` Clc@koL\Tp*[`zu(^gɍ 5[? =ss~mSs)\- a }fy FY7^Fce=uOw+qAM  t#Bbԗ^X"Q*цϽD#^ ~Z;>1ULFR'=ݸb`PCK9-m 2NVx#73j[濞0+wO;W X$w-I/-)Qd`C{ m΋Tx0mԳ-lf_^ՀO*Q#Jx2NÀ5U ]TmUA3w@ya`s.Un _.#0QprD?l)`/ :L _Ȳ io[.E# }Us^jPO6g R^q@V(O)H_c:qM¦ L͘ =giQP)3d㰚ooA')تK;|Kh2 'ȽSɇ}ykX\ .l ID: Iu=–`ܛ}#<\('%uG Q$uD]<(b/j[Ggj& 0o0CBdBvF =ܣvH$'nt+18y/ C|NN ?++;095wi7UU^춁BmA|V!f(4CBNy`XtO\RRþ1J` :q_l?\Ԋ(=}PiP .eVܤ${,}JsX#ѝ`Sh)r*透C>\Xόh`!|_fz/sv^^IsUXuOh=_ͽOԫYz%#%كv4.4< Y͆(];Z!-ti3"#evHq]=C WOHr"hZqZUZ 3v;pP>xT'뙣v:`,ï}{Z5Se/Q^U>hۅw 9/ |ʹc_$և"nU2uzQ5)`mHQ(Z UySR`&dznvtDmA9vW[hV E>oLpv;`U=#f =p3&=dWFYF?"ƓG!F:Дj8Zs|O X|n} [_^c(߷ꞠC4Dwp:[ֹ'}!D#W`P+]kFՖ{[t j?Zb*O9XL!T)WXbH{ąt)rS^7|/+ex=ưlnef.  IOp+hg!oh=ًǺ;*ƌp)5&O)"Y߳`+{Dyu2<™Ͽ}]}01q-3ٽh7dE|*%tH¢S14]=A(RB~1_&%L-/3[=$5AC٘.qO{ TX endstream endobj 235 0 obj << /Type /FontDescriptor /FontName /BFVHSQ+CMSL9 /Flags 4 /FontBBox [-61 -250 1150 750] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle -9 /StemV 82 /XHeight 431 /CharSet (/i/v) /FontFile 234 0 R >> endobj 236 0 obj << /Length1 1998 /Length2 11990 /Length3 0 /Length 13206 /Filter /FlateDecode >> stream xڍeT-;wi{pwo-@pw !\Kp 3$}ߏX zW}Nաȕ՘DMARnL@fV>:ʆDEnfAZ;:wm&n`@d|6VV.| ks3@D%bmiGw8@bmfP0qك+ͬAnV͉ӓޕRifP\<@怿dMAcF[Yǥhi vf Wp9P(9Co_613sw2qvXXہJRn^n&vxk;S0MR**t5svrsevK%_i-`.horpsE? kYb[GO/)N, Y&6K| g̊"N`NN psq_̭ Kkf0x \z!XxhMyUMEs2\@n/{۪lbH(` AoEGX@ _YIo?`D*7U V[^Y7:X?fkW)k/u+Y;]zL._xl+v U%D6N.7+x89@ʚr 8VptAj,x,"nVoHF8߈/aF/87ǙFf"N|0X:? #\`۰rp` b7nwgnnw+`vY;^. =,u"\g7jgjf<`Y!aey|3f.`qn?&!--84u?4y2Mpir'@ao[IQx˓'^ VLdG9]{LA1Ti$ S"Jn>V=Dz!?1\3/CtVpV&!p6u+d)49GƷeh|Rj%#'d$kVL7{0cp# e)#b&-dE;O ~%Iq% <ϧ m!} RӬ>81"ú@+I3+&>c;| ) 4JۡY*30нٯhT2$WjNzL~LA5Z< +"y9+G#GCDZ>jP|U%ֻF,Axq|lQ[|%];4xbUru.>{y-M dT=y$n *Z+3>, yC~P YO(})y+ J_:/z?ڈ2`8n, FLNiLkJ;ajTX8sC} |g_iyVӟ7Vi{,[ɾywu V&WNQ0-Wf*|5f9;ayʬ4snr1۲&̽MK,wvn KB'" :r_hN|ĺg/|4?U  |r3Kar;Y&U!vv)0<7Rlxad<)xtꉹ|h`#&b@rR? JxLs0'T7BGkx4DčN͔@wť["_ϰH|A2Xqްf4frl6_׊=ĹmUeQqo\Y !-zYŢϚ}wx~- 뺩E5>,HNPPIC?=̴155&I=>Wo*]n+[ /TlYIq6h8db)E:MԺrϫ Vl)$09>#`pţGsVz. ?;^|oŐ 13)2zlg=Cgö$Z &i˸DF8 mW,QYrVGc}KVxU o= *u#3ntdu8H>E"0MF+Z 9{\ɺC_p084+&oU38Cq{7,h6Q8A3?\'Q*B}l)-$Ώf487HG1A._E~ 'E\$>d%Y| {>S/}9*d>#f_O̺I#QaG^#I\|!1}yv^qj_=]lZWޚ=k\,*EuLʏ(Hf|ʑ|TW3d[Ϟ:5ڟE/vi0-4yizQ}dGgĆ1@ouid vwD!jv`*35X$X5Psc4]LZOzOCrfj?_kG._mqM=<%F_l'l"؁gw*͏Tn WfYȫ@s.'5 3/V|_*#]iS-}}h1Cxup">ј X=+C#}g꒾N5ݑI$ 9xirejlJU<D˜5= ` }3*f nșɖDlHZPY{姨W泂Fbi\_,.D:VK S{_%\M3sK|ԙ=`ڀehP/V:SǺe@l6jzWF2jn! Wt8r&XD9N@?4u,b:-7]( ҅{.g/wY!8Ib;z3фoPGٙEs2eH#SOcw+݆Y6V}0~ĻxP ʣ8:xr-ws_n73 P~>JD@:. 1@&} s{%*<}Zַi7A5y i݅F+ Y ɫdѡl_3Q 1f$, sS.#ǎzψ_D#qоk$u.>4Zxa }'~f~?$3U93(@ge-y(߫Gv9'kPYP2ug6 wnhxpF),ÊQ4Oʫg|tˈ+T cn!xЗVjbQ$1,8OvH|a?8ڸxo.>$S7~΂?|C}. 0%u{q5uc׃a};67ym{) bM+q6 K(8j&}6rϬM:$8Pg=U6nmp~au_6Ћ)eC1Y(" T@y(dJ13*Z7b:!^y(֣v IsTp6}zYUAk`x-fd ztQiˆ^jBFd#wWG<ڔ>UjD;ڗב _p<:~']DZE@aPxү""4'C)@ B򫹹y^G2I֛K ۵7tsiWbn"EI#2H]𵨝{vFJ5ick3J/#`>̶wHz&E l[ ckFW翇f1I,No*Ix 8uiќ(0`,⦻ާwDдʝX};{Y4 XL.L3nP@+g9ɀUhؗV𘢥#$Kfr-:x 哷j0}Kp5yGB8K9mpZ6&^uVz!z(CL[ xz`B(s $$bعS~ |ѠTT,A{!G:'WjP0sei5EX%`/C_ERv՞;;̳\ʓ5?K?a]1r5A" _+QY"~ *=^&!K9Y ¢,0Zz~&/m hy"I˝[´+v|\&1G0žw|4m>AKz@ZZPqIz9țŪ cLX~;=,Q7nh"yd(# G5㍎ZĞHPCYRF>!xPcIj%ȵejQ}rIdhMOz8rvmH^__V׸P!#C.CU=/T 6{݌[x^OrrE wRUPxl2B6,kNCKYf>H(!;X S#?/FU;̑=N7"/C lmp0F 1bH` "A@(DD)Fh~ Zm'%꜁Y%cҴ*ZmQuh&"S}4>W{Ubgc{? ~D{q❶g?OٽR84q Pfpo:6%!cjf\E_Q5TtSǠ#sm/:]pauV3oSC:lTF WȪtd3ѴڢBV5xǤ% QPRu㦚5,7)jrN1w5@yfKU c7S8\Mt qE /Kyv `*qɬYcqg) 5)P|&h/~.xsYc-xJ:yXOX_%#GyXcsw-,d1 *h\U"Cuy\7&VZ܆:~@[#Xm`+=5Gr5ԁ{dDR}ඝtAJD)0_{]o|eYq,<]I}hޘغg{x`é͖  }5g̚Z^]-;eW6TPtRK~P*ѾG2Y=ᜪV4cu)-jqnM@/!Ԟ0u :6U[XnٕpOp `0鎜OZ~5mN*a0mX)QpkhXF|kۏ?`!=jU>Q{WճV0tȞ|ֳv?::,|Y&zڄ8 {4/Vg"򃯀[~P?f&ti8],Њ\yv8MQ-VͶs,S۠74TjɁK.s Ynzt,tUi, $WΏhQsle>4HsHCĴ5LE'?: 4ìM)>zJN nQ"안υçA V#Vo_бqYvf+;R,ƽM=Qsh Xύ /C`8UR)Ͼ]$tm&0ImԹeK40k9I€DFE`i_Ռ!M-apݔ9,ɓ25?`Ery(w+{`7 h:ߠJYkE TɚI7vچ> ۓ2(G(5@ e{vkqDVPU0ʃS)6p+ޓ7K3{B~hm{J]6rLj%UWdz!|@dKs24'PՓ|b &^RЌFۡ;7ɠNG $h1pJyt(2)Ofy%-~T^ 29g(tZlL::gtY](=uaDN((壘LӻGR!jIh_ì"a_A'bLv䣈e&brd4%oz&BVLzxqc_eXF8eftP?*_R?#s-"r@f^QUo.wRܽ'#G@=*!bjψj!gFu8Bh M(Қ3."CPɝ+% Í&>^-2U>}\T ij?^vAOeZ.碽FJI i \]"OO\",Yb^EDؔ.hhBB8+ot3zZJN542{?+D@XT˚ oBnm⩩x#-Ji*qR|-/ͪ+EWr[ﹽwFbg~SbDDlC=Yp^߆4thR+^?|X nGo? zd0]<2vI,b߯SeSpNr偪-&c3$`24qM&1\̠w+,(VHO}P=f(9fH?·RL S5>NxrQzGT_X={Xq8~bNCATa7MV3C$},UɌdh!?1{#˅]kUbP;%š_נXyjrzAӗ!ѹrj91yJ!RZ^huC~qT þYZXmW, K\zD:lݢ}RQ!V Y$q^9T-{JڡCHw'_50mod->g"VtEIJ]P|Zw:R"2eFWpe'LުqJxyQ[#}~n&3†oѝYX" #uvE|'ⷐY.PRdaGζ!Jpb e<5qẮJc3-ܱp`u)wDI}t}*aVD Dgaw#jG7E2K)ElaB^ ٪BVIE bCү Bb~m[dW Q26y5wWnjn v'1%h2L]C@ፘPoO\ÄfQC-v '%Z}yCwv dz[C{Wө){<߭i^<r԰ܪmbE8X8W}hs綈_ǂa_bnl0~'R4k*P V.OI͐LBSdA55,mvJ4BNN|{!BDCJQYf:GsQܗ(TzU+}ӛp?XprCJ^+O#As>~O Xd^no(gA2B臌4eѣi n4A:Δ ۏT,L_.V>)8$攓]Xp)e:RǛdR 1x#ahFWat̀NRkHC~U7ur "r?ѓlcOܖ#+A:uogL Xnʧ WL@xKpX'nO=3gdd i3X^z_iXb*af!?WPT(mr=_#% v_!(؝ x$0r:\׌uJ ]`-6t*7֐q+D"ݗ"X\f=xwثΑRK.l1/C`IfC }֖H)G-ksg $>f~c~(g77gWF 6occ m^IX&u}ZKSJQ*( lVB爵ʬ!82|QjYRU7'n>%*nF8~6X6$@:H\ęR\fC$צ5Bk/z0z\1 *wێܨX3qw.E֭߾`)LK(. /8IM2]Rao! K 'Dt; G+M7#k.ΌWH?[D6}M4:.cm"EOqvTLcQn4(!Z혂,M Kc9b>;͑VԈČlqRIDp"p!S0h-k)J˕IR渱PgOR[;GKq$Vǿ~=fԦ%|VDVJ 'b5j2 RdPU0 (BiIPPVy\B"E6>ܯ6'(;1;1GZdtӃ("& ;ppy4> t{ ۰~90^Bzm& 1ԗqƴX}$~j%;cJ% 3¹9j;66I'c7\缁Дi`F w= VLذArF ^Qy^|[V\pKdv1K_-'e1 9"xJ>8Y 8?ž ϲ;G?}ŠOֱ.\ȷ޺hR0lK4{1ԉ|;&Jo>7.+OfJ y{iҭyuD?B߬5q@g&+:SJE\^qCr'G8C"$)dɊl5fY () sIaH(/˯LYj߅@cp4f]?7Z:R^G mOv*]:n'\B3%*pt]֒]1uJrl>e]#hgi'%AxJזo1Tް]Lҝı 3jX ]JWpZ Eƍz2 .ʰ5ş &ĵŜ_f[5dM 9<2獵rُ0c™*a4VvZXgǸ$C5KMWOlPW&Ȧq7 h m& pCkg-,GnȄ ҔU&Rӌ]"@0/l' endstream endobj 237 0 obj << /Type /FontDescriptor /FontName /VLYRYV+CMSLTT10 /Flags 4 /FontBBox [-20 -233 617 696] /Ascent 611 /CapHeight 611 /Descent -222 /ItalicAngle -9 /StemV 69 /XHeight 431 /CharSet (/C/E/F/G/M/N/R/T/a/b/c/colon/d/e/f/g/h/hyphen/i/j/k/l/m/n/o/p/parenleft/period/question/r/s/slash/t/u/v/w/x/y/z) /FontFile 236 0 R >> endobj 238 0 obj << /Length1 1423 /Length2 6058 /Length3 0 /Length 7015 /Filter /FlateDecode >> stream xڍwTk6" "C7 tw03 ] ҩRҡ4(Hwqyk}ߚy}Z !yyA?yA \}(⁀a(ja /HJ@$!(v/ A,p7_#UWݖȺB<`F:B\Qm. A+#& vE=9o(Ѕ ^;'e@ Cw"~;Ho@\ xꀞ:p;ݟ蟉_`[[ 9P΋Ar`O GŃP k`@IVᇰ!O|?ӠYf'wuܟSz@lQ07=fg QQAp9@0 wc䗓! أh@?@t{Am  '; FP@?Yfb>%%5c?v}~G@@}eCl?oa4(9Co٢,{GJ.. u@ 8j@` 5g *H0jDda.$iCUWP]06y< PCg댺UnrAP30[`_\Ja€??jJ > HT=pT ?jr")ֿNMm%ÝߜUx,Ě_lyb-d~+]9ediD ٠yGV\r.MgIn'BgvMYCKdmaƖd4q!)ZRj* E' )4xٜMXEs4O}ЄS7qTKf |yۓ*x\R<*CNwTdY 4V9$ݱ.X[6:]G:٩^7cnj5IiXCM-&Wg{Mh(jNN= )5I֪WPbC(nW`S ~v51sY^YB\jӝomW R?c. M=zG,oo&nN1&L^XyCJ^theNo=,I~BZFiXb&g-7 Z93GIY}bl|ȫ6_ܷZA>:e1w b1Fb1Xx ~szaα^RUrF be1d:kq毙6cB;@ra^Oumy88V<%Y7|8#b"MdݸivVO\}[c!̊v昺Gk.ԏn(Κ:yy =bARb'\dH :SM(d{ ?r ƖLL[)PwRyKDwTzp}x:'> c*kyNm:"‘O{lL!Vw|J8Lr ^xx[ӷÁP&Hgݝ[rLjw~$G T%A'٪~;s b=ή3WIVk/h9)>i'J/25)PpXq~Gbwؔ1g?ZGQ'K~.YNab>#kn+6LSXiM($9,"{lRE$;c{?؊!DӒ1K&(uwA@I\9QҀQ+ <hMddUCI"®1ZfZ(= PҊzd^-w~ g:ϞLg[g9Sh>, RNX vjmG:B?<+Ǖ ӗnc*3?&nD>ᮿ?Ϯ ~ Q$l)zyz]x!1=a%yx?6v-_o*􂊨_FE8qumoZ^I8%&$ɷ'POGCjjcy%{x^- d$EK:SFEPNR3 _,hRiLQ y-9r:nm1ocq~.4ʟҨj? o4/xd9OQZNaBoS<3T`Nݡ&*K${a4}z~̎ Jt_bdV&=.XmS䀑tيb'Vg*ùpüz[a8 =} 4>Cy u3sҭI⒯6'-KN+nsPmwc$m;DbU\Ixk½RILqmQl: ԆjTGktCy*GeE S/9H=:1oL-rV~i"rM/d6?,GDEb[#%.hq.ߩ{fjGeҽLG X{AǼ: OXȲo:f* ӕxqrA7-شy~J}}f8P8N.Y&1Su#B^ psEGu%9y \͵qNznH]$ʑR;^Pۋ閲ZzGOODPD)~) :z/;t 4^ dKrvy;,h]O5;*{L별RYGP`%O64lNwŻ939\kcN uO g*p vsNVV&/-+63y6<\aynAHbLhRnU(Ky|@Qk ԗ:.n<$hFy c]h C˙R~p̳fiW( C485a Pftlꪒj&ٌEnW Ϳ 3cM*7D7/)8@IKy1ó9#@g"uG1jVĕۍݨ<#* 3_o|~`rc!ʣ+rU"E̮'7<!Cj*s %_r }?k 2[a~ܗ<}YI@yiRIH}l~c˄ :݃EbU/LԴ| BUqH*U&ѠUҬSß4csU:j3X쨽Xi4y7Aq7&|"T;P"j<6^Okߣyqa݆勺ax-IE-vo6+Q_=VfN,˂V&Bɼo檒D$UVIJ}}t &f#z"ߧ-[on0ո;`8 VMI^={`[]l&ǥp^V.ʧ#E)mҔ_l\"u]Q 4k&rͳi'TTZi|z8ylEo=<_Rn_90|yûĔ_3S^FD Q`x>L,&}L1nDֺn="ܗYXd D7)`LxAPhI(N ]i^ 3aq0;ўw 3(Kx#M-m<G|Y6O\a<)xDK):EL@ѥrAo PU}景:y?u<]9PvcuwsEڢRiڅe +QzsEf&:d; Ѫq7RNzoȾFz41 T(,az dΌc6.v[ ŎBK{Eu0N5O:[jfoα8t*ú]Ywuu+!d~D߱cU%^`ps<"2DKTE6#e22XmaL_I2>ש|ǣըﶣA#^e?&fdNqNuc`sEN oӘ6vܢ獏ߣ*Sx+>6:[0r8aXXA,18d{fvJ]UJ? }+OUٍR$O~d>bRj~/5&e0}$_wxAwjDgVԱ.ŒעFh KPK1۬;>{~&20%RCDy6޾d)3x~91΂Y0!9vӾJ&oJHOu" endstream endobj 239 0 obj << /Type /FontDescriptor /FontName /FFYKXD+CMSS10 /Flags 4 /FontBBox [-61 -250 999 759] /Ascent 694 /CapHeight 694 /Descent -194 /ItalicAngle 0 /StemV 78 /XHeight 444 /CharSet (/parenleft/parenright) /FontFile 238 0 R >> endobj 240 0 obj << /Length1 1409 /Length2 5972 /Length3 0 /Length 6932 /Filter /FlateDecode >> stream xڍxT6"J5 ޥw)!!$t^7JGTRU&MtϽ_VJ=~<nCaeBbDU=+1 IMXo;)9 G!eaq65C!1 ,edj 8'BB1ܪ( #Pv $@u*A bbDPn BO8 ` @</}+5RnzܠC\;uLuh(/_!+ݟ_ 0!HG  4tE^X! !0(\<Gp[4 ?0`788J;fu$D Eb1wq-.H' ~рE͐Pm?6G( @^`'_Lf_4 h@0(nPtsE*&X$wv k ` O ד NaoZ3C_NWX\ ,#I%o!gwQ Cd";xQߟ> g(qob!,{Go?_r# pzvfCC- wwo6e#NbE1p/(;#( ׽ˇ= nZM?#(ȯ@ޤ8V_1ܬB^%A?r#X& PayIQR{{P/(tn u~vV)6L`)yK9Pi?ݳҴx+*_;B!(fQ'Q+{Flքּa]땟_t`l\E'Ti,X܎mV\KATq4nfq*m1L߼W2?~|D@JE8-=ܡ~&{<NBp{}A mpEINv-ڭf~%є$TK w2W%&d`vԛDZ7? 63QL&Uq3)C;zf1~7@MkM>tKHY/f2hM`W>k~"(=sg+Q[Fgi?`Khڡ)w_Ifv3\2ߔzTw/]lr$n)[|ۧMwޏ_Q3OUrݨU}Qq[N *VA y*?hK=ȃ;^?˳TJX{~_k/^ZOi5e9C  -̬@mGM$n]oa GĬOnm7?h(ygd$V^Eߡ!O#E` EymkMԵ5'ݬi[jXEO 50I@ꍷ2fC`fHۋŇMVSo , u/Wěh.Ei1zM0 lv3N[d3TO9(h?q @I]#kыQ }I(l "s X}a`\٦5|8T``"Czɗ?oSNZetw +vl_c#ĚF a lrI׋eZy󅱟-t!'=Zr$)vզܔKɮ ڷR\[Cj&UcBl#5'R&I%;~lvXb]Y6s.=>=dP3R:a#j:~:,{.AvVHx2C޸{φx$N qq:)n+.%C=(faW4)'IKFށ"B C+ғ')®j=d1fKjoFƲJִW}sqr]d Nr Y!o+:] w~+MJ> >/0~v!@!MzƑٍ`F;FL3Ohkфe[Lӵ@!RXCP g\F깻-IA< 5ma㧥6D}JyiY3W.J4rJ)2r`='n̷\^̒sյ ՑNPiц΁6D%xieWLdV&`K`a>:M\aξUYv2o8z$o ٙiG,{Lv8Ԧc"'wc'FMڰTPfwqf7 !k, doDYz_#:Ybf?0U?g)Х3h. nyv;?49}yn[:otք1~mv0%!C 7KLMʫ)ͯ۱|k< /̈^[a@S(4Vԁ2qLK_$;ֽdTWm嵐9\Yt6͌ 7wda[GAĽW-Wd|F.`$_-F Di0uv{w̪}*EL"&O:(F@]H稸4_2|9"Z&:G3\8up'Wc,:[@̖"Xd::2gkL<ћ3Wr:h܆g}Bk]Q#5y7}/-bO:1\3ki^ DL'mǀ$ЇLmèmP&O{/g-3tI`=D'oEZ'zvK]p]!P^r\f0 AJ#? ɄT|=XWo˔^ew$񀒜|[敓u,uߛ7?|6 {2zvʴ-;#"ŽM[5xɅuѾ,n·&.t fn}4݆Eo=4 ?=𓿌43&d|-f_]K etD+ U s.V:"KK2J )Q2<,Hg/DpzBɜ:) BW]"PuJ5iAv[F*Ge ZI(7r|=VQJJj:NvQX\RNW 뉣#'UnVq(4mқ'uvbď=?e< :c -o6hpF &31XƋ0+7DD=z)=!7+uh>Lk*s\Uk,;ƩīwϲA)[%"E}{XžHK&em~F3ʀϗViszX")8Dss#ϟv3T\n͕ )^6s7l3Haׁ_l6[Yt5]dM PR^NYؕv$9[CF+>ι;;]J%PgxQZ+]jg6Y!O}Փ {1-ePpћ/;1cO|\\\lnoWaM߫ZU -ҔHR4aBSImZwė:q<>rw:s\VoG궳}`xhhzy2r JX*ğ;4 ;jI]Z.8ŷRe=[BUfĞ- ,z5U+/Yc tXcq}z)O)x&[q $槲(cNؚbbf,̕S<[J:ngsӠfaذ;˪Z/O~f̤.௙kUX]O6aOC⚄>^}Lo"e0p΋|Oj4 9[uF&:Ҵr8%SNхX5 pB ¾xW~~l]%+-6V~&ϐ~c[L& !ҧ\%Ҵ̙O 5[T"NN5uf jY7jmE2,L_;st6[Y]loG.{kDJ]`C=iΣz 3z6d-=n&Q_\r3ZT%mᒶbHF 3ʐ$q/$^EaVT :ْc{Yj gEW o&Hc'>r:c97k0IMh??V}Ty/U4ISLN$Ah298Y>.ⅺg4S\ࣈ@P$~Pi`uacŋWlѵf>dbӼUsM7e3*ɷ\Obx;I~,[dYh|IX :ϻJ)ibM+RSN>?{#OoV³(y/zȈ\L;0{;$"y2G͆ cHǣk벊]ؔ"3puri .CU!/wي)Gq~P ˸5mk T_%"ɀ9qm`*u& ?*MOh3#C0GZCucِRfgkd蜘9ݸ#9[xdo*%jCܑ\}[yvDПHosZ7)\ӫ*ξؚNi&afVݖ>AB/X֮jH{?K s%j/lcg=B§07:wk%/G]-d`i# lDCeKsYxQgq݄iҼkIh<8+ZY [ZI*F0UBܻ:+Ww7ߗ*0d"lq&` Ak9 DlיjgX:0CgA"jlvmß2zS <#墉ٙRZf= I1:)ݷiD[Q5MB@Գ:Ǖà;J㪺GM ^>ui4-d]!0 gOHK|xf/ͩČ9v(;z5%1JdpmG™\ApA,KUN5vb,>G%OXyPV1o추 <&Xįx|_3mZ>Hp$uh!T˔{0% ֽ>^6-}'B\?7mt)+eRiĻTaH>vխx]9Nyw9K2v=L?!h\m0]ʸ6H^#ODZ ,Ι2D\sMn%.zdJDJ]PWO%R݃QX=lA;hWe7IաIg=s՘$t5"^2W h{O L>LxT ˏEhu|G2o @'QtA柞N0͉7) EμI4hybpq'!,. aﯬKs(B\`y%kO.ޛrn{ꚳ#WnHodgOlѤq-Awdg&4WLG so@?WLJȗH-v9[] 룅GԬ)2b$+EuduBǫMLҼ5y6Zq< TEtlUnGtXEOO"iYPehg WkjDB/R+_%Ys?ٰ@! "C3{181}+ؓ#<6߳b5҅V"RJ-]Ok?[ LIp񊬀NbMfR}Ιd)dH"j (w8x endstream endobj 241 0 obj << /Type /FontDescriptor /FontName /WCJTWI+CMSY10 /Flags 4 /FontBBox [-29 -960 1116 775] /Ascent 750 /CapHeight 683 /Descent -194 /ItalicAngle -14 /StemV 40 /XHeight 431 /CharSet (/circlecopyrt) /FontFile 240 0 R >> endobj 242 0 obj << /Length1 2246 /Length2 15143 /Length3 0 /Length 16472 /Filter /FlateDecode >> stream xڍP w$Ӹ{pNp NpwwC1sNrz^>{Ӑ+* mm"r**LFFzFFfX22s'+d6X8 eNr6ig+ _C[n1@ mkt%sw075szߏJ#*!k @ h lkdtrfNNv ֎TWs'34E o` =,@? e['W ]`enq|wq1:޳d v@ǀOsLL@6;ZظۘḼqYz'7'Z_V.Vn0xg?G#s;'GzGs82b6"@'Gؿ5wݝõu/21163PJwo) nFf %PqdK`Nmn|h898=T/eb9 6&`b|?&_?~y0c[+1'!(uxұYXl,v.vF-U40?I٘Cw\P4T o>@fdc4zyv7E[z ͭxfg͐}k:͝V}ClLmX1G2*:u},[|ߨ(fcdk1  a狙 @G@ocxg 0uH9 " b"Fo`~#NoE_>{߈T#v{>sVVuFuuFV7{L߱mNwޕ= 䝠ٿewږwV3opֿ3 ?RF y}P~{2l&[:^6&{s쬜( ew hl ? nGW{;0ۻ#sVfW;ed>n1 rs7o?j>{)M.NaLө{o )Mc̉'V_2F.7sNZ2C…Eѻ#nwvނ^DT$Q~Àk\ uFe2*Zy'h`AQ&1CUCp,u՝*ڪVڠ'ac/k>ܵ2̺NaXq)o*Br .ӹWRJ/&[ ձ`| w>-xȫpD)<CJnpR0e&x9DIUS?ʴ>!HeR u  6Jئ<-ܡg2 v.z᭯8&YJ/^UAiؒ|x~Evw]=ticm}#*?A*D u|r][ J #)z7tzUTbl$ÀV y(9kw;)~w kbB DJ>2 bS'HX2}S| Jl~nzSqN7~:4mYV7=6н>ڛ"m+6 Q5{گwC-yy{>kHh{qr`7ݦG `жg>}_QZ:F:vL5޶H~2 _/n5<ܯ_A<Ơ*L?P&RSW%#fEN$|{Qh3!cD<  7ƌCIMҠ%EΨMhЂUv(P-GVYNSUl ^DlY5=[U5߸Jg%*X7mq; |ݶ(0"Z(Rwv30{wUyjKMXR䃩 -ՑWylD!Yһ0N FG e `!6MHSLijeKoWKR䝡hޖX9P"%({^76zI*c%ΈvѧE WlDLQI ~$ >U<^OlNY8J| A$k1V chro:#G;);)FŞ6/@ZADCfk+ozbqFΪhu*8g̈?GyZuPۇ믚1@;_^ZiI3v ''^8VW$&.yZ$amC7܈'s71P!c:}$ kO2 WjyeAxF6̨DO-螾|;Ubwp.4 1w3XwXA%w:G@:=BYnG|l yAzEv{23 EA UgJ\R20K2=%7lEY>}X2Y}g ?o9nC6mecp}mzdʪȯ@ϔ#){Sp'IWC9)@ߛ6:13]Tè59Mgw) 8f 5.G 1tޛ4P+MgŦV'MrT YՈiӄ65CoŗD>"i$΅%-z,m}7-P<fИ/=s6Dǯשr+,kj!;,:q+7iՀsS%rs#JRބ.|5Yw ,\ݐIaاnDfƩl*8^S+86*I>+cX?=h9ÌUc했1kr#ϑ)X:69p'5yq6cӼ0DCAe#W@ݘӂ»/2%-2aQe69G_[C ZF+?c^(BIqZҜ^Mt/ aD?iB!4^q j,NœZQnlHxy/G>F11U.Q;h<?CBœ ΣqGirwKz-qKODшOͱlE=5mv:/mGJO'CҫB9{H#P'tg(A]AuWRm c`:H1|XpIAXC9j7JADh@hv$ FivazS"S.3~40Ĉ.Q\Eu$LGgrxeGaa)ȹYk%a}.RW)e;'7iɧO.WХ+1`}J@g*K BqL\V=[$ix"`|=?Gfguy HdPP_1AB?fJsJŀ0o`D*JS\*fc,=jPv`$g*gɦig_]$'kLed<69Ӽg>yӡ(- zS`Db yNW$P2h1nH ҋ߭B7LI hZk닋CMs{~>\MtHυm>SƷ'Ȫl min#RfXznX^_̡Z!.!O';ro}B_o+ٟ6i:ݕ27xtMTy򦻜ޯ6m`y߄>\}_sZǮ'0 pjHI!u?*| Q3c?m< ֗H@8Q@Sdx =\!X愱o %`bjO9;D=7GX%tj&)O` ]J8Jp6);Dm1y\;l(k)\e{@hQk,H@\j& M\қ i%+$La'(v5ՑKbĘQ"&zphyH!ur\*o^#gPZ<]wy@q}:RWLf``BiP]3љ(Iɫ;/D8 y%F@klh $,k[Q"_`Bf؜@?eOm'Cj~M֜QWK~sv٬s0ǜϝac@8=vQP_,F@DkGL[>Z :,foȨ퓂%:Ys7x  ~ai!rHI!4У76@` !vxMjJLqC"cuy!3 ZK8ǃC clKWڅhwr~?m} xXP`tËD3\n0aùeBgn̑QA^Ca"Xe~~:SWC N;a!M@*CrRͲQk4}MlCf:F,U^Fl-?XN&ҩ-t$X|zRW>U<\᳭jIˢ;D6]f N8p~vPK.(iP 'ET  Ld ȵEL#/4J]zSϫo𭭵x%_a9BZrL!G-Fo[ ֑+ J&<ѺQ:Zpdw96ivY)ڡ#ey@Zkk- F4t\YI,ۘgVDC q_wg1Ů}sNĎ/vk=̄NCBȹO4(M@%\^d|EA%1Z &02Vufc2\,ªMҞQ(`TMڴT/}zT1.X2čGV/-"VOd01Ж&`%?nWcAe?FU_Uf[iXMt, eb +\?4E>5DH Q8t"j1YF#hCdּ}-N'TQwNU k{r '?: o*\*;>pN#pk{\@e_vH>k쒓l p.qrSE.D6g+ \PD e'+pjY5>/MG)UzHZp޻_9@Vc2PC :wSH10ɓ޼ן QNOHq^&ѓN{U-:~Cݔ3$d&3`W`Tͩ]ߐnabQr+Q!8Y:5;\Z=OT?|jXCb^& GB?(A`:^~>gȎ_^E(I}/aM,=RʀH:_K_3j ̌S; X!]6W_깏ixP=$5y ac% tp^}P2 "~ ~FC 6w(B(uZT`R̿. .("o ScE{FCy9h8HܣUD&Xi,CQmVn1z%7ixْ !q.Z&^jowEj8 kl"$I<-ZЇ뮵DI4Vs;\UIdtf&BKH|gJnK8')@@ή0]Giqv2d>8{'ODz5 :kPOX%Qix.Rp~&=͜HRHBҋ̣_$0QSh,U#!'x d`Js[e·^j⮠!Kb}6i0xj_Q~ř0H sވzEh .fxVj5^>]lȑ6dml#&QKbwȅ&kk>nʞ2ج nle5qJmUՖ]@?DJ MK:~<"C+`،eAب-cSP?B[K>AxR6g+IcF#<FJNS 0х?i H7Byd-Mӏ&EzSr);K? [EhYb@ot/B9$JD}n"gS?HKeFQML+KL6( ^W "Zs{ 0x=&P5-_E甐4G~`Æ|Tg|t('d][~75bg{L Y(ܑQ]x]'}\SyEztxA܈\F=1s j^Щ%H#BR3΅+p2<)k)xxuz9TAQ[ާUAH_P(Jǯ<yXAXQ-#f!GrFvǹe! onlQ5 %RF0R+1s&`0.mM WóEF$}nɖ k鬆6R\Wǖ@-8)|PUk֠O S4D:9 8ΏũNh}x=#kb% K- oWW͹KQV9.kHyxđ;bCt. q"~y>V]#p0_8;_rNE|E=ŊW+q4V^w,_Hs;X)2hbbqIAM*$9Ρ3^=|^mcR?jw&3ȏĩ>or !̶ )Ldi+7UQTj=.K} ɞƧ# s><ސ׏A:ȉo` YMP0d<pf,ücZ`~+-BFˍ? •ea]Bȴ=ZW_JF?aзDO{W._o\f+ i_g£àz{']m&U+$[n: Ni&.4*z+l1OhT2M3k[fI9P 8;~Tg;p62QP`E/39 d֡tLH\\tlvYK0]!FUH*Y1QJ̈庶F7BN|a&5Na/1ZxyX ?(R7-~ЕKwُt(ꊨǿڔ\'ib/cx-?ȴnj}E<GBP,=h ^mFFt_E8\&Ld9Gv=!ܧ+Q"ec1Q4O5qyFM*{W8e G٦wdؼXo*u5 ]?XB^T1^"vcҒ|q_o2.Ӈ2]߳U &'U 1@QKCC嬗W7A9>Lh1znk9y=,kTYl 9Z">{lLDPR[Qig%˱AM;t*;N3Hӏe.Z0V&~JVZiO$ ,C"z_S;xitz ZϾ'}ؕi-WYhyV-50dPr"KF[?;B|E@B{ԝٙF*,%X;l`P5}d͠{Uۢ'd4;#fu5Y{E7G|g`gQel/(nhO-bdr|ra(W/ʵ^]}u~9(<y1}ww?k,ukqC;:N{  (\L8 -tkxmE`hCH:I>rƺ+ф$R]BbiAk-q=2>p@~FDҹYkFNF*|j-x@{Ӧc3"P);N7$Q3R ^_ȀNlGڨ(uASѤ4Q{PkfnG t>(? WmǛ}!˒VT~7\'q-")ڸQ^?кSwi#fD$pIm.fŷGui1Cj7{cŒ2 9f;O6.EAG pBxn-]y;W+Jo)g`Ⱦ)G53 Heݍ9va#fd_,mzE3GxYk+NXøERcsJjjXVK-x[0wދ'"] fl8w{@|j#=sidb_vond?=$sNⓃwRn tM:oYe8fP \iXp/졁Ă4K&eX3G#Rƙ ÈRlJ7! eat BEd/b*YXA{ G]F^Bw4'̢'5F6W yJ-xpcWg 4RJvgJx\U|(j.jqQ馎k)qk2愁 XyX6͊u4,Tx`ӫaW8^+iy%R )Wvۧ +o9,幽cA1XG`4| m5/bL dFvrGeKZBU\9{dG~dMmp+YWoC,:Pt0C\ qcD,9Bž$jSs|["JwBZ,uOK{?*rL 7n4uCZ_3|v0 )>\H|=I@ypa>G|ԔF1^bW=mQ3fOcy}D) D B2!svd 5eb,WmlnGf)4 [vm%SA *!6.q߉3lg0d'>2nzл`)=/sc>;?a ث{ɏƽXKE8tqظd&1avIye gŝnkr^m"K J4/YƆ^D(p&ėfR Ͱ#:>!%U㋊UZ&h^'Qh:yrgĖ$K0z׃<~u@`R[on\eN8磩1C0ݔoj8m6%Du3D+d9a'92\Q8HL:|-z`%/Ow[h LMj['2ēŞQT֖HZMtg">!Zf&^*2#V}3ȤUs "V)v!C ؋LfYK -tXzjЛOQ},zCRso2HZbPcsY,}˃^ YRH3idox}Β|Y(y1y,Y|,d<2IIiB&ҤN()Ql1];G5xf(qri,M36F' l\c溜A6=Ҥ_&ܰvYoc5Xw2=o>~\B;sCQ _`ޟ^^f86InZ4$ܬQ骤 $Q>@Lj;~d4/(Fl3φ"/>pX{юk+2Q"i{[,T%q+(M o[ΞNdT71Kv}R-$-#IT|Ud`E FY5ȼFDxd;ȦRo:jD$2|+:qrÈtΞ% eT+q8(t2R;qJOݳGc2R50ej E$y`[3:oMN*~@nUtMz ~K<}ɚ@|Y0ϻPF F=K  R?=TAΑ%T~ѫ>5 Gᒭ"8N+_+[FrZ&ozѕyV| @)Lژ ^%-j2g½NHwpL) 18Xmۗ @ f-5ȽmuB+Kki6w{hp6To_K,uoW~N0 t@$_h$p ҉ʠXfl@E>{~D#^lTA <4x9W+e!y\)i5\X'εDTS>rf!/)ָ2!E$3s?IؾBY$ҵsUyر`6&Elq*llN$Q^!3:xvG̽H lS1\Plt&YJ3 p|uwEXLgqible'>Ib=Wz^[wns!.O)?cfpĴK%|аDzr e4*K(V\CMYy]1i%9XC5r3.N}ɁhW?@)~4x_.laot}^w. ^khO&Ճ($^gxy/Rf,Pj q}*y:4G0U Ye.uy$U5R:.|, eNGďDyS*<q EEF;K{qTQXA(m9e[LoOښ QC]ӫ!4*y-YHŔ3 >Hrz+6e:Am˾ פ_M`S8 A̱x!_ĐAa{[nv]DeDɭi2s6zm.M[?b*P1fU .,)m&}i9bΡH#HdJt(7{*n @v1r}Qz^ku^lJ5) < * 3Ⱥҕuv$@nH1)I endstream endobj 243 0 obj << /Type /FontDescriptor /FontName /RRKLQA+CMTT10 /Flags 4 /FontBBox [-4 -233 537 696] /Ascent 611 /CapHeight 611 /Descent -222 /ItalicAngle 0 /StemV 69 /XHeight 431 /CharSet (/C/E/F/I/M/N/O/R/S/T/U/V/a/asciitilde/b/c/colon/d/e/eight/f/g/greater/h/hyphen/i/j/k/l/less/m/n/o/one/p/parenleft/parenright/period/plus/q/quotedbl/quoteright/r/s/semicolon/slash/t/three/u/v/w/x/y/z) /FontFile 242 0 R >> endobj 244 0 obj << /Length1 1530 /Length2 2494 /Length3 0 /Length 3454 /Filter /FlateDecode >> stream xڍT 8mﭷbH%S$dkLf0} Ũ3d<욦%+oBRIKH%iIT YH|i99>wkvУ0 q2`I$>@ M@X0}t`Cqh~\: qq\5?Ufka a5u>+ґ{ 7f a7  ?Ca|jP?| 0$0 E TPp:Hr#$Pv(Dh "?(1&J?~PD"< `ԏd~s K@֏>mC6Y?#ƻS}P`#$h! w߸O{h?L6+fF4:\6o%tSU~">5|8-b me8}C_ 2 ~Q{ Qd}Hk@ģMo̷1 Y { bțE5ES#4" E24DD P4yH L655ҩxƔo$x'MC?\2x4)D?L;|" B7{AHG=zG}CEUH2XP&N*ZE0ei2>R?ޥ8D:;y%{)!x{箌xG72ztw5)n8u˩0#pMBy2ݰ}5.-|_j8ٍׯח]F9ZVhqz^Ƽqo5w =P\(=:hhТ[i)% 6%,gz2wU_\>_3禗뢱p ;Y^Jd07L|cv[{k5?a/.fe6&0xx}X('td؄go>>1;,2;| ElLluZ-*vUAS2j w2tb3 }qN p^`Mx)G_KR.vƵ풂,ږ~,c._SϺ7 U}Kg(5o~cd2J~]ӿnaڵ2?ݧt ;yWZG$t &{On$- a'"\ ij4I?s<2R_`(g%dHdI]v~ :$͇*Й;ZIOږ?'4uQJV]uR)`+'1]G-: TC4`YX}ZgQ(&zήܬ6'*&@qZ%>~4n=mN$O%;G|#f>6JcEyx嘉}<6TN(ի>1JGhxWbhMA3M=sH/0?w̵'bvإRkYY%iEMf^GաO?;_7V|$ۨ+O|m^9֘ϳWk{!J[96g8򒯧qDC)# BA @/,il9v5vǫL^ĭVq٪W͓=*pM[(&]^4Pwahk) qkm:< lsH۬W7>5xgf ۀ ᩖzj̠͠~)#.d|6IT 9mu`zX,{gu]{NCZmђUsI)%/Sq$_ceB*FaViF}sj𓍿v_{ƃy*]WUH[26oj0񌔉SUlHݍE׹ՎPRA/Dlmb!ɪ?oPy>VE#Qy1[,"d# #jFRC?THL IZ@CrWN׊],gEߊ'3nqpAuBScb[fy]t'94HURV.Rev$D. ;zu{VklNփ>ȞZ cRkTK>WS>r_o꜏ɰLq9D!>nv; [qƭ|E1y{zRY)TaPbUtg7ljY)J8l:n$QѻbKVZp¯ovB)*URe8 1&B/2}>KcnzZٹ\-El EI *گLÛPF5yo9ē5nͧREJz "t٨"'>\b*}NuNSz`x0*,ݩeD4ph{A:5e@vc`7sиS\ endstream endobj 245 0 obj << /Type /FontDescriptor /FontName /PQAMIY+CMTT12 /Flags 4 /FontBBox [-1 -234 524 695] /Ascent 611 /CapHeight 611 /Descent -222 /ItalicAngle 0 /StemV 65 /XHeight 431 /CharSet (/d/e/f/hyphen/i/k/l/n/v/y) /FontFile 244 0 R >> endobj 246 0 obj << /Length1 2144 /Length2 12583 /Length3 0 /Length 13858 /Filter /FlateDecode >> stream xڍT.LwHH Hww4H7 0t )%)! !%-xgs{k  PWPW3PQ6(T@'g߿ ĝ`L SȹX\||,,6;$]Af&J da W)-Ow- djlP0[m!Mmj (h,`>ff777&c[g&{' !Zl P:\f? ( n rKfov3v )bgt@dJ@2`+?t{Adg0JRL`w0Ccg{1bg)Q1s6u9A6 ˒vf@;3I{05Yk;{7;9"\?؁]@D(e@0tM-WpS `)2Bx9`'׿PXYf S0hC;,c7}zx6s̚rʊUNL`dcgprxy>MO)O1X~ڙxҺTR}0hd pB>XO͟j?-o"!G`9 5u @3jeƐ g);L6s]3 l 0rm֐2?U@1wDI;S{? `dY.6NN+<̀5 q@;1P.NY70F<f7 Y7b0KFf)AXA<q#H~#?o`MA pp!!-!t!I[z8Xe![ BdoB2ia b o5KĐ:@nwx!"G{0y?++NO $ p1v$oR tD˿ {8n!:??_<ȵMQM?Z}r_#JƸ;!8KB򈁘H[t+8jm[Fd먵1-^gv)ɂ#7"{ώְ]rT9.<y8ne! *{\Q0F} (5ɜ'@3 acbgO"Ls^襳0B͹P{|KGWIQb -Ԓ]O޹-s!9"e4w=@& &eʞ]r)@u]J=fʙ' , ~1Zkٴ~u(OƲFЅEgLc8=rTRdXd.t?:¬yy0d$M$*J|y=hT!wvm9zqrq{^- P"Q,bm.qW?O vWV7Yps^ádXPs^t ppaR]OJwǎ֨][1~)3\G^tW)6^j53Vו(AkuV-)spqH| u&ySp,~i:I% ԑ{nlwpb|1R. e%'妘*uBfLOxkX_Yuo-' L8}%&Sݮzbx{̔iSq˸M "g,3J!cdĤOo]|ـ٣ 9Vyx Jap״ <ҧUNUɯE8"I? .6vs_2XA}=]!D!*m/x_(!,ٔ e)uգZN\0kF pMMM- `/MUŋx)PFmcJnS{oT%GQwEdVLCY4ŝ%HbCL2%JK ,zevxֈ#*|ճyEB:J\~,>iY!{A# z}Lulk%.&ӊX.WDn&FӼmBuHfrrh5,'WZE#$po8#.? .Hݠz!sY >ŒE,!tv# p.?z3,Ұr~@_^oIhݬͲĐZ({lSVrxEM F@Qv^Z Y*T;>K4hivq(BrT,m!PUz7ˎnw9YFהIpgQOǾ2] dNbj00GXKa$SL8MQ=U"ZDdacKX1ȷ+D'YCE(qd* W6Uf`8iT{\gFoA Iz'-X7a=L zc -SPVMLým9v " W70D^é,{u`Q Ի66@ 5@*p#jXIfE'g[H28.:/q^O'&Kp0ǁ2*ڡ ǑdAs3"؇$v 'U^ # K_J!N^`C)#ZIw@Xɸ@Õ%Ddl!ּC[ɘa/Fd!`<:{0j޴K7m}/Y *9),~T|~s_z [[pZaoݔX:K3rnv + UrDnH_o2} )Cg_f/YWJz.B1n:֩ ЊFγR.FzDFedBlhfp*ӎvaEplfPlKLpsq&Am|搥= B HwGϫ1&UIhMKeH8zm;)c9>2J(XPZ_e( ][VV8,5bwa!f B{ 9?pqwqO 5(DdeCuh%|(y ][(sثKZFͭ̓Slo:; Q9վ8 qߝ1j9rUNjmukߝ#*I^dis,~N0 %5:kOvNɇ'Y56 ҙcD4)tPL~;%OFv'̈fɟgG,%^kDU6e|z"ZZos]নY[7!U,Hl%Fi9!r՚/)ڦ#uSH$7}><+%AT_x"?_6 _A1gnd9|x@I.S ?`0!0]!ǧwCHu {jU˵BqBFo28l0FmPvV0ρ L槾5` }F%(&&ٚ<-j.mSJg:(|i9NOvͥKlC+߮)is(| 8rWZw$3e"FV? i|̖g&{ Fbh޾Mv %6 &ыT{GV/@^X@,*p':SȺ` QYrpzTCL5 me}ŁaM߹˞@` )k'K~*Wh; ^U7ħS;Kvc<"eڷ-4KDUˉ4!2j-KJnrK3xqSx1+gy qYh ygM("gZ`Jpi+ݷnI8h*ariq:l$mSMmnⰻa>pJ4;[0bM:I޴wҢ T>Sқ*Le sOJ-Udp̻y7=O_ T-lHYʢ| o\\nHb$Mڶ {uшؓ1 91֭D]';C/5M 8oc|j\d5=jmO#ĽcA8mw5N/N=?41k8 XRs\I_k@5aW}˷ 8Z#M-0443Cp~oiHLQLG\a^*b Zoe٭^Wqåm B| Զ#fL *KJ@$ne jFF,en oс3 O;?kHLE&:Zn^s170Q=w:|Hs^o>[\p72Y6V KkU1<,6SeoȺ9pqs7g #(> /gq6oBL -2ȸi;kt75§s;^| BS#I`\"Mb iX<' 9vYծŏ7)M1qo(zs"&ŕf &po$|r@O\<{s d -@@k2Vyʭ 3&]CB,}|CHoSFJԜ?ägԩ8`0[/0-uK#Ñ`7,'DhT`לlj~hԦ"fGɐy68+;s,i[bKjn9& 5L]Lϵ@56ˮD9˨30IVaZ̞Ѷh"LZ!ZeqY^ԏS+sK}YfȵKյōe7f?\k[n)0ճu/]%En3bT~kVFQuoq! wd` H2m te2zqSiqPǩ഍c#8C˫'+ΓZ*[H4~N%`XJvy~0re|YyY2$rIE7u_F#b{q do 4m;}tJsR=^osfN|F=-PpR, ՚6:Ehtx?Tĩ;#،5yZS:I.HiYXLtnPʖ}W%آ%nWѪrI`(2-%X@Zػ\׮3tC;?~-r/7>ӄ"6^#H@v4!$cH*,a#N4zj5c".$Όq#}k)y~.ZpevDB !&޻ xʛ2X~F/>m96%:fΝXkKu{V!v .O˲PfTSa:wV9+Së/u:,;bI5 &|7}%0٭!X41^w$7_>q>Vl":qBA;̶\4H듵i,F> vM T) ix\By!&ƿ@ 3Ԩdۣ`GJ5ybdbns|3{Qɯ{\I1Ec}F_U$E'˦H-q!*?ygͪ`gz;d1<('ً ZM0~Rmʻ)BTH}cbtM#ꫵvK0\[ZO\S7iM]v;I]"GsҡR`]Z\7 vc4;n57V( Nguj-瀓a}-b?ڑKUDե?8*yq&$mwF? DRdJ̄oaIMrXH1D|]7=nόW`!pqy _#H?%A"ͯ9xY)E9lw&R<5+ |ٓYY^ENR[0ͥ r-`FM\ lc%$G;G5]itKA&=H%v/"̩4X}tK]C>}dz5Ypou ?IQ=G.oZkH׼"2[x/7N3s8PaD|G{˽ QeLMqӋ&m&vm f󒃦nnvmuDh/7_knV G avj6xʽ~X#ȭ:Zz[;Nl[T=$˹s<[6Ւ*jo59!G K3Y'e_5PyigKJ;c\0y7}ܭش?=-;[^y[-׆\C+bYլ=PW;V^SuA6m --9 &*㌈ws 3S8}2n3p촧%nB-O* K\>J>TT,ޅ7d׽JTx*D#P񌊟X<0.V}Ҽc ?ڶ:K/ZA} h4\}wΒwwǡ|-wԨP$0uF Q\ぅ,L 0Fp]Rw`TO-y!\߲ʜ/&>Ю;{ _Hh|n]9t--G-zi%ԫX4Wx?hȐ*Xq2Nd)69`R\ײ +MQԿws^`WtvXk{|6hAfǁkf=sşKX_"7x1QmKЬ|A@0MZ|帋U_ iaz.;QE"Ϭmqœ|[|߰_g}ut?>/cZvpP#=;R)SQִDX&znx)2S w︴zf5X`ƚe_ׁ1qcXMKGna>Q;]wFb]|lErST(ehs^ҝ^4ɿwQq/&v V!7YwAA9.]2gަGQ,_kyۚOJKy_~< 'dzfr;J fx ű? Ms>W7e}uUD憪"/6rq'ŇdgZ z@WMЙұxm? {|TwMgB"tYjwÈ>e.Tv8[]Var ΖQs?6Ovf$vnŕKᥖW Ѻ2+1RĠ-i gJEKHȧwt+SX`d^ 8_>92(jʫf~>p$Q:ȹ WϩXفY#~R"w ՅaꖬmgThWAs:|o/7Ljr1rLj{%Ư,zKSMyTjx$ R2E?eHsZT{ʤP U*|;N]\ބtoN<(6{tq+PWY~5z`0Ljr+g vwO4Wү`a>3ZJ'`j7 GW"ʚ׏.Rt&Ȉg5n\W; W*BKPգq{?{5JTBcȣk0ݼȂn^P_xiR2+|=;HF̔w|EÆ̏-x22"qͨw8/JW{]ܽbs*}G*fcqKH{y,s1wNNR(Rf|Ƨ  nHaP>ܗA/r z!oMф7;?*SHH=h_y{xYR*}{VŇ$!4[DlяQUqvLd6[/YfdE4__*LքyqQލT(cUL؞zɀLjZ Syv’_4QV+i1OV@FP&n9_AGbrQAX:y7F/`Pz ϒu(<٦e|qJ8ᥲJyL@t朊b#-YaUիtm} \yI\h+p;-}S<.|hps9d2~w4 nCIc_?GЛF9UvS$l,|=bˋJI&4/Ӂ[Ba/i|1!ߣB+fz`|$s1sxkCxgZfԩ8tWY$Z!U ?H] SFYċ @;&g2z8hi;C}fMLcu^(z>͹d"ڰ?6d]~F˗}, 6W,&9_iA笠U?h3[ի)jMt 0 yTI qwTOxsR/H\%< E83yњ#yeyvznOGw|MԔ?ᇲ;] OK=-v#nH2I9HF`#9GH.-AvcS {.k} )#V3OK@UBa=]ĩYxgJhà-zP gYoCJjAN1?p T^CSBƔ(_2/ m)nzYx~Y.-{a }/狌]Okyukҥ!5!Я!b1ŚGQ [ea=t|>cko0GP).{ 9F6٩Jۆ~=#M~ѕ}/X5i9IQDlZJܪw)^cqA/W:'ڱ0Dž5Sbm~ᆧ~׵7lJ*P׉pzξ/\_%"(yh*sewr,aYP凲p\>i7܁+HjQ{ R gQ2|۽zp>jS͸RĚ&p` HqvS:BJh%fC)]ce3v_^veVCuq(iނ`od}gB%i@5zԹY{ƏcCb6c 1:LT?* ]AQSҩKXVy{f 7ḄR\D_H^?Q=qTtT_4Aӻ͏dqC lcI{\~[W0DdW:L e笪S}9ⱢC͸Iht#އ&(V~xP?*g3K '0G*JčpVKGDC>1{ʱZtY^9pU}gs O@^5e%ͧ܉ԇNx`oN.HV{FͫPUY.Z+fڧƣ3CLOsbYԚ[cc,#b.Xnt~Y_HP.窿,%aCCU,21:jp/odpvTxΑI") R5 3lI8eKyL\/<>U tQ_dd$4\Js'{  "\)-3t4/TJ`S]0JzWQ5 Vm1G٤'H=z2H1deѾECGVVd]lMٌe00|'G_V[0cl{Ʋ'FHAӁk?+\^eﱪgCs_~QN4߶`XK>r4 zh@pM6_=RV JIf ^]zlUN%Ih> m!*2Hg$ӷ;PB(g]U˲WzR>~S?+;*nR!7YH:\B/Gnt; os|<>I)" ezF ^<'^& Km;ԏ߿dT4vo)!x'gADD'3 !V%*9M F-Cp#(C[OT%`+/,wӅcKkeY!<<]#Ͼ>Q\TzmhYؚ5[1p؆ۅgaK[o6Z-J 1_i C&:f{8=#YF-bdP /Z%ۗuxYKưZUq`Gͩ:Vh^η)Xs)q߉Ɖ{O[z\ qv!=zJkPef]&a2M1)ml@Mp(c=}`X+d+T`#2>9j٣=;q+F W+D{JcڏYvv]ٺ<.bs„mBWhiN.UG_5v3EZ)nwsowm@O9-Tb"x_c^j3&28ͣ57:?-w8g,Jdk?ʄmr6<0@CxS 3`Ua(Jّ*o1%mp2,[*.<;ؗ|4dI3gF, Eܵ[r>! cirҒQh\G*qY9Lo54E;ހjIL]GiF#7PY)9#`$V7VВ$Iz>X}Mɑz'6CewAltȨ~7"e1ҍ.gXVqp{C˗D.ߑ5&`$H 9EH* yS]J݁IHRΧOR_n lirBKŔoܳ83]l|?/A endstream endobj 247 0 obj << /Type /FontDescriptor /FontName /WJRTPN+CMTT9 /Flags 4 /FontBBox [-6 -233 542 698] /Ascent 611 /CapHeight 611 /Descent -222 /ItalicAngle 0 /StemV 74 /XHeight 431 /CharSet (/A/B/C/D/F/G/I/L/N/P/S/T/U/V/a/b/c/colon/comma/d/e/f/g/h/hyphen/i/k/l/m/n/o/one/p/parenleft/parenright/period/quoteleft/quoteright/r/s/semicolon/slash/t/three/u/v/w/x/y) /FontFile 246 0 R >> endobj 161 0 obj << /Type /Font /Subtype /Type1 /BaseFont /AJOFCV+CMB10 /FontDescriptor 219 0 R /FirstChar 38 /LastChar 116 /Widths 203 0 R /ToUnicode 1 0 R >> endobj 7 0 obj << /Type /Font /Subtype /Type1 /BaseFont /FQEBNF+CMBX12 /FontDescriptor 221 0 R /FirstChar 31 /LastChar 121 /Widths 217 0 R /ToUnicode 1 0 R >> endobj 37 0 obj << /Type /Font /Subtype /Type1 /BaseFont /CUJHND+CMMI10 /FontDescriptor 223 0 R /FirstChar 58 /LastChar 58 /Widths 213 0 R >> endobj 36 0 obj << /Type /Font /Subtype /Type1 /BaseFont /GPANTX+CMMI12 /FontDescriptor 225 0 R /FirstChar 58 /LastChar 58 /Widths 214 0 R >> endobj 8 0 obj << /Type /Font /Subtype /Type1 /BaseFont /NYRYBF+CMR10 /FontDescriptor 227 0 R /FirstChar 11 /LastChar 124 /Widths 216 0 R /ToUnicode 1 0 R >> endobj 128 0 obj << /Type /Font /Subtype /Type1 /BaseFont /FYGEPU+CMR7 /FontDescriptor 229 0 R /FirstChar 49 /LastChar 50 /Widths 211 0 R >> endobj 131 0 obj << /Type /Font /Subtype /Type1 /BaseFont /POQFGH+CMR9 /FontDescriptor 231 0 R /FirstChar 11 /LastChar 121 /Widths 208 0 R /ToUnicode 1 0 R >> endobj 129 0 obj << /Type /Font /Subtype /Type1 /BaseFont /BMYQUM+CMSL10 /FontDescriptor 233 0 R /FirstChar 11 /LastChar 121 /Widths 210 0 R /ToUnicode 1 0 R >> endobj 132 0 obj << /Type /Font /Subtype /Type1 /BaseFont /BFVHSQ+CMSL9 /FontDescriptor 235 0 R /FirstChar 105 /LastChar 118 /Widths 207 0 R /ToUnicode 1 0 R >> endobj 130 0 obj << /Type /Font /Subtype /Type1 /BaseFont /VLYRYV+CMSLTT10 /FontDescriptor 237 0 R /FirstChar 40 /LastChar 122 /Widths 209 0 R /ToUnicode 3 0 R >> endobj 154 0 obj << /Type /Font /Subtype /Type1 /BaseFont /FFYKXD+CMSS10 /FontDescriptor 239 0 R /FirstChar 40 /LastChar 41 /Widths 204 0 R /ToUnicode 1 0 R >> endobj 13 0 obj << /Type /Font /Subtype /Type1 /BaseFont /WCJTWI+CMSY10 /FontDescriptor 241 0 R /FirstChar 13 /LastChar 13 /Widths 215 0 R >> endobj 38 0 obj << /Type /Font /Subtype /Type1 /BaseFont /RRKLQA+CMTT10 /FontDescriptor 243 0 R /FirstChar 34 /LastChar 126 /Widths 212 0 R /ToUnicode 3 0 R >> endobj 147 0 obj << /Type /Font /Subtype /Type1 /BaseFont /PQAMIY+CMTT12 /FontDescriptor 245 0 R /FirstChar 45 /LastChar 121 /Widths 205 0 R /ToUnicode 3 0 R >> endobj 133 0 obj << /Type /Font /Subtype /Type1 /BaseFont /WJRTPN+CMTT9 /FontDescriptor 247 0 R /FirstChar 39 /LastChar 121 /Widths 206 0 R /ToUnicode 3 0 R >> endobj 9 0 obj << /Type /Pages /Count 6 /Parent 248 0 R /Kids [5 0 R 11 0 R 33 0 R 126 0 R 135 0 R 138 0 R] >> endobj 143 0 obj << /Type /Pages /Count 6 /Parent 248 0 R /Kids [141 0 R 145 0 R 149 0 R 152 0 R 156 0 R 159 0 R] >> endobj 165 0 obj << /Type /Pages /Count 6 /Parent 248 0 R /Kids [163 0 R 167 0 R 171 0 R 174 0 R 178 0 R 182 0 R] >> endobj 189 0 obj << /Type /Pages /Count 4 /Parent 248 0 R /Kids [186 0 R 192 0 R 196 0 R 200 0 R] >> endobj 248 0 obj << /Type /Pages /Count 22 /Kids [9 0 R 143 0 R 165 0 R 189 0 R] >> endobj 249 0 obj << /Type /Outlines /First 53 0 R /Last 121 0 R /Count 7 >> endobj 121 0 obj << /Title 122 0 R /A 119 0 R /Parent 249 0 R /Prev 113 0 R >> endobj 117 0 obj << /Title 118 0 R /A 115 0 R /Parent 113 0 R >> endobj 113 0 obj << /Title 114 0 R /A 111 0 R /Parent 249 0 R /Prev 89 0 R /Next 121 0 R /First 117 0 R /Last 117 0 R /Count -1 >> endobj 109 0 obj << /Title 110 0 R /A 107 0 R /Parent 89 0 R /Prev 105 0 R >> endobj 105 0 obj << /Title 106 0 R /A 103 0 R /Parent 89 0 R /Prev 101 0 R /Next 109 0 R >> endobj 101 0 obj << /Title 102 0 R /A 99 0 R /Parent 89 0 R /Prev 97 0 R /Next 105 0 R >> endobj 97 0 obj << /Title 98 0 R /A 95 0 R /Parent 89 0 R /Prev 93 0 R /Next 101 0 R >> endobj 93 0 obj << /Title 94 0 R /A 91 0 R /Parent 89 0 R /Next 97 0 R >> endobj 89 0 obj << /Title 90 0 R /A 87 0 R /Parent 249 0 R /Prev 85 0 R /Next 113 0 R /First 93 0 R /Last 109 0 R /Count -5 >> endobj 85 0 obj << /Title 86 0 R /A 83 0 R /Parent 249 0 R /Prev 77 0 R /Next 89 0 R >> endobj 81 0 obj << /Title 82 0 R /A 79 0 R /Parent 77 0 R >> endobj 77 0 obj << /Title 78 0 R /A 75 0 R /Parent 249 0 R /Prev 65 0 R /Next 85 0 R /First 81 0 R /Last 81 0 R /Count -1 >> endobj 73 0 obj << /Title 74 0 R /A 71 0 R /Parent 65 0 R /Prev 69 0 R >> endobj 69 0 obj << /Title 70 0 R /A 67 0 R /Parent 65 0 R /Next 73 0 R >> endobj 65 0 obj << /Title 66 0 R /A 63 0 R /Parent 249 0 R /Prev 53 0 R /Next 77 0 R /First 69 0 R /Last 73 0 R /Count -2 >> endobj 61 0 obj << /Title 62 0 R /A 59 0 R /Parent 53 0 R /Prev 57 0 R >> endobj 57 0 obj << /Title 58 0 R /A 55 0 R /Parent 53 0 R /Next 61 0 R >> endobj 53 0 obj << /Title 54 0 R /A 51 0 R /Parent 249 0 R /Next 65 0 R /First 57 0 R /Last 61 0 R /Count -2 >> endobj 250 0 obj << /Names [(-1) 35 0 R (1) 39 0 R (10) 48 0 R (11) 49 0 R (12) 50 0 R (13) 176 0 R] /Limits [(-1) (13)] >> endobj 251 0 obj << /Names [(14) 180 0 R (15) 184 0 R (16) 188 0 R (17) 194 0 R (18) 198 0 R (19) 202 0 R] /Limits [(14) (19)] >> endobj 252 0 obj << /Names [(2) 40 0 R (3) 41 0 R (4) 42 0 R (5) 43 0 R (6) 44 0 R (7) 45 0 R] /Limits [(2) (7)] >> endobj 253 0 obj << /Names [(8) 46 0 R (9) 47 0 R (Command properties) 116 0 R (GNU Free Documentation License) 120 0 R (Hooks) 84 0 R (Installation) 56 0 R] /Limits [(8) (Installation)] >> endobj 254 0 obj << /Names [(Keymaps) 76 0 R (Macros) 88 0 R (Modes and states) 60 0 R (Motions) 92 0 R (Operators) 96 0 R (Other internals) 112 0 R] /Limits [(Keymaps) (Other internals)] >> endobj 255 0 obj << /Names [(Overview) 52 0 R (Settings) 64 0 R (States) 108 0 R (Text objects) 100 0 R (The cursor) 68 0 R (The initial state) 72 0 R] /Limits [(Overview) (The initial state)] >> endobj 256 0 obj << /Names [(Types) 104 0 R (evil-define-key) 80 0 R] /Limits [(Types) (evil-define-key)] >> endobj 257 0 obj << /Kids [250 0 R 251 0 R 252 0 R 253 0 R 254 0 R 255 0 R] /Limits [(-1) (The initial state)] >> endobj 258 0 obj << /Kids [256 0 R] /Limits [(Types) (evil-define-key)] >> endobj 259 0 obj << /Kids [257 0 R 258 0 R] /Limits [(-1) (evil-define-key)] >> endobj 260 0 obj << /Dests 259 0 R >> endobj 261 0 obj << /Type /Catalog /Pages 248 0 R /Outlines 249 0 R /Names 260 0 R /PageMode /UseOutlines >> endobj 262 0 obj << /Producer (pdfTeX-1.40.10) /Creator (TeX) /CreationDate (D:20110802183203+02'00') /ModDate (D:20110802183203+02'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.1415926-1.40.10-2.2 (TeX Live 2009/Debian) kpathsea version 5.0.0) >> endobj xref 0 263 0000000000 65535 f 0000000015 00000 n 0000000681 00000 n 0000001358 00000 n 0000002409 00000 n 0000002305 00000 n 0000001962 00000 n 0000235197 00000 n 0000235640 00000 n 0000237366 00000 n 0000003416 00000 n 0000003309 00000 n 0000002488 00000 n 0000236743 00000 n 0000005116 00000 n 0000005242 00000 n 0000005368 00000 n 0000005495 00000 n 0000005621 00000 n 0000005747 00000 n 0000005874 00000 n 0000006000 00000 n 0000006127 00000 n 0000006253 00000 n 0000006379 00000 n 0000006506 00000 n 0000006633 00000 n 0000006759 00000 n 0000006886 00000 n 0000007013 00000 n 0000007141 00000 n 0000007269 00000 n 0000007448 00000 n 0000004871 00000 n 0000003497 00000 n 0000007397 00000 n 0000235498 00000 n 0000235356 00000 n 0000236885 00000 n 0000011822 00000 n 0000014597 00000 n 0000016582 00000 n 0000018227 00000 n 0000020009 00000 n 0000021268 00000 n 0000024255 00000 n 0000027348 00000 n 0000030355 00000 n 0000032703 00000 n 0000034370 00000 n 0000037868 00000 n 0000007564 00000 n 0000011874 00000 n 0000239491 00000 n 0000007609 00000 n 0000007636 00000 n 0000011926 00000 n 0000239417 00000 n 0000007685 00000 n 0000007716 00000 n 0000011982 00000 n 0000239343 00000 n 0000007769 00000 n 0000007804 00000 n 0000014649 00000 n 0000239218 00000 n 0000007849 00000 n 0000007876 00000 n 0000016634 00000 n 0000239144 00000 n 0000007923 00000 n 0000007952 00000 n 0000016690 00000 n 0000239070 00000 n 0000008006 00000 n 0000008042 00000 n 0000018279 00000 n 0000238945 00000 n 0000008086 00000 n 0000008112 00000 n 0000020061 00000 n 0000238884 00000 n 0000008164 00000 n 0000008198 00000 n 0000021320 00000 n 0000238796 00000 n 0000008240 00000 n 0000008264 00000 n 0000024307 00000 n 0000238669 00000 n 0000008307 00000 n 0000008332 00000 n 0000024359 00000 n 0000238595 00000 n 0000008376 00000 n 0000008402 00000 n 0000024414 00000 n 0000238507 00000 n 0000008448 00000 n 0000008476 00000 n 0000027400 00000 n 0000238417 00000 n 0000008525 00000 n 0000008557 00000 n 0000030407 00000 n 0000238325 00000 n 0000008600 00000 n 0000008625 00000 n 0000032755 00000 n 0000238247 00000 n 0000008669 00000 n 0000008695 00000 n 0000034422 00000 n 0000238116 00000 n 0000008748 00000 n 0000008783 00000 n 0000034475 00000 n 0000238051 00000 n 0000008839 00000 n 0000008877 00000 n 0000037920 00000 n 0000237972 00000 n 0000008945 00000 n 0000011504 00000 n 0000011653 00000 n 0000012038 00000 n 0000011366 00000 n 0000008995 00000 n 0000235798 00000 n 0000236098 00000 n 0000236420 00000 n 0000235939 00000 n 0000236259 00000 n 0000237206 00000 n 0000014701 00000 n 0000014487 00000 n 0000012207 00000 n 0000016745 00000 n 0000016472 00000 n 0000014844 00000 n 0000018331 00000 n 0000018115 00000 n 0000016864 00000 n 0000237477 00000 n 0000020113 00000 n 0000019897 00000 n 0000018450 00000 n 0000237045 00000 n 0000021372 00000 n 0000021156 00000 n 0000020245 00000 n 0000024470 00000 n 0000024143 00000 n 0000021478 00000 n 0000236583 00000 n 0000027456 00000 n 0000027236 00000 n 0000024602 00000 n 0000030464 00000 n 0000030243 00000 n 0000027588 00000 n 0000235037 00000 n 0000032812 00000 n 0000032591 00000 n 0000030596 00000 n 0000237594 00000 n 0000034532 00000 n 0000034258 00000 n 0000032931 00000 n 0000037723 00000 n 0000037973 00000 n 0000037591 00000 n 0000034677 00000 n 0000041262 00000 n 0000041097 00000 n 0000038091 00000 n 0000041209 00000 n 0000044487 00000 n 0000044322 00000 n 0000041332 00000 n 0000044434 00000 n 0000047325 00000 n 0000047160 00000 n 0000044557 00000 n 0000047272 00000 n 0000050214 00000 n 0000050049 00000 n 0000047395 00000 n 0000050161 00000 n 0000237711 00000 n 0000055822 00000 n 0000053299 00000 n 0000053134 00000 n 0000050284 00000 n 0000053246 00000 n 0000056035 00000 n 0000055690 00000 n 0000053369 00000 n 0000055982 00000 n 0000057695 00000 n 0000057530 00000 n 0000056117 00000 n 0000057642 00000 n 0000057802 00000 n 0000058254 00000 n 0000058285 00000 n 0000058766 00000 n 0000059117 00000 n 0000059210 00000 n 0000059863 00000 n 0000060214 00000 n 0000060833 00000 n 0000060864 00000 n 0000061255 00000 n 0000061280 00000 n 0000061303 00000 n 0000061327 00000 n 0000061959 00000 n 0000062488 00000 n 0000071231 00000 n 0000071479 00000 n 0000088207 00000 n 0000088583 00000 n 0000095554 00000 n 0000095781 00000 n 0000102753 00000 n 0000102980 00000 n 0000127680 00000 n 0000128217 00000 n 0000135369 00000 n 0000135593 00000 n 0000150241 00000 n 0000150558 00000 n 0000163784 00000 n 0000164070 00000 n 0000171315 00000 n 0000171537 00000 n 0000184864 00000 n 0000185195 00000 n 0000192330 00000 n 0000192568 00000 n 0000199620 00000 n 0000199853 00000 n 0000216446 00000 n 0000216860 00000 n 0000220434 00000 n 0000220675 00000 n 0000234654 00000 n 0000237812 00000 n 0000237896 00000 n 0000239603 00000 n 0000239727 00000 n 0000239857 00000 n 0000239973 00000 n 0000240163 00000 n 0000240354 00000 n 0000240550 00000 n 0000240659 00000 n 0000240773 00000 n 0000240848 00000 n 0000240928 00000 n 0000240966 00000 n 0000241075 00000 n trailer << /Size 263 /Root 261 0 R /Info 262 0 R /ID [<34FBE5ACE61D81D8FF495F1FE06C8596> <34FBE5ACE61D81D8FF495F1FE06C8596>] >> startxref 241342 %%EOF evil-1.12.17/doc/evil.texi000066400000000000000000000566531360703323200152370ustar00rootroot00000000000000\input texinfo @c -*-texinfo-*- @setfilename evil.info @documentencoding ISO-8859-1 @include version.texi @settitle Evil-mode manual @include macros.texi @copying This manual is for Evil (version @value{VERSION} of @value{UPDATED}), an extensible vi layer for Emacs. Copyright @copyright{} 2011 @authors{}. @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. @end quotation The Evil team thanks everyone at gmane.emacs.vim-emulation for their feedback and contributions. @end copying @dircategory Emacs @direntry * Evil: (evil). Extensible vi layer for Emacs. @end direntry @titlepage @title Evil @subtitle Extensible vi layer for Emacs @author @authors{} @page @insertcopying @end titlepage @contents @ifnottex @node Top, Overview, (dir), (dir) @top Evil This is the manual for Evil, an extensible vi layer for Emacs. @end ifnottex @menu * Overview:: * Settings:: * Keymaps:: * Hooks:: * Macros:: * Other internals:: * GNU Free Documentation License:: @end menu @node Overview @chapter Overview Evil is an extensible vi layer for Emacs. It emulates the main features of Vim,@footnote{Vim is the most popular version of @dfn{vi}, a modal text editor with many implementations. Vim also adds some functions of its own, like Visual selection and text objects. For more information, see: @uref{http://www.vim.org/}} turning Emacs into a modal editor. Like Emacs in general, Evil is extensible in Emacs Lisp. @menu * Installation:: * Modes and states:: @end menu @node Installation @section Installation Evil lives in a Git repository. To download Evil, do: @example git clone https://github.com/emacs-evil/evil.git @end example @noindent Move Evil to @code{~/.emacs.d/evil}. Then add the following lines to @code{~/.emacs}: @lisp (add-to-list 'load-path "~/.emacs.d/evil") (require 'evil) (evil-mode 1) @end lisp @noindent Evil requires @code{undo-tree.el} to provide linear undo and undo branches. It is available from EmacsWiki.@footnote{@uref{http://www.emacswiki.org/emacs/UndoTree}} (A copy of @code{undo-tree.el} is also included in the Git repository.) @node Modes and states @section Modes and states The next time Emacs is started, it will come up in @dfn{Normal state}, denoted by @code{} on the mode line. This is where the main vi bindings are defined. Note that you can always disable Normal state with @kbd{C-z}, which switches to an ``Emacs state'' (denoted by @code{}) in which vi keys are completely disabled. Press @kbd{C-z} again to switch back to Normal state. Evil uses the term @dfn{state} for what is called a ``mode'' in vi, since ``mode'' already has its own meaning in Emacs. Evil defines a number of states, such as Normal state (@code{}), Insert state (@code{}), Visual state (@code{}), Replace state (@code{}), Operator-Pending state (@code{}), Motion state (@code{}) and Emacs state (@code{}). Each state has its own keymaps and customization variables. Meanwhile, a @dfn{mode} in Emacs is a set of key bindings for editing a certain sort of text, like @code{emacs-lisp-mode} for Emacs Lisp. Modes may include custom bindings for Evil states. @node Settings @chapter Settings Evil's behavior can be adjusted by setting various variables. The current values may be inspected by doing @kbd{M-x customize-group RET evil RET}. To change the value of a variable, add a @samp{setq} form to @code{~/.emacs}, preferably before Evil is loaded:@footnote{Strictly speaking, the order only matters if the variable affects the way Evil is loaded. This is the case with some of the @samp{evil-want-} variables.} @lisp (setq evil-shift-width 8) ;; @r{Load Evil} (require 'evil) @r{@dots{}} @end lisp @noindent Note that if a variable is buffer-local, you must use @samp{setq-default} instead of @samp{setq} to change its global value. @defvar evil-auto-indent Whether the current line is indented when entering Insert state. If @code{t} (the default), then the line is indented. If @code{nil}, then the line is not indented. Buffer-local. @end defvar @defvar evil-shift-width The number of columns a line is shifted by the commands @kbd{>} and @kbd{<}. @end defvar @defvar evil-repeat-move-cursor If @code{t} (the default), then repeating a command with @kbd{.} may change the position of the cursor. If @code{nil}, then the original position is preserved. @end defvar @defvar evil-find-skip-newlines If @code{t}, then @kbd{f}, @kbd{F}, @kbd{t} and @kbd{T} may skip over newlines to find a character. If @code{nil} (the default), then they are restricted to the current line. @end defvar @defvar evil-move-cursor-back If @code{t} (the default), then the cursor moves backwards when exiting Insert state. If @code{nil}, then the cursor does not move. @end defvar @defvar evil-want-fine-undo If @code{t}, then a change-based action like @kbd{cw} may be undone in several steps. If @code{nil} (the default), then it is undone in one step. @end defvar @defvar evil-regexp-search If @code{t} (the default), then @kbd{/} and @kbd{?} use regular expressions for searching. If @code{nil}, they use plain text. @end defvar @defvar evil-search-wrap If @code{t} (the default), then @kbd{/} and @kbd{?} wrap the search around the buffer. If @code{nil}, then they stop at buffer boundaries. @end defvar @defvar evil-flash-delay The number of seconds to flash search matches when pressing @kbd{n} and @kbd{N}. @end defvar @defvar evil-want-C-i-jump If @code{t} (the default), then @kbd{C-i} jumps forwards in the jump list. If @code{nil}, then @kbd{C-i} inserts a tab. @end defvar @defvar evil-want-C-u-scroll If @code{t}, then @kbd{C-u} scrolls the buffer. If @code{nil} (the default), then @kbd{C-u} begins a numeric prefix argument. @end defvar @menu * The cursor:: * The initial state:: @end menu @node The cursor @section The cursor A state may change the cursor's appearance. The cursor settings are stored in the variables below, which may contain a cursor type as per the @samp{cursor-type} variable, a color string as passed to the @samp{set-cursor-color} function, a zero-argument function for changing the cursor, or a list of the above. For example, the following changes the cursor in Replace state to a red box: @lisp (setq evil-replace-state-cursor '("red" box)) @end lisp @noindent If the state does not specify a cursor, @samp{evil-default-cursor} is used. @defvar evil-default-cursor The default cursor. @end defvar @defvar evil-normal-state-cursor The cursor for Normal state. @end defvar @defvar evil-insert-state-cursor The cursor for Insert state. @end defvar @defvar evil-visual-state-cursor The cursor for Visual state. @end defvar @defvar evil-replace-state-cursor The cursor for Replace state. @end defvar @defvar evil-operator-state-cursor The cursor for Operator-Pending state. @end defvar @defvar evil-motion-state-cursor The cursor for Motion state. @end defvar @defvar evil-emacs-state-cursor The cursor for Emacs state. @end defvar @node The initial state @section The initial state By default, a new buffer comes up in Normal state. This can be changed with the function @samp{evil-set-initial-state}. @defun evil-set-initial-state mode state Set the initial state for a buffer in which @var{mode} is active to @var{state}. @var{mode} should be a major mode such as @code{text-mode}, although minor modes work as well. @end defun @node Keymaps @chapter Keymaps Evil's key bindings are stored in a number of keymaps. Each state has a @dfn{global keymap}, where the default key bindings for the state are stored. For example, the global keymap for Normal state is @samp{evil-normal-state-map}, and the key bindings in this map are seen in all buffers that are currently in Normal state. Keymaps are modified with the Emacs function @samp{define-key}: @lisp (define-key evil-normal-state-map "w" 'foo) @end lisp @noindent This binds the key @kbd{w} to the command @samp{foo} in Normal state. The file @code{evil-maps.el} contains all the key bindings. @defvar evil-normal-state-map The global keymap for Normal state. @end defvar @defvar evil-insert-state-map The global keymap for Insert state. @end defvar @defvar evil-visual-state-map The global keymap for Visual state. @end defvar @defvar evil-replace-state-map The global keymap for Replace state. @end defvar @defvar evil-operator-state-map The global keymap for Operator-Pending state. @end defvar @defvar evil-motion-state-map The global keymap for Motion state. @end defvar @noindent Each state also has a @dfn{buffer-local keymap}, which is specific to the current buffer and has precedence over the global keymap. These maps may be changed from a mode hook. @defvar evil-normal-state-local-map Buffer-local keymap for Normal state. @end defvar @defvar evil-insert-state-local-map Buffer-local keymap for Insert state. @end defvar @defvar evil-visual-state-local-map Buffer-local keymap for Visual state. @end defvar @defvar evil-replace-state-local-map Buffer-local keymap for Replace state. @end defvar @defvar evil-operator-state-local-map Buffer-local keymap for Operator-Pending state. @end defvar @defvar evil-motion-state-local-map Buffer-local keymap for Motion state. @end defvar @menu * @samp{evil-define-key}:: @end menu @node @samp{evil-define-key} @section @samp{evil-define-key} Finally, Evil provides the function @samp{evil-define-key} for adding state bindings to a regular keymap. @defun evil-define-key state keymap key def In @var{keymap}, create a binding from @var{key} to @var{def} in @var{state}. @var{state} is one of @samp{normal}, @samp{insert}, @samp{visual}, @samp{replace}, @samp{operator} and @samp{motion}. The other parameters are like those of @samp{define-key}. @end defun @noindent @samp{evil-define-key} can be used to augment existing modes with state bindings, as well as create packages for custom bindings. For example, the following will create a minor mode @code{foo-mode} with Normal state bindings for the keys @kbd{w} and @kbd{e}: @lisp (define-minor-mode foo-mode "Foo mode." :keymap (make-sparse-keymap)) (evil-define-key 'normal foo-mode-map "w" 'bar) (evil-define-key 'normal foo-mode-map "e" 'baz) @end lisp @noindent This minor mode can then be enabled in any buffers where the custom bindings are desired: @lisp (add-hook 'text-mode-hook 'foo-mode) ; @r{enable alongside @code{text-mode}} @end lisp @noindent If the minor mode is put into its own file @code{foo.el} with a @code{(provide 'foo)} statement, it becomes an Emacs package. @node Hooks @chapter Hooks A @dfn{hook} is a list of functions to execute. Hooks are modified with the Emacs function @samp{add-hook}. Evil provides entry and exit hooks for all of its states. @defvar evil-normal-state-entry-hook Run when entering Normal state. @end defvar @defvar evil-normal-state-exit-hook Run when exiting Normal state. @end defvar @defvar evil-insert-state-entry-hook Run when entering Insert state. @end defvar @defvar evil-insert-state-exit-hook Run when exiting Insert state. @end defvar @defvar evil-visual-state-entry-hook Run when entering Visual state. @end defvar @defvar evil-visual-state-exit-hook Run when exiting Visual state. @end defvar @defvar evil-replace-state-entry-hook Run when entering Replace state. @end defvar @defvar evil-replace-state-exit-hook Run when exiting Replace state. @end defvar @defvar evil-operator-state-entry-hook Run when entering Operator-Pending state. @end defvar @defvar evil-operator-state-exit-hook Run when exiting Operator-Pending state. @end defvar @defvar evil-motion-state-entry-hook Run when entering Motion state. @end defvar @defvar evil-motion-state-exit-hook Run when exiting Motion state. @end defvar @noindent When these hooks are run, the variables @samp{evil-next-state} and @samp{evil-previous-state} hold information about the states being switched to and from. @defvar evil-next-state The state being switched to. @end defvar @defvar evil-previous-state The state being switched from. @end defvar @node Macros @chapter Macros Evil is implemented in terms of reusable macros. Package writers can use these to define new commands. @menu * Motions:: * Operators:: * Text objects:: * Types:: * States:: @end menu @node Motions @section Motions A @dfn{motion} is a command which moves the cursor, such as @kbd{w} and @kbd{e}. Motions are defined with the macro @samp{evil-define-motion}. Motions not defined in this way should be declared with @samp{evil-declare-motion}. @defun evil-declare-motion command Declare @var{command} to be a motion. This ensures that it works properly in Visual state. @end defun @defmac evil-define-motion motion (count args@dots{}) doc keyword-args@dots{} body@dots{} Define a movement command @var{motion}. A motion can have any number of arguments, but the first argument, if any, has a predefined meaning as the @var{count}. It is a positive or negative number, or @code{nil}. The argument list is followed by the documentation string @var{doc}, which is followed by optional keyword arguments: @table @code @item :type @var{type} The @var{type} determines how the motion works after an operator. If @var{type} is @samp{inclusive}, then the ending position is included in the motion range. If @var{type} is @samp{line}, then the range is expanded to linewise positions. If @var{type} is @samp{block}, then the range is blockwise. The default is @samp{exclusive}, which means that the range is used as-is. @item :jump @var{jump} If @var{jump} is @code{t}, then the previous position is stored in the jump list so it can be restored with @kbd{C-o}. The default is @code{nil}. @end table The keyword arguments are followed by the @var{body}, which is where the motion's behavior is defined. For instance: @lisp (evil-define-motion foo-forward (count) "Move to the right by COUNT characters." :type inclusive (forward-char (or count 1))) @end lisp For more examples, you can view the source code for any command with @kbd{C-h k}. For instance, @samp{evil-goto-line} may be viewed by typing @kbd{C-h k G} and following the file link. @end defmac @node Operators @section Operators An @dfn{operator} is a command which acts on the text moved over by a motion, such as @kbd{c}, @kbd{d} and @kbd{y}. Operators are defined with the macro @samp{evil-define-operator}. @defmac evil-define-operator operator (beg end type args@dots{}) doc keyword-args@dots{} body@dots{} Define an operator command @var{operator}. An operator must have at least two or three arguments, which have predefined meanings. @var{beg} is the beginning position, @var{end} is the ending position, and @var{type}, if given, is the type of the motion range. The argument list is followed by the documentation string @var{doc}, which is followed by optional keyword arguments: @table @code @item :type @var{type} Make the input range be a certain @var{type}. For example, an operator which only works with whole lines may set @var{type} to @samp{line}. @item :motion @var{motion} Use the motion @var{motion} instead of reading one from the keyboard. This does not affect the behavior in Visual state, where the selection boundaries are used instead. @item :repeat @var{repeat} If @var{repeat} is @code{t} (the default), then @kbd{.} will repeat the operator. If @var{repeat} is @code{nil}, then the operator will not be repeated. @item :move-point @var{move-point} If @var{move-point} is @code{t} (the default), then the cursor is positioned at the beginning of the range. If @var{move-point} is @code{nil}, then the original position is preserved. @item :keep-visual @var{keep-visual} If @var{keep-visual} is @code{t}, then the selection is not disabled when the operator is run in Visual state; it is up to the operator to do this. The default is @code{nil}, which means that Visual state is exited automatically. @end table The keyword arguments are followed by the @var{body}, which is where the operator's actions on @var{beg} and @var{end} are defined. For example, @samp{evil-rot13}, which is bound to @kbd{g?} and performs ROT13 encryption on the text, may be defined as: @lisp (evil-define-operator evil-rot13 (beg end) "ROT13 encrypt text." (rot13-region beg end)) @end lisp Pressing @kbd{g?w} will encrypt a word by calling @samp{rot13-region} on the text moved over by the @kbd{w} motion. @end defmac @node Text objects @section Text objects A @dfn{text object} is a special kind of motion which sets a beginning position as well as an ending position, such as @kbd{iw} and @kbd{a(}. In Visual state, text objects alter both ends of the selection. Text objects are defined with the macro @samp{evil-define-text-object}. @defmac evil-define-text-object object (count args@dots{}) doc keyword-args@dots{} body@dots{} Define a text object @var{object}. The first argument has a predefined meaning as the @var{count}: it is a positive or negative number. The argument list is followed by the documentation string @var{doc}, which is followed by optional keyword arguments: @table @code @item :type @var{type} Use the type @var{type} after an operator. In Visual state, this is the type of the selection. @item :extend-selection @var{extend-selection} If @var{extend-selection} is @code{t} (the default), then the text object always enlarges the current selection. If @code{nil}, then the object replaces the selection. @end table The keyword arguments are followed by the @var{body}, which should evaluate to a list @code{(@var{beg} @var{end})} of two positions in the buffer. For example, a text object which selects three characters following the current position could be defined as: @lisp (evil-define-text-object foo (count) "Select three characters." (list (point) (+ (point) 3))) @end lisp @end defmac @noindent Evil provides several functions which return a list of positions, for use in the definition of a text object. These functions follow the rule that a positive @var{count} selects text after the current position, while a negative @var{count} selects text before it. @defun evil-inner-object-range count forward backward Return a text range @code{(@var{beg} @var{end})} of @var{count} ``inner'' text objects (e.g., @kbd{iw}, @kbd{is}). @var{forward} is a function which moves to the end of an object, and @var{backward} is a function which moves to the beginning. @end defun @defun evil-an-object-range count forward backward Return a text range @code{(@var{beg} @var{end})} of @var{count} text objects with whitespace (e.g., @kbd{aw}, @kbd{as}). @var{forward} is a function which moves to the end of an object, and @var{backward} is a function which moves to the beginning. @end defun @defun evil-paren-range count open close &optional exclusive Return a text range @code{(@var{beg} @var{end})} of @var{count} delimited blocks (e.g., @kbd{i(}, @kbd{a(}). @var{open} and @var{close} are characters. If @var{exclusive} is non-nil, then the delimiters are excluded from the range. This function uses Emacs' syntax table and is only applicable for single-character delimiters; use @samp{evil-regexp-range} to match multiple characters. @end defun @defun evil-regexp-range count open close &optional exclusive Return a text range @code{(@var{beg} @var{end})} of @var{count} delimited blocks (e.g., @kbd{it}, @kbd{at}). @var{open} and @var{close} are regular expressions. If @var{exclusive} is non-nil, then the delimiters are excluded from the range. @end defun @node Types @section Types A @dfn{type} is a transformation on a pair of buffer positions. Evil defines the types @samp{exclusive}, @samp{inclusive}, @samp{line} and @samp{block}, which are used for motion ranges and Visual selection. Types are defined with the macro @samp{evil-define-type}. @defmac evil-define-type type doc keyword-args@dots{} Define a type @var{type}, described by the documentation string @var{doc}. Then follows keyword arguments: @table @code @item :expand @var{expand} A function which takes two buffer positions and returns a list @code{(@var{beg} @var{end})} of expanded positions. @item :contract @var{contract} A function which takes two expanded buffer positions and returns a list @code{(@var{beg} @var{end})} of unexpanded positions. Optional. @item :normalize @var{normalize} A function which takes two unexpanded buffer positions and returns a list @code{(@var{beg} @var{end})} of adjusted positions. Optional. @item :injective @var{injective} If @code{t} (the default), then expansion is one-to-one -- i.e., @var{expand} followed by @var{contract} always returns the original positions. If @code{nil}, then several positions may expand to the same (for example, the @samp{line} type is one-to-many as it expands to the containing lines). @end table Further keywords and functions may be specified. These are understood to be transformations on buffer positions, like @var{expand} and @var{contract}. @end defmac @node States @section States States are defined with the macro @samp{evil-define-state}. The macro defines the necessary hooks, keymaps and variables for a state, as well as a toggle function @samp{evil-@var{state}-state} for entering the state, and a predicate function @samp{evil-@var{state}-state-p} which returns @code{t} when the state is active, and @code{nil} otherwise. @defmac evil-define-state state doc keyword-args@dots{} body@dots{} Define an Evil state @var{state}, described by the documentation string @var{doc}. Then follows optional keyword arguments: @table @code @item :tag @var{tag} Mode line indicitor, e.g., @code{""}. @item :message @var{message} String shown in the echo area. @item :cursor @var{cursor} Cursor specification. @item :enable @var{enable} List of other modes and states to enable. A state may enable another state's keymaps in addition to its own. @end table This is followed the @var{body}, which is executed whenever the state is enabled or disabled. The state's predicate function may be used to distinguish between the two. @end defmac @node Other internals @chapter Other internals @menu * Command properties:: @end menu @node Command properties @section Command properties Evil defines @dfn{command properties} to store information about commands, such as whether they should be repeated. A command property is a @code{@var{:keyword}} with an associated value, e.g., @code{:repeat nil}. @defun evil-add-command-properties command &rest properties Add @var{properties} to @var{command}. The properties should be specified as a list of keywords and values: @lisp (evil-add-command-properties 'my-command :repeat t) @end lisp @end defun @defun evil-set-command-properties command &rest properties Like @samp{evil-add-command-properties}, but resets all previous properties. @end defun @defun evil-get-command-property command property Return the value of a command property. @end defun @defmac evil-define-command command (args@dots{}) doc keyword-args@dots{} body@dots{} Define a command with command properties @var{keyword-args}. @end defmac @noindent For setting repeat properties, Evil provides the following functions: @defun evil-declare-repeat command Declare @var{command} to be repeatable. @end defun @defun evil-declare-not-repeat command Declare @var{command} to be nonrepeatable. @end defun @defun evil-declare-change-repeat command Declare @var{command} to be repeatable by buffer changes rather than keystrokes. @end defun @node GNU Free Documentation License @appendix GNU Free Documentation License @include fdl-1.3.texi @bye @c Local Variables: @c mode: texinfo @c TeX-master: t @c sentence-end-double-space: t @c End: evil-1.12.17/doc/fdl-1.3.texi000066400000000000000000000556061360703323200153410ustar00rootroot00000000000000@c The GNU Free Documentation License. @center Version 1.3, 3 November 2008 @c This file is intended to be included within another document, @c hence no sectioning command or @node. @display Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. @uref{http://fsf.org/} Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @end display @enumerate 0 @item PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document @dfn{free} in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of ``copyleft'', which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. @item APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The ``Document'', below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as ``you''. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A ``Modified Version'' of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A ``Secondary Section'' is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The ``Invariant Sections'' are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The ``Cover Texts'' are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A ``Transparent'' copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not ``Transparent'' is called ``Opaque''. Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, La@TeX{} input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The ``Title Page'' means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, ``Title Page'' means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. The ``publisher'' means any person or entity that distributes copies of the Document to the public. A section ``Entitled XYZ'' means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as ``Acknowledgements'', ``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title'' of such a section when you modify the Document means that it remains a section ``Entitled XYZ'' according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. @item VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. @item COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. @item MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: @enumerate A @item Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. @item List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. @item State on the Title page the name of the publisher of the Modified Version, as the publisher. @item Preserve all the copyright notices of the Document. @item Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. @item Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. @item Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. @item Include an unaltered copy of this License. @item Preserve the section Entitled ``History'', Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled ``History'' in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. @item Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the ``History'' section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. @item For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. @item Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. @item Delete any section Entitled ``Endorsements''. Such a section may not be included in the Modified Version. @item Do not retitle any existing section to be Entitled ``Endorsements'' or to conflict in title with any Invariant Section. @item Preserve any Warranty Disclaimers. @end enumerate If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled ``Endorsements'', provided it contains nothing but endorsements of your Modified Version by various parties---for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. @item COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled ``History'' in the various original documents, forming one section Entitled ``History''; likewise combine any sections Entitled ``Acknowledgements'', and any sections Entitled ``Dedications''. You must delete all sections Entitled ``Endorsements.'' @item COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. @item AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an ``aggregate'' if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. @item TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled ``Acknowledgements'', ``Dedications'', or ``History'', the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. @item TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License. However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it. @item FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See @uref{http://www.gnu.org/copyleft/}. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License ``or any later version'' applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Document. @item RELICENSING ``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A ``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the site means any set of copyrightable works thus published on the MMC site. ``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization. ``Incorporate'' means to publish or republish a Document, in whole or in part, as part of another Document. An MMC is ``eligible for relicensing'' if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008. The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing. @end enumerate @page @heading ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: @smallexample @group Copyright (C) @var{year} @var{your name}. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. @end group @end smallexample If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the ``with@dots{}Texts.'' line with this: @smallexample @group with the Invariant Sections being @var{list their titles}, with the Front-Cover Texts being @var{list}, and with the Back-Cover Texts being @var{list}. @end group @end smallexample If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. @c Local Variables: @c ispell-local-pdict: "ispell-dict" @c End: evil-1.12.17/doc/front.png000066400000000000000000000062721360703323200152330ustar00rootroot00000000000000PNG  IHDRf9NPLTE!!!111911B11J11R11Z11ZB111999911BBBBJJJ11RRRR11Z1BZZZZ1JcZckZcs1J5ZZc{Zg1R1Z1c1ccJ1ccccckckkkckkkkccsckscc{kk{Zkkc]kckkcZkyPH{gosc{e~wk{kskskaVksk{kk9k)k9kJJsk{sksss{s{gw{{{^umx{ssk{s{o{stnox=ފc}Ğ~㷇{ɺS|c}imiz膸ބ󱱱ӕΥk)s)k1o5{){1)1kBkJs={BsJsVscxm159JBBBO^ZZZkhuބΌ֌ތΔ֔֔ޔέ֭֜ޜֵֵۭ޽޽@;tRNSS% pHYs B4tIME$hgAIDATx lSUQO" *Tt@WSdl`ձnh1c&0g*!$b%LL!JR z{}}̠{${wι޾uv t#Xb` #V `MKX(V6%H8,"&X1QH:K,`'IK.DGQVRrqqgREur4_tmK\d`1e$+,A<׎tEAQִ`PD*A#!d(>02#a;b !Pڋ.9Nb w?bE t+5p|߸\:eF,°ڋE=#Y@`IgUUb% 6Be aԓ),Xr%HMA*b}Ϳda8:RrAaa#fCa1E"Zp-Z!pF̡l 3,xlI]  G @vXT:g] ֺdvՑ7ϱ"U,N*lRH41E,ra[|ɦEX,a7*ɦEXM"]K&$&S,Xd$Vb6Qg-dE+1J$Xz!t%,wtvHbZperZpe+ W~$k,%7z:?\IXFX5ʑ8s A;U() K% {, Q%ay Ha10rlM E]a +_2‚G]eUQ]a\Ж gݦ%E``F@7q*IT, `!X`!X`@`!X`!X`!XB, B_XDJi9T[C]Łl/!hXўX֚Ӈ?=l](.@3"u1BÈ =3i}:L7u.eH5RHgcek 1FmfFWI /RkFBm@@s-|r`00::B"Tp8tm7nDNN222 @1&BZvBׯ188(//SH ͛ػw/nݺ^D2}LP M###~:̙/M\tש$/rl6tww?tuu1_AvZLJhӧwʕ+qaړ /jAԸ\.\v Z===\pQQQհJBMM |rد QPP0twwjm?{,8IBOvYNgcӦMXp>)))8ur92J+V@&̭4_B755Q1 RGEQQ~0 N qEf?gh42ŊD"憅(((@||<,YL)_Ь-`V$WXR:33̰8)!!Sn%UFXZ Famnn)]z!SX,֭[Jf0^V{{;~GD$4G9rI|ٷ$c۶m̱---n2<~8m@ $4/hZ̚5f *JN$4/HR^F#"2$ݻN'%d2lBKB\իWz-Ŀ} )]Ӣ/Hx9˙;w.3͆W^V@ ###~CիpJ^6 ۷og^&8ДrH صkU&СAIIOHP :H$ڿ?U" Zy_ZZI^R ΁8/_|$tIOODӲ2H > image/svg+xml EVIL evil-1.12.17/doc/macros.texi000066400000000000000000000004011360703323200155400ustar00rootroot00000000000000@c -*-texinfo-*- @c This is part of the Evil manual. @c Copyright (C) 2011 Frank Fischer and Vegard ye. @c See the file evil.texi for copying conditions. @ifclear macros @set macros @macro authors {} Frank Fischer and Vegard ye @end macro @end ifclear evil-1.12.17/doc/version.texi000066400000000000000000000003061360703323200157450ustar00rootroot00000000000000@c -*-texinfo-*- @c This is part of the Evil manual. @c Copyright (C) 2011 Frank Fischer and Vegard Øye. @c See the file evil.texi for copying conditions. @set VERSION 0.1 @set UPDATED 2011-07-30 evil-1.12.17/evil-command-window.el000066400000000000000000000154531360703323200170330ustar00rootroot00000000000000;;; evil-command-window.el --- Evil command line window implementation ;; Author: Emanuel Evans ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . ;;; Commentary: ;; This provides an implementation of the vim command line window for ;; editing and repeating past ex commands and searches. ;;; Code: (require 'evil-vars) (require 'evil-common) (require 'evil-search) (require 'evil-ex) (defvar evil-search-module) (define-derived-mode evil-command-window-mode fundamental-mode "Evil-cmd" "Major mode for the Evil command line window." (auto-fill-mode 0) (setq-local after-change-functions (cons 'evil-command-window-draw-prefix after-change-functions))) (defun evil-command-window (hist cmd-key execute-fn) "Open a command line window for HIST with CMD-KEY and EXECUTE-FN. HIST should be a list of commands. CMD-KEY should be the string of the key whose history is being shown (one of \":\", \"/\", or \"?\"). EXECUTE-FN should be a function of one argument to execute on the result that the user selects." (when (eq major-mode 'evil-command-window-mode) (user-error "Cannot recursively open command line window")) (dolist (win (window-list)) (when (equal (buffer-name (window-buffer win)) "*Command Line*") (kill-buffer (window-buffer win)) (delete-window win))) (split-window nil (unless (zerop evil-command-window-height) evil-command-window-height) 'above) (setq evil-command-window-current-buffer (current-buffer)) (ignore-errors (kill-buffer "*Command Line*")) (switch-to-buffer "*Command Line*") (setq-local evil-command-window-execute-fn execute-fn) (setq-local evil-command-window-cmd-key cmd-key) (evil-command-window-mode) (evil-command-window-insert-commands hist)) (defun evil-command-window-ex (&optional current-command) "Open a command line window for editing and executing ex commands. If CURRENT-COMMAND is present, it will be inserted under the cursor as the current command to be edited." (interactive) (evil-command-window (cons (or current-command "") evil-ex-history) ":" 'evil-command-window-ex-execute)) (defun evil-command-window-execute () "Execute the command under the cursor in the appropriate buffer. The local var `evil-command-window-execute-fn' determines which function to execute." (interactive) (let ((result (buffer-substring (line-beginning-position) (line-end-position))) (execute-fn evil-command-window-execute-fn) (command-window (get-buffer-window))) (select-window (previous-window)) (unless (equal evil-command-window-current-buffer (current-buffer)) (user-error "Originating buffer is no longer active")) (kill-buffer "*Command Line*") (delete-window command-window) (funcall execute-fn result) (setq evil-command-window-current-buffer nil))) (defun evil-command-window-ex-execute (result) "Execute RESULT as an ex command in the appropriate buffer." (unless (string-match-p "^ *$" result) (unless (equal result (car evil-ex-history)) (setq evil-ex-history (cons result evil-ex-history))) (let ((evil-ex-current-buffer evil-command-window-current-buffer)) (evil-ex-execute result)))) (defun evil-command-window-search-forward () "Open a command line window for forward searches." (interactive) (evil-command-window (cons "" (if (eq evil-search-module 'evil-search) evil-ex-search-history evil-search-forward-history)) "/" (lambda (result) (evil-command-window-search-execute result t)))) (defun evil-command-window-search-backward () "Open a command line window for backward searches." (interactive) (evil-command-window (cons "" (if (eq evil-search-module 'evil-search) evil-ex-search-history evil-search-backward-history)) "?" (lambda (result) (evil-command-window-search-execute result nil)))) (defun evil-command-window-search-execute (result forward) "Search for RESULT using FORWARD to determine direction." (unless (zerop (length result)) (if (eq evil-search-module 'evil-search) (progn (setq evil-ex-search-pattern (evil-ex-make-search-pattern result) evil-ex-search-direction (if forward 'forward 'backward)) (unless (equal result (car-safe evil-ex-search-history)) (push result evil-ex-search-history)) (evil-ex-search)) (if forward (unless (equal result (car-safe evil-search-forward-history)) (push result evil-search-forward-history)) (unless (equal result (car-safe evil-search-backward-history)) (push result evil-search-backward-history))) (evil-search result forward evil-regexp-search)))) (defun evil-command-window-draw-prefix (&rest ignored) "Display `evil-command-window-cmd-key' as a prefix to the current line. Parameters passed in through IGNORED are ignored." (let ((prefix (propertize evil-command-window-cmd-key 'font-lock-face 'minibuffer-prompt))) (set-text-properties (line-beginning-position) (line-beginning-position 2) (list 'line-prefix prefix)))) (defun evil-command-window-insert-commands (hist) "Insert the commands in HIST." (let ((inhibit-modification-hooks t)) (mapc #'(lambda (cmd) (insert cmd) (newline)) hist) (reverse-region (point-min) (point-max))) (let ((prefix (propertize evil-command-window-cmd-key 'font-lock-face 'minibuffer-prompt))) (set-text-properties (point-min) (point-max) (list 'line-prefix prefix))) (goto-char (point-max)) (when (and (bolp) (not (bobp))) (backward-char)) (evil-adjust-cursor)) (provide 'evil-command-window) ;;; evil-command-window.el ends here evil-1.12.17/evil-commands.el000066400000000000000000005174641360703323200157220ustar00rootroot00000000000000;;; evil-commands.el --- Evil commands and operators ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . (require 'evil-common) (require 'evil-digraphs) (require 'evil-search) (require 'evil-ex) (require 'evil-types) (require 'evil-command-window) (require 'evil-jumps) (require 'flyspell) (require 'cl-lib) (require 'reveal) ;;; Motions ;; Movement commands, or motions, are defined with the macro ;; `evil-define-motion'. A motion is a command with an optional ;; argument COUNT (interactively accessed by the code ""). ;; It may specify the :type command property (e.g., :type line), ;; which determines how it is handled by an operator command. ;; Furthermore, the command must have the command properties ;; :keep-visual t and :repeat motion; these are automatically ;; set by the `evil-define-motion' macro. ;;; Code: (evil-define-motion evil-forward-char (count &optional crosslines noerror) "Move cursor to the right by COUNT characters. Movement is restricted to the current line unless CROSSLINES is non-nil. If NOERROR is non-nil, don't signal an error upon reaching the end of the line or the buffer; just return nil." :type exclusive (interactive "" (list evil-cross-lines (evil-kbd-macro-suppress-motion-error))) (cond (noerror (condition-case nil (evil-forward-char count crosslines nil) (error nil))) ((not crosslines) ;; for efficiency, narrow the buffer to the projected ;; movement before determining the current line (evil-with-restriction (point) (save-excursion (evil-forward-char (1+ (or count 1)) t t) (point)) (condition-case err (evil-narrow-to-line (evil-forward-char count t noerror)) (error ;; Restore the previous command (this one never happend). ;; Actually, this preserves the current column if the ;; previous command was `evil-next-line' or ;; `evil-previous-line'. (setq this-command last-command) (signal (car err) (cdr err)))))) (t (evil-motion-loop (nil (or count 1)) (forward-char) ;; don't put the cursor on a newline (when (and (not evil-move-beyond-eol) (not (evil-visual-state-p)) (not (evil-operator-state-p)) (eolp) (not (eobp)) (not (bolp))) (forward-char)))))) (evil-define-motion evil-backward-char (count &optional crosslines noerror) "Move cursor to the left by COUNT characters. Movement is restricted to the current line unless CROSSLINES is non-nil. If NOERROR is non-nil, don't signal an error upon reaching the beginning of the line or the buffer; just return nil." :type exclusive (interactive "" (list evil-cross-lines (evil-kbd-macro-suppress-motion-error))) (cond (noerror (condition-case nil (evil-backward-char count crosslines nil) (error nil))) ((not crosslines) ;; restrict movement to the current line (evil-with-restriction (save-excursion (evil-backward-char (1+ (or count 1)) t t) (point)) (1+ (point)) (condition-case err (evil-narrow-to-line (evil-backward-char count t noerror)) (error ;; Restore the previous command (this one never happened). ;; Actually, this preserves the current column if the ;; previous command was `evil-next-line' or ;; `evil-previous-line'. (setq this-command last-command) (signal (car err) (cdr err)))))) (t (evil-motion-loop (nil (or count 1)) (backward-char) ;; don't put the cursor on a newline (unless (or (evil-visual-state-p) (evil-operator-state-p)) (evil-adjust-cursor)))))) (evil-define-motion evil-next-line (count) "Move the cursor COUNT lines down." :type line (let (line-move-visual) (evil-line-move (or count 1)))) (evil-define-motion evil-previous-line (count) "Move the cursor COUNT lines up." :type line (let (line-move-visual) (evil-line-move (- (or count 1))))) (evil-define-motion evil-next-visual-line (count) "Move the cursor COUNT screen lines down." :type exclusive (let ((line-move-visual t)) (evil-line-move (or count 1)))) (evil-define-motion evil-previous-visual-line (count) "Move the cursor COUNT screen lines up." :type exclusive (let ((line-move-visual t)) (evil-line-move (- (or count 1))))) ;; used for repeated commands like "dd" (evil-define-motion evil-line (count) "Move COUNT - 1 lines down." :type line (let (line-move-visual) ;; Catch bob and eob errors. These are caused when not moving ;; point starting in the first or last line, respectively. In this ;; case the current line should be selected. (condition-case err (evil-line-move (1- (or count 1))) ((beginning-of-buffer end-of-buffer))))) (evil-define-motion evil-line-or-visual-line (count) "Move COUNT - 1 lines down." :type screen-line (let ((line-move-visual (and evil-respect-visual-line-mode visual-line-mode))) ;; Catch bob and eob errors. These are caused when not moving ;; point starting in the first or last line, respectively. In this ;; case the current line should be selected. (condition-case err (evil-line-move (1- (or count 1))) ((beginning-of-buffer end-of-buffer))))) (evil-define-motion evil-beginning-of-line () "Move the cursor to the beginning of the current line." :type exclusive (move-beginning-of-line nil)) (evil-define-motion evil-end-of-line (count) "Move the cursor to the end of the current line. If COUNT is given, move COUNT - 1 lines downward first." :type inclusive (move-end-of-line count) (when evil-track-eol (setq temporary-goal-column most-positive-fixnum this-command 'next-line)) (unless (evil-visual-state-p) (evil-adjust-cursor) (when (eolp) ;; prevent "c$" and "d$" from deleting blank lines (setq evil-this-type 'exclusive)))) (evil-define-motion evil-beginning-of-visual-line () "Move the cursor to the first character of the current screen line." :type exclusive (if (fboundp 'beginning-of-visual-line) (beginning-of-visual-line) (beginning-of-line))) (evil-define-motion evil-end-of-visual-line (count) "Move the cursor to the last character of the current screen line. If COUNT is given, move COUNT - 1 screen lines downward first." :type inclusive (if (fboundp 'end-of-visual-line) (end-of-visual-line count) (end-of-line count))) (evil-define-motion evil-end-of-line-or-visual-line (count) "Move the cursor to the last character of the current screen line if `visual-line-mode' is active and `evil-respect-visual-line-mode' is non-nil. If COUNT is given, move COUNT - 1 screen lines downward first." :type inclusive (if (and (fboundp 'end-of-visual-line) evil-respect-visual-line-mode visual-line-mode) (end-of-visual-line count) (evil-end-of-line count))) (evil-define-motion evil-middle-of-visual-line () "Move the cursor to the middle of the current visual line." :type exclusive (beginning-of-visual-line) (evil-with-restriction nil (save-excursion (end-of-visual-line) (point)) (move-to-column (+ (current-column) -1 (/ (with-no-warnings (window-body-width)) 2))))) (evil-define-motion evil-beginning-of-line-or-digit-argument () "Move the cursor to the beginning of the current line. This function passes its command to `digit-argument' (usually a 0) if it is not the first event." :type exclusive (cond (current-prefix-arg (setq this-command #'digit-argument) (call-interactively #'digit-argument)) (t (setq this-command #'evil-beginning-of-line) (call-interactively #'evil-beginning-of-line)))) (evil-define-motion evil-first-non-blank () "Move the cursor to the first non-blank character of the current line." :type exclusive (evil-narrow-to-line (back-to-indentation))) (evil-define-motion evil-last-non-blank (count) "Move the cursor to the last non-blank character of the current line. If COUNT is given, move COUNT - 1 lines downward first." :type inclusive (goto-char (save-excursion (evil-move-beginning-of-line count) (if (re-search-forward "[ \t]*$") (max (line-beginning-position) (1- (match-beginning 0))) (line-beginning-position))))) (evil-define-motion evil-first-non-blank-of-visual-line () "Move the cursor to the first non blank character of the current screen line." :type exclusive (evil-beginning-of-visual-line) (skip-chars-forward " \t\r")) (evil-define-motion evil-next-line-first-non-blank (count) "Move the cursor COUNT lines down on the first non-blank character." :type line (let ((this-command this-command)) (evil-next-line (or count 1))) (evil-first-non-blank)) (evil-define-motion evil-next-line-1-first-non-blank (count) "Move the cursor COUNT-1 lines down on the first non-blank character." :type line (let ((this-command this-command)) (evil-next-line (1- (or count 1)))) (evil-first-non-blank)) (evil-define-motion evil-previous-line-first-non-blank (count) "Move the cursor COUNT lines up on the first non-blank character." :type line (let ((this-command this-command)) (evil-previous-line (or count 1))) (evil-first-non-blank)) (evil-define-motion evil-goto-line (count) "Go to the first non-blank character of line COUNT. By default the last line." :jump t :type line (if (null count) (with-no-warnings (end-of-buffer)) (goto-char (point-min)) (forward-line (1- count))) (evil-first-non-blank)) (evil-define-motion evil-goto-first-line (count) "Go to the first non-blank character of line COUNT. By default the first line." :jump t :type line (evil-goto-line (or count 1))) (evil-define-motion evil-forward-word-begin (count &optional bigword) "Move the cursor to the beginning of the COUNT-th next word. If BIGWORD is non-nil, move by WORDS. If this command is called in operator-pending state it behaves differently. If point reaches the beginning of a word on a new line point is moved back to the end of the previous line. If called after a change operator, i.e. cw or cW, `evil-want-change-word-to-end' is non-nil and point is on a word, then both behave like ce or cE. If point is at the end of the buffer and cannot be moved signal 'end-of-buffer is raised. " :type exclusive (let ((thing (if bigword 'evil-WORD 'evil-word)) (orig (point)) (count (or count 1))) (evil-signal-at-bob-or-eob count) (cond ;; default motion, beginning of next word ((not (evil-operator-state-p)) (evil-forward-beginning thing count)) ;; the evil-change operator, maybe behave like ce or cE ((and evil-want-change-word-to-end (memq evil-this-operator evil-change-commands) (< orig (or (cdr-safe (bounds-of-thing-at-point thing)) orig))) ;; forward-thing moves point to the correct position because ;; this is an exclusive motion (forward-thing thing count)) ;; operator state (t (prog1 (evil-forward-beginning thing count) ;; if we reached the beginning of a word on a new line in ;; Operator-Pending state, go back to the end of the previous ;; line (when (and (> (line-beginning-position) orig) (looking-back "^[[:space:]]*" (line-beginning-position))) ;; move cursor back as long as the line contains only ;; whitespaces and is non-empty (evil-move-end-of-line 0) ;; skip non-empty lines containing only spaces (while (and (looking-back "^[[:space:]]+$" (line-beginning-position)) (not (<= (line-beginning-position) orig))) (evil-move-end-of-line 0)) ;; but if the previous line is empty, delete this line (when (bolp) (forward-char)))))))) (evil-define-motion evil-forward-word-end (count &optional bigword) "Move the cursor to the end of the COUNT-th next word. If BIGWORD is non-nil, move by WORDS." :type inclusive (let ((thing (if bigword 'evil-WORD 'evil-word)) (count (or count 1))) (evil-signal-at-bob-or-eob count) ;; Evil special behaviour: e or E on a one-character word in ;; operator state does not move point (unless (and (evil-operator-state-p) (= 1 count) (let ((bnd (bounds-of-thing-at-point thing))) (and bnd (= (car bnd) (point)) (= (cdr bnd) (1+ (point))))) (looking-at "[[:word:]]")) (evil-forward-end thing count)))) (evil-define-motion evil-backward-word-begin (count &optional bigword) "Move the cursor to the beginning of the COUNT-th previous word. If BIGWORD is non-nil, move by WORDS." :type exclusive (let ((thing (if bigword 'evil-WORD 'evil-word))) (evil-signal-at-bob-or-eob (- (or count 1))) (evil-backward-beginning thing count))) (evil-define-motion evil-backward-word-end (count &optional bigword) "Move the cursor to the end of the COUNT-th previous word. If BIGWORD is non-nil, move by WORDS." :type inclusive (let ((thing (if bigword 'evil-WORD 'evil-word))) (evil-signal-at-bob-or-eob (- (or count 1))) (evil-backward-end thing count))) (evil-define-motion evil-forward-WORD-begin (count) "Move the cursor to the beginning of the COUNT-th next WORD." :type exclusive (evil-forward-word-begin count t)) (evil-define-motion evil-forward-WORD-end (count) "Move the cursor to the end of the COUNT-th next WORD." :type inclusive (evil-forward-word-end count t)) (evil-define-motion evil-backward-WORD-begin (count) "Move the cursor to the beginning of the COUNT-th previous WORD." :type exclusive (evil-backward-word-begin count t)) (evil-define-motion evil-backward-WORD-end (count) "Move the cursor to the end of the COUNT-th previous WORD." :type inclusive (evil-backward-word-end count t)) ;; section movement (evil-define-motion evil-forward-section-begin (count) "Move the cursor to the beginning of the COUNT-th next section." :jump t :type exclusive (evil-signal-at-bob-or-eob count) (evil-forward-beginning 'evil-defun count)) (evil-define-motion evil-forward-section-end (count) "Move the cursor to the end of the COUNT-th next section." :jump t :type inclusive (evil-signal-at-bob-or-eob count) (evil-forward-end 'evil-defun count) (unless (eobp) (forward-line))) (evil-define-motion evil-backward-section-begin (count) "Move the cursor to the beginning of the COUNT-th previous section." :jump t :type exclusive (evil-signal-at-bob-or-eob (- (or count 1))) (evil-backward-beginning 'evil-defun count)) (evil-define-motion evil-backward-section-end (count) "Move the cursor to the end of the COUNT-th previous section." :jump t :type inclusive (evil-signal-at-bob-or-eob (- (or count 1))) (end-of-line -1) (evil-backward-end 'evil-defun count) (unless (eobp) (forward-line))) (evil-define-motion evil-forward-sentence-begin (count) "Move to the next COUNT-th beginning of a sentence or end of a paragraph." :jump t :type exclusive (evil-signal-at-bob-or-eob count) (evil-forward-nearest count #'(lambda (cnt) (evil-forward-beginning 'evil-sentence)) #'evil-forward-paragraph)) (evil-define-motion evil-backward-sentence-begin (count) "Move to the previous COUNT-th beginning of a sentence or paragraph." :jump t :type exclusive (evil-signal-at-bob-or-eob (- (or count 1))) (evil-forward-nearest (- (or count 1)) #'(lambda (cnt) (evil-backward-beginning 'evil-sentence)) #'(lambda (cnt) (evil-backward-paragraph)))) (evil-define-motion evil-forward-paragraph (count) "Move to the end of the COUNT-th next paragraph." :jump t :type exclusive (evil-signal-at-bob-or-eob count) (evil-forward-end 'evil-paragraph count) (unless (eobp) (forward-line))) (evil-define-motion evil-backward-paragraph (count) "Move to the beginning of the COUNT-th previous paragraph." :jump t :type exclusive (evil-signal-at-bob-or-eob (- (or count 1))) (unless (eobp) (forward-line)) (evil-backward-beginning 'evil-paragraph count) (unless (bobp) (forward-line -1))) (evil-define-motion evil-jump-item (count) "Find the next item in this line after or under the cursor and jump to the corresponding one." :jump t :type inclusive (cond ;; COUNT% jumps to a line COUNT percentage down the file (count (goto-char (evil-normalize-position (let ((size (- (point-max) (point-min)))) (+ (point-min) (if (> size 80000) (* count (/ size 100)) (/ (* count size) 100)))))) (back-to-indentation) (setq evil-this-type 'line)) ((and (evil-looking-at-start-comment t) (let ((pnt (point))) (forward-comment 1) (or (not (bolp)) (prog1 nil (goto-char pnt))))) (backward-char)) ((and (not (eolp)) (evil-looking-at-end-comment t)) (forward-comment -1)) ((and (memq major-mode '(c-mode c++-mode)) (require 'hideif nil t) (with-no-warnings (let* ((hif-else-regexp (concat hif-cpp-prefix "\\(?:else\\|elif[ \t]+\\)")) (hif-ifx-else-endif-regexp (concat hif-ifx-regexp "\\|" hif-else-regexp "\\|" hif-endif-regexp))) (cond ((save-excursion (beginning-of-line) (or (hif-looking-at-ifX) (hif-looking-at-else))) (hif-find-next-relevant) (while (hif-looking-at-ifX) (hif-ifdef-to-endif) (hif-find-next-relevant)) t) ((save-excursion (beginning-of-line) (hif-looking-at-endif)) (hif-endif-to-ifdef) t)))))) (t (let* ((open (point-max)) (close (point-max)) (open-pair (condition-case nil (save-excursion ;; consider the character right before eol given that ;; point may be placed there, e.g. in visual state (when (and (eolp) (not (bolp))) (backward-char)) (setq open (1- (scan-lists (point) 1 -1))) (when (< open (line-end-position)) (goto-char open) (forward-list) (1- (point)))) (error nil))) (close-pair (condition-case nil (save-excursion ;; consider the character right before eol given that ;; point may be placed there, e.g. in visual state (when (and (eolp) (not (bolp))) (backward-char)) (setq close (1- (scan-lists (point) 1 1))) (when (< close (line-end-position)) (goto-char (1+ close)) (backward-list) (point))) (error nil)))) (cond ((not (or open-pair close-pair)) ;; nothing found, check if we are inside a string (let ((pnt (point)) (state (syntax-ppss (point))) (bnd (bounds-of-thing-at-point 'evil-string))) (if (not (and bnd (< (point) (cdr bnd)))) ;; no, then we really failed (user-error "No matching item found on the current line") ;; yes, go to the end of the string and try again (let ((endstr (cdr bnd))) (when (or (save-excursion (goto-char endstr) (let ((b (bounds-of-thing-at-point 'evil-string))) (and b (< (point) (cdr b))))) ; not at end of string (condition-case nil (progn (goto-char endstr) (evil-jump-item) nil) (error t))) ;; failed again, go back to original point (goto-char pnt) (user-error "No matching item found on the current line")))))) ((< open close) (goto-char open-pair)) (t (goto-char close-pair))))))) (defun evil--flyspell-overlays-in-p (beg end) (let ((ovs (overlays-in beg end)) done) (while (and ovs (not done)) (when (flyspell-overlay-p (car ovs)) (setq done t)) (setq ovs (cdr ovs))) done)) (defun evil--flyspell-overlay-at (pos forwardp) (when (not forwardp) (setq pos (max (1- pos) (point-min)))) (let ((ovs (overlays-at pos)) done) (while (and ovs (not done)) (if (flyspell-overlay-p (car ovs)) (setq done t) (setq ovs (cdr ovs)))) (when done (car ovs)))) (defun evil--flyspell-overlay-after (pos limit forwardp) (let (done) (while (and (if forwardp (< pos limit) (> pos limit)) (not done)) (let ((ov (evil--flyspell-overlay-at pos forwardp))) (when ov (setq done ov))) (setq pos (if forwardp (next-overlay-change pos) (previous-overlay-change pos)))) done)) (defun evil--next-flyspell-error (forwardp) (when (evil--flyspell-overlays-in-p (point-min) (point-max)) (let ((pos (point)) limit ov) (when (evil--flyspell-overlay-at pos forwardp) (if (/= pos (point-min)) (setq pos (save-excursion (goto-char pos) (forward-word (if forwardp 1 -1)) (point))) (setq pos (point-max)))) (setq limit (if forwardp (point-max) (point-min)) ov (evil--flyspell-overlay-after pos limit forwardp)) (if ov (goto-char (overlay-start ov)) (when evil-search-wrap (setq limit pos pos (if forwardp (point-min) (point-max)) ov (evil--flyspell-overlay-after pos limit forwardp)) (when ov (goto-char (overlay-start ov)))))))) (evil-define-motion evil-next-flyspell-error (count) "Go to the COUNT'th spelling mistake after point." (interactive "p") (dotimes (_ count) (evil--next-flyspell-error t))) (evil-define-motion evil-prev-flyspell-error (count) "Go to the COUNT'th spelling mistake preceding point." (interactive "p") (dotimes (_ count) (evil--next-flyspell-error nil))) (evil-define-motion evil-previous-open-paren (count) "Go to [count] previous unmatched '('." :type exclusive (evil-up-paren ?\( ?\) (- (or count 1)))) (evil-define-motion evil-next-close-paren (count) "Go to [count] next unmatched ')'." :type exclusive (forward-char) (evil-up-paren ?\( ?\) (or count 1)) (backward-char)) (evil-define-motion evil-previous-open-brace (count) "Go to [count] previous unmatched '{'." :type exclusive (evil-up-paren ?{ ?} (- (or count 1)))) (evil-define-motion evil-next-close-brace (count) "Go to [count] next unmatched '}'." :type exclusive (forward-char) (evil-up-paren ?{ ?} (or count 1)) (backward-char)) (evil-define-motion evil-find-char (count char) "Move to the next COUNT'th occurrence of CHAR. Movement is restricted to the current line unless `evil-cross-lines' is non-nil." :type inclusive (interactive "") (setq count (or count 1)) (let ((fwd (> count 0)) (visual (and evil-respect-visual-line-mode visual-line-mode))) (setq evil-last-find (list #'evil-find-char char fwd)) (when fwd (forward-char)) (let ((case-fold-search nil)) (unless (prog1 (search-forward (char-to-string char) (cond (evil-cross-lines nil) ((and fwd visual) (save-excursion (end-of-visual-line) (point))) (fwd (line-end-position)) (visual (save-excursion (beginning-of-visual-line) (point))) (t (line-beginning-position))) t count) (when fwd (backward-char))) (user-error "Can't find %c" char))))) (evil-define-motion evil-find-char-backward (count char) "Move to the previous COUNT'th occurrence of CHAR." :type exclusive (interactive "") (evil-find-char (- (or count 1)) char)) (evil-define-motion evil-find-char-to (count char) "Move before the next COUNT'th occurrence of CHAR." :type inclusive (interactive "") (unwind-protect (progn (evil-find-char count char) (if (> (or count 1) 0) (backward-char) (forward-char))) (setcar evil-last-find #'evil-find-char-to))) (evil-define-motion evil-find-char-to-backward (count char) "Move before the previous COUNT'th occurrence of CHAR." :type exclusive (interactive "") (evil-find-char-to (- (or count 1)) char)) (evil-define-motion evil-repeat-find-char (count) "Repeat the last find COUNT times." :type inclusive (setq count (or count 1)) (if evil-last-find (let ((cmd (car evil-last-find)) (char (nth 1 evil-last-find)) (fwd (nth 2 evil-last-find)) evil-last-find) ;; ensure count is non-negative (when (< count 0) (setq count (- count) fwd (not fwd))) ;; skip next character when repeating t or T (and (eq cmd #'evil-find-char-to) evil-repeat-find-to-skip-next (= count 1) (or (and fwd (= (char-after (1+ (point))) char)) (and (not fwd) (= (char-before) char))) (setq count (1+ count))) (funcall cmd (if fwd count (- count)) char) (unless (nth 2 evil-last-find) (setq evil-this-type 'exclusive))) (user-error "No previous search"))) (evil-define-motion evil-repeat-find-char-reverse (count) "Repeat the last find COUNT times in the opposite direction." :type inclusive (evil-repeat-find-char (- (or count 1)))) ;; ceci n'est pas une pipe (evil-define-motion evil-goto-column (count) "Go to column COUNT on the current line. Columns are counted from zero." :type exclusive (move-to-column (or count 0))) (evil-define-command evil-goto-mark (char &optional noerror) "Go to the marker specified by CHAR." :keep-visual t :repeat nil :type exclusive :jump t (interactive (list (read-char))) (let ((marker (evil-get-marker char))) (cond ((markerp marker) (switch-to-buffer (marker-buffer marker)) (goto-char (marker-position marker))) ((numberp marker) (goto-char marker)) ((consp marker) (when (or (find-buffer-visiting (car marker)) (and (y-or-n-p (format "Visit file %s again? " (car marker))) (find-file (car marker)))) (goto-char (cdr marker)))) ((not noerror) (user-error "Marker `%c' is not set%s" char (if (evil-global-marker-p char) "" " in this buffer")))))) (evil-define-command evil-goto-mark-line (char &optional noerror) "Go to the line of the marker specified by CHAR." :keep-visual t :repeat nil :type line :jump t (interactive (list (read-char))) (evil-goto-mark char noerror) (evil-first-non-blank)) (evil-define-motion evil-jump-backward (count) "Go to older position in jump list. To go the other way, press \ \\\\[evil-jump-forward]." (evil--jump-backward count)) (evil-define-motion evil-jump-forward (count) "Go to newer position in jump list. To go the other way, press \ \\\\[evil-jump-backward]." (evil--jump-forward count)) (evil-define-motion evil-jump-backward-swap (count) "Go to the previous position in jump list. The current position is placed in the jump list." (let ((pnt (point))) (evil--jump-backward 1) (evil-set-jump pnt))) (evil-define-motion evil-jump-to-tag (arg) "Jump to tag under point. If called with a prefix argument, provide a prompt for specifying the tag." :jump t (interactive "P") (cond ((fboundp 'xref-find-definitions) (let ((xref-prompt-for-identifier arg)) (call-interactively #'xref-find-definitions))) ((fboundp 'find-tag) (if arg (call-interactively #'find-tag) (let ((tag (funcall (or find-tag-default-function (get major-mode 'find-tag-default-function) #'find-tag-default)))) (unless tag (user-error "No tag candidate found around point")) (find-tag tag)))))) (evil-define-motion evil-lookup () "Look up the keyword at point. Calls `evil-lookup-func'." (funcall evil-lookup-func)) (defun evil-ret-gen (count indent?) (let* ((field (get-char-property (point) 'field)) (button (get-char-property (point) 'button)) (doc (get-char-property (point) 'widget-doc)) (widget (or field button doc))) (cond ((and widget (fboundp 'widget-type) (fboundp 'widget-button-press) (or (and (symbolp widget) (get widget 'widget-type)) (and (consp widget) (get (widget-type widget) 'widget-type)))) (when (evil-operator-state-p) (setq evil-inhibit-operator t)) (when (fboundp 'widget-button-press) (widget-button-press (point)))) ((and (fboundp 'button-at) (fboundp 'push-button) (button-at (point))) (when (evil-operator-state-p) (setq evil-inhibit-operator t)) (push-button)) ((or (evil-emacs-state-p) (and (evil-insert-state-p) (not buffer-read-only))) (if (not indent?) (newline count) (delete-horizontal-space t) (newline count) (indent-according-to-mode))) (t (evil-next-line-first-non-blank count))))) (evil-define-motion evil-ret (count) "Move the cursor COUNT lines down. If point is on a widget or a button, click on it. In Insert state, insert a newline." :type line (evil-ret-gen count nil)) (evil-define-motion evil-ret-and-indent (count) "Move the cursor COUNT lines down. If point is on a widget or a button, click on it. In Insert state, insert a newline and indent." :type line (evil-ret-gen count t)) (evil-define-motion evil-window-top (count) "Move the cursor to line COUNT from the top of the window on the first non-blank character." :jump t :type line (move-to-window-line (max (or count 0) (if (= (point-min) (window-start)) 0 scroll-margin))) (back-to-indentation)) (evil-define-motion evil-window-middle () "Move the cursor to the middle line in the window on the first non-blank character." :jump t :type line (move-to-window-line (/ (1+ (save-excursion (move-to-window-line -1))) 2)) (back-to-indentation)) (evil-define-motion evil-window-bottom (count) "Move the cursor to line COUNT from the bottom of the window on the first non-blank character." :jump t :type line (move-to-window-line (- (max (or count 1) (1+ scroll-margin)))) (back-to-indentation)) ;; scrolling (evil-define-command evil-scroll-line-up (count) "Scrolls the window COUNT lines upwards." :repeat nil :keep-visual t (interactive "p") (let ((scroll-preserve-screen-position nil)) (scroll-down count))) (evil-define-command evil-scroll-line-down (count) "Scrolls the window COUNT lines downwards." :repeat nil :keep-visual t (interactive "p") (let ((scroll-preserve-screen-position nil)) (scroll-up count))) (evil-define-command evil-scroll-count-reset () "Sets `evil-scroll-count' to 0. `evil-scroll-up' and `evil-scroll-down' will scroll for a half of the screen(default)." :repeat nil :keep-visual t (interactive) (setq evil-scroll-count 0)) (evil-define-command evil-scroll-up (count) "Scrolls the window and the cursor COUNT lines upwards. If COUNT is not specified the function scrolls down `evil-scroll-count', which is the last used count. If the scroll count is zero the command scrolls half the screen." :repeat nil :keep-visual t (interactive "") (evil-save-column (setq count (or count (max 0 evil-scroll-count))) (setq evil-scroll-count count) (when (= (point-min) (line-beginning-position)) (signal 'beginning-of-buffer nil)) (when (zerop count) (setq count (/ (window-body-height) 2))) (let ((xy (evil-posn-x-y (posn-at-point)))) (condition-case nil (progn (scroll-down count) (goto-char (posn-point (posn-at-x-y (car xy) (cdr xy))))) (beginning-of-buffer (condition-case nil (with-no-warnings (previous-line count)) (beginning-of-buffer))))))) (evil-define-command evil-scroll-down (count) "Scrolls the window and the cursor COUNT lines downwards. If COUNT is not specified the function scrolls down `evil-scroll-count', which is the last used count. If the scroll count is zero the command scrolls half the screen." :repeat nil :keep-visual t (interactive "") (evil-save-column (setq count (or count (max 0 evil-scroll-count))) (setq evil-scroll-count count) (when (eobp) (signal 'end-of-buffer nil)) (when (zerop count) (setq count (/ (window-body-height) 2))) ;; BUG #660: First check whether the eob is visible. ;; In that case we do not scroll but merely move point. (if (<= (point-max) (window-end)) (with-no-warnings (next-line count nil)) (let ((xy (evil-posn-x-y (posn-at-point)))) (condition-case nil (progn (scroll-up count) (let* ((wend (window-end nil t)) (p (posn-at-x-y (car xy) (cdr xy))) (margin (max 0 (- scroll-margin (cdr (posn-col-row p)))))) (goto-char (posn-point p)) ;; ensure point is not within the scroll-margin (when (> margin 0) (with-no-warnings (next-line margin)) (recenter scroll-margin)) (when (<= (point-max) wend) (save-excursion (goto-char (point-max)) (recenter (- (max 1 scroll-margin))))))) (end-of-buffer (goto-char (point-max)) (recenter (- (max 1 scroll-margin))))))))) (evil-define-command evil-scroll-page-up (count) "Scrolls the window COUNT pages upwards." :repeat nil :keep-visual t (interactive "p") (evil-save-column (dotimes (i count) (condition-case err (scroll-down nil) (beginning-of-buffer (if (and (bobp) (zerop i)) (signal (car err) (cdr err)) (goto-char (point-min)))))))) (evil-define-command evil-scroll-page-down (count) "Scrolls the window COUNT pages downwards." :repeat nil :keep-visual t (interactive "p") (evil-save-column (dotimes (i count) (condition-case err (scroll-up nil) (end-of-buffer (if (and (eobp) (zerop i)) (signal (car err) (cdr err)) (goto-char (point-max)))))))) (evil-define-command evil-scroll-line-to-top (count) "Scrolls line number COUNT (or the cursor line) to the top of the window." :repeat nil :keep-visual t (interactive "") (evil-save-column (let ((line (or count (line-number-at-pos (point))))) (goto-char (point-min)) (forward-line (1- line))) (recenter (1- (max 1 scroll-margin))))) (evil-define-command evil-scroll-line-to-center (count) "Scrolls line number COUNT (or the cursor line) to the center of the window." :repeat nil :keep-visual t (interactive "") (evil-save-column (when count (goto-char (point-min)) (forward-line (1- count))) (recenter nil))) (evil-define-command evil-scroll-line-to-bottom (count) "Scrolls line number COUNT (or the cursor line) to the bottom of the window." :repeat nil :keep-visual t (interactive "") (evil-save-column (let ((line (or count (line-number-at-pos (point))))) (goto-char (point-min)) (forward-line (1- line))) (recenter (- (max 1 scroll-margin))))) (evil-define-command evil-scroll-bottom-line-to-top (count) "Scrolls the line right below the window, or line COUNT to the top of the window." :repeat nil :keep-visual t (interactive "") (if count (progn (goto-char (point-min)) (forward-line (1- count))) (goto-char (window-end)) (evil-move-cursor-back)) (recenter (1- (max 0 scroll-margin))) (evil-first-non-blank)) (evil-define-command evil-scroll-top-line-to-bottom (count) "Scrolls the line right below the window, or line COUNT to the top of the window." :repeat nil :keep-visual t (interactive "") (if count (progn (goto-char (point-min)) (forward-line (1- count))) (goto-char (window-start))) (recenter (- (max 1 scroll-margin))) (evil-first-non-blank)) (evil-define-command evil-scroll-left (count) "Scrolls the window COUNT half-screenwidths to the left." :repeat nil :keep-visual t (interactive "p") (evil-with-hproject-point-on-window (scroll-right (* count (/ (window-width) 2))))) (evil-define-command evil-scroll-right (count) "Scrolls the window COUNT half-screenwidths to the right." :repeat nil :keep-visual t (interactive "p") (evil-with-hproject-point-on-window (scroll-left (* count (/ (window-width) 2))))) (evil-define-command evil-scroll-column-left (count) "Scrolls the window COUNT columns to the left." :repeat nil :keep-visual t (interactive "p") (evil-with-hproject-point-on-window (scroll-right count))) (evil-define-command evil-scroll-column-right (count) "Scrolls the window COUNT columns to the right." :repeat nil :keep-visual t (interactive "p") (evil-with-hproject-point-on-window (scroll-left count))) ;;; Text objects ;; Text objects are defined with `evil-define-text-object'. In Visual ;; state, they modify the current selection; in Operator-Pending ;; state, they return a pair of buffer positions. Outer text objects ;; are bound in the keymap `evil-outer-text-objects-map', and inner ;; text objects are bound in `evil-inner-text-objects-map'. ;; ;; Common text objects like words, WORDS, paragraphs and sentences are ;; defined via a corresponding move-function. This function must have ;; the following properties: ;; ;; 1. Take exactly one argument, the count. ;; 2. When the count is positive, move point forward to the first ;; character after the end of the next count-th object. ;; 3. When the count is negative, move point backward to the first ;; character of the count-th previous object. ;; 4. If point is placed on the first character of an object, the ;; backward motion does NOT count that object. ;; 5. If point is placed on the last character of an object, the ;; forward motion DOES count that object. ;; 6. The return value is "count left", i.e., in forward direction ;; count is decreased by one for each successful move and in ;; backward direction count is increased by one for each ;; successful move, returning the final value of count. ;; Therefore, if the complete move is successful, the return ;; value is 0. ;; ;; A useful macro in this regard is `evil-motion-loop', which quits ;; when point does not move further and returns the count difference. ;; It also provides a "unit value" of 1 or -1 for use in each ;; iteration. For example, a hypothetical "foo-bar" move could be ;; written as such: ;; ;; (defun foo-bar (count) ;; (evil-motion-loop (var count) ;; (forward-foo var) ; `var' is 1 or -1 depending on COUNT ;; (forward-bar var))) ;; ;; If "forward-foo" and "-bar" didn't accept negative arguments, ;; we could choose their backward equivalents by inspecting `var': ;; ;; (defun foo-bar (count) ;; (evil-motion-loop (var count) ;; (cond ;; ((< var 0) ;; (backward-foo 1) ;; (backward-bar 1)) ;; (t ;; (forward-foo 1) ;; (forward-bar 1))))) ;; ;; After a forward motion, point has to be placed on the first ;; character after some object, unless no motion was possible at all. ;; Similarly, after a backward motion, point has to be placed on the ;; first character of some object. This implies that point should ;; NEVER be moved to eob or bob, unless an object ends or begins at ;; eob or bob. (Usually, Emacs motions always move as far as possible. ;; But we want to use the motion-function to identify certain objects ;; in the buffer, and thus exact movement to object boundaries is ;; required.) (evil-define-text-object evil-a-word (count &optional beg end type) "Select a word." (evil-select-an-object 'evil-word beg end type count)) (evil-define-text-object evil-inner-word (count &optional beg end type) "Select inner word." (evil-select-inner-object 'evil-word beg end type count)) (evil-define-text-object evil-a-WORD (count &optional beg end type) "Select a WORD." (evil-select-an-object 'evil-WORD beg end type count)) (evil-define-text-object evil-inner-WORD (count &optional beg end type) "Select inner WORD." (evil-select-inner-object 'evil-WORD beg end type count)) (evil-define-text-object evil-a-symbol (count &optional beg end type) "Select a symbol." (evil-select-an-object 'evil-symbol beg end type count)) (evil-define-text-object evil-inner-symbol (count &optional beg end type) "Select inner symbol." (evil-select-inner-object 'evil-symbol beg end type count)) (evil-define-text-object evil-a-sentence (count &optional beg end type) "Select a sentence." (evil-select-an-object 'evil-sentence beg end type count)) (evil-define-text-object evil-inner-sentence (count &optional beg end type) "Select inner sentence." (evil-select-inner-object 'evil-sentence beg end type count)) (evil-define-text-object evil-a-paragraph (count &optional beg end type) "Select a paragraph." :type line (evil-select-an-object 'evil-paragraph beg end type count t)) (evil-define-text-object evil-inner-paragraph (count &optional beg end type) "Select inner paragraph." :type line (evil-select-inner-object 'evil-paragraph beg end type count t)) (evil-define-text-object evil-a-paren (count &optional beg end type) "Select a parenthesis." :extend-selection nil (evil-select-paren ?\( ?\) beg end type count t)) (evil-define-text-object evil-inner-paren (count &optional beg end type) "Select inner parenthesis." :extend-selection nil (evil-select-paren ?\( ?\) beg end type count)) (evil-define-text-object evil-a-bracket (count &optional beg end type) "Select a square bracket." :extend-selection nil (evil-select-paren ?\[ ?\] beg end type count t)) (evil-define-text-object evil-inner-bracket (count &optional beg end type) "Select inner square bracket." :extend-selection nil (evil-select-paren ?\[ ?\] beg end type count)) (evil-define-text-object evil-a-curly (count &optional beg end type) "Select a curly bracket (\"brace\")." :extend-selection nil (evil-select-paren ?{ ?} beg end type count t)) (evil-define-text-object evil-inner-curly (count &optional beg end type) "Select inner curly bracket (\"brace\")." :extend-selection nil (evil-select-paren ?{ ?} beg end type count)) (evil-define-text-object evil-an-angle (count &optional beg end type) "Select an angle bracket." :extend-selection nil (evil-select-paren ?< ?> beg end type count t)) (evil-define-text-object evil-inner-angle (count &optional beg end type) "Select inner angle bracket." :extend-selection nil (evil-select-paren ?< ?> beg end type count)) (evil-define-text-object evil-a-single-quote (count &optional beg end type) "Select a single-quoted expression." :extend-selection t (evil-select-quote ?' beg end type count t)) (evil-define-text-object evil-inner-single-quote (count &optional beg end type) "Select inner single-quoted expression." :extend-selection nil (evil-select-quote ?' beg end type count)) (evil-define-text-object evil-a-double-quote (count &optional beg end type) "Select a double-quoted expression." :extend-selection t (evil-select-quote ?\" beg end type count t)) (evil-define-text-object evil-inner-double-quote (count &optional beg end type) "Select inner double-quoted expression." :extend-selection nil (evil-select-quote ?\" beg end type count)) (evil-define-text-object evil-a-back-quote (count &optional beg end type) "Select a back-quoted expression." :extend-selection t (evil-select-quote ?\` beg end type count t)) (evil-define-text-object evil-inner-back-quote (count &optional beg end type) "Select inner back-quoted expression." :extend-selection nil (evil-select-quote ?\` beg end type count)) (evil-define-text-object evil-a-tag (count &optional beg end type) "Select a tag block." :extend-selection nil (evil-select-xml-tag beg end type count t)) (evil-define-text-object evil-inner-tag (count &optional beg end type) "Select inner tag block." :extend-selection nil (evil-select-xml-tag beg end type count)) (evil-define-text-object evil-next-match (count &optional beg end type) "Select next match." (unless (and (boundp 'evil-search-module) (eq evil-search-module 'evil-search)) (user-error "next-match text objects only work with Evil search module.")) (let ((pnt (point))) (cond ((eq evil-ex-search-direction 'forward) (unless (eobp) (forward-char)) (evil-ex-search-previous 1) (when (and (<= evil-ex-search-match-beg pnt) (> evil-ex-search-match-end pnt) (not (evil-visual-state-p))) (setq count (1- count))) (if (> count 0) (evil-ex-search-next count))) (t (unless (eobp) (forward-char)) (evil-ex-search-next count)))) ;; active visual state if command is executed in normal state (when (evil-normal-state-p) (evil-visual-select evil-ex-search-match-beg evil-ex-search-match-end 'inclusive +1 t)) (list evil-ex-search-match-beg evil-ex-search-match-end)) (evil-define-text-object evil-previous-match (count &optional beg end type) "Select next match." (unless (and (boundp 'evil-search-module) (eq evil-search-module 'evil-search)) (user-error "previous-match text objects only work with Evil search module.")) (let ((evil-ex-search-direction (if (eq evil-ex-search-direction 'backward) 'forward 'backward))) (evil-next-match count beg end type))) ;;; Operator commands (evil-define-operator evil-yank (beg end type register yank-handler) "Saves the characters in motion into the kill-ring." :move-point nil :repeat nil (interactive "") (let ((evil-was-yanked-without-register (and evil-was-yanked-without-register (not register)))) (cond ((and (fboundp 'cua--global-mark-active) (fboundp 'cua-copy-region-to-global-mark) (cua--global-mark-active)) (cua-copy-region-to-global-mark beg end)) ((eq type 'block) (evil-yank-rectangle beg end register yank-handler)) ((memq type '(line screen-line)) (evil-yank-lines beg end register yank-handler)) (t (evil-yank-characters beg end register yank-handler))))) (evil-define-operator evil-yank-line (beg end type register) "Saves whole lines into the kill-ring." :motion evil-line-or-visual-line :move-point nil (interactive "") (when (evil-visual-state-p) (unless (memq type '(line block screen-line)) (let ((range (evil-expand beg end (if (and evil-respect-visual-line-mode visual-line-mode) 'screen-line 'line)))) (setq beg (evil-range-beginning range) end (evil-range-end range) type (evil-type range)))) (evil-exit-visual-state)) (evil-yank beg end type register)) (evil-define-operator evil-delete (beg end type register yank-handler) "Delete text from BEG to END with TYPE. Save in REGISTER or in the kill-ring with YANK-HANDLER." (interactive "") (unless register (let ((text (filter-buffer-substring beg end))) (unless (string-match-p "\n" text) ;; set the small delete register (evil-set-register ?- text)))) (let ((evil-was-yanked-without-register nil)) (evil-yank beg end type register yank-handler)) (cond ((eq type 'block) (evil-apply-on-block #'delete-region beg end nil)) ((and (eq type 'line) (= end (point-max)) (or (= beg end) (/= (char-before end) ?\n)) (/= beg (point-min)) (= (char-before beg) ?\n)) (delete-region (1- beg) end)) (t (delete-region beg end))) ;; place cursor on beginning of line (when (and (called-interactively-p 'any) (eq type 'line)) (evil-first-non-blank))) (evil-define-operator evil-delete-line (beg end type register yank-handler) "Delete to end of line." :motion nil :keep-visual t (interactive "") ;; act linewise in Visual state (let* ((beg (or beg (point))) (end (or end beg)) (visual-line-mode (and evil-respect-visual-line-mode visual-line-mode)) (line-end (if visual-line-mode (save-excursion (end-of-visual-line) (point)) (line-end-position)))) (when (evil-visual-state-p) (unless (memq type '(line screen-line block)) (let ((range (evil-expand beg end (if visual-line-mode 'screen-line 'line)))) (setq beg (evil-range-beginning range) end (evil-range-end range) type (evil-type range)))) (evil-exit-visual-state)) (cond ((eq type 'block) ;; equivalent to $d, i.e., we use the block-to-eol selection and ;; call `evil-delete'. In this case we fake the call to ;; `evil-end-of-line' by setting `temporary-goal-column' and ;; `last-command' appropriately as `evil-end-of-line' would do. (let ((temporary-goal-column most-positive-fixnum) (last-command 'next-line)) (evil-delete beg end 'block register yank-handler))) ((memq type '(line screen-line)) (evil-delete beg end type register yank-handler)) (t (evil-delete beg line-end type register yank-handler))))) (evil-define-operator evil-delete-whole-line (beg end type register yank-handler) "Delete whole line." :motion evil-line-or-visual-line (interactive "") (evil-delete beg end type register yank-handler)) (evil-define-operator evil-delete-char (beg end type register) "Delete next character." :motion evil-forward-char (interactive "") (evil-delete beg end type register)) (evil-define-operator evil-delete-backward-char (beg end type register) "Delete previous character." :motion evil-backward-char (interactive "") (evil-delete beg end type register)) (evil-define-command evil-delete-backward-char-and-join (count) "Delete previous character and join lines. If point is at the beginning of a line then the current line will be joined with the previous line if and only if `evil-backspace-join-lines'." (interactive "p") (if (or evil-backspace-join-lines (not (bolp))) (call-interactively 'delete-backward-char) (user-error "Beginning of line"))) (evil-define-command evil-delete-backward-word () "Delete previous word." (if (and (bolp) (not (bobp))) (progn (unless evil-backspace-join-lines (user-error "Beginning of line")) (delete-char -1)) (delete-region (max (save-excursion (evil-backward-word-begin) (point)) (line-beginning-position)) (point)))) (defun evil-ex-delete-or-yank (should-delete beg end type register count yank-handler) "Execute evil-delete or evil-yank on the given region. If SHOULD-DELETE is t, evil-delete will be executed, otherwise evil-yank. The region specified by BEG and END will be adjusted if COUNT is given." (when count ;; with COUNT, the command should go the end of the region and delete/yank ;; COUNT lines from there (setq beg (save-excursion (goto-char end) (forward-line -1) (point)) end (save-excursion (goto-char end) (point-at-bol count)) type 'line)) (funcall (if should-delete 'evil-delete 'evil-yank) beg end type register yank-handler)) (evil-define-operator evil-ex-delete (beg end type register count yank-handler) "The Ex delete command. \[BEG,END]delete [REGISTER] [COUNT]" (interactive "") (evil-ex-delete-or-yank t beg end type register count yank-handler)) (evil-define-operator evil-ex-yank (beg end type register count yank-handler) "The Ex yank command. \[BEG,END]yank [REGISTER] [COUNT]" (interactive "") (evil-ex-delete-or-yank nil beg end type register count yank-handler)) (evil-define-operator evil-change (beg end type register yank-handler delete-func) "Change text from BEG to END with TYPE. Save in REGISTER or the kill-ring with YANK-HANDLER. DELETE-FUNC is a function for deleting text, default `evil-delete'. If TYPE is `line', insertion starts on an empty line. If TYPE is `block', the inserted text in inserted at each line of the block." (interactive "") (let ((delete-func (or delete-func #'evil-delete)) (nlines (1+ (evil-count-lines beg end))) (opoint (save-excursion (goto-char beg) (line-beginning-position)))) (unless (eq evil-want-fine-undo t) (evil-start-undo-step)) (funcall delete-func beg end type register yank-handler) (cond ((eq type 'line) (if ( = opoint (point)) (evil-open-above 1) (evil-open-below 1))) ((eq type 'block) (evil-insert 1 nlines)) (t (evil-insert 1))))) (evil-define-operator evil-change-line (beg end type register yank-handler) "Change to end of line." :motion evil-end-of-line-or-visual-line (interactive "") (evil-change beg end type register yank-handler #'evil-delete-line)) (evil-define-operator evil-change-whole-line (beg end type register yank-handler) "Change whole line." :motion evil-line-or-visual-line (interactive "") (evil-change beg end type register yank-handler #'evil-delete-whole-line)) (evil-define-command evil-copy (beg end address) "Copy lines in BEG END below line given by ADDRESS." :motion evil-line-or-visual-line (interactive "") (goto-char (point-min)) (forward-line address) (let* ((txt (buffer-substring-no-properties beg end)) (len (length txt))) ;; ensure text consists of complete lines (when (or (zerop len) (/= (aref txt (1- len)) ?\n)) (setq txt (concat txt "\n"))) (when (and (eobp) (not (bolp))) (newline)) ; incomplete last line (insert txt) (forward-line -1))) (evil-define-command evil-move (beg end address) "Move lines in BEG END below line given by ADDRESS." :motion evil-line-or-visual-line (interactive "") (goto-char (point-min)) (forward-line address) (let* ((m (set-marker (make-marker) (point))) (txt (buffer-substring-no-properties beg end)) (len (length txt))) (delete-region beg end) (goto-char m) (set-marker m nil) ;; ensure text consists of complete lines (when (or (zerop len) (/= (aref txt (1- len)) ?\n)) (setq txt (concat txt "\n"))) (when (and (eobp) (not (bolp))) (newline)) ; incomplete last line (when (evil-visual-state-p) (move-marker evil-visual-mark (point))) (insert txt) (forward-line -1) (when (evil-visual-state-p) (move-marker evil-visual-point (point))))) (evil-define-operator evil-substitute (beg end type register) "Change a character." :motion evil-forward-char (interactive "") (evil-change beg end type register)) (evil-define-operator evil-upcase (beg end type) "Convert text to upper case." (if (eq type 'block) (evil-apply-on-block #'evil-upcase beg end nil) (upcase-region beg end))) (evil-define-operator evil-downcase (beg end type) "Convert text to lower case." (if (eq type 'block) (evil-apply-on-block #'evil-downcase beg end nil) (downcase-region beg end))) (evil-define-operator evil-invert-case (beg end type) "Invert case of text." (let (char) (if (eq type 'block) (evil-apply-on-block #'evil-invert-case beg end nil) (save-excursion (goto-char beg) (while (< beg end) (setq char (following-char)) (delete-char 1 nil) (if (eq (upcase char) char) (insert-char (downcase char) 1) (insert-char (upcase char) 1)) (setq beg (1+ beg))))))) (evil-define-operator evil-invert-char (beg end type) "Invert case of character." :motion evil-forward-char (if (eq type 'block) (evil-apply-on-block #'evil-invert-case beg end nil) (evil-invert-case beg end) (when evil-this-motion (goto-char end) (when (and evil-cross-lines (not evil-move-beyond-eol) (not (evil-visual-state-p)) (not (evil-operator-state-p)) (eolp) (not (eobp)) (not (bolp))) (forward-char))))) (evil-define-operator evil-rot13 (beg end type) "ROT13 encrypt text." (if (eq type 'block) (evil-apply-on-block #'evil-rot13 beg end nil) (rot13-region beg end))) (evil-define-operator evil-join (beg end) "Join the selected lines." :motion evil-line (let ((count (count-lines beg end))) (when (> count 1) (setq count (1- count))) (goto-char beg) (dotimes (var count) (join-line 1)))) (evil-define-operator evil-join-whitespace (beg end) "Join the selected lines without changing whitespace. \\Like \\[evil-join], \ but doesn't insert or remove any spaces." :motion evil-line (let ((count (count-lines beg end))) (when (> count 1) (setq count (1- count))) (goto-char beg) (dotimes (var count) (evil-move-end-of-line 1) (unless (eobp) (delete-char 1))))) (evil-define-operator evil-ex-join (beg end &optional count bang) "Join the selected lines with optional COUNT and BANG." (interactive "") (if (and count (not (string-match-p "^[1-9][0-9]*$" count))) (user-error "Invalid count") (let ((join-fn (if bang 'evil-join-whitespace 'evil-join))) (cond ((not count) ;; without count - just join the given region (funcall join-fn beg end)) (t ;; emulate vim's :join when count is given - start from the ;; end of the region and join COUNT lines from there (let* ((count-num (string-to-number count)) (beg-adjusted (save-excursion (goto-char end) (forward-line -1) (point))) (end-adjusted (save-excursion (goto-char end) (point-at-bol count-num)))) (funcall join-fn beg-adjusted end-adjusted))))))) (evil-define-operator evil-fill (beg end) "Fill text." :move-point nil :type line (save-excursion (condition-case nil (fill-region beg end) (error nil)))) (evil-define-operator evil-fill-and-move (beg end) "Fill text and move point to the end of the filled region." :move-point nil :type line (let ((marker (make-marker))) (move-marker marker (1- end)) (condition-case nil (progn (fill-region beg end) (goto-char marker) (evil-first-non-blank)) (error nil)))) (evil-define-operator evil-indent (beg end) "Indent text." :move-point nil :type line (if (and (= beg (line-beginning-position)) (= end (line-beginning-position 2))) ;; since some Emacs modes can only indent one line at a time, ;; implement "==" as a call to `indent-according-to-mode' (indent-according-to-mode) (goto-char beg) (indent-region beg end)) ;; We also need to tabify or untabify the leading white characters (when evil-indent-convert-tabs (let* ((beg-line (line-number-at-pos beg)) (end-line (line-number-at-pos end)) (ln beg-line) (convert-white (if indent-tabs-mode 'tabify 'untabify))) (save-excursion (while (<= ln end-line) (goto-char (point-min)) (forward-line (- ln 1)) (back-to-indentation) ;; Whether tab or space should be used is determined by indent-tabs-mode (funcall convert-white (line-beginning-position) (point)) (setq ln (1+ ln))))) (back-to-indentation))) (evil-define-operator evil-indent-line (beg end) "Indent the line." :motion evil-line (evil-indent beg end)) (evil-define-operator evil-shift-left (beg end &optional count preserve-empty) "Shift text from BEG to END to the left. The text is shifted to the nearest multiple of `evil-shift-width' \(the rounding can be disabled by setting `evil-shift-round'). If PRESERVE-EMPTY is non-nil, lines that contain only spaces are indented, too, otherwise they are ignored. The relative column of point is preserved if this function is not called interactively. Otherwise, if the function is called as an operator, point is moved to the first non-blank character. See also `evil-shift-right'." :type line (interactive "") (evil-shift-right beg end (- (or count 1)) preserve-empty)) (evil-define-operator evil-shift-right (beg end &optional count preserve-empty) "Shift text from BEG to END to the right. The text is shifted to the nearest multiple of `evil-shift-width' \(the rounding can be disabled by setting `evil-shift-round'). If PRESERVE-EMPTY is non-nil, lines that contain only spaces are indented, too, otherwise they are ignored. The relative column of point is preserved if this function is not called interactively. Otherwise, if the function is called as an operator, point is moved to the first non-blank character. See also `evil-shift-left'." :type line (interactive "") (setq count (or count 1)) (let ((beg (set-marker (make-marker) beg)) (end (set-marker (make-marker) end)) (pnt-indent (current-column)) first-shift) ; shift of first line (save-excursion (goto-char beg) (while (< (point) end) (let* ((indent (current-indentation)) (new-indent (max 0 (if (not evil-shift-round) (+ indent (* count evil-shift-width)) (* (+ (/ indent evil-shift-width) count (cond ((> count 0) 0) ((zerop (mod indent evil-shift-width)) 0) (t 1))) evil-shift-width))))) (unless first-shift (setq first-shift (- new-indent indent))) (when (or preserve-empty (save-excursion (skip-chars-forward " \t") (not (eolp)))) (indent-to new-indent 0)) (delete-region (point) (progn (skip-chars-forward " \t") (point))) (forward-line 1)))) ;; in case we're in an empty buffer first-shift is still unchanged (unless first-shift (if (< count 0) (setq first-shift 0) (setq first-shift (* count evil-shift-width)) (indent-to first-shift))) ;; assuming that point is in the first line, adjust its position (if (called-interactively-p 'any) (evil-first-non-blank) (move-to-column (max 0 (+ pnt-indent first-shift)))))) (evil-define-command evil-shift-right-line (count) "Shift the current line COUNT times to the right. The text is shifted to the nearest multiple of `evil-shift-width'. Like `evil-shift-right' but always works on the current line." (interactive "") (evil-shift-right (line-beginning-position) (line-beginning-position 2) count t)) (evil-define-command evil-shift-left-line (count) "Shift the current line COUNT times to the left. The text is shifted to the nearest multiple of `evil-shift-width'. Like `evil-shift-left' but always works on the current line." (interactive "") (evil-shift-left (line-beginning-position) (line-beginning-position 2) count t)) (evil-define-operator evil-align-left (beg end type &optional width) "Right-align lines in the region at WIDTH columns. The default for width is the value of `fill-column'." :motion evil-line :type line (interactive "") (evil-justify-lines beg end 'left (if width (string-to-number width) 0))) (evil-define-operator evil-align-right (beg end type &optional width) "Right-align lines in the region at WIDTH columns. The default for width is the value of `fill-column'." :motion evil-line :type line (interactive "") (evil-justify-lines beg end 'right (if width (string-to-number width) fill-column))) (evil-define-operator evil-align-center (beg end type &optional width) "Centers lines in the region between WIDTH columns. The default for width is the value of `fill-column'." :motion evil-line :type line (interactive "") (evil-justify-lines beg end 'center (if width (string-to-number width) fill-column))) (evil-define-operator evil-replace (beg end type char) "Replace text from BEG to END with CHAR." :motion evil-forward-char (interactive "" (unwind-protect (let ((evil-force-cursor 'replace)) (evil-refresh-cursor) (list (evil-read-key))) (evil-refresh-cursor))) (when char (if (eq type 'block) (save-excursion (evil-apply-on-rectangle #'(lambda (begcol endcol char) (let ((maxcol (evil-column (line-end-position)))) (when (< begcol maxcol) (setq endcol (min endcol maxcol)) (let ((beg (evil-move-to-column begcol nil t)) (end (evil-move-to-column endcol nil t))) (delete-region beg end) (insert (make-string (- endcol begcol) char)))))) beg end char)) (goto-char beg) (cond ((eq char ?\n) (delete-region beg end) (newline) (when evil-auto-indent (indent-according-to-mode))) (t (while (< (point) end) (if (eq (char-after) ?\n) (forward-char) (delete-char 1) (insert-char char 1))) (goto-char (max beg (1- end)))))))) (evil-define-command evil-paste-before (count &optional register yank-handler) "Pastes the latest yanked text before the cursor position. The return value is the yanked text." :suppress-operator t (interactive "P") (if (evil-visual-state-p) (evil-visual-paste count register) (evil-with-undo (let* ((text (if register (evil-get-register register) (current-kill 0))) (yank-handler (or yank-handler (when (stringp text) (car-safe (get-text-property 0 'yank-handler text))))) (opoint (point))) (when text (if (functionp yank-handler) (let ((evil-paste-count count) ;; for non-interactive use (this-command #'evil-paste-before)) (push-mark opoint t) (insert-for-yank text)) ;; no yank-handler, default (when (vectorp text) (setq text (evil-vector-to-string text))) (set-text-properties 0 (length text) nil text) (push-mark opoint t) (dotimes (i (or count 1)) (insert-for-yank text)) (setq evil-last-paste (list #'evil-paste-before count opoint opoint ; beg (point))) ; end (evil-set-marker ?\[ opoint) (evil-set-marker ?\] (1- (point))) (when (and evil-move-cursor-back (> (length text) 0)) (backward-char)))) ;; no paste-pop after pasting from a register (when register (setq evil-last-paste nil)) (and (> (length text) 0) text))))) (evil-define-command evil-paste-after (count &optional register yank-handler) "Pastes the latest yanked text behind point. The return value is the yanked text." :suppress-operator t (interactive "P") (if (evil-visual-state-p) (evil-visual-paste count register) (evil-with-undo (let* ((text (if register (evil-get-register register) (current-kill 0))) (yank-handler (or yank-handler (when (stringp text) (car-safe (get-text-property 0 'yank-handler text))))) (opoint (point))) (when text (if (functionp yank-handler) (let ((evil-paste-count count) ;; for non-interactive use (this-command #'evil-paste-after)) (insert-for-yank text)) ;; no yank-handler, default (when (vectorp text) (setq text (evil-vector-to-string text))) (set-text-properties 0 (length text) nil text) (unless (eolp) (forward-char)) (push-mark (point) t) ;; TODO: Perhaps it is better to collect a list of all ;; (point . mark) pairs to undo the yanking for COUNT > 1. ;; The reason is that this yanking could very well use ;; `yank-handler'. (let ((beg (point))) (dotimes (i (or count 1)) (insert-for-yank text)) (setq evil-last-paste (list #'evil-paste-after count opoint beg ; beg (point))) ; end (evil-set-marker ?\[ beg) (evil-set-marker ?\] (1- (point))) (when (evil-normal-state-p) (evil-move-cursor-back))))) (when register (setq evil-last-paste nil)) (and (> (length text) 0) text))))) (evil-define-command evil-visual-paste (count &optional register) "Paste over Visual selection." :suppress-operator t (interactive "P") ;; evil-visual-paste is typically called from evil-paste-before or ;; evil-paste-after, but we have to mark that the paste was from ;; visual state (setq this-command 'evil-visual-paste) (let* ((text (if register (evil-get-register register) (current-kill 0))) (yank-handler (car-safe (get-text-property 0 'yank-handler text))) new-kill paste-eob) (evil-with-undo (let* ((kill-ring (list (current-kill 0))) (kill-ring-yank-pointer kill-ring)) (when (evil-visual-state-p) (evil-visual-rotate 'upper-left) ;; if we replace the last buffer line that does not end in a ;; newline, we use `evil-paste-after' because `evil-delete' ;; will move point to the line above (when (and (= evil-visual-end (point-max)) (/= (char-before (point-max)) ?\n)) (setq paste-eob t)) (evil-delete evil-visual-beginning evil-visual-end (evil-visual-type)) (when (and (eq yank-handler #'evil-yank-line-handler) (not (eq (evil-visual-type) 'line)) (not (= evil-visual-end (point-max)))) (insert "\n")) (evil-normal-state) (setq new-kill (current-kill 0)) (current-kill 1)) (if paste-eob (evil-paste-after count register) (evil-paste-before count register))) (when evil-kill-on-visual-paste (kill-new new-kill)) ;; mark the last paste as visual-paste (setq evil-last-paste (list (nth 0 evil-last-paste) (nth 1 evil-last-paste) (nth 2 evil-last-paste) (nth 3 evil-last-paste) (nth 4 evil-last-paste) t))))) (defun evil-paste-from-register (register) "Paste from REGISTER." (interactive (let ((overlay (make-overlay (point) (point))) (string "\"")) (unwind-protect (progn ;; display " in the buffer while reading register (put-text-property 0 1 'face 'minibuffer-prompt string) (put-text-property 0 1 'cursor t string) (overlay-put overlay 'after-string string) (list (or evil-this-register (read-char)))) (delete-overlay overlay)))) (when (evil-paste-before nil register t) ;; go to end of pasted text (unless (eobp) (forward-char)))) (defun evil-paste-last-insertion () "Paste last insertion." (interactive) (evil-paste-from-register ?.)) (evil-define-command evil-use-register (register) "Use REGISTER for the next command." :keep-visual t :repeat ignore (interactive "") (setq evil-this-register register)) (defvar evil-macro-buffer nil "The buffer that has been active on macro recording.") (evil-define-command evil-record-macro (register) "Record a keyboard macro into REGISTER. If REGISTER is :, /, or ?, the corresponding command line window will be opened instead." :keep-visual t :suppress-operator t (interactive (list (unless (and evil-this-macro defining-kbd-macro) (or evil-this-register (evil-read-key))))) (cond ((eq register ?\C-g) (keyboard-quit)) ((and evil-this-macro defining-kbd-macro) (setq evil-macro-buffer nil) (condition-case nil (end-kbd-macro) (error nil)) (when last-kbd-macro (when (member last-kbd-macro '("" [])) (setq last-kbd-macro nil)) (evil-set-register evil-this-macro last-kbd-macro)) (setq evil-this-macro nil)) ((eq register ?:) (evil-command-window-ex)) ((eq register ?/) (evil-command-window-search-forward)) ((eq register ??) (evil-command-window-search-backward)) ((or (and (>= register ?0) (<= register ?9)) (and (>= register ?a) (<= register ?z)) (and (>= register ?A) (<= register ?Z))) (when defining-kbd-macro (end-kbd-macro)) (setq evil-this-macro register) (evil-set-register evil-this-macro nil) (start-kbd-macro nil) (setq evil-macro-buffer (current-buffer))) (t (error "Invalid register")))) (evil-define-command evil-execute-macro (count macro) "Execute keyboard macro MACRO, COUNT times. When called with a non-numerical prefix \ \(such as \\[universal-argument]), COUNT is infinite. MACRO is read from a register when called interactively." :keep-visual t :suppress-operator t (interactive (let (count macro register) (setq count (if current-prefix-arg (if (numberp current-prefix-arg) current-prefix-arg 0) 1) register (or evil-this-register (read-char))) (cond ((or (and (eq register ?@) (eq evil-last-register ?:)) (eq register ?:)) (setq macro (lambda () (evil-ex-repeat nil)) evil-last-register ?:)) ((eq register ?@) (unless evil-last-register (user-error "No previously executed keyboard macro.")) (setq macro (evil-get-register evil-last-register t))) (t (setq macro (evil-get-register register t) evil-last-register register))) (list count macro))) (cond ((functionp macro) (evil-repeat-abort) (dotimes (i (or count 1)) (funcall macro))) ((or (and (not (stringp macro)) (not (vectorp macro))) (member macro '("" []))) ;; allow references to currently empty registers ;; when defining macro (unless evil-this-macro (user-error "No previous macro"))) (t (condition-case err (evil-with-single-undo (execute-kbd-macro macro count)) ;; enter Normal state if the macro fails (error (evil-normal-state) (evil-normalize-keymaps) (signal (car err) (cdr err))))))) ;;; Visual commands (evil-define-motion evil-visual-restore () "Restore previous selection." (let* ((point (point)) (mark (or (mark t) point)) (dir evil-visual-direction) (type (evil-visual-type)) range) (unless (evil-visual-state-p) (cond ;; No previous selection. ((or (null evil-visual-selection) (null evil-visual-mark) (null evil-visual-point))) ;; If the type was one-to-one, it is preferable to infer ;; point and mark from the selection's boundaries. The reason ;; is that a destructive operation may displace the markers ;; inside the selection. ((evil-type-property type :one-to-one) (setq range (evil-contract-range (evil-visual-range)) mark (evil-range-beginning range) point (evil-range-end range)) (when (< dir 0) (evil-swap mark point))) ;; If the type wasn't one-to-one, we have to restore the ;; selection on the basis of the previous point and mark. (t (setq mark evil-visual-mark point evil-visual-point))) (evil-visual-make-selection mark point type t)))) (evil-define-motion evil-visual-exchange-corners () "Rearrange corners in Visual Block mode. M---+ +---M | | <=> | | +---P P---+ For example, if mark is in the upper left corner and point in the lower right, this function puts mark in the upper right corner and point in the lower left." (cond ((eq evil-visual-selection 'block) (let* ((point (point)) (mark (or (mark t) point)) (point-col (evil-column point)) (mark-col (evil-column mark)) (mark (save-excursion (goto-char mark) (evil-move-to-column point-col) (point))) (point (save-excursion (goto-char point) (evil-move-to-column mark-col) (point)))) (evil-visual-refresh mark point))) (t (evil-exchange-point-and-mark) (evil-visual-refresh)))) (evil-define-command evil-visual-rotate (corner &optional beg end type) "In Visual Block selection, put point in CORNER. Corner may be one of `upper-left', `upper-right', `lower-left' and `lower-right': upper-left +---+ upper-right | | lower-left +---+ lower-right When called interactively, the selection is rotated blockwise." :keep-visual t (interactive (let ((corners '(upper-left upper-right lower-right lower-left))) (list (or (cadr (memq (evil-visual-block-corner) corners)) 'upper-left)))) (let* ((beg (or beg (point))) (end (or end (mark t) beg)) (type (or type evil-this-type)) range) (cond ((memq type '(rectangle block)) (setq range (evil-block-rotate beg end :corner corner) beg (pop range) end (pop range)) (unless (eq corner (evil-visual-block-corner corner beg end)) (evil-swap beg end)) (goto-char beg) (when (evil-visual-state-p) (evil-move-mark end) (evil-visual-refresh nil nil nil :corner corner))) ((memq corner '(upper-right lower-right)) (goto-char (max beg end)) (when (evil-visual-state-p) (evil-move-mark (min beg end)))) (t (goto-char (min beg end)) (when (evil-visual-state-p) (evil-move-mark (max beg end))))))) ;;; Insertion commands (defun evil-insert (count &optional vcount skip-empty-lines) "Switch to Insert state just before point. The insertion will be repeated COUNT times and repeated once for the next VCOUNT - 1 lines starting at the same column. If SKIP-EMPTY-LINES is non-nil, the insertion will not be performed on lines on which the insertion point would be after the end of the lines. This is the default behaviour for Visual-state insertion." (interactive (list (prefix-numeric-value current-prefix-arg) (and (evil-visual-state-p) (memq (evil-visual-type) '(line block)) (save-excursion (let ((m (mark))) ;; go to upper-left corner temporarily so ;; `count-lines' yields accurate results (evil-visual-rotate 'upper-left) (prog1 (count-lines evil-visual-beginning evil-visual-end) (set-mark m))))) (evil-visual-state-p))) (if (and (called-interactively-p 'any) (evil-visual-state-p)) (cond ((eq (evil-visual-type) 'line) (evil-visual-rotate 'upper-left) (evil-insert-line count vcount)) ((eq (evil-visual-type) 'block) (let ((column (min (evil-column evil-visual-beginning) (evil-column evil-visual-end)))) (evil-visual-rotate 'upper-left) (move-to-column column t) (evil-insert count vcount skip-empty-lines))) (t (evil-visual-rotate 'upper-left) (evil-insert count vcount skip-empty-lines))) (setq evil-insert-count count evil-insert-lines nil evil-insert-vcount (and vcount (> vcount 1) (list (line-number-at-pos) (current-column) vcount)) evil-insert-skip-empty-lines skip-empty-lines) (evil-insert-state 1))) (defun evil-append (count &optional vcount skip-empty-lines) "Switch to Insert state just after point. The insertion will be repeated COUNT times and repeated once for the next VCOUNT - 1 lines starting at the same column. If SKIP-EMPTY-LINES is non-nil, the insertion will not be performed on lines on which the insertion point would be after the end of the lines." (interactive (list (prefix-numeric-value current-prefix-arg) (and (evil-visual-state-p) (memq (evil-visual-type) '(line block)) (save-excursion (let ((m (mark))) ;; go to upper-left corner temporarily so ;; `count-lines' yields accurate results (evil-visual-rotate 'upper-left) (prog1 (count-lines evil-visual-beginning evil-visual-end) (set-mark m))))))) (if (and (called-interactively-p 'any) (evil-visual-state-p)) (cond ((or (eq (evil-visual-type) 'line) (and (eq (evil-visual-type) 'block) (memq last-command '(next-line previous-line)) (numberp temporary-goal-column) (= temporary-goal-column most-positive-fixnum))) (evil-visual-rotate 'upper-left) (evil-append-line count vcount)) ((eq (evil-visual-type) 'block) (let ((column (max (evil-column evil-visual-beginning) (evil-column evil-visual-end)))) (evil-visual-rotate 'upper-left) (move-to-column column t) (evil-insert count vcount skip-empty-lines))) (t (evil-visual-rotate 'lower-right) (backward-char) (evil-append count))) (unless (eolp) (forward-char)) (evil-insert count vcount skip-empty-lines) (add-hook 'post-command-hook #'evil-maybe-remove-spaces))) (defun evil-insert-resume (count) "Switch to Insert state at previous insertion point. The insertion will be repeated COUNT times. If called from visual state, only place point at the previous insertion position but do not switch to insert state." (interactive "p") (evil-goto-mark ?^ t) (unless (evil-visual-state-p) (evil-insert count))) (defun evil-open-above (count) "Insert a new line above point and switch to Insert state. The insertion will be repeated COUNT times." (interactive "p") (unless (eq evil-want-fine-undo t) (evil-start-undo-step)) (evil-insert-newline-above) (setq evil-insert-count count evil-insert-lines t evil-insert-vcount nil) (evil-insert-state 1) (when evil-auto-indent (indent-according-to-mode))) (defun evil-open-below (count) "Insert a new line below point and switch to Insert state. The insertion will be repeated COUNT times." (interactive "p") (unless (eq evil-want-fine-undo t) (evil-start-undo-step)) (push (point) buffer-undo-list) (evil-insert-newline-below) (setq evil-insert-count count evil-insert-lines t evil-insert-vcount nil) (evil-insert-state 1) (when evil-auto-indent (indent-according-to-mode))) (defun evil-insert-line (count &optional vcount) "Switch to insert state at beginning of current line. Point is placed at the first non-blank character on the current line. The insertion will be repeated COUNT times. If VCOUNT is non nil it should be number > 0. The insertion will be repeated in the next VCOUNT - 1 lines below the current one." (interactive "p") (push (point) buffer-undo-list) (if (and visual-line-mode evil-respect-visual-line-mode) (goto-char (max (save-excursion (back-to-indentation) (point)) (save-excursion (beginning-of-visual-line) (point)))) (back-to-indentation)) (setq evil-insert-count count evil-insert-lines nil evil-insert-vcount (and vcount (> vcount 1) (list (line-number-at-pos) #'evil-first-non-blank vcount))) (evil-insert-state 1)) (defun evil-append-line (count &optional vcount) "Switch to Insert state at the end of the current line. The insertion will be repeated COUNT times. If VCOUNT is non nil it should be number > 0. The insertion will be repeated in the next VCOUNT - 1 lines below the current one." (interactive "p") (if (and visual-line-mode evil-respect-visual-line-mode) (evil-end-of-visual-line) (evil-move-end-of-line)) (setq evil-insert-count count evil-insert-lines nil evil-insert-vcount (and vcount (> vcount 1) (list (line-number-at-pos) #'end-of-line vcount))) (evil-insert-state 1)) (evil-define-command evil-insert-digraph (count) "Insert COUNT digraphs." :repeat change (interactive "p") (let ((digraph (evil-read-digraph-char 0))) (insert-char digraph count))) (evil-define-command evil-ex-show-digraphs () "Shows a list of all available digraphs." :repeat nil (let ((columns 3)) (evil-with-view-list :name "evil-digraphs" :mode-name "Evil Digraphs" :format (cl-loop repeat columns vconcat [("Digraph" 8 nil) ("Sequence" 16 nil)]) :entries (let* ((digraphs (mapcar #'(lambda (digraph) (cons (cdr digraph) (car digraph))) (append evil-digraphs-table evil-digraphs-table-user))) (entries (cl-loop for digraph in digraphs collect `(,(concat (char-to-string (nth 1 digraph)) (char-to-string (nth 2 digraph))) ,(char-to-string (nth 0 digraph))))) (row) (rows) (clength (* columns 2))) (cl-loop for e in entries do (push (nth 0 e) row) (push (nth 1 e) row) (when (eq (length row) clength) (push `(nil ,(apply #'vector row)) rows) (setq row nil))) rows)))) (defun evil--self-insert-string (string) "Insert STRING as if typed interactively." (let ((chars (append string nil))) (dolist (char chars) (let ((last-command-event char)) (self-insert-command 1))))) (defun evil-copy-from-above (arg) "Copy characters from preceding non-blank line. The copied text is inserted before point. ARG is the number of lines to move backward. See also \\\\[evil-copy-from-below]." (interactive (cond ;; if a prefix argument was given, repeat it for subsequent calls ((and (null current-prefix-arg) (eq last-command #'evil-copy-from-above)) (setq current-prefix-arg last-prefix-arg) (list (prefix-numeric-value current-prefix-arg))) (t (list (prefix-numeric-value current-prefix-arg))))) (evil--self-insert-string (evil-copy-chars-from-line arg -1))) (defun evil-copy-from-below (arg) "Copy characters from following non-blank line. The copied text is inserted before point. ARG is the number of lines to move forward. See also \\\\[evil-copy-from-above]." (interactive (cond ((and (null current-prefix-arg) (eq last-command #'evil-copy-from-below)) (setq current-prefix-arg last-prefix-arg) (list (prefix-numeric-value current-prefix-arg))) (t (list (prefix-numeric-value current-prefix-arg))))) (evil--self-insert-string (evil-copy-chars-from-line arg 1))) ;; adapted from `copy-from-above-command' in misc.el (defun evil-copy-chars-from-line (n num &optional col) "Return N characters from line NUM, starting at column COL. NUM is relative to the current line and can be negative. COL defaults to the current column." (interactive "p") (let ((col (or col (current-column))) prefix) (save-excursion (forward-line num) (when (looking-at "[[:space:]]*$") (if (< num 0) (skip-chars-backward " \t\n") (skip-chars-forward " \t\n"))) (evil-move-beginning-of-line) (move-to-column col) ;; if the column winds up in middle of a tab, ;; return the appropriate number of spaces (when (< col (current-column)) (if (eq (preceding-char) ?\t) (let ((len (min n (- (current-column) col)))) (setq prefix (make-string len ?\s) n (- n len))) ;; if in middle of a control char, return the whole char (backward-char 1))) (concat prefix (buffer-substring (point) (min (line-end-position) (+ n (point)))))))) ;; completion (evil-define-command evil-complete-next (&optional arg) "Complete to the nearest following word. Search backward if a match isn't found. Calls `evil-complete-next-func'." :repeat change (interactive "P") (if (minibufferp) (funcall evil-complete-next-minibuffer-func) (funcall evil-complete-next-func arg))) (evil-define-command evil-complete-previous (&optional arg) "Complete to the nearest preceding word. Search forward if a match isn't found. Calls `evil-complete-previous-func'." :repeat change (interactive "P") (if (minibufferp) (funcall evil-complete-previous-minibuffer-func) (funcall evil-complete-previous-func arg))) (evil-define-command evil-complete-next-line (&optional arg) "Complete a whole line. Calls `evil-complete-next-line-func'." :repeat change (interactive "P") (if (minibufferp) (funcall evil-complete-next-minibuffer-func) (funcall evil-complete-next-line-func arg))) (evil-define-command evil-complete-previous-line (&optional arg) "Complete a whole line. Calls `evil-complete-previous-line-func'." :repeat change (interactive "P") (if (minibufferp) (funcall evil-complete-previous-minibuffer-func) (funcall evil-complete-previous-line-func arg))) ;;; Search (defun evil-repeat-search (flag) "Called to record a search command. FLAG is either 'pre or 'post if the function is called before resp. after executing the command." (cond ((and (evil-operator-state-p) (eq flag 'pre)) (evil-repeat-record (this-command-keys)) (evil-clear-command-keys)) ((and (evil-operator-state-p) (eq flag 'post)) ;; The value of (this-command-keys) at this point should be the ;; key-sequence that called the last command that finished the ;; search, usually RET. Therefore this key-sequence will be ;; recorded in the post-command of the operator. Alternatively we ;; could do it here. (evil-repeat-record (if evil-regexp-search (car-safe regexp-search-ring) (car-safe search-ring)))) (t (evil-repeat-motion flag)))) (evil-define-motion evil-search-forward () (format "Search forward for user-entered text. Searches for regular expression if `evil-regexp-search' is t.%s" (if (and (fboundp 'isearch-forward) (documentation 'isearch-forward)) (format "\n\nBelow is the documentation string \ for `isearch-forward',\nwhich lists available keys:\n\n%s" (documentation 'isearch-forward)) "")) :jump t :type exclusive :repeat evil-repeat-search (evil-search-incrementally t evil-regexp-search)) (evil-define-motion evil-search-backward () (format "Search backward for user-entered text. Searches for regular expression if `evil-regexp-search' is t.%s" (if (and (fboundp 'isearch-forward) (documentation 'isearch-forward)) (format "\n\nBelow is the documentation string \ for `isearch-forward',\nwhich lists available keys:\n\n%s" (documentation 'isearch-forward)) "")) :jump t :type exclusive :repeat evil-repeat-search (evil-search-incrementally nil evil-regexp-search)) (evil-define-motion evil-search-next (count) "Repeat the last search." :jump t :type exclusive (let ((orig (point)) (search-string (if evil-regexp-search (car-safe regexp-search-ring) (car-safe search-ring)))) (goto-char ;; Wrap in `save-excursion' so that multiple searches have no visual effect. (save-excursion (evil-search search-string isearch-forward evil-regexp-search) (when (and (> (point) orig) (save-excursion (evil-adjust-cursor) (= (point) orig))) ;; Point won't move after first attempt and `evil-adjust-cursor' takes ;; effect, so start again. (evil-search search-string isearch-forward evil-regexp-search)) (point))) (when (and count (> count 1)) (dotimes (var (1- count)) (evil-search search-string isearch-forward evil-regexp-search))))) (evil-define-motion evil-search-previous (count) "Repeat the last search in the opposite direction." :jump t :type exclusive (dotimes (var (or count 1)) (evil-search (if evil-regexp-search (car-safe regexp-search-ring) (car-safe search-ring)) (not isearch-forward) evil-regexp-search))) (evil-define-motion evil-search-word-backward (count &optional symbol) "Search backward for symbol under point." :jump t :type exclusive (interactive (list (prefix-numeric-value current-prefix-arg) evil-symbol-word-search)) (dotimes (var (or count 1)) (evil-search-word nil nil symbol))) (evil-define-motion evil-search-word-forward (count &optional symbol) "Search forward for symbol under point." :jump t :type exclusive (interactive (list (prefix-numeric-value current-prefix-arg) evil-symbol-word-search)) (dotimes (var (or count 1)) (evil-search-word t nil symbol))) (evil-define-motion evil-search-unbounded-word-backward (count &optional symbol) "Search backward for symbol under point. The search is unbounded, i.e., the pattern is not wrapped in \\<...\\>." :jump t :type exclusive (interactive (list (prefix-numeric-value current-prefix-arg) evil-symbol-word-search)) (dotimes (var (or count 1)) (evil-search-word nil t symbol))) (evil-define-motion evil-search-unbounded-word-forward (count &optional symbol) "Search forward for symbol under point. The search is unbounded, i.e., the pattern is not wrapped in \\<...\\>." :jump t :type exclusive (interactive (list (prefix-numeric-value current-prefix-arg) evil-symbol-word-search)) (dotimes (var (or count 1)) (evil-search-word t t symbol))) (defun evil-goto-definition-imenu (string _position) "Find definition for STRING with imenu." (require 'imenu nil t) (let (ientry ipos) (when (fboundp 'imenu--make-index-alist) (ignore-errors (setq ientry (imenu--make-index-alist))) (setq ientry (assoc string ientry)) (setq ipos (cdr ientry)) (when (and (markerp ipos) (eq (marker-buffer ipos) (current-buffer))) (setq ipos (marker-position ipos)) (when (numberp ipos) (evil-search (format "\\_<%s\\_>" (regexp-quote string)) t t ipos) t))))) (defun evil-goto-definition-semantic (_string position) "Find definition for POSITION with semantic." (and (fboundp 'semantic-ia-fast-jump) (ignore-errors (semantic-ia-fast-jump position)))) (declare-function xref-backend-identifier-at-point "xref") (defun evil-goto-definition-xref (_string position) "Find definition at POSITION with xref." (when (fboundp 'xref-find-definitions) (let ((identifier (save-excursion (goto-char position) (xref-backend-identifier-at-point (xref-find-backend))))) (condition-case () (xref-find-definitions identifier) (user-error nil))))) (defun evil-goto-definition-search (string _position) "Find definition for STRING with evil-search." (evil-search (format "\\_<%s\\_>" (regexp-quote string)) t t (point-min)) t) (evil-define-motion evil-goto-definition () "Go to definition or first occurrence of symbol under point. See also `evil-goto-definition-functions'." :jump t :type exclusive (let* ((match (evil--find-thing t 'symbol)) (string (car match)) (position (cdr match))) (if (null string) (user-error "No symbol under cursor") (setq isearch-forward t) (run-hook-with-args-until-success 'evil-goto-definition-functions string position)))) ;;; Folding (defun evil-fold-action (list action) "Perform fold ACTION for each matching major or minor mode in LIST. ACTION will be performed for the first matching handler in LIST. For more information on its features and format, see the documentation for `evil-fold-list'. If no matching ACTION is found in LIST, an error will signaled. Handler errors will be demoted, so a problem in one handler will (hopefully) not interfere with another." (if (null list) (user-error "Enable one of the following modes for folding to work: %s" (mapconcat 'symbol-name (mapcar 'caar evil-fold-list) ", ")) (let* ((modes (caar list))) (if (evil--mode-p modes) (let* ((actions (cdar list)) (fn (plist-get actions action))) (when fn (with-demoted-errors (funcall fn)))) (evil-fold-action (cdr list) action))))) (defun evil--mode-p (modes) "Determines whether any symbol in MODES represents the current buffer's major mode or any of its minors." (unless (eq modes '()) (let ((mode (car modes))) (or (eq major-mode mode) (and (boundp mode) (symbol-value mode)) (evil--mode-p (cdr modes)))))) (evil-define-command evil-toggle-fold () "Open or close a fold under point. See also `evil-open-fold' and `evil-close-fold'." (evil-fold-action evil-fold-list :toggle)) (evil-define-command evil-open-folds () "Open all folds. See also `evil-close-folds'." (evil-fold-action evil-fold-list :open-all)) (evil-define-command evil-close-folds () "Close all folds. See also `evil-open-folds'." (evil-fold-action evil-fold-list :close-all)) (evil-define-command evil-open-fold () "Open fold at point. See also `evil-close-fold'." (evil-fold-action evil-fold-list :open)) (evil-define-command evil-open-fold-rec () "Open fold at point recursively. See also `evil-open-fold' and `evil-close-fold'." (evil-fold-action evil-fold-list :open-rec)) (evil-define-command evil-close-fold () "Close fold at point. See also `evil-open-fold'." (evil-fold-action evil-fold-list :close)) ;;; Ex (evil-define-operator evil-write (beg end type file-or-append &optional bang) "Save the current buffer, from BEG to END, to FILE-OR-APPEND. If FILE-OR-APPEND is of the form \">> FILE\", append to FILE instead of overwriting. The current buffer's filename is not changed unless it has no associated file and no region is specified. If the file already exists and the BANG argument is non-nil, it is overwritten without confirmation." :motion nil :move-point nil :type line :repeat nil (interactive "") (let* ((append-and-filename (evil-extract-append file-or-append)) (append (car append-and-filename)) (filename (cdr append-and-filename)) (bufname (buffer-file-name (buffer-base-buffer)))) (when (zerop (length filename)) (setq filename bufname)) (cond ((zerop (length filename)) (user-error "Please specify a file name for the buffer")) ;; execute command on region ((eq (aref filename 0) ?!) (shell-command-on-region beg end (substring filename 1))) ;; with region or append, always save to file without resetting ;; modified flag ((or append (and beg end)) (write-region beg end filename append nil nil (not (or append bang)))) ;; no current file ((null bufname) (write-file filename (not bang))) ;; save current buffer to its file ((string= filename bufname) (if (not bang) (save-buffer) (write-file filename))) ;; save to another file (t (write-region nil nil filename nil (not bufname) nil (not bang)))))) (evil-define-command evil-write-all (bang) "Saves all buffers visiting a file. If BANG is non nil then read-only buffers are saved, too, otherwise they are skipped. " :repeat nil :move-point nil (interactive "") (if bang (save-some-buffers t) ;; save only buffer that are not read-only and ;; that are visiting a file (save-some-buffers t #'(lambda () (and (not buffer-read-only) (buffer-file-name)))))) (evil-define-command evil-save (filename &optional bang) "Save the current buffer to FILENAME. Changes the file name of the current buffer to FILENAME. If no FILENAME is given, the current file name is used." :repeat nil :move-point nil (interactive "") (when (zerop (length filename)) (setq filename (buffer-file-name (buffer-base-buffer)))) (write-file filename (not bang))) (evil-define-command evil-edit (file &optional bang) "Open FILE. If no FILE is specified, reload the current buffer from disk." :repeat nil (interactive "") (if file (find-file file) (revert-buffer bang (or bang (not (buffer-modified-p))) t))) (evil-define-command evil-read (count file) "Inserts the contents of FILE below the current line or line COUNT." :repeat nil :move-point nil (interactive "P") (when (and file (not (zerop (length file)))) (when count (goto-char (point-min))) (when (or (not (zerop (forward-line (or count 1)))) (not (bolp))) (insert "\n")) (if (/= (aref file 0) ?!) (let ((result (insert-file-contents file))) (save-excursion (forward-char (cadr result)) (unless (bolp) (insert "\n")))) (shell-command (substring file 1) t) (save-excursion (goto-char (mark)) (unless (bolp) (insert "\n")))))) (evil-define-command evil-show-files () "Shows the file-list. The same as `buffer-menu', but shows only buffers visiting files." :repeat nil (buffer-menu 1)) (evil-define-command evil-goto-error (count) "Go to error number COUNT. If no COUNT supplied, move to the current error. Acts like `first-error' other than when given no counts, goes to the current error instead of the first, like in Vim's :cc command." :repeat nil (interactive "") (if count (first-error (if (eql 0 count) 1 count)) (next-error 0))) (evil-define-command evil-buffer (buffer) "Switches to another buffer." :repeat nil (interactive "") (cond ;; no buffer given, switch to "other" buffer ((null buffer) (switch-to-buffer (other-buffer))) ;; we are given the name of an existing buffer ((get-buffer buffer) (switch-to-buffer buffer)) ;; try to complete the buffer ((let ((all-buffers (internal-complete-buffer buffer nil t))) (when (= (length all-buffers) 1) (switch-to-buffer (car all-buffers))))) (t (when (y-or-n-p (format "No buffer with name \"%s\" exists. Create new buffer? " buffer)) (switch-to-buffer buffer))))) (evil-define-command evil-next-buffer (&optional count) "Goes to the `count'-th next buffer in the buffer list." :repeat nil (interactive "p") (dotimes (i (or count 1)) (next-buffer))) (evil-define-command evil-prev-buffer (&optional count) "Goes to the `count'-th prev buffer in the buffer list." :repeat nil (interactive "p") (dotimes (i (or count 1)) (previous-buffer))) (evil-define-command evil-delete-buffer (buffer &optional bang) "Deletes a buffer. All windows currently showing this buffer will be closed except for the last window in each frame." (interactive "") (with-current-buffer (or buffer (current-buffer)) (when bang (set-buffer-modified-p nil) (dolist (process (process-list)) (when (eq (process-buffer process) (current-buffer)) (set-process-query-on-exit-flag process nil)))) ;; get all windows that show this buffer (let ((wins (get-buffer-window-list (current-buffer) nil t))) ;; if the buffer which was initiated by emacsclient, ;; call `server-edit' from server.el to avoid ;; "Buffer still has clients" message (if (and (fboundp 'server-edit) (boundp 'server-buffer-clients) server-buffer-clients) (server-edit) (kill-buffer nil)) ;; close all windows that showed this buffer (mapc #'(lambda (w) (condition-case nil (delete-window w) (error nil))) wins)))) (evil-define-command evil-quit (&optional force) "Closes the current window, current frame, Emacs. If the current frame belongs to some client the client connection is closed." :repeat nil (interactive "") (condition-case nil (delete-window) (error (if (and (boundp 'server-buffer-clients) (fboundp 'server-edit) (fboundp 'server-buffer-done) server-buffer-clients) (if force (server-buffer-done (current-buffer)) (server-edit)) (condition-case nil (delete-frame) (error (if force (kill-emacs) (save-buffers-kill-emacs)))))))) (evil-define-command evil-quit-all (&optional bang) "Exits Emacs, asking for saving." :repeat nil (interactive "") (if (null bang) (save-buffers-kill-terminal) (let ((proc (frame-parameter (selected-frame) 'client))) (if proc (with-no-warnings (server-delete-client proc)) (dolist (process (process-list)) (set-process-query-on-exit-flag process nil)) (kill-emacs))))) (evil-define-command evil-quit-all-with-error-code (&optional force) "Exits Emacs without saving, returning an non-zero error code. The FORCE argument is only there for compatibility and is ignored. This function fails with an error if Emacs is run in server mode." :repeat nil (interactive "") (if (and (boundp 'server-buffer-clients) (fboundp 'server-edit) (fboundp 'server-buffer-done) server-buffer-clients) (user-error "Cannot exit client process with error code.") (kill-emacs 1))) (evil-define-command evil-save-and-quit () "Save all buffers and exit Emacs." (save-buffers-kill-terminal t)) (evil-define-command evil-save-and-close (file &optional bang) "Saves the current buffer and closes the window." :repeat nil (interactive "") (evil-write nil nil nil file bang) (evil-quit)) (evil-define-command evil-save-modified-and-close (file &optional bang) "Saves the current buffer and closes the window." :repeat nil (interactive "") (when (buffer-modified-p) (evil-write nil nil nil file bang)) (evil-quit)) (evil-define-operator evil-shell-command (beg end type command &optional previous) "Execute a shell command. If BEG, END and TYPE is specified, COMMAND is executed on the region, which is replaced with the command's output. Otherwise, the output is displayed in its own buffer. If PREVIOUS is non-nil, the previous shell command is executed instead." (interactive "") (if (not (evil-ex-p)) (let ((evil-ex-initial-input (if (and beg (not (evil-visual-state-p)) (not current-prefix-arg)) (let ((range (evil-range beg end type))) (evil-contract-range range) ;; TODO: this is not exactly the same as Vim, which ;; uses .,+count as range. However, this is easier ;; to achieve with the current implementation and ;; the very inconvenient range interface. ;; ;; TODO: the range interface really needs some ;; rework! (format "%d,%d!" (line-number-at-pos (evil-range-beginning range)) (line-number-at-pos (evil-range-end range)))) "!"))) (call-interactively 'evil-ex)) (when command (setq command (evil-ex-replace-special-filenames command))) (if (zerop (length command)) (when previous (setq command evil-previous-shell-command)) (setq evil-previous-shell-command command)) (cond ((zerop (length command)) (if previous (user-error "No previous shell command") (user-error "No shell command"))) (evil-ex-range (if (not evil-display-shell-error-in-message) (shell-command-on-region beg end command nil t) (let ((output-buffer (generate-new-buffer " *temp*")) (error-buffer (generate-new-buffer " *temp*"))) (unwind-protect (if (zerop (shell-command-on-region beg end command output-buffer nil error-buffer)) (progn (delete-region beg end) (insert-buffer-substring output-buffer) (goto-char beg) (evil-first-non-blank)) (display-message-or-buffer error-buffer)) (kill-buffer output-buffer) (kill-buffer error-buffer))))) (t (shell-command command))))) (evil-define-command evil-make (arg) "Call a build command in the current directory. If ARG is nil this function calls `recompile', otherwise it calls `compile' passing ARG as build command." (interactive "") (if (and (fboundp 'recompile) (not arg)) (recompile) (compile arg))) ;; TODO: escape special characters (currently only \n) ... perhaps ;; there is some Emacs function doing this? (evil-define-command evil-show-registers () "Shows the contents of all registers." :repeat nil (evil-with-view-list :name "evil-registers" :mode-name "Evil Registers" :format [("Register" 10 nil) ("Value" 1000 nil)] :entries (cl-loop for (key . val) in (evil-register-list) collect `(nil [,(char-to-string key) ,(cond ((stringp val) (replace-regexp-in-string "\n" "^J" val)) ((vectorp val) (key-description val)) (t ""))])))) (evil-define-command evil-show-marks (mrks) "Shows all marks. If MRKS is non-nil it should be a string and only registers corresponding to the characters of this string are shown." :repeat nil (interactive "") ;; To get markers and positions, we can't rely on 'global-mark-ring' ;; provided by Emacs (although it will be much simpler and faster), ;; because 'global-mark-ring' does not store mark characters, but ;; only buffer name and position. Instead, 'evil-markers-alist' is ;; used; this is list maintained by Evil for each buffer. (let ((all-markers ;; get global and local marks (append (cl-remove-if (lambda (m) (or (evil-global-marker-p (car m)) (not (markerp (cdr m))))) evil-markers-alist) (cl-remove-if (lambda (m) (or (not (evil-global-marker-p (car m))) (not (markerp (cdr m))))) (default-value 'evil-markers-alist))))) (when mrks (setq mrks (string-to-list mrks)) (setq all-markers (cl-delete-if (lambda (m) (not (member (car m) mrks))) all-markers))) ;; map marks to list of 4-tuples (char row col file) (setq all-markers (mapcar (lambda (m) (with-current-buffer (marker-buffer (cdr m)) (save-excursion (goto-char (cdr m)) (list (car m) (line-number-at-pos (point)) (current-column) (buffer-name))))) all-markers)) (evil-with-view-list :name "evil-marks" :mode-name "Evil Marks" :format [("Mark" 8 nil) ("Line" 8 nil) ("Column" 8 nil) ("Buffer" 1000 nil)] :entries (cl-loop for m in (sort all-markers (lambda (a b) (< (car a) (car b)))) collect `(nil [,(char-to-string (nth 0 m)) ,(number-to-string (nth 1 m)) ,(number-to-string (nth 2 m)) (,(nth 3 m))])) :select-action #'evil--show-marks-select-action))) (defun evil--show-marks-select-action (entry) (kill-buffer) (switch-to-buffer (car (elt entry 3))) (evil-goto-mark (string-to-char (elt entry 0)))) (evil-define-command evil-delete-marks (marks &optional force) "Delete all marks. MARKS is a string denoting all marks to be deleted. Mark names are either single characters or a range of characters in the form A-Z. If FORCE is non-nil all local marks except 0-9 are removed. " (interactive "") (cond ;; delete local marks except 0-9 (force (setq evil-markers-alist (cl-delete-if (lambda (m) (not (and (>= (car m) ?0) (<= (car m) ?9)))) evil-markers-alist))) (t (let ((i 0) (n (length marks)) delmarks) (while (< i n) (cond ;; skip spaces ((= (aref marks i) ?\s) (cl-incf i)) ;; ranges of marks ((and (< (+ i 2) n) (= (aref marks (1+ i)) ?-) (or (and (>= (aref marks i) ?a) (<= (aref marks i) ?z) (>= (aref marks (+ 2 i)) ?a) (<= (aref marks (+ 2 i)) ?z)) (and (>= (aref marks i) ?A) (<= (aref marks i) ?Z) (>= (aref marks (+ 2 i)) ?A) (<= (aref marks (+ 2 i)) ?Z)))) (let ((m (aref marks i))) (while (<= m (aref marks (+ 2 i))) (push m delmarks) (cl-incf m))) (cl-incf i 2)) ;; single marks (t (push (aref marks i) delmarks) (cl-incf i)))) ;; now remove all marks (setq evil-markers-alist (cl-delete-if (lambda (m) (member (car m) delmarks)) evil-markers-alist)) (set-default 'evil-markers-alist (cl-delete-if (lambda (m) (member (car m) delmarks)) (default-value 'evil-markers-alist))))))) (eval-when-compile (require 'ffap)) (evil-define-command evil-find-file-at-point-with-line () "Opens the file at point and goes to line-number." (require 'ffap) (let ((fname (with-no-warnings (ffap-file-at-point)))) (if fname (let ((line (save-excursion (goto-char (cadr ffap-string-at-point-region)) (and (re-search-backward ":\\([0-9]+\\)\\=" (line-beginning-position) t) (string-to-number (match-string 1)))))) (with-no-warnings (ffap-other-window)) (when line (goto-char (point-min)) (forward-line (1- line)))) (user-error "File does not exist.")))) (evil-ex-define-argument-type state "Defines an argument type which can take state names." :collection (lambda (arg predicate flag) (let ((completions (append '("nil") (mapcar #'(lambda (state) (format "%s" (car state))) evil-state-properties)))) (when arg (cond ((eq flag nil) (try-completion arg completions predicate)) ((eq flag t) (all-completions arg completions predicate)) ((eq flag 'lambda) (test-completion arg completions predicate)) ((eq (car-safe flag) 'boundaries) (cons 'boundaries (completion-boundaries arg completions predicate (cdr flag))))))))) (evil-define-interactive-code "" "A valid evil state." :ex-arg state (list (when (and (evil-ex-p) evil-ex-argument) (intern evil-ex-argument)))) ;; TODO: should we merge this command with `evil-set-initial-state'? (evil-define-command evil-ex-set-initial-state (state) "Set the initial state for the current major mode to STATE. This is the state the buffer comes up in. See `evil-set-initial-state'." :repeat nil (interactive "") (if (not (or (assq state evil-state-properties) (null state))) (user-error "State %s cannot be set as initial Evil state" state) (let ((current-initial-state (evil-initial-state major-mode))) (unless (eq current-initial-state state) ;; only if we selected a new mode (when (y-or-n-p (format "Major-mode `%s' has initial mode `%s'. \ Change to `%s'? " major-mode (or current-initial-state "DEFAULT") (or state "DEFAULT"))) (evil-set-initial-state major-mode state) (when (y-or-n-p "Save setting in customization file? ") (dolist (s (list current-initial-state state)) (when s (let ((var (intern (format "evil-%s-state-modes" s)))) (customize-save-variable var (symbol-value var))))))))))) (evil-define-command evil-force-normal-state () "Switch to normal state without recording current command." :repeat abort :suppress-operator t (evil-normal-state)) (evil-define-motion evil-ex-search-next (count) "Goes to the next occurrence." :jump t :type exclusive (evil-ex-search count)) (evil-define-motion evil-ex-search-previous (count) "Goes the the previous occurrence." :jump t :type exclusive (let ((evil-ex-search-direction (if (eq evil-ex-search-direction 'backward) 'forward 'backward))) (evil-ex-search count))) (defun evil-repeat-ex-search (flag) "Called to record a search command. FLAG is either 'pre or 'post if the function is called before resp. after executing the command." (cond ((and (evil-operator-state-p) (eq flag 'pre)) (evil-repeat-record (this-command-keys)) (evil-clear-command-keys)) ((and (evil-operator-state-p) (eq flag 'post)) ;; The value of (this-command-keys) at this point should be the ;; key-sequence that called the last command that finished the ;; search, usually RET. Therefore this key-sequence will be ;; recorded in the post-command of the operator. Alternatively we ;; could do it here. (evil-repeat-record (evil-ex-pattern-regex evil-ex-search-pattern))) (t (evil-repeat-motion flag)))) (evil-define-motion evil-ex-search-forward (count) "Starts a forward search." :jump t :type exclusive :repeat evil-repeat-ex-search (evil-ex-start-search 'forward count)) (evil-define-motion evil-ex-search-backward (count) "Starts a forward search." :jump t :repeat evil-repeat-ex-search (evil-ex-start-search 'backward count)) (evil-define-motion evil-ex-search-word-forward (count &optional symbol) "Search for the next occurrence of word under the cursor." :jump t :type exclusive (interactive (list (prefix-numeric-value current-prefix-arg) evil-symbol-word-search)) (evil-ex-start-word-search nil 'forward count symbol)) (evil-define-motion evil-ex-search-word-backward (count &optional symbol) "Search for the next occurrence of word under the cursor." :jump t :type exclusive (interactive (list (prefix-numeric-value current-prefix-arg) evil-symbol-word-search)) (evil-ex-start-word-search nil 'backward count symbol)) (evil-define-motion evil-ex-search-unbounded-word-forward (count &optional symbol) "Search for the next occurrence of word under the cursor." :jump t :type exclusive (interactive (list (prefix-numeric-value current-prefix-arg) evil-symbol-word-search)) (evil-ex-start-word-search t 'forward count symbol)) (evil-define-motion evil-ex-search-unbounded-word-backward (count &optional symbol) "Search for the next occurrence of word under the cursor." :jump t :type exclusive (interactive (list (prefix-numeric-value current-prefix-arg) evil-symbol-word-search)) (evil-ex-start-word-search t 'backward count symbol)) (defun evil-revert-reveal (open-spots) "Unconditionally close overlays in OPEN-SPOTS in current window. Modified version of `reveal-close-old-overlays' from reveal.el. OPEN-SPOTS is a local version of `reveal-open-spots'." (dolist (spot open-spots) (let ((window (car spot)) (ol (cdr spot))) (unless (eq window (selected-window)) (error "evil-revert-reveal: slot with wrong window")) (let* ((inv (overlay-get ol 'reveal-invisible)) (open (or (overlay-get ol 'reveal-toggle-invisible) (get inv 'reveal-toggle-invisible) (overlay-get ol 'isearch-open-invisible-temporary)))) (if (and (overlay-start ol) ;Check it's still live. open) (condition-case err (funcall open ol t) (error (message "!!Reveal-hide (funcall %s %s t): %s !!" open ol err))) (overlay-put ol 'invisible inv)) ;; Remove the overlay from the list of open spots. (overlay-put ol 'reveal-invisible nil))))) (evil-define-operator evil-ex-substitute (beg end pattern replacement flags) "The Ex substitute command. \[BEG,END]substitute/PATTERN/REPLACEMENT/FLAGS" :repeat nil :jump t :move-point nil :motion evil-line (interactive "") (evil-ex-nohighlight) (unless pattern (user-error "No pattern given")) (setq replacement (or replacement "")) (setq evil-ex-last-was-search nil) (let* ((flags (append flags nil)) (count-only (memq ?n flags)) (confirm (and (memq ?c flags) (not count-only))) (case-fold-search (evil-ex-pattern-ignore-case pattern)) (case-replace case-fold-search) (evil-ex-substitute-regex (evil-ex-pattern-regex pattern)) (evil-ex-substitute-nreplaced 0) (evil-ex-substitute-last-point (point)) (whole-line (evil-ex-pattern-whole-line pattern)) (evil-ex-substitute-overlay (make-overlay (point) (point))) (evil-ex-substitute-hl (evil-ex-make-hl 'evil-ex-substitute)) (orig-point-marker (move-marker (make-marker) (point))) (end-marker (move-marker (make-marker) end)) (use-reveal confirm) reveal-open-spots zero-length-match match-contains-newline transient-mark-mode) (setq evil-ex-substitute-pattern pattern evil-ex-substitute-replacement replacement evil-ex-substitute-flags flags isearch-string evil-ex-substitute-regex) (isearch-update-ring evil-ex-substitute-regex t) (unwind-protect (progn (evil-ex-hl-change 'evil-ex-substitute pattern) (overlay-put evil-ex-substitute-overlay 'face 'isearch) (overlay-put evil-ex-substitute-overlay 'priority 1001) (goto-char beg) (catch 'exit-search (while (re-search-forward evil-ex-substitute-regex end-marker t) (when (not (and query-replace-skip-read-only (text-property-any (match-beginning 0) (match-end 0) 'read-only t))) (let ((match-str (match-string 0)) (match-beg (move-marker (make-marker) (match-beginning 0))) (match-end (move-marker (make-marker) (match-end 0))) (match-data (match-data))) (goto-char match-beg) (setq match-contains-newline (string-match-p "\n" (buffer-substring-no-properties match-beg match-end))) (setq zero-length-match (= match-beg match-end)) (when (and (string= "^" evil-ex-substitute-regex) (= (point) end-marker)) ;; The range (beg end) includes the final newline which means ;; end-marker is on one line down. With the regex "^" the ;; beginning of this last line will be matched which we don't ;; want, so we abort here. (throw 'exit-search t)) (setq evil-ex-substitute-last-point match-beg) (if confirm (let ((prompt (format "Replace %s with %s (y/n/a/q/l/^E/^Y)? " match-str (evil-match-substitute-replacement evil-ex-substitute-replacement (not case-replace)))) (search-invisible t) response) (move-overlay evil-ex-substitute-overlay match-beg match-end) ;; Simulate `reveal-mode'. `reveal-mode' uses ;; `post-command-hook' but that won't work here. (when use-reveal (reveal-post-command)) (catch 'exit-read-char (while (setq response (read-char prompt)) (when (member response '(?y ?a ?l)) (unless count-only (set-match-data match-data) (evil-replace-match evil-ex-substitute-replacement (not case-replace))) (setq evil-ex-substitute-nreplaced (1+ evil-ex-substitute-nreplaced)) (evil-ex-hl-set-region 'evil-ex-substitute (save-excursion (forward-line) (point)) (evil-ex-hl-get-max 'evil-ex-substitute))) (cl-case response ((?y ?n) (throw 'exit-read-char t)) (?a (setq confirm nil) (throw 'exit-read-char t)) ((?q ?l ?\C-\[) (throw 'exit-search t)) (?\C-e (evil-scroll-line-down 1)) (?\C-y (evil-scroll-line-up 1)))))) (setq evil-ex-substitute-nreplaced (1+ evil-ex-substitute-nreplaced)) (unless count-only (set-match-data match-data) (evil-replace-match evil-ex-substitute-replacement (not case-replace)))) (goto-char match-end) (cond ((>= (point) end-marker) ;; Don't want to perform multiple replacements at the end ;; of the search region. (throw 'exit-search t)) ((and (not whole-line) (not match-contains-newline)) (forward-line) ;; forward-line just moves to the end of the line on the ;; last line of the buffer. (when (or (eobp) (> (point) end-marker)) (throw 'exit-search t))) ;; For zero-length matches check to see if point won't ;; move next time. This is a problem when matching the ;; regexp "$" because we can enter an infinite loop, ;; repeatedly matching the same character ((and zero-length-match (let ((pnt (point))) (save-excursion (and (re-search-forward evil-ex-substitute-regex end-marker t) (= pnt (point)))))) (if (or (eobp) (>= (point) end-marker)) (throw 'exit-search t) (forward-char))))))))) (evil-ex-delete-hl 'evil-ex-substitute) (delete-overlay evil-ex-substitute-overlay) (if count-only (goto-char orig-point-marker) (goto-char evil-ex-substitute-last-point)) (move-marker orig-point-marker nil) (move-marker end-marker nil) (when use-reveal (evil-revert-reveal reveal-open-spots))) (message "%s %d occurrence%s" (if count-only "Found" "Replaced") evil-ex-substitute-nreplaced (if (/= evil-ex-substitute-nreplaced 1) "s" "")) (evil-first-non-blank))) (evil-define-operator evil-ex-repeat-substitute (beg end flags) "Repeat last substitute command. This is the same as :s//~/" :repeat nil :jump t :move-point nil :motion evil-line (interactive "") (apply #'evil-ex-substitute beg end (evil-ex-get-substitute-info (concat "//~/" flags)))) (evil-define-operator evil-ex-repeat-substitute-with-flags (beg end flags) "Repeat last substitute command with last flags. This is the same as :s//~/&" :repeat nil :jump t :move-point nil :motion evil-line (interactive "") (apply #'evil-ex-substitute beg end (evil-ex-get-substitute-info (concat "//~/&" flags)))) (evil-define-operator evil-ex-repeat-substitute-with-search (beg end flags) "Repeat last substitute command with last search pattern. This is the same as :s//~/r" :repeat nil :jump t :move-point nil :motion evil-line (interactive "") (apply #'evil-ex-substitute beg end (evil-ex-get-substitute-info (concat "//~/r" flags)))) (evil-define-operator evil-ex-repeat-substitute-with-search-and-flags (beg end flags) "Repeat last substitute command with last search pattern and last flags. This is the same as :s//~/&r" :repeat nil :jump t :move-point nil :motion evil-line (interactive "") (apply #'evil-ex-substitute beg end (evil-ex-get-substitute-info (concat "//~/&r" flags)))) (evil-define-operator evil-ex-repeat-global-substitute () "Repeat last substitute command on the whole buffer. This is the same as :%s//~/&" :repeat nil :jump t :move-point nil :motion evil-line (interactive) (apply #'evil-ex-substitute (point-min) (point-max) (evil-ex-get-substitute-info (concat "//~/&")))) (evil-define-operator evil-ex-global (beg end pattern command &optional invert) "The Ex global command. \[BEG,END]global[!]/PATTERN/COMMAND" :motion mark-whole-buffer :move-point nil (interactive "") (unless pattern (user-error "No pattern given")) (unless command (user-error "No command given")) ;; TODO: `evil-ex-make-substitute-pattern' should be executed so ;; :substitute can re-use :global's pattern depending on its `r' ;; flag. This isn't supported currently but should be simple to add (evil-with-single-undo (let ((case-fold-search (eq (evil-ex-regex-case pattern evil-ex-search-case) 'insensitive)) (command-form (evil-ex-parse command)) (transient-mark-mode transient-mark-mode) (deactivate-mark deactivate-mark) match markers) (when (and pattern command) (setq isearch-string pattern) (isearch-update-ring pattern t) (goto-char beg) (evil-move-beginning-of-line) (while (< (point) end) (setq match (re-search-forward pattern (line-end-position) t)) (when (or (and match (not invert)) (and invert (not match))) (push (move-marker (make-marker) (or (and match (match-beginning 0)) (line-beginning-position))) markers)) (forward-line)) (setq markers (nreverse markers)) (unwind-protect (dolist (marker markers) (goto-char marker) (eval command-form)) ;; ensure that all markers are deleted afterwards, ;; even in the event of failure (dolist (marker markers) (set-marker marker nil))))))) (evil-define-operator evil-ex-global-inverted (beg end pattern command &optional invert) "The Ex vglobal command. \[BEG,END]vglobal/PATTERN/COMMAND" :motion mark-whole-buffer :move-point nil (interactive "") (evil-ex-global beg end pattern command (not invert))) (evil-define-operator evil-ex-normal (beg end commands) "The Ex normal command. Execute the argument as normal command on each line in the range. The given argument is passed straight to `execute-kbd-macro'. The default is the current line." :motion evil-line (interactive "") (evil-with-single-undo (let (markers evil-ex-current-buffer prefix-arg current-prefix-arg) (goto-char beg) (while (and (< (point) end) (progn (push (move-marker (make-marker) (line-beginning-position)) markers) (and (= (forward-line) 0) (bolp))))) (setq markers (nreverse markers)) (deactivate-mark) (evil-force-normal-state) ;; replace ^[ by escape (setq commands (vconcat (mapcar #'(lambda (ch) (if (equal ch ?) 'escape ch)) (append commands nil)))) (dolist (marker markers) (goto-char marker) (condition-case nil (execute-kbd-macro commands) (error nil)) (evil-force-normal-state) (set-marker marker nil))))) (evil-define-command evil-goto-char (position) "Go to POSITION in the buffer. Default position is the beginning of the buffer." (interactive "p") (let ((position (evil-normalize-position (or position (point-min))))) (goto-char position))) (evil-define-operator evil-ex-line-number (beg end) "Print the last line number." :motion mark-whole-buffer :move-point nil (interactive "") (message "%d" (count-lines (point-min) end))) (evil-define-command evil-show-file-info () "Shows basic file information." (let* ((nlines (count-lines (point-min) (point-max))) (curr (line-number-at-pos (point))) (perc (if (> nlines 0) (format "%d%%" (* (/ (float curr) (float nlines)) 100.0)) "No lines in buffer")) (file (buffer-file-name (buffer-base-buffer))) (writable (and file (file-writable-p file))) (readonly (if (and file (not writable)) "[readonly] " ""))) (if file (message "\"%s\" %d %slines --%s--" file nlines readonly perc) (message "%d lines --%s--" nlines perc)))) (evil-define-operator evil-ex-sort (beg end &optional options reverse) "The Ex sort command. \[BEG,END]sort[!] [i][u] The following additional options are supported: * i ignore case * u remove duplicate lines The 'bang' argument means to sort in reverse order." :motion mark-whole-buffer :move-point nil (interactive "") (let ((beg (copy-marker beg)) (end (copy-marker end)) sort-fold-case uniq) (dolist (opt (append options nil)) (cond ((eq opt ?i) (setq sort-fold-case t)) ((eq opt ?u) (setq uniq t)) (t (user-error "Unsupported sort option: %c" opt)))) (sort-lines reverse beg end) (when uniq (let (line prev-line) (goto-char beg) (while (and (< (point) end) (not (eobp))) (setq line (buffer-substring-no-properties (line-beginning-position) (line-end-position))) (if (and (stringp prev-line) (eq t (compare-strings line nil nil prev-line nil nil sort-fold-case))) (delete-region (progn (forward-line 0) (point)) (progn (forward-line 1) (point))) (setq prev-line line) (forward-line 1))))) (goto-char beg) (set-marker beg nil) (set-marker end nil))) ;;; Window navigation (defun evil-resize-window (new-size &optional horizontal) "Set the current window's width or height to NEW-SIZE. If HORIZONTAL is non-nil the width of the window is changed, otherwise its height is changed." (let ((count (- new-size (if horizontal (window-width) (window-height))))) (enlarge-window count horizontal))) (defun evil-get-buffer-tree (wintree) "Extracts the buffer tree from a given window tree WINTREE." (if (consp wintree) (cons (car wintree) (mapcar #'evil-get-buffer-tree (cddr wintree))) (window-buffer wintree))) (defun evil-restore-window-tree (win tree) "Restore the given buffer-tree layout as subwindows of WIN. TREE is the tree layout to be restored. A tree layout is either a buffer or a list of the form (DIR TREE ...), where DIR is t for horizontal split and nil otherwise. All other elements of the list are tree layouts itself." (if (bufferp tree) (set-window-buffer win tree) ;; if tree is buffer list with one buffer only, do not split ;; anymore (if (not (cddr tree)) (evil-restore-window-tree win (cadr tree)) ;; tree is a regular list, split recursively (let ((newwin (split-window win nil (not (car tree))))) (evil-restore-window-tree win (cadr tree)) (evil-restore-window-tree newwin (cons (car tree) (cddr tree))))))) (defun evil-alternate-buffer (&optional window) "Return the last buffer WINDOW has displayed other than the current one (equivalent to Vim's alternate buffer). Returns the first item in `window-prev-buffers' that isn't `window-buffer' of WINDOW." ;; If the last buffer visited has been killed, then `window-prev-buffers' ;; returns a list with `current-buffer' at the head, we account for this ;; possibility. (let* ((prev-buffers (window-prev-buffers)) (head (car prev-buffers))) (if (eq (car head) (window-buffer window)) (cadr prev-buffers) head))) (evil-define-command evil-switch-to-windows-last-buffer () "Switch to current windows last open buffer." :repeat nil (let ((previous-place (evil-alternate-buffer))) (when previous-place (switch-to-buffer (car previous-place)) (goto-char (car (last previous-place)))))) (evil-define-command evil-window-delete () "Deletes the current window. If `evil-auto-balance-windows' is non-nil then all children of the deleted window's parent window are rebalanced." (let ((p (window-parent))) (delete-window) (when evil-auto-balance-windows ;; balance-windows raises an error if the parent does not have ;; any further children (then rebalancing is not necessary anyway) (condition-case nil (balance-windows p) (error))))) (evil-define-command evil-window-split (&optional count file) "Splits the current window horizontally, COUNT lines height, editing a certain FILE. The new window will be created below when `evil-split-window-below' is non-nil. If COUNT and `evil-auto-balance-windows' are both non-nil then all children of the parent of the splitted window are rebalanced." :repeat nil (interactive "P") (split-window (selected-window) count (if evil-split-window-below 'above 'below)) (when (and (not count) evil-auto-balance-windows) (balance-windows (window-parent))) (when file (evil-edit file))) (evil-define-command evil-window-vsplit (&optional count file) "Splits the current window vertically, COUNT columns width, editing a certain FILE. The new window will be created to the right when `evil-vsplit-window-right' is non-nil. If COUNT and `evil-auto-balance-windows'are both non-nil then all children of the parent of the splitted window are rebalanced." :repeat nil (interactive "P") (split-window (selected-window) count (if evil-vsplit-window-right 'left 'right)) (when (and (not count) evil-auto-balance-windows) (balance-windows (window-parent))) (when file (evil-edit file))) (evil-define-command evil-split-buffer (buffer) "Splits window and switches to another buffer." :repeat nil (interactive "") (evil-window-split) (evil-buffer buffer)) (evil-define-command evil-split-next-buffer (&optional count) "Splits the window and goes to the COUNT-th next buffer in the buffer list." :repeat nil (interactive "p") (evil-window-split) (evil-next-buffer count)) (evil-define-command evil-split-prev-buffer (&optional count) "Splits window and goes to the COUNT-th prev buffer in the buffer list." :repeat nil (interactive "p") (evil-window-split) (evil-prev-buffer count)) (evil-define-command evil-window-left (count) "Move the cursor to new COUNT-th window left of the current one." :repeat nil (interactive "p") (dotimes (i count) (windmove-left))) (evil-define-command evil-window-right (count) "Move the cursor to new COUNT-th window right of the current one." :repeat nil (interactive "p") (dotimes (i count) (windmove-right))) (evil-define-command evil-window-up (count) "Move the cursor to new COUNT-th window above the current one." :repeat nil (interactive "p") (dotimes (i (or count 1)) (windmove-up))) (evil-define-command evil-window-down (count) "Move the cursor to new COUNT-th window below the current one." :repeat nil (interactive "p") (dotimes (i (or count 1)) (windmove-down))) (evil-define-command evil-window-bottom-right () "Move the cursor to bottom-right window." :repeat nil (let ((last-sibling (frame-root-window))) (while (and last-sibling (not (window-live-p last-sibling))) (setq last-sibling (window-last-child last-sibling))) (when last-sibling (select-window last-sibling)))) (evil-define-command evil-window-top-left () "Move the cursor to top-left window." :repeat nil (let ((first-child (window-child (frame-root-window)))) (while (and first-child (not (window-live-p first-child))) (setq first-child (window-child first-child))) (when first-child (select-window first-child)))) (evil-define-command evil-window-mru () "Move the cursor to the previous (last accessed) buffer in another window. More precisely, it selects the most recently used buffer that is shown in some other window, preferably of the current frame, and is different from the current one." :repeat nil (catch 'done (dolist (buf (buffer-list (selected-frame))) (let ((win (get-buffer-window buf))) (when (and (not (eq buf (current-buffer))) win (not (eq win (selected-window)))) (select-window win) (throw 'done nil)))))) (evil-define-command evil-window-next (count) "Move the cursor to the next window in the cyclic order. With COUNT go to the count-th window in the order starting from top-left." :repeat nil (interactive "") (if (not count) (select-window (next-window)) (evil-window-top-left) (other-window (1- count)))) (evil-define-command evil-window-prev (count) "Move the cursor to the previous window in the cyclic order. With COUNT go to the count-th window in the order starting from top-left." :repeat nil (interactive "") (if (not count) (select-window (previous-window)) (evil-window-top-left) (other-window (1- count)))) (evil-define-command evil-window-new (count file) "Splits the current window horizontally and opens a new buffer or edits a certain FILE." :repeat nil (interactive "P") (let ((new-window (split-window (selected-window) count (if evil-split-window-below 'below 'above)))) (when (and (not count) evil-auto-balance-windows) (balance-windows (window-parent))) (if file (evil-edit file) (let ((buffer (generate-new-buffer "*new*"))) (set-window-buffer new-window buffer) (select-window new-window) (with-current-buffer buffer (funcall (default-value 'major-mode))))))) (evil-define-command evil-window-vnew (count file) "Splits the current window vertically and opens a new buffer name or edits a certain FILE." :repeat nil (interactive "P") (let ((new-window (split-window (selected-window) count (if evil-vsplit-window-right 'right 'left)))) (when (and (not count) evil-auto-balance-windows) (balance-windows (window-parent))) (if file (evil-edit file) (let ((buffer (generate-new-buffer "*new*"))) (set-window-buffer new-window buffer) (select-window new-window) (with-current-buffer buffer (funcall (default-value 'major-mode))))))) (evil-define-command evil-buffer-new (count file) "Creates a new buffer replacing the current window, optionally editing a certain FILE" :repeat nil (interactive "P") (if file (evil-edit file) (let ((buffer (generate-new-buffer "*new*"))) (set-window-buffer nil buffer) (with-current-buffer buffer (funcall (default-value 'major-mode)))))) (evil-define-command evil-window-increase-height (count) "Increase current window height by COUNT." :repeat nil (interactive "p") (evil-resize-window (+ (window-height) count))) (evil-define-command evil-window-decrease-height (count) "Decrease current window height by COUNT." :repeat nil (interactive "p") (evil-resize-window (- (window-height) count))) (evil-define-command evil-window-increase-width (count) "Increase current window width by COUNT." :repeat nil (interactive "p") (evil-resize-window (+ (window-width) count) t)) (evil-define-command evil-window-decrease-width (count) "Decrease current window width by COUNT." :repeat nil (interactive "p") (evil-resize-window (- (window-width) count) t)) (evil-define-command evil-window-set-height (count) "Sets the height of the current window to COUNT." :repeat nil (interactive "") (evil-resize-window (or count (frame-height)) nil)) (evil-define-command evil-window-set-width (count) "Sets the width of the current window to COUNT." :repeat nil (interactive "") (evil-resize-window (or count (frame-width)) t)) (evil-define-command evil-ex-resize (arg) "The ex :resize command. If ARG is a signed positive integer, increase the current window height by ARG. If ARG is a signed negative integer, decrease the current window height by ARG. If ARG is a positive integer without explicit sign, set the current window height to ARG. If ARG is empty, maximize the current window height." (interactive "") (if (or (not arg) (= 0 (length arg))) (evil-window-set-height nil) (let ((n (string-to-number arg))) (if (> n 0) (if (= ?+ (aref arg 0)) (evil-window-increase-height n) (evil-window-set-height n)) (evil-window-decrease-height (- n)))))) (evil-define-command evil-window-rotate-upwards () "Rotates the windows according to the currenty cyclic ordering." :repeat nil (let ((wlist (window-list)) (blist (mapcar #'(lambda (w) (window-buffer w)) (window-list)))) (setq blist (append (cdr blist) (list (car blist)))) (while (and wlist blist) (set-window-buffer (car wlist) (car blist)) (setq wlist (cdr wlist) blist (cdr blist))) (select-window (car (last (window-list)))))) (evil-define-command evil-window-rotate-downwards () "Rotates the windows according to the currenty cyclic ordering." :repeat nil (let ((wlist (window-list)) (blist (mapcar #'(lambda (w) (window-buffer w)) (window-list)))) (setq blist (append (last blist) blist)) (while (and wlist blist) (set-window-buffer (car wlist) (car blist)) (setq wlist (cdr wlist) blist (cdr blist))) (select-window (cadr (window-list))))) (evil-define-command evil-window-move-very-top () "Closes the current window, splits the upper-left one horizontally and redisplays the current buffer there." :repeat nil (unless (one-window-p) (save-excursion (let ((b (current-buffer))) (delete-window) (let ((btree (evil-get-buffer-tree (car (window-tree))))) (delete-other-windows) (let ((newwin (selected-window)) (subwin (split-window))) (evil-restore-window-tree subwin btree) (set-window-buffer newwin b) (select-window newwin))))) (balance-windows))) (evil-define-command evil-window-move-far-left () "Closes the current window, splits the upper-left one vertically and redisplays the current buffer there." :repeat nil (unless (one-window-p) (save-excursion (let ((b (current-buffer))) (delete-window) (let ((btree (evil-get-buffer-tree (car (window-tree))))) (delete-other-windows) (let ((newwin (selected-window)) (subwin (split-window-horizontally))) (evil-restore-window-tree subwin btree) (set-window-buffer newwin b) (select-window newwin))))) (balance-windows))) (evil-define-command evil-window-move-far-right () "Closes the current window, splits the lower-right one vertically and redisplays the current buffer there." :repeat nil (unless (one-window-p) (save-excursion (let ((b (current-buffer))) (delete-window) (let ((btree (evil-get-buffer-tree (car (window-tree))))) (delete-other-windows) (let ((subwin (selected-window)) (newwin (split-window-horizontally))) (evil-restore-window-tree subwin btree) (set-window-buffer newwin b) (select-window newwin))))) (balance-windows))) (evil-define-command evil-window-move-very-bottom () "Closes the current window, splits the lower-right one horizontally and redisplays the current buffer there." :repeat nil (unless (one-window-p) (save-excursion (let ((b (current-buffer))) (delete-window) (let ((btree (evil-get-buffer-tree (car (window-tree))))) (delete-other-windows) (let ((subwin (selected-window)) (newwin (split-window))) (evil-restore-window-tree subwin btree) (set-window-buffer newwin b) (select-window newwin))))) (balance-windows))) ;;; Mouse handling ;; Large parts of this code are taken from mouse.el which is ;; distributed with GNU Emacs (defun evil-mouse-drag-region (start-event) "Set the region to the text that the mouse is dragged over. Highlight the drag area as you move the mouse. This must be bound to a button-down mouse event. If the click is in the echo area, display the `*Messages*' buffer. START-EVENT should be the event that started the drag." (interactive "e") ;; Give temporary modes such as isearch a chance to turn off. (run-hooks 'mouse-leave-buffer-hook) (evil-mouse-drag-track start-event t)) (evil-set-command-property 'evil-mouse-drag-region :keep-visual t) (defun evil-mouse-drag-track (start-event &optional do-mouse-drag-region-post-process) "Track mouse drags by highlighting area between point and cursor. The region will be defined with mark and point. DO-MOUSE-DRAG-REGION-POST-PROCESS should only be used by `mouse-drag-region'." (mouse-minibuffer-check start-event) (setq mouse-selection-click-count-buffer (current-buffer)) (deactivate-mark) (let* ((scroll-margin 0) ; Avoid margin scrolling (Bug#9541). (original-window (selected-window)) ;; We've recorded what we needed from the current buffer and ;; window, now let's jump to the place of the event, where things ;; are happening. (_ (mouse-set-point start-event)) (echo-keystrokes 0) (start-posn (event-start start-event)) (start-point (posn-point start-posn)) (start-window (posn-window start-posn)) (start-window-start (window-start start-window)) (start-hscroll (window-hscroll start-window)) (bounds (window-edges start-window)) (make-cursor-line-fully-visible nil) (top (nth 1 bounds)) (bottom (if (or (window-minibuffer-p start-window) (not mode-line-format)) (nth 3 bounds) ;; Don't count the mode line. (1- (nth 3 bounds)))) (on-link (and mouse-1-click-follows-link (or mouse-1-click-in-non-selected-windows (eq start-window original-window)) ;; Use start-point before the intangibility ;; treatment, in case we click on a link inside an ;; intangible text. (mouse-on-link-p start-posn))) (click-count (1- (event-click-count start-event))) (remap-double-click (and on-link (eq mouse-1-click-follows-link 'double) (= click-count 1))) ;; Suppress automatic hscrolling, because that is a nuisance ;; when setting point near the right fringe (but see below). (auto-hscroll-mode-saved auto-hscroll-mode) (auto-hscroll-mode nil) event end end-point) (setq mouse-selection-click-count click-count) ;; In case the down click is in the middle of some intangible text, ;; use the end of that text, and put it in START-POINT. (if (< (point) start-point) (goto-char start-point)) (setq start-point (point)) (if remap-double-click (setq click-count 0)) (setq click-count (mod click-count 4)) ;; activate correct visual state (let ((range (evil-mouse-start-end start-point start-point click-count))) (set-mark (nth 0 range)) (goto-char (nth 1 range))) (cond ((= click-count 0) (when (evil-visual-state-p) (evil-exit-visual-state))) ((= click-count 1) (evil-visual-char) (evil-visual-post-command)) ((= click-count 2) (evil-visual-line) (evil-visual-post-command)) ((= click-count 3) (evil-visual-block) (evil-visual-post-command))) ;; Track the mouse until we get a non-movement event. (track-mouse (while (progn (setq event (read-key)) (or (mouse-movement-p event) (memq (car-safe event) '(switch-frame select-window)))) (unless (evil-visual-state-p) (cond ((= click-count 0) (evil-visual-char)) ((= click-count 1) (evil-visual-char)) ((= click-count 2) (evil-visual-line)) ((= click-count 3) (evil-visual-block)))) (evil-visual-pre-command) (unless (memq (car-safe event) '(switch-frame select-window)) ;; Automatic hscrolling did not occur during the call to ;; `read-event'; but if the user subsequently drags the ;; mouse, go ahead and hscroll. (let ((auto-hscroll-mode auto-hscroll-mode-saved)) (redisplay)) (setq end (event-end event) end-point (posn-point end)) (if (and (eq (posn-window end) start-window) (integer-or-marker-p end-point)) (evil-mouse--drag-set-mark-and-point start-point end-point click-count) (let ((mouse-row (cdr (cdr (mouse-position))))) (cond ((null mouse-row)) ((< mouse-row top) (mouse-scroll-subr start-window (- mouse-row top) nil start-point)) ((>= mouse-row bottom) (mouse-scroll-subr start-window (1+ (- mouse-row bottom)) nil start-point)))))) (evil-visual-post-command))) ;; Handle the terminating event if possible. (when (consp event) ;; Ensure that point is on the end of the last event. (when (and (setq end-point (posn-point (event-end event))) (eq (posn-window end) start-window) (integer-or-marker-p end-point) (/= start-point end-point)) (evil-mouse--drag-set-mark-and-point start-point end-point click-count)) ;; Find its binding. (let* ((fun (key-binding (vector (car event)))) (do-multi-click (and (> (event-click-count event) 0) (functionp fun) (not (memq fun '(mouse-set-point mouse-set-region)))))) (if (and (or (/= (mark) (point)) (= click-count 1) ; word selection (and (memq (evil-visual-type) '(line block)))) (not do-multi-click)) ;; If point has moved, finish the drag. (let (last-command this-command) (and mouse-drag-copy-region do-mouse-drag-region-post-process (let (deactivate-mark) (evil-visual-expand-region) (copy-region-as-kill (mark) (point)) (evil-visual-contract-region)))) ;; If point hasn't moved, run the binding of the ;; terminating up-event. (if do-multi-click (goto-char start-point) (deactivate-mark)) (when (and (functionp fun) (= start-hscroll (window-hscroll start-window)) ;; Don't run the up-event handler if the window ;; start changed in a redisplay after the ;; mouse-set-point for the down-mouse event at ;; the beginning of this function. When the ;; window start has changed, the up-mouse event ;; contains a different position due to the new ;; window contents, and point is set again. (or end-point (= (window-start start-window) start-window-start))) (when (and on-link (= start-point (point)) (evil-mouse--remap-link-click-p start-event event)) ;; If we rebind to mouse-2, reselect previous selected ;; window, so that the mouse-2 event runs in the same ;; situation as if user had clicked it directly. Fixes ;; the bug reported by juri@jurta.org on 2005-12-27. (if (or (vectorp on-link) (stringp on-link)) (setq event (aref on-link 0)) (select-window original-window) (setcar event 'mouse-2) ;; If this mouse click has never been done by the ;; user, it doesn't have the necessary property to be ;; interpreted correctly. (put 'mouse-2 'event-kind 'mouse-click))) (push event unread-command-events))))))) ;; This function is a plain copy of `mouse--drag-set-mark-and-point', ;; which is only available in Emacs 24 (defun evil-mouse--drag-set-mark-and-point (start click click-count) (let* ((range (evil-mouse-start-end start click click-count)) (beg (nth 0 range)) (end (nth 1 range))) (cond ((eq (mark) beg) (goto-char end)) ((eq (mark) end) (goto-char beg)) ((< click (mark)) (set-mark end) (goto-char beg)) (t (set-mark beg) (goto-char end))))) ;; This function is a plain copy of `mouse--remap-link-click-p', ;; which is only available in Emacs 23 (defun evil-mouse--remap-link-click-p (start-event end-event) (or (and (eq mouse-1-click-follows-link 'double) (= (event-click-count start-event) 2)) (and (not (eq mouse-1-click-follows-link 'double)) (= (event-click-count start-event) 1) (= (event-click-count end-event) 1) (or (not (integerp mouse-1-click-follows-link)) (let ((t0 (posn-timestamp (event-start start-event))) (t1 (posn-timestamp (event-end end-event)))) (and (integerp t0) (integerp t1) (if (> mouse-1-click-follows-link 0) (<= (- t1 t0) mouse-1-click-follows-link) (< (- t0 t1) mouse-1-click-follows-link)))))))) (defun evil-mouse-start-end (start end mode) "Return a list of region bounds based on START and END according to MODE. If MODE is not 1 then set point to (min START END), mark to (max START END). If MODE is 1 then set point to start of word at (min START END), mark to end of word at (max START END)." (evil-sort start end) (setq mode (mod mode 4)) (if (/= mode 1) (list start end) (list (save-excursion (goto-char (min (point-max) (1+ start))) (if (zerop (forward-thing evil-mouse-word -1)) (let ((bpnt (point))) (forward-thing evil-mouse-word +1) (if (> (point) start) bpnt (point))) (point-min))) (save-excursion (goto-char end) (1- (if (zerop (forward-thing evil-mouse-word +1)) (let ((epnt (point))) (forward-thing evil-mouse-word -1) (if (<= (point) end) epnt (point))) (point-max))))))) ;;; State switching (evil-define-command evil-exit-emacs-state (&optional buffer message) "Exit Emacs state. Changes the state to the previous state, or to Normal state if the previous state was Emacs state." :keep-visual t :suppress-operator t (interactive '(nil t)) (with-current-buffer (or buffer (current-buffer)) (when (evil-emacs-state-p) (evil-change-to-previous-state buffer message) (when (evil-emacs-state-p) (evil-normal-state (and message 1)))))) (defun evil-execute-in-normal-state () "Execute the next command in Normal state." (interactive) (evil-delay '(not (memq this-command '(evil-execute-in-normal-state evil-use-register digit-argument negative-argument universal-argument universal-argument-minus universal-argument-more universal-argument-other-key))) `(progn (with-current-buffer ,(current-buffer) (evil-change-state ',evil-state) (setq evil-move-cursor-back ',evil-move-cursor-back))) 'post-command-hook) (setq evil-move-cursor-back nil) (evil-normal-state) (evil-echo "Switched to Normal state for the next command ...")) (defun evil-stop-execute-in-emacs-state () (when (and (not (eq this-command #'evil-execute-in-emacs-state)) (not (minibufferp))) (remove-hook 'post-command-hook 'evil-stop-execute-in-emacs-state) (when (buffer-live-p evil-execute-in-emacs-state-buffer) (with-current-buffer evil-execute-in-emacs-state-buffer (if (and (eq evil-previous-state 'visual) (not (use-region-p))) (progn (evil-change-to-previous-state) (evil-exit-visual-state)) (evil-change-to-previous-state)))) (setq evil-execute-in-emacs-state-buffer nil))) (evil-define-command evil-execute-in-emacs-state () "Execute the next command in Emacs state." (add-hook 'post-command-hook #'evil-stop-execute-in-emacs-state t) (setq evil-execute-in-emacs-state-buffer (current-buffer)) (cond ((evil-visual-state-p) (let ((mrk (mark)) (pnt (point))) (evil-emacs-state) (set-mark mrk) (goto-char pnt))) (t (evil-emacs-state))) (evil-echo "Switched to Emacs state for the next command ...")) (defun evil-exit-visual-and-repeat (event) "Exit insert state and repeat event. This special command should be used if some command called from visual state should actually be called in normal-state. The main reason for doing this is that the repeat system should *not* record the visual state information for some command. This command should be bound to exactly the same event in visual state as the original command is bound in normal state. EVENT is the event that triggered the execution of this command." (interactive "e") (when (evil-visual-state-p) (evil-exit-visual-state) (push event unread-command-events))) (evil-declare-ignore-repeat 'evil-exit-visual-and-repeat) (provide 'evil-commands) ;;; evil-commands.el ends here evil-1.12.17/evil-common.el000066400000000000000000004624011360703323200153770ustar00rootroot00000000000000;;; evil-common.el --- Common functions and utilities ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . (require 'evil-vars) (require 'evil-digraphs) (require 'rect) (require 'thingatpt) (require 'cl-lib) ;;; Code: (declare-function evil-visual-state-p "evil-states") (declare-function evil-visual-restore "evil-states") (declare-function evil-motion-state "evil-states") (declare-function evil-ex-p "evil-ex") (declare-function evil-set-jump "evil-jumps") (condition-case nil (require 'windmove) (error (message "evil: Could not load `windmove', \ window commands not available.") nil)) ;;; Compatibility with different Emacs versions ;; x-set-selection and x-get-selection have been deprecated since 25.1 ;; by gui-set-selection and gui-get-selection (defalias 'evil-get-selection (if (fboundp 'gui-get-selection) 'gui-get-selection 'x-get-selection)) (defalias 'evil-set-selection (if (fboundp 'gui-set-selection) 'gui-set-selection 'x-set-selection)) (defmacro evil-called-interactively-p () "Wrapper for `called-interactively-p'. In older versions of Emacs, `called-interactively-p' takes no arguments. In Emacs 23.2 and newer, it takes one argument." (called-interactively-p 'any)) (make-obsolete 'evil-called-interactively-p "please use (called-interactively-p 'any) instead." "Git commit 222b791") ;; macro helper (eval-and-compile (defun evil-unquote (exp) "Return EXP unquoted." (while (eq (car-safe exp) 'quote) (setq exp (cadr exp))) exp)) (defun evil-delay (condition form hook &optional append local name) "Execute FORM when CONDITION becomes true, checking with HOOK. NAME specifies the name of the entry added to HOOK. If APPEND is non-nil, the entry is appended to the hook. If LOCAL is non-nil, the buffer-local value of HOOK is modified." (if (and (not (booleanp condition)) (eval condition)) (eval form) (let* ((name (or name (format "evil-delay-form-in-%s" hook))) (fun (make-symbol name)) (condition (or condition t))) (fset fun `(lambda (&rest args) (when ,condition (remove-hook ',hook #',fun ',local) ,form))) (put fun 'permanent-local-hook t) (add-hook hook fun append local)))) (put 'evil-delay 'lisp-indent-function 2) ;;; List functions (defun evil-add-to-alist (list-var key val &rest elements) "Add the assocation of KEY and VAL to the value of LIST-VAR. If the list already contains an entry for KEY, update that entry; otherwise add at the end of the list." (let ((tail (symbol-value list-var))) (while (and tail (not (equal (car-safe (car-safe tail)) key))) (setq tail (cdr tail))) (if tail (setcar tail (cons key val)) (set list-var (append (symbol-value list-var) (list (cons key val))))) (if elements (apply #'evil-add-to-alist list-var elements) (symbol-value list-var)))) ;; custom version of `delete-if' (defun evil-filter-list (predicate list &optional pointer) "Delete by side-effect all items satisfying PREDICATE in LIST. Stop when reaching POINTER. If the first item satisfies PREDICATE, there is no way to remove it by side-effect; therefore, write \(setq foo (evil-filter-list 'predicate foo)) to be sure of changing the value of `foo'." (let ((tail list) elt head) (while (and tail (not (eq tail pointer))) (setq elt (car tail)) (cond ((funcall predicate elt) (setq tail (cdr tail)) (if head (setcdr head tail) (setq list tail))) (t (setq head tail tail (cdr tail))))) list)) (defun evil-member-if (predicate list &optional pointer) "Find the first item satisfying PREDICATE in LIST. Stop when reaching POINTER, which should point at a link in the list." (let (elt) (catch 'done (while (and (consp list) (not (eq list pointer))) (setq elt (car list)) (if (funcall predicate elt) (throw 'done elt) (setq list (cdr list))))))) (defun evil-member-recursive-if (predicate tree) "Find the first item satisfying PREDICATE in TREE." (cond ((funcall predicate tree) tree) ((listp tree) (catch 'done (dolist (elt tree) (when (setq elt (evil-member-recursive-if predicate elt)) (throw 'done elt))))))) (defun evil-concat-lists (&rest sequences) "Concatenate lists, removing duplicates. Elements are compared with `eq'." (let (result) (dolist (sequence sequences) (dolist (elt sequence) (add-to-list 'result elt nil #'eq))) (nreverse result))) (defun evil-concat-alists (&rest sequences) "Concatenate association lists, removing duplicates. An alist is a list of cons cells (KEY . VALUE) where each key may occur only once. Later values overwrite earlier values." (let (result) (dolist (sequence sequences) (dolist (elt sequence) (setq result (assq-delete-all (car-safe elt) result)) (push elt result))) (nreverse result))) (defun evil-concat-plists (&rest sequences) "Concatenate property lists, removing duplicates. A property list is a list (:KEYWORD1 VALUE1 :KEYWORD2 VALUE2...) where each keyword may occur only once. Later values overwrite earlier values." (let (result) (dolist (sequence sequences result) (while sequence (setq result (plist-put result (pop sequence) (pop sequence))))))) (defun evil-concat-keymap-alists (&rest sequences) "Concatenate keymap association lists, removing duplicates. A keymap alist is a list of cons cells (VAR . MAP) where each keymap may occur only once, but where the variables may be repeated \(e.g., (VAR . MAP1) (VAR . MAP2) is allowed). The order matters, with the highest priority keymaps being listed first." (let (result) (dolist (sequence sequences) (dolist (elt sequence) (unless (rassq (cdr-safe elt) result) (push elt result)))) (nreverse result))) (defun evil-plist-delete (prop plist) "Delete by side effect the property PROP from PLIST. If PROP is the first property in PLIST, there is no way to remove it by side-effect; therefore, write \(setq foo (evil-plist-delete :prop foo)) to be sure of changing the value of `foo'." (let ((tail plist) elt head) (while tail (setq elt (car tail)) (cond ((eq elt prop) (setq tail (cdr (cdr tail))) (if head (setcdr (cdr head) tail) (setq plist tail))) (t (setq head tail tail (cdr (cdr tail)))))) plist)) (defun evil-get-property (alist key &optional prop) "Return property PROP for KEY in ALIST. ALIST is an association list with entries of the form \(KEY . PLIST), where PLIST is a property list. If PROP is nil, return all properties for KEY. If KEY is t, return an association list of keys and their PROP values." (cond ((null prop) (cdr (assq key alist))) ((eq key t) (let (result val) (dolist (entry alist result) (setq key (car entry) val (cdr entry)) (when (plist-member val prop) (setq val (plist-get val prop)) (push (cons key val) result))))) (t (plist-get (cdr (assq key alist)) prop)))) (defun evil-put-property (alist-var key prop val &rest properties) "Set PROP to VAL for KEY in ALIST-VAR. ALIST-VAR points to an association list with entries of the form \(KEY . PLIST), where PLIST is a property list storing PROP and VAL." (set alist-var (let* ((alist (symbol-value alist-var)) (plist (cdr (assq key alist)))) (setq plist (plist-put plist prop val)) (when properties (setq plist (evil-concat-plists plist properties) val (car (last properties)))) (setq alist (assq-delete-all key alist)) (push (cons key plist) alist))) val) (defun evil-state-property (state prop &optional value) "Return the value of property PROP for STATE. PROP is a keyword as used by `evil-define-state'. STATE is the state's symbolic name. If VALUE is non-nil and the value is a variable, return the value of that variable." (let ((val (evil-get-property evil-state-properties state prop))) (if (and value (symbolp val) (boundp val)) (symbol-value val) val))) (defmacro evil-swap (this that &rest vars) "Swap the values of variables THIS and THAT. If three or more arguments are given, the values are rotated. E.g., (evil-swap A B C) sets A to B, B to C, and C to A." `(progn (setq ,this (prog1 ,that (setq ,that ,this))) ,@(when vars `((evil-swap ,that ,@vars))))) (defmacro evil-sort (min max &rest vars) "Place the smallest value in MIN and the largest in MAX. If three or more arguments are given, place the smallest value in the first argument and the largest in the last, sorting in between." (let ((sorted (make-symbol "sortvar"))) `(let ((,sorted (sort (list ,min ,max ,@vars) '<))) (setq ,min (pop ,sorted) ,max (pop ,sorted) ,@(apply #'append (mapcar #'(lambda (var) (list var `(pop ,sorted))) vars)))))) (defun evil-vector-to-string (vector) "Turns vector into a string, changing to '\\e'" (mapconcat (lambda (c) (if (equal c 'escape) "\e" (make-string 1 c))) vector "")) ;;; Command properties (defmacro evil-define-command (command &rest body) "Define a command COMMAND. \(fn COMMAND (ARGS...) DOC [[KEY VALUE]...] BODY...)" (declare (indent defun) (doc-string 3) (debug (&define name [&optional lambda-list] [&optional stringp] [&rest keywordp sexp] [&optional ("interactive" [&rest form])] def-body))) (let ((interactive '(interactive)) arg args doc doc-form key keys) ;; collect arguments (when (listp (car-safe body)) (setq args (pop body))) ;; collect docstring (when (> (length body) 1) (if (eq (car-safe (car-safe body)) 'format) (setq doc-form (pop body)) (when (stringp (car-safe body)) (setq doc (pop body))))) ;; collect keywords (setq keys (plist-put keys :repeat t)) (while (keywordp (car-safe body)) (setq key (pop body) arg (pop body)) (unless nil ; TODO: add keyword check (setq keys (plist-put keys key arg)))) ;; collect `interactive' form (when (and body (consp (car body)) (eq (car (car body)) 'interactive)) (let* ((iform (pop body)) (result (apply #'evil-interactive-form (cdr iform))) (form (car result)) (attrs (cdr result))) (setq interactive `(interactive ,form) keys (evil-concat-plists keys attrs)))) `(progn ;; the compiler does not recognize `defun' inside `let' ,(when (and command body) `(defun ,command ,args ,@(when doc `(,doc)) ,interactive ,@body)) ,(when (and command doc-form) `(put ',command 'function-documentation ,doc-form)) ;; set command properties for symbol or lambda function (let ((func ',(if (and (null command) body) `(lambda ,args ,interactive ,@body) command))) (apply #'evil-set-command-properties func ',keys) func)))) ;; If no Evil properties are defined for the command, several parts of ;; Evil apply certain default rules; e.g., the repeat system decides ;; whether the command is repeatable by monitoring buffer changes. (defun evil-has-command-property-p (command property) "Whether COMMAND has Evil PROPERTY. See also `evil-has-command-properties-p'." (plist-member (evil-get-command-properties command) property)) (defun evil-has-command-properties-p (command) "Whether Evil properties are defined for COMMAND. See also `evil-has-command-property-p'." (and (evil-get-command-properties command) t)) (defun evil-get-command-property (command property &optional default) "Return the value of Evil PROPERTY of COMMAND. If the command does not have the property, return DEFAULT. See also `evil-get-command-properties'." (if (evil-has-command-property-p command property) (evil-get-property evil-command-properties command property) default)) (defun evil-get-command-properties (command) "Return all Evil properties of COMMAND. See also `evil-get-command-property'." (evil-get-property evil-command-properties command)) (defun evil-set-command-property (command property value) "Set PROPERTY to VALUE for COMMAND. To set multiple properties at once, see `evil-set-command-properties' and `evil-add-command-properties'." (evil-put-property 'evil-command-properties command property value)) (defalias 'evil-put-command-property 'evil-set-command-property) (defun evil-add-command-properties (command &rest properties) "Add PROPERTIES to COMMAND. PROPERTIES should be a property list. To replace all properties at once, use `evil-set-command-properties'." (apply #'evil-put-property 'evil-command-properties command properties)) (defun evil-set-command-properties (command &rest properties) "Replace all of COMMAND's properties with PROPERTIES. PROPERTIES should be a property list. This erases all previous properties; to only add properties, use `evil-set-command-property'." (setq evil-command-properties (assq-delete-all command evil-command-properties)) (when properties (apply #'evil-add-command-properties command properties))) (defun evil-remove-command-properties (command &rest properties) "Remove PROPERTIES from COMMAND. PROPERTIES should be a list of properties (:PROP1 :PROP2 ...). If PROPERTIES is the empty list, all properties are removed." (let (plist) (when properties (setq plist (evil-get-command-properties command)) (dolist (property properties) (setq plist (evil-plist-delete property plist)))) (apply #'evil-set-command-properties command plist))) (defun evil-yank-handler (&optional motion) "Return the yank handler for MOTION. MOTION defaults to the current motion." (setq motion (or motion evil-this-motion)) (evil-get-command-property motion :yank-handler)) (defun evil-declare-motion (command) "Declare COMMAND to be a movement function. This ensures that it behaves correctly in Visual state." (evil-add-command-properties command :keep-visual t :repeat 'motion)) (defun evil-declare-repeat (command) "Declare COMMAND to be repeatable." (evil-add-command-properties command :repeat t)) (defun evil-declare-not-repeat (command) "Declare COMMAND to be nonrepeatable." (evil-add-command-properties command :repeat nil)) (defun evil-declare-ignore-repeat (command) "Declare COMMAND to be nonrepeatable." (evil-add-command-properties command :repeat 'ignore)) (defun evil-declare-change-repeat (command) "Declare COMMAND to be repeatable by buffer changes." (evil-add-command-properties command :repeat 'change)) (defun evil-declare-insert-at-point-repeat (command) "Declare COMMAND to be repeatable by buffer changes." (evil-add-command-properties command :repeat 'insert-at-point)) (defun evil-declare-abort-repeat (command) "Declare COMMAND to be nonrepeatable." (evil-add-command-properties command :repeat 'abort)) (defun evil-delimited-arguments (string &optional num) "Parse STRING as a sequence of delimited arguments. Returns a list of NUM strings, or as many arguments as the string contains. The first non-blank character is taken to be the delimiter. If some arguments are missing from STRING, the resulting list is padded with nil values. Two delimiters following directly after each other gives an empty string." (save-match-data (let ((string (or string "")) (count (or num -1)) (idx 0) argument delim match result) (when (string-match "^[[:space:]]*\\([^[:space:]]\\)" string) (setq delim (match-string 1 string) argument (format "%s\\(\\(?:[\\].\\|[^%s]\\)*\\)" (regexp-quote delim) delim)) (while (and (/= count 0) (string-match argument string idx)) (setq match (match-string 1 string) idx (match-end 1) count (1- count)) (when (= count 0) (unless (save-match-data (string-match (format "%s[[:space:]]*$" delim) string idx)) (setq match (substring string (match-beginning 1))))) (unless (and (zerop (length match)) (zerop (length (substring string idx)))) (push match result)))) (when (and num (< (length result) num)) (dotimes (i (- num (length result))) (push nil result))) (nreverse result)))) (defun evil-concat-charsets (&rest sets) "Concatenate character sets. A character set is the part between [ and ] in a regular expression. If any character set is complemented, the result is also complemented." (let ((bracket "") (complement "") (hyphen "") result) (save-match-data (dolist (set sets) (when (string-match-p "^\\^" set) (setq set (substring set 1) complement "^")) (when (string-match-p "^]" set) (setq set (substring set 1) bracket "]")) (when (string-match-p "^-" set) (setq set (substring set 1) hyphen "-")) (setq result (concat result set))) (format "%s%s%s%s" complement bracket hyphen result)))) ;;; Key sequences (defun evil-keypress-parser (&optional input) "Read from keyboard or INPUT and build a command description. Returns (CMD COUNT), where COUNT is the numeric prefix argument. Both COUNT and CMD may be nil." (let (count negative) (when input (setq unread-command-events (append input unread-command-events))) (catch 'done (while t (let ((seq (read-key-sequence ""))) (when seq (let ((cmd (key-binding seq))) (cond ((null cmd) (throw 'done (list nil nil))) ((arrayp cmd) ; keyboard macro, recursive call (let ((cmd (evil-keypress-parser cmd))) (throw 'done (list (car cmd) (if (or count (cadr cmd)) (list (car cmd) (* (or count 1) (or (cadr cmd) 1)))))))) ((or (eq cmd #'digit-argument) (and (eq cmd 'evil-digit-argument-or-evil-beginning-of-line) count)) (let* ((event (aref seq (- (length seq) 1))) (char (or (when (characterp event) event) (when (symbolp event) (get event 'ascii-character)))) (digit (if (or (characterp char) (integerp char)) (- (logand char ?\177) ?0)))) (setq count (+ (* 10 (or count 0)) digit)))) ((eq cmd #'negative-argument) (setq negative (not negative))) (t (throw 'done (list cmd (and count (* count (if negative -1 1)))))))))))))) (defun evil-read-key (&optional prompt) "Read a key from the keyboard. Translates it according to the input method." (let ((old-global-map (current-global-map)) (new-global-map (make-sparse-keymap)) (overriding-terminal-local-map nil) (overriding-local-map evil-read-key-map) seq char cmd) (unwind-protect (condition-case nil (progn (define-key new-global-map [menu-bar] (lookup-key global-map [menu-bar])) (define-key new-global-map [tab-bar] (lookup-key global-map [tab-bar])) (define-key new-global-map [tool-bar] (lookup-key global-map [tool-bar])) (add-to-list 'new-global-map (make-char-table 'display-table 'self-insert-command) t) (use-global-map new-global-map) (setq seq (read-key-sequence prompt nil t) char (aref seq 0) cmd (key-binding seq)) (while (arrayp cmd) (setq char (aref cmd 0) cmd (key-binding cmd))) (cond ((eq cmd 'self-insert-command) char) (cmd (call-interactively cmd)) (t (user-error "No replacement character typed")))) (quit (when (fboundp 'evil-repeat-abort) (evil-repeat-abort)) (signal 'quit nil))) (use-global-map old-global-map)))) (defun evil-read-quoted-char () "Command that calls `read-quoted-char'. This command can be used wherever `read-quoted-char' is required as a command. Its main use is in the `evil-read-key-map'." (interactive) (read-quoted-char)) (defun evil-read-digraph-char (&optional hide-chars) "Read two keys from keyboard forming a digraph. This function creates an overlay at (point), hiding the next HIDE-CHARS characters. HIDE-CHARS defaults to 1." (interactive) (let (char1 char2 string overlay) (unwind-protect (progn (setq overlay (make-overlay (point) (min (point-max) (+ (or hide-chars 1) (point))))) (overlay-put overlay 'invisible t) ;; create overlay prompt (setq string "?") (put-text-property 0 1 'face 'minibuffer-prompt string) ;; put cursor at (i.e., right before) the prompt (put-text-property 0 1 'cursor t string) (overlay-put overlay 'after-string string) (setq char1 (read-key)) (setq string (string char1)) (put-text-property 0 1 'face 'minibuffer-prompt string) (put-text-property 0 1 'cursor t string) (overlay-put overlay 'after-string string) (setq char2 (read-key))) (delete-overlay overlay)) (or (evil-digraph (list char1 char2)) ;; use the last character if undefined char2))) (defun evil-read-motion (&optional motion count type modifier) "Read a MOTION, motion COUNT and motion TYPE from the keyboard. The type may be overridden with MODIFIER, which may be a type or a Visual selection as defined by `evil-define-visual-selection'. Return a list (MOTION COUNT [TYPE])." (let ((modifiers '((evil-visual-char . char) (evil-visual-line . line) (evil-visual-block . block))) command prefix) (setq evil-this-type-modified nil) (unless motion (while (progn (setq command (evil-keypress-parser) motion (pop command) prefix (pop command)) (when prefix (if count (setq count (string-to-number (concat (number-to-string count) (number-to-string prefix)))) (setq count prefix))) ;; if the command is a type modifier, read more (when (rassq motion evil-visual-alist) (setq modifier (or modifier (car (rassq motion evil-visual-alist)))))))) (when modifier (setq type (or type (evil-type motion 'exclusive))) (cond ((eq modifier 'char) ;; TODO: this behavior could be less hard-coded (if (eq type 'exclusive) (setq type 'inclusive) (setq type 'exclusive))) (t (setq type modifier))) (setq evil-this-type-modified type)) (list motion count type))) (defun evil-mouse-events-p (keys) "Returns non-nil iff KEYS contains a mouse event." (catch 'done (dotimes (i (length keys)) (when (or (and (fboundp 'mouse-event-p) (mouse-event-p (aref keys i))) (mouse-movement-p (aref keys i))) (throw 'done t))) nil)) (defun evil-extract-count (keys) "Splits the key-sequence KEYS into prefix-argument and the rest. Returns the list (PREFIX CMD SEQ REST), where PREFIX is the prefix count, CMD the command to be executed, SEQ the subsequence calling CMD, and REST is all remaining events in the key-sequence. PREFIX and REST may be nil if they do not exist. If a command is bound to some keyboard macro, it is expanded recursively." (catch 'done (let* ((len (length keys)) (beg 0) (end 1) (found-prefix nil)) (while (and (<= end len)) (let ((cmd (key-binding (substring keys beg end)))) (cond ((memq cmd '(undefined nil)) (user-error "No command bound to %s" (substring keys beg end))) ((arrayp cmd) ; keyboard macro, replace command with macro (setq keys (vconcat (substring keys 0 beg) cmd (substring keys end)) end (1+ beg) len (length keys))) ((functionp cmd) (if (or (memq cmd '(digit-argument negative-argument)) (and found-prefix (evil-get-command-property cmd :digit-argument-redirection))) ;; skip those commands (setq found-prefix t ; found at least one prefix argument beg end end (1+ end)) ;; a real command, finish (throw 'done (list (unless (zerop beg) (string-to-number (concat (substring keys 0 beg)))) cmd (substring keys beg end) (when (< end len) (substring keys end)))))) (t ; append a further event (setq end (1+ end)))))) (user-error "Key sequence contains no complete binding")))) (defmacro evil-redirect-digit-argument (map keys target) "Bind a wrapper function calling TARGET or `digit-argument'. MAP is a keymap for binding KEYS to the wrapper for TARGET. The wrapper only calls `digit-argument' if a prefix-argument has already been started; otherwise TARGET is called." (let* ((target (eval target)) (wrapper (intern (format "evil-digit-argument-or-%s" target)))) `(progn (define-key ,map ,keys ',wrapper) (evil-define-command ,wrapper () :digit-argument-redirection ,target :keep-visual t :repeat nil (interactive) (cond (current-prefix-arg (setq this-command #'digit-argument) (call-interactively #'digit-argument)) (t (let ((target (or (command-remapping #',target) #',target))) (setq this-command target) (call-interactively target)))))))) (defun evil-extract-append (file-or-append) "Return an (APPEND . FILENAME) pair based on FILE-OR-APPEND. FILE-OR-APPEND should either be a filename or a \">> FILE\" directive. APPEND will be t if FILE-OR-APPEND is an append directive and nil otherwise. FILENAME will be the extracted filename." (if (and (stringp file-or-append) (string-match "\\(>> *\\)" file-or-append)) (cons t (substring file-or-append(match-end 1))) (cons nil file-or-append))) (defun evil-set-keymap-prompt (map prompt) "Set the prompt-string of MAP to PROMPT." (delq (keymap-prompt map) map) (when prompt (setcdr map (cons prompt (cdr map))))) (defun evil-lookup-key (map key) "Returns non-nil value if KEY is bound in MAP." (let ((definition (lookup-key map key))) (if (numberp definition) ; in-band error nil definition))) ;;; Display (defun evil-set-cursor (specs) "Change the cursor's apperance according to SPECS. SPECS may be a cursor type as per `cursor-type', a color string as passed to `set-cursor-color', a zero-argument function for changing the cursor, or a list of the above." (unless (and (not (functionp specs)) (listp specs) (null (cdr-safe (last specs)))) (setq specs (list specs))) (dolist (spec specs) (cond ((functionp spec) (condition-case nil (funcall spec) (error nil))) ((stringp spec) (evil-set-cursor-color spec)) (t (setq cursor-type spec))))) (defun evil-set-cursor-color (color) "Set the cursor color to COLOR." (unless (equal (frame-parameter nil 'cursor-color) color) ;; `set-cursor-color' forces a redisplay, so only ;; call it when the color actually changes (set-cursor-color color))) (defun evil-refresh-cursor (&optional state buffer) "Refresh the cursor for STATE in BUFFER. BUFFER defaults to the current buffer. If STATE is nil the cursor type is either `evil-force-cursor' or the current state." (when (and (boundp 'evil-local-mode) evil-local-mode) (let* ((state (or state evil-force-cursor evil-state 'normal)) (default (or evil-default-cursor t)) (cursor (evil-state-property state :cursor t)) (color (or (and (stringp cursor) cursor) (and (listp cursor) (evil-member-if #'stringp cursor)) (frame-parameter nil 'cursor-color)))) (with-current-buffer (or buffer (current-buffer)) ;; if both STATE and `evil-default-cursor' ;; specify a color, don't set it twice (when (and color (listp default)) (setq default (evil-filter-list #'stringp default))) (evil-set-cursor default) (evil-set-cursor cursor))))) (defmacro evil-save-cursor (&rest body) "Save the current cursor; execute BODY; restore the cursor." (declare (indent defun) (debug t)) `(let ((cursor cursor-type) (color (frame-parameter (selected-frame) 'cursor-color)) (inhibit-quit t)) (unwind-protect (progn ,@body) (evil-set-cursor cursor) (evil-set-cursor color)))) (defun evil-echo (string &rest args) "Display an unlogged message in the echo area. That is, the message is not logged in the *Messages* buffer. \(To log the message, just use `message'.)" (unless evil-no-display (let (message-log-max) (apply #'message string args)))) (defun evil-echo-area-save () "Save the current echo area in `evil-echo-area-message'." (setq evil-echo-area-message (current-message))) (defun evil-echo-area-restore () "Restore the echo area from `evil-echo-area-message'. Does not restore if `evil-write-echo-area' is non-nil." (unless evil-write-echo-area (if evil-echo-area-message (message "%s" evil-echo-area-message) (message nil))) (setq evil-echo-area-message nil evil-write-echo-area nil)) ;; toggleable version of `with-temp-message' (defmacro evil-save-echo-area (&rest body) "Save the echo area; execute BODY; restore the echo area. Intermittent messages are not logged in the *Messages* buffer." (declare (indent defun) (debug t)) `(let ((inhibit-quit t) evil-echo-area-message evil-write-echo-area) (unwind-protect (progn (evil-echo-area-save) ,@body) (evil-echo-area-restore)))) (defmacro evil-without-display (&rest body) "Execute BODY without Evil displays. Inhibits echo area messages, mode line updates and cursor changes." (declare (indent defun) (debug t)) `(let ((evil-no-display t)) ,@body)) (defvar evil-cached-header-line-height nil "Cached height of the header line.") (defun evil-header-line-height () "Return the height of the header line. If there is no header line, return nil." (let ((posn (posn-at-x-y 0 0))) (when (eq (posn-area posn) 'header-line) (cdr (posn-object-width-height posn))))) (defun evil-posn-x-y (position) "Return the x and y coordinates in POSITION. This function returns y offset from the top of the buffer area including the header line. On Emacs 24 and later versions, the y-offset returned by `posn-at-point' is relative to the text area excluding the header line, while y offset taken by `posn-at-x-y' is relative to the buffer area including the header line. This asymmetry is by design according to GNU Emacs team. This function fixes the asymmetry between them. Learned from mozc.el." (let ((xy (posn-x-y position))) (when header-line-format (setcdr xy (+ (cdr xy) (or evil-cached-header-line-height (setq evil-cached-header-line-height (evil-header-line-height)) 0)))) xy)) (defun evil-count-lines (beg end) "Return absolute line-number-difference betweeen `beg` and `end`. This should give the same results no matter where on the line `beg` and `end` are." (if (= beg end) 0 (let* ((last (max beg end)) (end-at-bol (save-excursion (goto-char last) (bolp)))) (if end-at-bol (count-lines beg end) (1- (count-lines beg end)))))) ;;; Movement (defun evil-normalize-position (pos) "Return POS if it does not exceed the buffer boundaries. If POS is less than `point-min', return `point-min'. Is POS is more than `point-max', return `point-max'. If POS is a marker, return its position." (cond ((not (number-or-marker-p pos)) pos) ((< pos (point-min)) (point-min)) ((> pos (point-max)) (point-max)) ((markerp pos) (marker-position pos)) (t pos))) (defmacro evil-save-goal-column (&rest body) "Restores the goal column after execution of BODY. See also `evil-save-column'." (declare (indent defun) (debug t)) `(let ((goal-column goal-column) (temporary-goal-column temporary-goal-column)) ,@body)) (defmacro evil-save-column (&rest body) "Restores the column after execution of BODY. See also `evil-save-goal-column'." (declare (indent defun) (debug t)) `(let ((col (current-column))) (evil-save-goal-column ,@body (move-to-column col)))) (defun evil-narrow (beg end) "Restrict the buffer to BEG and END. BEG or END may be nil, specifying a one-sided restriction including `point-min' or `point-max'. See also `evil-with-restriction.'" (setq beg (or (evil-normalize-position beg) (point-min))) (setq end (or (evil-normalize-position end) (point-max))) (narrow-to-region beg end)) (defmacro evil-with-restriction (beg end &rest body) "Execute BODY with the buffer narrowed to BEG and END. BEG or END may be nil as passed to `evil-narrow'; this creates a one-sided restriction." (declare (indent 2) (debug t)) `(save-restriction (let ((evil-restriction-stack (cons (cons (point-min) (point-max)) evil-restriction-stack))) (evil-narrow ,beg ,end) ,@body))) (defmacro evil-without-restriction (&rest body) "Execute BODY with the top-most narrowing removed. This works only if the previous narrowing has been generated by `evil-with-restriction'." (declare (indent defun) (debug t)) `(save-restriction (widen) (narrow-to-region (car (car evil-restriction-stack)) (cdr (car evil-restriction-stack))) (let ((evil-restriction-stack (cdr evil-restriction-stack))) ,@body))) (defmacro evil-narrow-to-field (&rest body) "Narrow to the current field." (declare (indent defun) (debug t)) `(evil-with-restriction (field-beginning) (field-end) ,@body)) (defun evil-move-beginning-of-line (&optional arg) "Move to the beginning of the line as displayed. Like `move-beginning-of-line', but retains the goal column." (evil-save-goal-column (move-beginning-of-line arg) (beginning-of-line))) (defun evil-move-end-of-line (&optional arg) "Move to the end of the line as displayed. Like `move-end-of-line', but retains the goal column." (evil-save-goal-column (move-end-of-line arg) (end-of-line))) (defun evil-adjust-cursor (&optional _) "Move point one character back if at the end of a non-empty line. This behavior is controled by `evil-move-beyond-eol'." (when (and (eolp) (not evil-move-beyond-eol) (not (bolp)) (= (point) (save-excursion (evil-move-end-of-line) (point)))) (evil-move-cursor-back t))) (defun evil-move-cursor-back (&optional force) "Move point one character back within the current line. Contingent on the variable `evil-move-cursor-back' or the FORCE argument. Honors field boundaries, i.e., constrains the movement to the current field as recognized by `line-beginning-position'." (when (or evil-move-cursor-back force) (unless (or (= (point) (line-beginning-position)) (and (boundp 'visual-line-mode) visual-line-mode (= (point) (save-excursion (beginning-of-visual-line) (point))))) (backward-char)))) (defun evil-line-position (line &optional column) "Return the position of LINE. If COLUMN is specified, return its position on the line. A negative number means the end of the line." (save-excursion (when (fboundp 'evil-goto-line) (evil-goto-line line)) (if (numberp column) (if (< column 0) (beginning-of-line 2) (move-to-column column)) (beginning-of-line)) (point))) (defun evil-column (&optional pos) "Return the horizontal position of POS. POS defaults to point." (save-excursion (when pos (goto-char pos)) (current-column))) (defun evil-move-to-column (column &optional dir force) "Move point to column COLUMN in the current line. Places point at left of the tab character (at the right if DIR is non-nil) and returns point." (interactive "p") (move-to-column column force) (unless force (when (or (not dir) (and (numberp dir) (< dir 1))) (when (> (current-column) column) (evil-move-cursor-back)))) (point)) (defmacro evil-loop (spec &rest body) "Loop with countdown variable. Evaluate BODY with VAR counting down from COUNT to 0. COUNT can be negative, in which case VAR counts up instead. The return value is the value of VAR when the loop terminates, which is 0 if the loop completes successfully. RESULT specifies a variable for storing this value. \(fn (VAR COUNT [RESULT]) BODY...)" (declare (indent defun) (debug dolist)) (let* ((i (make-symbol "loopvar")) (var (pop spec)) (count (pop spec)) (result (pop spec))) (setq var (or (unless (eq var result) var) i) result (or result var)) `(let ((,var ,count)) (setq ,result ,var) (while (/= ,var 0) ,@body (if (> ,var 0) (setq ,var (1- ,var)) (setq ,var (1+ ,var))) (setq ,result ,var)) ,var))) ;;; Motions (defmacro evil-motion-loop (spec &rest body) "Loop a certain number of times. Evaluate BODY repeatedly COUNT times with VAR bound to 1 or -1, depending on the sign of COUNT. RESULT, if specified, holds the number of unsuccessful iterations, which is 0 if the loop completes successfully. This is also the return value. Each iteration must move point; if point does not change, the loop immediately quits. See also `evil-loop'. \(fn (VAR COUNT [RESULT]) BODY...)" (declare (indent defun) (debug ((symbolp form &optional symbolp) body))) (let* ((var (or (pop spec) (make-symbol "unitvar"))) (countval (or (pop spec) 0)) (result (pop spec)) (i (make-symbol "loopvar")) (count (make-symbol "countvar")) (done (make-symbol "donevar")) (orig (make-symbol "origvar"))) `(let* ((,count ,countval) (,var (if (< ,count 0) -1 1))) (catch ',done (evil-loop (,i ,count ,result) (let ((,orig (point))) ,@body (when (= (point) ,orig) (throw ',done ,i)))))))) (defmacro evil-signal-without-movement (&rest body) "Catches errors provided point moves within this scope." (declare (indent defun) (debug t)) `(let ((p (point))) (condition-case err (progn ,@body) (error (when (= p (point)) (signal (car err) (cdr err))))))) (defun evil-signal-at-bob-or-eob (&optional count) "Signals error if `point' is at boundaries. If `point' is at bob and COUNT is negative this function signal 'beginning-of-buffer. If `point' is at eob and COUNT is positive this function singal 'end-of-buffer. This function should be used in motions. COUNT defaults to 1." (setq count (or count 1)) (cond ((< count 0) (evil-signal-at-bob)) ((> count 0) (evil-signal-at-eob)))) (defun evil-signal-at-bob () "Signals 'beginning-of-buffer if `point' is at bob. This function should be used in backward motions. If `point' is at bob so that no further backward motion is possible the error 'beginning-of-buffer is raised." (when (bobp) (signal 'beginning-of-buffer nil))) (defun evil-signal-at-eob () "Signals 'end-of-buffer if `point' is at eob. This function should be used in forward motions. If `point' is close to eob so that no further forward motion is possible the error 'end-of-buffer is raised. This is the case if `point' is at `point-max' or if is one position before `point-max', `evil-move-beyond-eol' is nil and `point' is not at the end of a line. The latter is necessary because `point' cannot be moved to `point-max' if `evil-move-beyond-eol' is nil and the last line in the buffer is not empty." (when (or (eobp) (and (not (eolp)) (not evil-move-beyond-eol) (save-excursion (forward-char) (eobp)))) (signal 'end-of-buffer nil))) (defmacro evil-with-hproject-point-on-window (&rest body) "Project point after BODY to current window. If point is on a position left or right of the current window then it is moved to the left and right boundary of the window, respectively. If `auto-hscroll-mode' is non-nil then the left and right positions are increased or decreased, respectively, by `horizontal-margin' so that no automatic scrolling occurs." (declare (indent defun) (debug t)) (let ((diff (make-symbol "diff")) (left (make-symbol "left")) (right (make-symbol "right"))) `(let ((,diff (if auto-hscroll-mode (1+ hscroll-margin) 0)) auto-hscroll-mode) ,@body (let* ((,left (+ (window-hscroll) ,diff)) (,right (+ (window-hscroll) (window-width) (- ,diff) -1))) (move-to-column (min (max (current-column) ,left) ,right)))))) (defun evil-goto-min (&rest positions) "Go to the smallest position in POSITIONS. Non-numerical elements are ignored. See also `evil-goto-max'." (when (setq positions (evil-filter-list #'(lambda (elt) (not (number-or-marker-p elt))) positions)) (goto-char (apply #'min positions)))) (defun evil-goto-max (&rest positions) "Go to the largest position in POSITIONS. Non-numerical elements are ignored. See also `evil-goto-min'." (when (setq positions (evil-filter-list #'(lambda (elt) (not (number-or-marker-p elt))) positions)) (goto-char (apply #'max positions)))) (defun evil-forward-not-thing (thing &optional count) "Move point to the end or beginning of the complement of THING." (evil-motion-loop (dir (or count 1)) (let (bnd) (cond ((> dir 0) (while (and (setq bnd (bounds-of-thing-at-point thing)) (< (point) (cdr bnd))) (goto-char (cdr bnd))) ;; no thing at (point) (if (zerop (forward-thing thing)) ;; now at the end of the next thing (let ((bnd (bounds-of-thing-at-point thing))) (if (or (< (car bnd) (point)) ; end of a thing (= (car bnd) (cdr bnd))) ; zero width thing (goto-char (car bnd)) ;; beginning of yet another thing, go back (forward-thing thing -1))) (goto-char (point-max)))) (t (while (and (not (bobp)) (or (backward-char) t) (setq bnd (bounds-of-thing-at-point thing)) (< (point) (cdr bnd))) (goto-char (car bnd))) ;; either bob or no thing at point (goto-char (if (and (not (bobp)) (zerop (forward-thing thing -1)) (setq bnd (bounds-of-thing-at-point thing))) (cdr bnd) (point-min)))))))) (defun evil-bounds-of-not-thing-at-point (thing &optional which) "Returns the bounds of a complement of THING at point. If there is a THING at point nil is returned. Otherwise if WHICH is nil or 0 a cons cell (BEG . END) is returned. If WHICH is negative the beginning is returned. If WHICH is positive the END is returned." (let ((pnt (point))) (let ((beg (save-excursion (and (zerop (forward-thing thing -1)) (forward-thing thing)) (if (> (point) pnt) (point-min) (point)))) (end (save-excursion (and (zerop (forward-thing thing)) (forward-thing thing -1)) (if (< (point) pnt) (point-max) (point))))) (when (and (<= beg (point)) (<= (point) end) (< beg end)) (cond ((or (not which) (zerop which)) (cons beg end)) ((< which 0) beg) ((> which 0) end)))))) (defun evil-forward-nearest (count &rest forwards) "Moves point forward to the first of several motions. FORWARDS is a list of forward motion functions (i.e. each moves point forward to the next end of a text object (if passed a +1) or backward to the preceeding beginning of a text object (if passed a -1)). This function calls each of these functions once and moves point to the nearest of the resulting positions. If COUNT is positive point is moved forward COUNT times, if negative point is moved backward -COUNT times." (evil-motion-loop (dir (or count 1)) (let ((pnt (point)) (nxt (if (> dir 0) (point-max) (point-min)))) (dolist (fwd forwards) (goto-char pnt) (condition-case nil (evil-with-restriction (and (< dir 0) (save-excursion (goto-char nxt) (line-beginning-position 0))) (and (> dir 0) (save-excursion (goto-char nxt) (line-end-position 2))) (if (and (zerop (funcall fwd dir)) (/= (point) pnt) (or (and (> dir 0) (< (point) nxt)) (and (< dir 0) (> (point) nxt)))) (setq nxt (point)))) (error))) (goto-char nxt)))) (defun bounds-of-evil-string-at-point (&optional state) "Return the bounds of a string at point. If STATE is given it used a parsing state at point." (save-excursion (let ((state (or state (syntax-ppss)))) (and (nth 3 state) (cons (nth 8 state) (and (parse-partial-sexp (point) (point-max) nil nil state 'syntax-table) (point))))))) (put 'evil-string 'bounds-of-thing-at-point #'bounds-of-evil-string-at-point) (defun bounds-of-evil-comment-at-point () "Return the bounds of a string at point." (save-excursion (let ((state (syntax-ppss))) (and (nth 4 state) (cons (nth 8 state) (and (parse-partial-sexp (point) (point-max) nil nil state 'syntax-table) (point))))))) (put 'evil-comment 'bounds-of-thing-at-point #'bounds-of-evil-comment-at-point) ;; The purpose of this function is the provide line motions which ;; preserve the column. This is how `previous-line' and `next-line' ;; work, but unfortunately the behaviour is hard-coded: if and only if ;; the last command was `previous-line' or `next-line', the column is ;; preserved. Furthermore, in contrast to Vim, when we cannot go ;; further, those motions move point to the beginning resp. the end of ;; the line (we never want point to leave its column). The code here ;; comes from simple.el, and I hope it will work in future. (defun evil-line-move (count &optional noerror) "A wrapper for line motions which conserves the column. Signals an error at buffer boundaries unless NOERROR is non-nil." (cond (noerror (condition-case nil (evil-line-move count) (error nil))) (t (evil-signal-without-movement (setq this-command (if (>= count 0) #'next-line #'previous-line)) (let ((opoint (point))) (condition-case err (with-no-warnings (funcall this-command (abs count))) ((beginning-of-buffer end-of-buffer) (let ((col (or goal-column (if (consp temporary-goal-column) (car temporary-goal-column) temporary-goal-column)))) (if line-move-visual (vertical-motion (cons col 0)) (line-move-finish col opoint (< count 0))) ;; Maybe we should just `ding'? (signal (car err) (cdr err)))))))))) (defun evil-forward-syntax (syntax &optional count) "Move point to the end or beginning of a sequence of characters in SYNTAX. Stop on reaching a character not in SYNTAX." (let ((notsyntax (if (= (aref syntax 0) ?^) (substring syntax 1) (concat "^" syntax)))) (evil-motion-loop (dir (or count 1)) (cond ((< dir 0) (skip-syntax-backward notsyntax) (skip-syntax-backward syntax)) (t (skip-syntax-forward notsyntax) (skip-syntax-forward syntax)))))) (defun evil-forward-chars (chars &optional count) "Move point to the end or beginning of a sequence of CHARS. CHARS is a character set as inside [...] in a regular expression." (let ((notchars (if (= (aref chars 0) ?^) (substring chars 1) (concat "^" chars)))) (evil-motion-loop (dir (or count 1)) (cond ((< dir 0) (skip-chars-backward notchars) (skip-chars-backward chars)) (t (skip-chars-forward notchars) (skip-chars-forward chars)))))) (defun evil-up-block (beg end &optional count) "Move point to the end or beginning of text enclosed by BEG and END. BEG and END should be regular expressions matching the opening and closing delimiters, respectively. If COUNT is greater than zero point is moved forward otherwise it is moved backwards. Whenever an opening delimiter is found the COUNT is increased by one, if a closing delimiter is found the COUNT is decreased by one. The motion stops when COUNT reaches zero. The match-data reflects the last successful match (that caused COUNT to reach zero). The behaviour of this functions is similar to `up-list'." (let* ((count (or count 1)) (forwardp (> count 0)) (dir (if forwardp +1 -1))) (catch 'done (while (not (zerop count)) (let* ((pnt (point)) (cl (save-excursion (and (re-search-forward (if forwardp end beg) nil t dir) (or (/= pnt (point)) (progn ;; zero size match, repeat search from ;; the next position (forward-char dir) (re-search-forward (if forwardp end beg) nil t dir))) (point)))) (match (match-data t)) (op (save-excursion (and (not (equal beg end)) (re-search-forward (if forwardp beg end) cl t dir) (or (/= pnt (point)) (progn ;; zero size match, repeat search from ;; the next position (forward-char dir) (re-search-forward (if forwardp beg end) cl t dir))) (point))))) (cond ((not cl) (goto-char (if forwardp (point-max) (point-min))) (set-match-data nil) (throw 'done count)) (t (if op (progn (setq count (if forwardp (1+ count) (1- count))) (goto-char op)) (setq count (if forwardp (1- count) (1+ count))) (if (zerop count) (set-match-data match)) (goto-char cl)))))) 0))) (defun evil-up-paren (open close &optional count) "Move point to the end or beginning of balanced parentheses. OPEN and CLOSE should be characters identifying the opening and closing parenthesis, respectively. If COUNT is greater than zero point is moved forward otherwise it is moved backwards. Whenever an opening delimiter is found the COUNT is increased by one, if a closing delimiter is found the COUNT is decreased by one. The motion stops when COUNT reaches zero. The match-data reflects the last successful match (that caused COUNT to reach zero)." ;; Always use the default `forward-sexp-function'. This is important ;; for modes that use a custom one like `python-mode'. ;; (addresses #364) (let (forward-sexp-function) (with-syntax-table (copy-syntax-table (syntax-table)) (modify-syntax-entry open (format "(%c" close)) (modify-syntax-entry close (format ")%c" open)) (let ((rest (evil-motion-loop (dir count) (let ((pnt (point))) (condition-case nil (cond ((> dir 0) (while (progn (up-list dir) (/= (char-before) close)))) (t (while (progn (up-list dir) (/= (char-after) open))))) (error (goto-char pnt))))))) (cond ((= rest count) (set-match-data nil)) ((> count 0) (set-match-data (list (1- (point)) (point)))) (t (set-match-data (list (point) (1+ (point)))))) rest)))) (defun evil-up-xml-tag (&optional count) "Move point to the end or beginning of balanced xml tags. OPEN and CLOSE should be characters identifying the opening and closing parenthesis, respectively. If COUNT is greater than zero point is moved forward otherwise it is moved backwards. Whenever an opening delimiter is found the COUNT is increased by one, if a closing delimiter is found the COUNT is decreased by one. The motion stops when COUNT reaches zero. The match-data reflects the last successful match (that caused COUNT to reach zero)." (let* ((dir (if (> (or count 1) 0) +1 -1)) (count (abs (or count 1))) (match (> count 0)) (op (if (> dir 0) 1 2)) (cl (if (> dir 0) 2 1)) (orig (point)) pnt tags match) (catch 'done (while (> count 0) ;; find the previous opening tag (while (and (setq match (re-search-forward "<\\([^/ >]+\\)\\(?:[^\"/>]\\|\"[^\"]*\"\\)*?>\\|]+?\\)>" nil t dir)) (cond ((match-beginning op) (push (match-string op) tags)) ((null tags) nil) ; free closing tag ((and (< dir 0) (string= (car tags) (match-string cl))) ;; in backward direction we only accept matching ;; tags. If the current tag is a free opener ;; without matching closing tag, the subsequents ;; test will make us ignore this tag (pop tags)) ((and (> dir 0)) ;; non matching openers are considered free openers (while (and tags (not (string= (car tags) (match-string cl)))) (pop tags)) (pop tags))))) (unless (setq match (and match (match-data t))) (setq match nil) (throw 'done count)) ;; found closing tag, look for corresponding opening tag (cond ((> dir 0) (setq pnt (match-end 0)) (goto-char (match-beginning 0))) (t (setq pnt (match-beginning 0)) (goto-char (match-end 0)))) (let* ((tag (match-string cl)) (refwd (concat "<\\(/\\)?" (regexp-quote tag) "\\(?:>\\| \\(?:[^\"/>]\\|\"[^\"]*\"\\)*?>\\)")) (cnt 1)) (while (and (> cnt 0) (re-search-backward refwd nil t dir)) (setq cnt (+ cnt (if (match-beginning 1) dir (- dir))))) (if (zerop cnt) (setq count (1- count) tags nil)) (goto-char pnt))) (if (> count 0) (set-match-data nil) (set-match-data match) (goto-char (if (> dir 0) (match-end 0) (match-beginning 0))))) ;; if not found, set to point-max/point-min (unless (zerop count) (set-match-data nil) (goto-char (if (> dir 0) (point-max) (point-min))) (if (/= (point) orig) (setq count (1- count)))) (* dir count))) (defun evil-forward-quote (quote &optional count) "Move point to the end or beginning of a string. QUOTE is the character delimiting the string. If COUNT is greater than zero point is moved forward otherwise it is moved backwards." (let (reset-parser) (with-syntax-table (copy-syntax-table (syntax-table)) (unless (= (char-syntax quote) ?\") (modify-syntax-entry quote "\"") (setq reset-parser t)) ;; global parser state is out of state, use local one (let* ((pnt (point)) (state (save-excursion (beginning-of-defun) (parse-partial-sexp (point) pnt nil nil (syntax-ppss)))) (bnd (bounds-of-evil-string-at-point state))) (when (and bnd (< (point) (cdr bnd))) ;; currently within a string (if (> count 0) (progn (goto-char (cdr bnd)) (setq count (1- count))) (goto-char (car bnd)) (setq count (1+ count)))) ;; forward motions work with local parser state (cond ((> count 0) ;; no need to reset global parser state because we only use ;; the local one (setq reset-parser nil) (catch 'done (while (and (> count 0) (not (eobp))) (setq state (parse-partial-sexp (point) (point-max) nil nil state 'syntax-table)) (cond ((nth 3 state) (setq bnd (bounds-of-thing-at-point 'evil-string)) (goto-char (cdr bnd)) (setq count (1- count))) ((eobp) (goto-char pnt) (throw 'done nil)))))) ((< count 0) ;; need to update global cache because of backward motion (setq reset-parser (and reset-parser (point))) (save-excursion (beginning-of-defun) (syntax-ppss-flush-cache (point))) (catch 'done (while (and (< count 0) (not (bobp))) (setq pnt (point)) (while (and (not (bobp)) (or (eobp) (/= (char-after) quote))) (backward-char)) (cond ((setq bnd (bounds-of-thing-at-point 'evil-string)) (goto-char (car bnd)) (setq count (1+ count))) ((bobp) (goto-char pnt) (throw 'done nil)) (t (backward-char)))))) (t (setq reset-parser nil))))) (when reset-parser ;; reset global cache (save-excursion (goto-char reset-parser) (beginning-of-defun) (syntax-ppss-flush-cache (point)))) count)) ;;; Thing-at-point motion functions for Evil text objects and motions (defun forward-evil-empty-line (&optional count) "Move forward COUNT empty lines." (setq count (or count 1)) (cond ((> count 0) (while (and (> count 0) (not (eobp))) (when (and (bolp) (eolp)) (setq count (1- count))) (forward-line 1))) (t (while (and (< count 0) (not (bobp)) (zerop (forward-line -1))) (when (and (bolp) (eolp)) (setq count (1+ count)))))) count) (defun forward-evil-space (&optional count) "Move forward COUNT whitespace sequences [[:space:]]+." (evil-forward-chars "[:space:]" count)) (defun forward-evil-word (&optional count) "Move forward COUNT words. Moves point COUNT words forward or (- COUNT) words backward if COUNT is negative. Point is placed after the end of the word (if forward) or at the first character of the word (if backward). A word is a sequence of word characters matching \[[:word:]] (recognized by `forward-word'), a sequence of non-whitespace non-word characters '[^[:word:]\\n\\r\\t\\f ]', or an empty line matching ^$." (evil-forward-nearest count #'(lambda (&optional cnt) (let ((word-separating-categories evil-cjk-word-separating-categories) (word-combining-categories evil-cjk-word-combining-categories) (pnt (point))) (forward-word cnt) (if (= pnt (point)) cnt 0))) #'(lambda (&optional cnt) (evil-forward-chars "^[:word:]\n\r\t\f " cnt)) #'forward-evil-empty-line)) (defun forward-evil-WORD (&optional count) "Move forward COUNT \"WORDS\". Moves point COUNT WORDS forward or (- COUNT) WORDS backward if COUNT is negative. Point is placed after the end of the WORD (if forward) or at the first character of the WORD (if backward). A WORD is a sequence of non-whitespace characters '[^\\n\\r\\t\\f ]', or an empty line matching ^$." (evil-forward-nearest count #'(lambda (&optional cnt) (evil-forward-chars "^\n\r\t\f " cnt)) #'forward-evil-empty-line)) (defun forward-evil-symbol (&optional count) "Move forward COUNT symbols. Moves point COUNT symbols forward or (- COUNT) symbols backward if COUNT is negative. Point is placed after the end of the symbol (if forward) or at the first character of the symbol (if backward). A symbol is either determined by `forward-symbol', or is a sequence of characters not in the word, symbol or whitespace syntax classes." (evil-forward-nearest count #'(lambda (&optional cnt) (evil-forward-syntax "^w_->" cnt)) #'(lambda (&optional cnt) (let ((pnt (point))) (forward-symbol cnt) (if (= pnt (point)) cnt 0))) #'forward-evil-empty-line)) (defun forward-evil-defun (&optional count) "Move forward COUNT defuns. Moves point COUNT defuns forward or (- COUNT) defuns backward if COUNT is negative. A defun is defined by `beginning-of-defun' and `end-of-defun' functions." (evil-motion-loop (dir (or count 1)) (if (> dir 0) (end-of-defun) (beginning-of-defun)))) (defun forward-evil-sentence (&optional count) "Move forward COUNT sentences. Moves point COUNT sentences forward or (- COUNT) sentences backward if COUNT is negative. This function is the same as `forward-sentence' but returns the number of sentences that could NOT be moved over." (evil-motion-loop (dir (or count 1)) (condition-case nil (forward-sentence dir) (error)))) (defun forward-evil-paragraph (&optional count) "Move forward COUNT paragraphs. Moves point COUNT paragraphs forward or (- COUNT) paragraphs backward if COUNT is negative. A paragraph is defined by `start-of-paragraph-text' and `forward-paragraph' functions." (evil-motion-loop (dir (or count 1)) (cond ((> dir 0) (forward-paragraph)) ((not (bobp)) (start-of-paragraph-text) (beginning-of-line))))) (defvar evil-forward-quote-char ?\" "The character to be used by `forward-evil-quote'.") (defun forward-evil-quote (&optional count) "Move forward COUNT strings. The quotation character is specified by the global variable `evil-forward-quote-char'. This character is passed to `evil-forward-quote'." (evil-forward-quote evil-forward-quote-char count)) (defun forward-evil-quote-simple (&optional count) "Move forward COUNT strings. The quotation character is specified by the global variable `evil-forward-quote-char'. This functions uses Vim's rules parsing from the beginning of the current line for quotation characters. It should only be used when looking for strings within comments and buffer *must* be narrowed to the comment." (let ((dir (if (> (or count 1) 0) 1 -1)) (ch evil-forward-quote-char) (pnt (point)) (cnt 0)) (beginning-of-line) ;; count number of quotes before pnt (while (< (point) pnt) (when (= (char-after) ch) (setq cnt (1+ cnt))) (forward-char)) (setq cnt (- (* 2 (abs count)) (mod cnt 2))) (cond ((> dir 0) (while (and (not (eolp)) (not (zerop cnt))) (when (= (char-after) ch) (setq cnt (1- cnt))) (forward-char)) (when (not (zerop cnt)) (goto-char (point-max)))) (t (while (and (not (bolp)) (not (zerop cnt))) (when (= (char-before) ch) (setq cnt (1- cnt))) (forward-char -1)) (when (not (zerop cnt)) (goto-char (point-min))))) (/ cnt 2))) ;;; Motion functions (defun evil-forward-beginning (thing &optional count) "Move forward to beginning of THING. The motion is repeated COUNT times." (setq count (or count 1)) (if (< count 0) (forward-thing thing count) (let ((bnd (bounds-of-thing-at-point thing)) rest) (when (and bnd (< (point) (cdr bnd))) (goto-char (cdr bnd))) (condition-case nil (when (zerop (setq rest (forward-thing thing count))) (when (and (bounds-of-thing-at-point thing) (not (bobp)) ;; handle final empty line (not (and (bolp) (eobp)))) (forward-char -1)) (beginning-of-thing thing)) (error)) rest))) (defun evil-backward-beginning (thing &optional count) "Move backward to beginning of THING. The motion is repeated COUNT times. This is the same as calling `evil-backward-beginning' with -COUNT." (evil-forward-beginning thing (- (or count 1)))) (defun evil-forward-end (thing &optional count) "Move forward to end of THING. The motion is repeated COUNT times." (setq count (or count 1)) (cond ((> count 0) (unless (eobp) (forward-char)) (prog1 (forward-thing thing count) (unless (bobp) (forward-char -1)))) (t (let ((bnd (bounds-of-thing-at-point thing)) rest) (when (and bnd (< (point) (cdr bnd) )) (goto-char (car bnd))) (condition-case nil (when (zerop (setq rest (forward-thing thing count))) (end-of-thing thing) (forward-char -1)) (error)) rest)))) (defun evil-backward-end (thing &optional count) "Move backward to end of THING. The motion is repeated COUNT times. This is the same as calling `evil-backward-end' with -COUNT." (evil-forward-end thing (- (or count 1)))) (defun evil-forward-word (&optional count) "Move by words. Moves point COUNT words forward or (- COUNT) words backward if COUNT is negative. This function is the same as `forward-word' but returns the number of words by which point could *not* be moved." (setq count (or count 1)) (let* ((dir (if (>= count 0) +1 -1)) (count (abs count))) (while (and (> count 0) (forward-word dir)) (setq count (1- count))) count)) (defun evil-in-comment-p (&optional pos) "Checks if POS is within a comment according to current syntax. If POS is nil, (point) is used. The return value is the beginning position of the comment." (setq pos (or pos (point))) (let ((chkpos (cond ((eobp) pos) ((= (char-syntax (char-after)) ?<) (1+ pos)) ((and (not (zerop (logand (car (syntax-after (point))) (lsh 1 16)))) (not (zerop (logand (or (car (syntax-after (1+ (point)))) 0) (lsh 1 17))))) (+ pos 2)) ((and (not (zerop (logand (car (syntax-after (point))) (lsh 1 17)))) (not (zerop (logand (or (car (syntax-after (1- (point)))) 0) (lsh 1 16))))) (1+ pos)) (t pos)))) (let ((syn (save-excursion (syntax-ppss chkpos)))) (and (nth 4 syn) (nth 8 syn))))) (defun evil-looking-at-start-comment (&optional move) "Returns t if point is at the start of a comment. point must be on one of the opening characters of a block comment according to the current syntax table. Futhermore these characters must been parsed as opening characters, i.e. they won't be considered as comment starters inside a string or possibly another comment. Point is moved to the first character of the comment opener if MOVE is non-nil." (cond ;; one character opener ((= (char-syntax (char-after)) ?<) (equal (point) (evil-in-comment-p (1+ (point))))) ;; two character opener on first char ((and (not (zerop (logand (car (syntax-after (point))) (lsh 1 16)))) (not (zerop (logand (or (car (syntax-after (1+ (point)))) 0) (lsh 1 17))))) (equal (point) (evil-in-comment-p (+ 2 (point))))) ;; two character opener on second char ((and (not (zerop (logand (car (syntax-after (point))) (lsh 1 17)))) (not (zerop (logand (or (car (syntax-after (1- (point)))) 0) (lsh 1 16))))) (and (equal (1- (point)) (evil-in-comment-p (1+ (point)))) (prog1 t (when move (backward-char))))))) (defun evil-looking-at-end-comment (&optional move) "Returns t if point is at the end of a comment. point must be on one of the opening characters of a block comment according to the current syntax table. Futhermore these characters must been parsed as opening characters, i.e. they won't be considered as comment starters inside a string or possibly another comment. Point is moved right after the comment closer if MOVE is non-nil." (cond ;; one char closer ((= (char-syntax (char-after)) ?>) (and (evil-in-comment-p) ; in comment (not (evil-in-comment-p (1+ (point)))) (prog1 t (when move (forward-char))))) ;; two char closer on first char ((and (not (zerop (logand (car (syntax-after (point))) (lsh 1 18)))) (not (zerop (logand (or (car (syntax-after (1+ (point)))) 0) (lsh 1 19))))) (and (evil-in-comment-p) (not (evil-in-comment-p (+ (point) 2))) (prog1 t (when move (forward-char 2))))) ;; two char closer on second char ((and (not (zerop (logand (car (syntax-after (point))) (lsh 1 19)))) (not (zerop (logand (or (car (syntax-after (1- (point)))) 0) (lsh 1 18))))) (and (evil-in-comment-p) (not (evil-in-comment-p (1+ (point)))) (prog1 t (when move (forward-char))))))) (defun evil-insert-newline-above () "Inserts a new line above point and places point in that line with regard to indentation." (evil-narrow-to-field (evil-move-beginning-of-line) (insert (if use-hard-newlines hard-newline "\n")) (forward-line -1) (back-to-indentation))) (defun evil-insert-newline-below () "Inserts a new line below point and places point in that line with regard to indentation." (evil-narrow-to-field (evil-move-end-of-line) (insert (if use-hard-newlines hard-newline "\n")) (back-to-indentation))) ;;; Markers (defun evil-global-marker-p (char) "Whether CHAR denotes a global marker." (or (and (>= char ?A) (<= char ?Z)) (assq char (default-value 'evil-markers-alist)))) (defun evil-set-marker (char &optional pos advance) "Set the marker denoted by CHAR to position POS. POS defaults to the current position of point. If ADVANCE is t, the marker advances when inserting text at it; otherwise, it stays behind." (interactive (list (read-char))) (catch 'done (let ((marker (evil-get-marker char t)) alist) (unless (markerp marker) (cond ((and marker (symbolp marker) (boundp marker)) (set marker (or (symbol-value marker) (make-marker))) (setq marker (symbol-value marker))) ((eq marker 'evil-jump-backward-swap) (evil-set-jump) (throw 'done nil)) ((functionp marker) (user-error "Cannot set special marker `%c'" char)) ((evil-global-marker-p char) (setq alist (default-value 'evil-markers-alist) marker (make-marker)) (evil-add-to-alist 'alist char marker) (setq-default evil-markers-alist alist)) (t (setq marker (make-marker)) (evil-add-to-alist 'evil-markers-alist char marker)))) (add-hook 'kill-buffer-hook #'evil-swap-out-markers nil t) (set-marker-insertion-type marker advance) (set-marker marker (or pos (point)))))) (defun evil-get-marker (char &optional raw) "Return the marker denoted by CHAR. This is either a marker object as returned by `make-marker', a number, a cons cell (FILE . POS) with FILE being a string and POS a number, or nil. If RAW is non-nil, then the return value may also be a variable, a movement function, or a marker object pointing nowhere." (let ((marker (if (evil-global-marker-p char) (cdr-safe (assq char (default-value 'evil-markers-alist))) (cdr-safe (assq char evil-markers-alist))))) (save-excursion (if raw marker (when (and (symbolp marker) (boundp marker)) (setq marker (symbol-value marker))) (when (functionp marker) (save-window-excursion (funcall marker) (setq marker (move-marker (make-marker) (point))))) (when (markerp marker) (if (eq (marker-buffer marker) (current-buffer)) (setq marker (marker-position marker)) (setq marker (and (marker-buffer marker) marker)))) (when (or (numberp marker) (markerp marker) (and (consp marker) (stringp (car marker)) (numberp (cdr marker)))) marker))))) (defun evil-swap-out-markers () "Turn markers into file references when the buffer is killed." (and buffer-file-name (dolist (entry evil-markers-alist) (and (markerp (cdr entry)) (eq (marker-buffer (cdr entry)) (current-buffer)) (setcdr entry (cons buffer-file-name (marker-position (cdr entry)))))))) (put 'evil-swap-out-markers 'permanent-local-hook t) (defun evil-get-register (register &optional noerror) "Return contents of REGISTER. Signal an error if empty, unless NOERROR is non-nil. The following special registers are supported. \" the unnamed register * the clipboard contents + the clipboard contents the word at point (ex mode only) the WORD at point (ex mode only) the symbol at point (ex mode only) the current file at point (ex mode only) % the current file name (read only) # the alternate file name (read only) / the last search pattern (read only) : the last command line (read only) . the last inserted text (read only) - the last small (less than a line) delete _ the black hole register = the expression register (read only)" (condition-case err (when (characterp register) (or (cond ((eq register ?\") (current-kill 0)) ((and (<= ?1 register) (<= register ?9)) (let ((reg (- register ?1))) (and (< reg (length kill-ring)) (current-kill reg t)))) ((memq register '(?* ?+)) ;; the following code is modified from ;; `x-selection-value-internal' (let ((what (if (eq register ?*) 'PRIMARY 'CLIPBOARD)) (request-type (or (and (boundp 'x-select-request-type) x-select-request-type) '(UTF8_STRING COMPOUNT_TEXT STRING))) text) (unless (consp request-type) (setq request-type (list request-type))) (while (and request-type (not text)) (condition-case nil (setq text (evil-get-selection what (pop request-type))) (error nil))) (when text (remove-text-properties 0 (length text) '(foreign-selection nil) text)) text)) ((eq register ?\C-W) (unless (evil-ex-p) (user-error "Register only available in ex state")) (with-current-buffer evil-ex-current-buffer (thing-at-point 'evil-word))) ((eq register ?\C-A) (unless (evil-ex-p) (user-error "Register only available in ex state")) (with-current-buffer evil-ex-current-buffer (thing-at-point 'evil-WORD))) ((eq register ?\C-O) (unless (evil-ex-p) (user-error "Register only available in ex state")) (with-current-buffer evil-ex-current-buffer (thing-at-point 'evil-symbol))) ((eq register ?\C-F) (unless (evil-ex-p) (user-error "Register only available in ex state")) (with-current-buffer evil-ex-current-buffer (thing-at-point 'filename))) ((eq register ?%) (or (buffer-file-name (and (evil-ex-p) (minibufferp) evil-ex-current-buffer)) (user-error "No file name"))) ((= register ?#) (or (with-current-buffer (other-buffer) (buffer-file-name)) (user-error "No file name"))) ((eq register ?/) (or (car-safe (or (and (boundp 'evil-search-module) (eq evil-search-module 'evil-search) evil-ex-search-history) (and isearch-regexp regexp-search-ring) search-ring)) (user-error "No previous regular expression"))) ((eq register ?:) (or (car-safe evil-ex-history) (user-error "No previous command line"))) ((eq register ?.) evil-last-insertion) ((eq register ?-) evil-last-small-deletion) ((eq register ?=) (let* ((enable-recursive-minibuffers t) (result (eval (car (read-from-string (read-string "=")))))) (cond ((or (stringp result) (numberp result) (symbolp result)) (prin1-to-string result)) ((sequencep result) (mapconcat #'prin1-to-string result "\n")) (t (user-error "Using %s as a string" (type-of result)))))) ((eq register ?_) ; the black hole register "") (t (setq register (downcase register)) (get-register register))) (user-error "Register `%c' is empty" register))) (error (unless err (signal (car err) (cdr err)))))) (defun evil-set-register (register text) "Set the contents of register REGISTER to TEXT. If REGISTER is an upcase character then text is appended to that register instead of replacing its content." (cond ((not (characterp register)) (user-error "Invalid register")) ;; don't allow modification of read-only registers ((member register '(?: ?. ?%)) (user-error "Can't modify read-only register")) ((eq register ?\") (kill-new text)) ((and (<= ?1 register) (<= register ?9)) (if (null kill-ring) (kill-new text) (let ((kill-ring-yank-pointer kill-ring-yank-pointer) interprogram-paste-function interprogram-cut-function) (current-kill (- register ?1)) (setcar kill-ring-yank-pointer text)))) ((eq register ?*) (evil-set-selection 'PRIMARY text)) ((eq register ?+) (evil-set-selection 'CLIPBOARD text)) ((eq register ?-) (setq evil-last-small-deletion text)) ((eq register ?_) ; the black hole register nil) ((and (<= ?A register) (<= register ?Z)) (setq register (downcase register)) (let ((content (get-register register))) (cond ((not content) (set-register register text)) ((or (text-property-not-all 0 (length content) 'yank-handler nil content) (text-property-not-all 0 (length text) 'yank-handler nil text)) ;; some non-trivial yank-handler -> always switch to line handler ;; ensure complete lines (when (and (> (length content) 0) (/= (aref content (1- (length content))) ?\n)) (setq content (concat content "\n"))) (when (and (> (length text) 0) (/= (aref text (1- (length text))) ?\n)) (setq text (concat text "\n"))) (setq text (concat content text)) (remove-list-of-text-properties 0 (length text) '(yank-handler) text) (setq text (propertize text 'yank-handler '(evil-yank-line-handler))) (set-register register text)) (t (set-register register (concat content text)))))) (t (set-register register text)))) (defun evil-register-list () "Returns an alist of all registers, but only those named with number or character. Registers with symbol or string in names are ignored to keep Vim compatibility with register jumps." (sort (append (mapcar #'(lambda (reg) (cons reg (evil-get-register reg t))) '(?\" ?* ?+ ?% ?# ?/ ?: ?. ?- ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9)) (cl-remove-if-not (lambda (reg) (number-or-marker-p (car reg))) register-alist) nil) #'(lambda (reg1 reg2) (< (car reg1) (car reg2))))) (defsubst evil-kbd-macro-suppress-motion-error () "Returns non-nil if a motion error should be suppressed. Whether the motion error should be suppressed depends on the variable `evil-kbd-macro-suppress-motion-error'." (or (and defining-kbd-macro (memq evil-kbd-macro-suppress-motion-error '(t record))) (and executing-kbd-macro (memq evil-kbd-macro-suppress-motion-error '(t replay))))) ;;; Region ;; `set-mark' does too much at once (defun evil-move-mark (pos) "Set buffer's mark to POS. If POS is nil, delete the mark." (when pos (setq pos (evil-normalize-position pos))) (set-marker (mark-marker) pos)) (defun evil-save-transient-mark-mode () "Save Transient Mark mode and make it buffer-local. Any changes to Transient Mark mode are now local to the current buffer, until `evil-restore-transient-mark-mode' is called. Variables pertaining to Transient Mark mode are listed in `evil-transient-vars', and their values are stored in `evil-transient-vals'." (dolist (var evil-transient-vars) (when (and (boundp var) (not (assq var evil-transient-vals))) (push (list var (symbol-value var) (local-variable-p var)) evil-transient-vals) (make-variable-buffer-local var) (put var 'permanent-local t)))) (defun evil-restore-transient-mark-mode () "Restore Transient Mark mode. This presupposes that `evil-save-transient-mark-mode' has been called earlier. If Transient Mark mode was disabled before but enabled in the meantime, this function disables it; if it was enabled before but disabled in the meantime, this function enables it. The earlier settings of Transient Mark mode are stored in `evil-transient-vals'." (let (entry local var val) (while (setq entry (pop evil-transient-vals)) (setq var (pop entry) val (pop entry) local (pop entry)) (unless local (kill-local-variable var)) (unless (equal (symbol-value var) val) (if (fboundp var) (funcall var (if val 1 -1)) (setq var val)))))) (defun evil-save-mark () "Save the current mark, including whether it is transient. See also `evil-restore-mark'." (unless evil-visual-previous-mark (setq evil-visual-previous-mark (mark t)) (evil-save-transient-mark-mode))) (defun evil-restore-mark () "Restore the mark, including whether it was transient. See also `evil-save-mark'." (when evil-visual-previous-mark (evil-restore-transient-mark-mode) (evil-move-mark evil-visual-previous-mark) (setq evil-visual-previous-mark nil))) ;; In theory, an active region implies Transient Mark mode, and ;; disabling Transient Mark mode implies deactivating the region. ;; In practice, Emacs never clears `mark-active' except in Transient ;; Mark mode, so we define our own toggle functions to make things ;; more predictable. (defun evil-transient-mark (&optional arg) "Toggle Transient Mark mode. Ensure that the region is properly deactivated. Enable with positive ARG, disable with negative ARG." (unless (numberp arg) (setq arg (if transient-mark-mode -1 1))) (cond ((< arg 1) (evil-active-region -1) ;; Transient Mark mode cannot be disabled ;; while CUA mode is enabled (when (fboundp 'cua-mode) (cua-mode -1)) (when transient-mark-mode (transient-mark-mode -1))) (t (unless transient-mark-mode (evil-active-region -1) (transient-mark-mode 1))))) (defun evil-active-region (&optional arg) "Toggle active region. Ensure that Transient Mark mode is properly enabled. Enable with positive ARG, disable with negative ARG." (unless (numberp arg) (setq arg (if (region-active-p) -1 1))) (cond ((and (< arg 1)) (when (or transient-mark-mode mark-active) (setq mark-active nil deactivate-mark nil) (when (boundp 'cua--explicit-region-start) (setq cua--explicit-region-start nil)) (run-hooks 'deactivate-mark-hook))) (t (evil-transient-mark 1) (when deactivate-mark (setq deactivate-mark nil)) (unless (mark t) (evil-move-mark (point))) (unless (region-active-p) (set-mark (mark t))) (when (boundp 'cua--explicit-region-start) (setq cua--explicit-region-start t))))) (defmacro evil-with-transient-mark-mode (&rest body) "Execute BODY with Transient Mark mode. Then restore Transient Mark mode to its previous setting." (declare (indent defun) (debug t)) `(let ((inhibit-quit t) evil-transient-vals) (unwind-protect (progn (evil-save-transient-mark-mode) (evil-transient-mark 1) ,@body) (evil-restore-transient-mark-mode)))) (defmacro evil-with-active-region (beg end &rest body) "Execute BODY with an active region from BEG to END." (declare (indent 2) (debug t)) `(let ((beg ,beg) (end ,end) evil-transient-vals) (evil-with-transient-mark-mode (save-excursion (evil-active-region 1) (evil-move-mark beg) (goto-char end) ,@body)))) (defun evil-exchange-point-and-mark () "Exchange point and mark without activating the region." (let* ((point (point)) (mark (or (mark t) point))) (set-marker (mark-marker) point) (goto-char mark))) (defun evil-apply-on-block (func beg end pass-columns &rest args) "Call FUNC for each line of a block selection. The selection is specified by the region BEG and END. FUNC must take at least two arguments, the beginning and end of each line. If PASS-COLUMNS is non-nil, these values are the columns, otherwise tey are buffer positions. Extra arguments to FUNC may be passed via ARGS." (let ((eol-col (and (memq last-command '(next-line previous-line)) (numberp temporary-goal-column) temporary-goal-column)) startcol startpt endcol endpt) (save-excursion (goto-char beg) (setq startcol (current-column)) (beginning-of-line) (setq startpt (point)) (goto-char end) (setq endcol (current-column)) (forward-line 1) (setq endpt (point-marker)) ;; ensure the start column is the left one. (evil-sort startcol endcol) ;; maybe find maximal column (when eol-col (setq eol-col 0) (goto-char startpt) (while (< (point) endpt) (setq eol-col (max eol-col (evil-column (line-end-position)))) (forward-line 1)) (setq endcol (max endcol (min eol-col (1+ (min (1- most-positive-fixnum) (truncate temporary-goal-column))))))) ;; start looping over lines (goto-char startpt) (while (< (point) endpt) (if pass-columns (apply func startcol endcol args) (apply func (save-excursion (evil-move-to-column startcol)) (save-excursion (evil-move-to-column endcol t)) args)) (forward-line 1))))) (defun evil-apply-on-rectangle (function start end &rest args) "Like `apply-on-rectangle' but maybe extends to eol. If `temporary-goal-column' is set to a big number, then the region of each line is extended to the end of each line. The end column is set to the maximal column in all covered lines." (apply #'evil-apply-on-block function start end t args)) ;;; Insertion (defun evil-concat-ranges (ranges) "Concatenate RANGES. RANGES must be a list of ranges. They must be ordered so that successive ranges share their boundaries. The return value is a single range of disjoint union of the ranges or nil if the disjoint union is not a single range." (let ((range (car-safe ranges)) (ranges (cdr ranges)) r) (while (and range (setq r (car-safe ranges))) (setq range (cond ((and (= (cdr r) (car range))) (cons (car r) (cdr range))) ((and (= (cdr range) (car r))) (cons (car range) (cdr r))))) (setq ranges (cdr ranges))) range)) (defun evil-track-last-insertion (beg end len) "Track the last insertion range and its text. The insertion range is stored as a pair of buffer positions in `evil-current-insertion'. If a subsequent change is compatible, then the current range is modified, otherwise it is replaced by a new range. Compatible changes are changes that do not create a disjoin range." ;; deletion (when (> len 0) (if (and evil-current-insertion (>= beg (car evil-current-insertion)) (<= (+ beg len) (cdr evil-current-insertion))) (setcdr evil-current-insertion (- (cdr evil-current-insertion) len)) (setq evil-current-insertion nil))) ;; insertion (if (and evil-current-insertion (>= beg (car evil-current-insertion)) (<= beg (cdr evil-current-insertion))) (setcdr evil-current-insertion (+ (- end beg) (cdr evil-current-insertion))) (setq evil-current-insertion (cons beg end)))) (put 'evil-track-last-insertion 'permanent-local-hook t) (defun evil-start-track-last-insertion () "Start tracking the last insertion." (setq evil-current-insertion nil) (add-hook 'after-change-functions #'evil-track-last-insertion nil t)) (defun evil-stop-track-last-insertion () "Stop tracking the last insertion. The tracked insertion is set to `evil-last-insertion'." (setq evil-last-insertion (and evil-current-insertion ;; Check whether the insertion range is a valid buffer ;; range. If a buffer modification is done from within ;; another change hook or modification-hook (yasnippet ;; does this using overlay modification-hooks), then the ;; insertion information may be invalid. There is no way ;; to detect this situation, but at least we should ;; ensure that no error occurs (see bug #272). (>= (car evil-current-insertion) (point-min)) (<= (cdr evil-current-insertion) (point-max)) (buffer-substring-no-properties (car evil-current-insertion) (cdr evil-current-insertion)))) (remove-hook 'after-change-functions #'evil-track-last-insertion t)) ;;; Paste (defun evil-yank-characters (beg end &optional register yank-handler) "Saves the characters defined by the region BEG and END in the kill-ring." (let ((text (filter-buffer-substring beg end))) (when yank-handler (setq text (propertize text 'yank-handler (list yank-handler)))) (when register (evil-set-register register text)) (when evil-was-yanked-without-register (evil-set-register ?0 text)) ; "0 register contains last yanked text (unless (eq register ?_) (kill-new text)))) (defun evil-yank-lines (beg end &optional register yank-handler) "Saves the lines in the region BEG and END into the kill-ring." (let* ((text (filter-buffer-substring beg end)) (yank-handler (list (or yank-handler #'evil-yank-line-handler) nil t))) ;; Ensure the text ends with a newline. This is required ;; if the deleted lines were the last lines in the buffer. (when (or (zerop (length text)) (/= (aref text (1- (length text))) ?\n)) (setq text (concat text "\n"))) (setq text (propertize text 'yank-handler yank-handler)) (when register (evil-set-register register text)) (when evil-was-yanked-without-register (evil-set-register ?0 text)) ; "0 register contains last yanked text (unless (eq register ?_) (kill-new text)))) (defun evil-yank-rectangle (beg end &optional register yank-handler) "Saves the rectangle defined by region BEG and END into the kill-ring." (let ((lines (list nil))) (evil-apply-on-rectangle #'extract-rectangle-line beg end lines) ;; We remove spaces from the beginning and the end of the next. ;; Spaces are inserted explicitly in the yank-handler in order to ;; NOT insert lines full of spaces. (setq lines (nreverse (cdr lines))) ;; `text' is used as default insert text when pasting this rectangle ;; in another program, e.g., using the X clipboard. (let* ((yank-handler (list (or yank-handler #'evil-yank-block-handler) lines t 'evil-delete-yanked-rectangle)) (text (propertize (mapconcat #'identity lines "\n") 'yank-handler yank-handler))) (when register (evil-set-register register text)) (when evil-was-yanked-without-register (evil-set-register ?0 text)) ; "0 register contains last yanked text (unless (eq register ?_) (kill-new text))))) (defun evil-remove-yank-excluded-properties (text) "Removes `yank-excluded-properties' from TEXT." (if (eq yank-excluded-properties t) (set-text-properties 0 (length text) nil text) (remove-list-of-text-properties 0 (length text) yank-excluded-properties text))) (defun evil-yank-line-handler (text) "Inserts the current text linewise." (let ((text (apply #'concat (make-list (or evil-paste-count 1) text))) (opoint (point))) (evil-remove-yank-excluded-properties text) (cond ((eq this-command 'evil-paste-before) (evil-move-beginning-of-line) (evil-move-mark (point)) (insert text) (setq evil-last-paste (list 'evil-paste-before evil-paste-count opoint (mark t) (point))) (evil-set-marker ?\[ (mark)) (evil-set-marker ?\] (1- (point))) (evil-exchange-point-and-mark) (back-to-indentation)) ((eq this-command 'evil-paste-after) (evil-move-end-of-line) (evil-move-mark (point)) (insert "\n") (insert text) (evil-set-marker ?\[ (1+ (mark))) (evil-set-marker ?\] (1- (point))) (delete-char -1) ; delete the last newline (setq evil-last-paste (list 'evil-paste-after evil-paste-count opoint (mark t) (point))) (evil-move-mark (1+ (mark t))) (evil-exchange-point-and-mark) (back-to-indentation)) (t (insert text))))) (defun evil-yank-block-handler (lines) "Inserts the current text as block." (let ((count (or evil-paste-count 1)) (col (if (eq this-command 'evil-paste-after) (1+ (current-column)) (current-column))) (current-line (line-number-at-pos (point))) (opoint (point)) epoint) (dolist (line lines) ;; concat multiple copies according to count (setq line (apply #'concat (make-list count line))) ;; strip whitespaces at beginning and end (string-match "^ *\\(.*?\\) *$" line) (let ((text (match-string 1 line)) (begextra (match-beginning 1)) (endextra (- (match-end 0) (match-end 1)))) ;; maybe we have to insert a new line at eob (while (< (line-number-at-pos (point)) current-line) (goto-char (point-max)) (insert "\n")) (setq current-line (1+ current-line)) ;; insert text unless we insert an empty line behind eol (unless (and (< (evil-column (line-end-position)) col) (zerop (length text))) ;; if we paste behind eol, it may be sufficient to insert tabs (if (< (evil-column (line-end-position)) col) (move-to-column (+ col begextra) t) (move-to-column col t) (insert (make-string begextra ?\s))) (evil-remove-yank-excluded-properties text) (insert text) (unless (eolp) ;; text follows, so we have to insert spaces (insert (make-string endextra ?\s))) (setq epoint (point))) (forward-line 1))) (setq evil-last-paste (list this-command evil-paste-count opoint (length lines) ; number of rows (* count (length (car lines))))) ; number of colums (evil-set-marker ?\[ opoint) (evil-set-marker ?\] (1- epoint)) (goto-char opoint) (when (and (eq this-command 'evil-paste-after) (not (eolp))) (forward-char)))) (defun evil-delete-yanked-rectangle (nrows ncols) "Special function to delete the block yanked by a previous paste command." (let ((opoint (point)) (col (if (eq last-command 'evil-paste-after) (1+ (current-column)) (current-column)))) (dotimes (i nrows) (delete-region (save-excursion (move-to-column col) (point)) (save-excursion (move-to-column (+ col ncols)) (point))) (unless (eobp) (forward-line))) (goto-char opoint))) ;; TODO: if undoing is disabled in the current buffer, paste-pop won't ;; work. Although this is probably not a big problem, because usually ;; buffers where `evil-paste-pop' may be useful have undoing enabled. ;; A solution would be to temporarily enable undo when pasting and ;; store the undo information in a special variable that does not ;; interfere with `buffer-undo-list'. (defun evil-paste-pop (count) "Replace the just-yanked stretch of killed text with a different stretch. This command is allowed only immediatly after a `yank', `evil-paste-before', `evil-paste-after' or `evil-paste-pop'. This command uses the same paste command as before, i.e., when used after `evil-paste-after' the new text is also yanked using `evil-paste-after', used with the same paste-count argument. The COUNT argument inserts the COUNTth previous kill. If COUNT is negative this is a more recent kill." (interactive "p") (unless (memq last-command '(evil-paste-after evil-paste-before evil-visual-paste)) (user-error "Previous command was not an evil-paste: %s" last-command)) (unless evil-last-paste (user-error "Previous paste command used a register")) (evil-undo-pop) (goto-char (nth 2 evil-last-paste)) (setq this-command (nth 0 evil-last-paste)) ;; use temporary kill-ring, so the paste cannot modify it (let ((kill-ring (list (current-kill (if (and (> count 0) (nth 5 evil-last-paste)) ;; if was visual paste then skip the ;; text that has been replaced (1+ count) count)))) (kill-ring-yank-pointer kill-ring)) (when (eq last-command 'evil-visual-paste) (let ((evil-no-display t)) (evil-visual-restore))) (funcall (nth 0 evil-last-paste) (nth 1 evil-last-paste)) ;; if this was a visual paste, then mark the last paste as NOT ;; being the first visual paste (when (eq last-command 'evil-visual-paste) (setcdr (nthcdr 4 evil-last-paste) nil)))) (defun evil-paste-pop-next (count) "Same as `evil-paste-pop' but with negative argument." (interactive "p") (evil-paste-pop (- count))) ;;; Interactive forms (defun evil-match-interactive-code (interactive &optional pos) "Match an interactive code at position POS in string INTERACTIVE. Returns the first matching entry in `evil-interactive-alist', or nil." (let ((length (length interactive)) (pos (or pos 0))) (catch 'done (dolist (entry evil-interactive-alist) (let* ((string (car entry)) (end (+ (length string) pos))) (when (and (<= end length) (string= string (substring interactive pos end))) (throw 'done entry))))))) (defun evil-concatenate-interactive-forms (&rest forms) "Concatenate interactive list expressions FORMS. Returns a single expression where successive expressions are joined, if possible." (let (result) (when forms (while (cdr forms) (cond ((null (car forms)) (pop forms)) ((and (eq (car (car forms)) 'list) (eq (car (cadr forms)) 'list)) (setq forms (cons (append (car forms) (cdr (cadr forms))) (cdr (cdr forms))))) (t (push (pop forms) result)))) (when (car forms) (push (pop forms) result)) (setq result (nreverse result)) (cond ((null result)) ((null (cdr result)) (car result)) (t `(append ,@result)))))) (defun evil-interactive-string (string) "Evaluate the interactive string STRING. The string may contain extended interactive syntax. The return value is a cons cell (FORM . PROPERTIES), where FORM is a single list-expression to be passed to a standard `interactive' statement, and PROPERTIES is a list of command properties as passed to `evil-define-command'." (let ((length (length string)) (pos 0) code expr forms match plist prompt properties) (while (< pos length) (if (eq (aref string pos) ?\n) (setq pos (1+ pos)) (setq match (evil-match-interactive-code string pos)) (if (null match) (user-error "Unknown interactive code: `%s'" (substring string pos)) (setq code (car match) expr (car (cdr match)) plist (cdr (cdr match)) pos (+ pos (length code))) (when (functionp expr) (setq prompt (substring string pos (or (string-match "\n" string pos) length)) pos (+ pos (length prompt)) expr `(funcall ,expr ,prompt))) (setq forms (append forms (list expr)) properties (append properties plist))))) (cons `(append ,@forms) properties))) (defun evil-interactive-form (&rest args) "Evaluate interactive forms ARGS. The return value is a cons cell (FORM . PROPERTIES), where FORM is a single list-expression to be passed to a standard `interactive' statement, and PROPERTIES is a list of command properties as passed to `evil-define-command'." (let (forms properties) (dolist (arg args) (if (not (stringp arg)) (setq forms (append forms (list arg))) (setq arg (evil-interactive-string arg) forms (append forms (cdr (car arg))) properties (append properties (cdr arg))))) (cons (apply #'evil-concatenate-interactive-forms forms) properties))) ;;; Types (defun evil-type (object &optional default) "Return the type of OBJECT, or DEFAULT if none." (let (type) (cond ((overlayp object) (setq type (overlay-get object :type))) ((evil-range-p object) (setq type (nth 2 object))) ((listp object) (setq type (plist-get object :type))) ((commandp object) (setq type (evil-get-command-property object :type))) ((symbolp object) (setq type (get object 'type)))) (setq type (or type default)) (and (evil-type-p type) type))) (defun evil-set-type (object type) "Set the type of OBJECT to TYPE. For example, (evil-set-type 'next-line 'line) will make `line' the type of the `next-line' command." (cond ((overlayp object) (overlay-put object :type type)) ((evil-range-p object) (evil-set-range-type object type)) ((listp object) (plist-put object :type type)) ((commandp object) (evil-set-command-property object :type type)) ((symbolp object) (put object 'type type))) object) (defun evil-type-property (type prop) "Return property PROP for TYPE." (evil-get-property evil-type-properties type prop)) (defun evil-type-p (sym) "Whether SYM is the name of a type." (assq sym evil-type-properties)) (defun evil-expand (beg end type &rest properties) "Expand BEG and END as TYPE with PROPERTIES. Returns a list (BEG END TYPE PROPERTIES ...), where the tail may contain a property list." (apply #'evil-transform ;; don't expand if already expanded (unless (plist-get properties :expanded) :expand) beg end type properties)) (defun evil-contract (beg end type &rest properties) "Contract BEG and END as TYPE with PROPERTIES. Returns a list (BEG END TYPE PROPERTIES ...), where the tail may contain a property list." (apply #'evil-transform :contract beg end type properties)) (defun evil-normalize (beg end type &rest properties) "Normalize BEG and END as TYPE with PROPERTIES. Returns a list (BEG END TYPE PROPERTIES ...), where the tail may contain a property list." (apply #'evil-transform :normalize beg end type properties)) (defun evil-transform (transform beg end type &rest properties) "Apply TRANSFORM on BEG and END with PROPERTIES. Returns a list (BEG END TYPE PROPERTIES ...), where the tail may contain a property list. If TRANSFORM is undefined, return positions unchanged." (let* ((type (or type (evil-type properties))) (transform (when (and type transform) (evil-type-property type transform)))) (if transform (apply transform beg end properties) (apply #'evil-range beg end type properties)))) (defun evil-describe (beg end type &rest properties) "Return description of BEG and END with PROPERTIES. If no description is available, return the empty string." (let* ((type (or type (evil-type properties))) (properties (plist-put properties :type type)) (describe (evil-type-property type :string))) (or (when describe (apply describe beg end properties)) ""))) ;;; Ranges (defun evil-range (beg end &optional type &rest properties) "Return a list (BEG END [TYPE] PROPERTIES...). BEG and END are buffer positions (numbers or markers), TYPE is a type as per `evil-type-p', and PROPERTIES is a property list." (let ((beg (evil-normalize-position beg)) (end (evil-normalize-position end))) (when (and (numberp beg) (numberp end)) (append (list (min beg end) (max beg end)) (when (evil-type-p type) (list type)) properties)))) (defun evil-range-p (object) "Whether OBJECT is a range." (and (listp object) (>= (length object) 2) (numberp (nth 0 object)) (numberp (nth 1 object)))) (defun evil-range-beginning (range) "Return beginning of RANGE." (when (evil-range-p range) (let ((beg (evil-normalize-position (nth 0 range))) (end (evil-normalize-position (nth 1 range)))) (min beg end)))) (defun evil-range-end (range) "Return end of RANGE." (when (evil-range-p range) (let ((beg (evil-normalize-position (nth 0 range))) (end (evil-normalize-position (nth 1 range)))) (max beg end)))) (defun evil-range-properties (range) "Return properties of RANGE." (when (evil-range-p range) (if (evil-type range) (nthcdr 3 range) (nthcdr 2 range)))) (defun evil-copy-range (range) "Return a copy of RANGE." (copy-sequence range)) (defun evil-set-range (range &optional beg end type &rest properties) "Set RANGE to have beginning BEG and end END. The TYPE and additional PROPERTIES may also be specified. If an argument is nil, it's not used; the previous value is retained. See also `evil-set-range-beginning', `evil-set-range-end', `evil-set-range-type' and `evil-set-range-properties'." (when (evil-range-p range) (let ((beg (or (evil-normalize-position beg) (evil-range-beginning range))) (end (or (evil-normalize-position end) (evil-range-end range))) (type (or type (evil-type range))) (plist (evil-range-properties range))) (evil-sort beg end) (setq plist (evil-concat-plists plist properties)) (evil-set-range-beginning range beg) (evil-set-range-end range end) (evil-set-range-type range type) (evil-set-range-properties range plist) range))) (defun evil-set-range-beginning (range beg &optional copy) "Set RANGE's beginning to BEG. If COPY is non-nil, return a copy of RANGE." (when copy (setq range (evil-copy-range range))) (setcar range beg) range) (defun evil-set-range-end (range end &optional copy) "Set RANGE's end to END. If COPY is non-nil, return a copy of RANGE." (when copy (setq range (evil-copy-range range))) (setcar (cdr range) end) range) (defun evil-set-range-type (range type &optional copy) "Set RANGE's type to TYPE. If COPY is non-nil, return a copy of RANGE." (when copy (setq range (evil-copy-range range))) (if type (setcdr (cdr range) (cons type (evil-range-properties range))) (setcdr (cdr range) (evil-range-properties range))) range) (defun evil-set-range-properties (range properties &optional copy) "Set RANGE's properties to PROPERTIES. If COPY is non-nil, return a copy of RANGE." (when copy (setq range (evil-copy-range range))) (if (evil-type range) (setcdr (cdr (cdr range)) properties) (setcdr (cdr range) properties)) range) (defun evil-range-union (range1 range2 &optional type) "Return the union of the ranges RANGE1 and RANGE2. If the ranges have conflicting types, use RANGE1's type. This can be overridden with TYPE." (when (and (evil-range-p range1) (evil-range-p range2)) (evil-range (min (evil-range-beginning range1) (evil-range-beginning range2)) (max (evil-range-end range1) (evil-range-end range2)) (or type (evil-type range1) (evil-type range2))))) (defun evil-subrange-p (range1 range2) "Whether RANGE1 is contained within RANGE2." (and (evil-range-p range1) (evil-range-p range2) (<= (evil-range-beginning range2) (evil-range-beginning range1)) (>= (evil-range-end range2) (evil-range-end range1)))) (defun evil-select-inner-object (thing beg end type &optional count line) "Return an inner text object range of COUNT objects. If COUNT is positive, return objects following point; if COUNT is negative, return objects preceding point. If one is unspecified, the other is used with a negative argument. THING is a symbol understood by thing-at-point. BEG, END and TYPE specify the current selection. If LINE is non-nil, the text object should be linewise, otherwise it is character wise." (let* ((count (or count 1)) (bnd (or (let ((b (bounds-of-thing-at-point thing))) (and b (< (point) (cdr b)) b)) (evil-bounds-of-not-thing-at-point thing)))) ;; check if current object is selected (when (or (not beg) (not end) (> beg (car bnd)) (< end (cdr bnd)) (and (eq type 'inclusive) (= (1+ beg) end))) ; empty region does not count (when (or (not beg) (< (car bnd) beg)) (setq beg (car bnd))) (when (or (not end) (> (cdr bnd) end)) (setq end (cdr bnd))) (setq count (if (> count 0) (1- count) (1+ count)))) (goto-char (if (< count 0) beg end)) (evil-forward-nearest count #'(lambda (cnt) (forward-thing thing cnt)) #'(lambda (cnt) (evil-forward-not-thing thing cnt))) (evil-range (if (>= count 0) beg (point)) (if (< count 0) end (point)) (if line 'line type) :expanded t))) (defun evil-select-an-object (thing beg end type count &optional line) "Return an outer text object range of COUNT objects. If COUNT is positive, return objects following point; if COUNT is negative, return objects preceding point. If one is unspecified, the other is used with a negative argument. THING is a symbol understood by thing-at-point. BEG, END and TYPE specify the current selection. If LINE is non-nil, the text object should be linewise, otherwise it is character wise." (let* ((dir (if (> (or count 1) 0) +1 -1)) (count (abs (or count 1))) (objbnd (let ((b (bounds-of-thing-at-point thing))) (and b (< (point) (cdr b)) b))) (bnd (or objbnd (evil-bounds-of-not-thing-at-point thing))) addcurrent other) ;; check if current object is not selected (when (or (not beg) (not end) (> beg (car bnd)) (< end (cdr bnd)) (and (eq type 'inclusive) (= (1+ beg) end))) ; empty region does not count ;; if not, enlarge selection (when (or (not beg) (< (car bnd) beg)) (setq beg (car bnd))) (when (or (not end) (> (cdr bnd) end)) (setq end (cdr bnd))) (if objbnd (setq addcurrent t))) ;; make other and (point) reflect the selection (cond ((> dir 0) (goto-char end) (setq other beg)) (t (goto-char beg) (setq other end))) (cond ;; do nothing more than only current is selected ((not (and (= beg (car bnd)) (= end (cdr bnd))))) ;; current match is thing, add whitespace (objbnd (let ((wsend (evil-with-restriction ;; restrict to current line if we do non-line selection (and (not line) (line-beginning-position)) (and (not line) (line-end-position)) (evil-bounds-of-not-thing-at-point thing dir)))) (cond (wsend ;; add whitespace at end (goto-char wsend) (setq addcurrent t)) (t ;; no whitespace at end, try beginning (save-excursion (goto-char other) (setq wsend (evil-with-restriction ;; restrict to current line if we do non-line selection (and (not line) (line-beginning-position)) (and (not line) (line-end-position)) (evil-bounds-of-not-thing-at-point thing (- dir)))) (when wsend (setq other wsend addcurrent t))))))) ;; current match is whitespace, add thing (t (forward-thing thing dir) (setq addcurrent t))) ;; possibly count current object as selection (if addcurrent (setq count (1- count))) ;; move (dotimes (var count) (let ((wsend (evil-bounds-of-not-thing-at-point thing dir))) (if (and wsend (/= wsend (point))) ;; start with whitespace (forward-thing thing dir) ;; start with thing (forward-thing thing dir) (setq wsend (evil-bounds-of-not-thing-at-point thing dir)) (when wsend (goto-char wsend))))) ;; return range (evil-range (if (> dir 0) other (point)) (if (< dir 0) other (point)) (if line 'line type) :expanded t))) (defun evil--get-block-range (op cl selection-type) "Return the exclusive range of a visual selection. OP and CL are pairs of buffer positions for the opening and closing delimiter of a range. SELECTION-TYPE is the desired type of selection. It is a symbol that determines which parts of the block are selected. If it is 'inclusive or t the returned range is \(cons (car OP) (cdr CL)). If it is 'exclusive or nil the returned range is (cons (cdr OP) (car CL)). If it is 'exclusive-line the returned range will skip whitespace at the end of the line of OP and at the beginning of the line of CL." (cond ((memq selection-type '(inclusive t)) (cons (car op) (cdr cl))) ((memq selection-type '(exclusive nil)) (cons (cdr op) (car cl))) ((eq selection-type 'exclusive-line) (let ((beg (cdr op)) (end (car cl))) (save-excursion (goto-char beg) (when (and (eolp) (not (eobp))) (setq beg (line-beginning-position 2))) (goto-char end) (skip-chars-backward " \t") (when (bolp) (setq end (point)) (goto-char beg) (when (and (not (bolp)) (< beg end)) (setq end (1- end))))) (cons beg end))) (t (user-error "Unknown selection-type %s" selection-type)))) (defun evil-select-block (thing beg end type count &optional selection-type countcurrent fixedscan) "Return a range (BEG END) of COUNT delimited text objects. BEG END TYPE are the currently selected (visual) range. The delimited object must be given by THING-up function (see `evil-up-block'). SELECTION-TYPE is symbol that determines which parts of the block are selected. If it is 'inclusive or t OPEN and CLOSE are included in the range. If it is 'exclusive or nil the delimiters are not contained. If it is 'exclusive-line the delimiters are not included as well as adjacent whitespace until the beginning of the next line or the end of the previous line. If the resulting selection consists of complete lines only and visual state is not active, the returned selection is linewise. If COUNTCURRENT is non-nil an objected is counted if the current selection matches that object exactly. Usually scanning for the surrounding block starts at (1+ beg) and (1- end). If this might fail due to the behavior of THING then FIXEDSCAN can be set to t. In this case the scan starts at BEG and END. One example where this might fail is if BEG and END are the delimiters of a string or comment." (save-excursion (save-match-data (let* ((orig-beg beg) (orig-end end) (beg (or beg (point))) (end (or end (point))) (count (abs (or count 1))) op cl op-end cl-end) ;; We always assume at least one selected character. (if (= beg end) (setq end (1+ end))) ;; We scan twice: starting at (1+ beg) forward and at (1- end) ;; backward. The resulting selection is the smaller one. (goto-char (if fixedscan beg (1+ beg))) (when (and (zerop (funcall thing +1)) (match-beginning 0)) (setq cl (cons (match-beginning 0) (match-end 0))) (goto-char (car cl)) (when (and (zerop (funcall thing -1)) (match-beginning 0)) (setq op (cons (match-beginning 0) (match-end 0))))) ;; start scanning from end (goto-char (if fixedscan end (1- end))) (when (and (zerop (funcall thing -1)) (match-beginning 0)) (setq op-end (cons (match-beginning 0) (match-end 0))) (goto-char (cdr op-end)) (when (and (zerop (funcall thing +1)) (match-beginning 0)) (setq cl-end (cons (match-beginning 0) (match-end 0))))) ;; Bug #607: use the tightest selection that contains the ;; original selection. If non selection contains the original, ;; use the larger one. (cond ((and (not op) (not cl-end)) (error "No surrounding delimiters found")) ((or (not op) ; first not found (and cl-end ; second found (>= (car op-end) (car op)) ; second smaller (<= (cdr cl-end) (cdr cl)) (<= (car op-end) beg) ; second contains orig (>= (cdr cl-end) end))) (setq op op-end cl cl-end))) (setq op-end op cl-end cl) ; store copy ;; if the current selection contains the surrounding ;; delimiters, they do not count as new selection (let ((cnt (if (and orig-beg orig-end (not countcurrent)) (let ((sel (evil--get-block-range op cl selection-type))) (if (and (<= orig-beg (car sel)) (>= orig-end (cdr sel))) count (1- count))) (1- count)))) ;; starting from the innermost surrounding delimiters ;; increase selection (when (> cnt 0) (setq op (progn (goto-char (car op-end)) (funcall thing (- cnt)) (if (match-beginning 0) (cons (match-beginning 0) (match-end 0)) op)) cl (progn (goto-char (cdr cl-end)) (funcall thing cnt) (if (match-beginning 0) (cons (match-beginning 0) (match-end 0)) cl))))) (let ((sel (evil--get-block-range op cl selection-type))) (setq op (car sel) cl (cdr sel))) (cond ((and (equal op orig-beg) (equal cl orig-end) (or (not countcurrent) (and countcurrent (/= count 1)))) (error "No surrounding delimiters found")) ((save-excursion (and (not (evil-visual-state-p)) (eq type 'inclusive) (progn (goto-char op) (bolp)) (progn (goto-char cl) (bolp)))) (evil-range op cl 'line :expanded t)) (t (evil-range op cl type :expanded t))))))) (defun evil-select-paren (open close beg end type count &optional inclusive) "Return a range (BEG END) of COUNT delimited text objects. OPEN and CLOSE specify the opening and closing delimiter, respectively. BEG END TYPE are the currently selected (visual) range. If INCLUSIVE is non-nil, OPEN and CLOSE are included in the range; otherwise they are excluded. The types of OPEN and CLOSE specify which kind of THING is used for parsing with `evil-select-block'. If OPEN and CLOSE are characters `evil-up-paren' is used. Otherwise OPEN and CLOSE must be regular expressions and `evil-up-block' is used. If the selection is exclusive, whitespace at the end or at the beginning of the selection until the end-of-line or beginning-of-line is ignored." ;; we need special linewise exclusive selection (unless inclusive (setq inclusive 'exclusive-line)) (cond ((and (characterp open) (characterp close)) (let ((thing #'(lambda (&optional cnt) (evil-up-paren open close cnt))) (bnd (or (bounds-of-thing-at-point 'evil-string) (bounds-of-thing-at-point 'evil-comment) ;; If point is at the opening quote of a string, ;; this must be handled as if point is within the ;; string, i.e. the selection must be extended ;; around the string. Otherwise ;; `evil-select-block' might do the wrong thing ;; because it accidentally moves point inside the ;; string (for inclusive selection) when looking ;; for the current surrounding block. (re #364) (and (= (point) (or beg (point))) (save-excursion (goto-char (1+ (or beg (point)))) (or (bounds-of-thing-at-point 'evil-string) (bounds-of-thing-at-point 'evil-comment))))))) (if (not bnd) (evil-select-block thing beg end type count inclusive) (or (evil-with-restriction (car bnd) (cdr bnd) (condition-case nil (evil-select-block thing beg end type count inclusive) (error nil))) (save-excursion (setq beg (or beg (point)) end (or end (point))) (goto-char (car bnd)) (let ((extbeg (min beg (car bnd))) (extend (max end (cdr bnd)))) (evil-select-block thing extbeg extend type count inclusive (or (< extbeg beg) (> extend end)) t))))))) (t (evil-select-block #'(lambda (&optional cnt) (evil-up-block open close cnt)) beg end type count inclusive)))) (defun evil-select-quote-thing (thing beg end type count &optional inclusive) "Selection THING as if it described a quoted object. THING is typically either 'evil-quote or 'evil-chars. This function is called from `evil-select-quote'." (save-excursion (let* ((count (or count 1)) (dir (if (> count 0) 1 -1)) (bnd (let ((b (bounds-of-thing-at-point thing))) (and b (< (point) (cdr b)) b))) contains-string addcurrent wsboth) (if inclusive (setq inclusive t) (when (= (abs count) 2) (setq count dir) (setq inclusive 'quote-only)) ;; never extend with exclusive selection (setq beg nil end nil)) ;; check if the previously selected range does not contain a ;; string (unless (and beg end (save-excursion (goto-char (if (> dir 0) beg end)) (forward-thing thing dir) (and (<= beg (point)) (< (point) end)))) ;; if so forget the range (setq beg nil end nil)) ;; check if there is a current object, if not fetch one (when (not bnd) (unless (and (zerop (forward-thing thing dir)) (setq bnd (bounds-of-thing-at-point thing))) (error "No quoted string found")) (if (> dir 0) (setq end (point)) (setq beg (point))) (setq addcurrent t)) ;; check if current object is not selected (when (or (not beg) (not end) (> beg (car bnd)) (< end (cdr bnd))) ;; if not, enlarge selection (when (or (not beg) (< (car bnd) beg)) (setq beg (car bnd))) (when (or (not end) (> (cdr bnd) end)) (setq end (cdr bnd))) (setq addcurrent t wsboth t)) ;; maybe count current element (when addcurrent (setq count (if (> dir 0) (1- count) (1+ count)))) ;; enlarge selection (goto-char (if (> dir 0) end beg)) (when (and (not addcurrent) (= count (forward-thing thing count))) (error "No quoted string found")) (if (> dir 0) (setq end (point)) (setq beg (point))) ;; add whitespace (cond ((not inclusive) (setq beg (1+ beg) end (1- end))) ((not (eq inclusive 'quote-only)) ;; try to add whitespace in forward direction (goto-char (if (> dir 0) end beg)) (if (setq bnd (bounds-of-thing-at-point 'evil-space)) (if (> dir 0) (setq end (cdr bnd)) (setq beg (car bnd))) ;; if not found try backward direction (goto-char (if (> dir 0) beg end)) (if (and wsboth (setq bnd (bounds-of-thing-at-point 'evil-space))) (if (> dir 0) (setq beg (car bnd)) (setq end (cdr bnd))))))) (evil-range beg end ;; HACK: fixes #583 ;; When not in visual state, an empty range is ;; possible. However, this cannot be achieved with ;; inclusive ranges, hence we use exclusive ranges ;; in this case. In visual state the range must be ;; inclusive because otherwise the selection would ;; be wrong. (if (evil-visual-state-p) 'inclusive 'exclusive) :expanded t)))) (defun evil-select-quote (quote beg end type count &optional inclusive) "Return a range (BEG END) of COUNT quoted text objects. QUOTE specifies the quotation delimiter. BEG END TYPE are the currently selected (visual) range. If INCLUSIVE is nil the previous selection is ignore. If there is quoted string at point this object will be selected, otherwise the following (if (> COUNT 0)) or preceeding object (if (< COUNT 0)) is selected. If (/= (abs COUNT) 2) the delimiting quotes are not contained in the range, otherwise they are contained in the range. If INCLUSIVE is non-nil the selection depends on the previous selection. If the currently selection contains at least one character that is contained in a quoted string then the selection is extended, otherwise it is thrown away. If there is a non-selected object at point then this object is added to the selection. Otherwise the selection is extended to the following (if (> COUNT 0)) or preceeding object (if (< COUNT 0)). Any whitespace following (or preceeding if (< COUNT 0)) the new selection is added to the selection. If no such whitespace exists and the selection contains only one quoted string then the preceeding (or following) whitespace is added to the range. " (let ((evil-forward-quote-char quote)) (or (let ((bnd (or (bounds-of-thing-at-point 'evil-comment) (bounds-of-thing-at-point 'evil-string)))) (when (and bnd (< (point) (cdr bnd)) (/= (char-after (car bnd)) quote) (/= (char-before (cdr bnd)) quote)) (evil-with-restriction (car bnd) (cdr bnd) (condition-case nil (evil-select-quote-thing 'evil-quote-simple beg end type count inclusive) (error nil))))) (let ((evil-forward-quote-char quote)) (evil-select-quote-thing 'evil-quote beg end type count inclusive))))) (defun evil-select-xml-tag (beg end type &optional count inclusive) "Return a range (BEG END) of COUNT matching XML tags. If INCLUSIVE is non-nil, the tags themselves are included from the range." (cond ((and (not inclusive) (= (abs (or count 1)) 1)) (let ((rng (evil-select-block #'evil-up-xml-tag beg end type count nil t))) (if (or (and beg (= beg (evil-range-beginning rng)) end (= end (evil-range-end rng))) (= (evil-range-beginning rng) (evil-range-end rng))) (evil-select-block #'evil-up-xml-tag beg end type count t) rng))) (t (evil-select-block #'evil-up-xml-tag beg end type count inclusive)))) (defun evil-expand-range (range &optional copy) "Expand RANGE according to its type. Return a new range if COPY is non-nil." (when copy (setq range (evil-copy-range range))) (unless (plist-get (evil-range-properties range) :expanded) (setq range (evil-transform-range :expand range))) range) (defun evil-contract-range (range &optional copy) "Contract RANGE according to its type. Return a new range if COPY is non-nil." (evil-transform-range :contract range copy)) (defun evil-normalize-range (range &optional copy) "Normalize RANGE according to its type. Return a new range if COPY is non-nil." (evil-transform-range :normalize range copy)) (defun evil-transform-range (transform range &optional copy) "Apply TRANSFORM to RANGE according to its type. Return a new range if COPY is non-nil." (when copy (setq range (evil-copy-range range))) (when (evil-type range) (apply #'evil-set-range range (apply #'evil-transform transform range))) range) (defun evil-describe-range (range) "Return description of RANGE. If no description is available, return the empty string." (apply #'evil-describe range)) ;;; Undo (defun evil-start-undo-step (&optional continue) "Start a undo step. All following buffer modifications are grouped together as a single action. If CONTINUE is non-nil, preceding modifications are included. The step is terminated with `evil-end-undo-step'." (when (and (listp buffer-undo-list) (not evil-in-single-undo)) (if evil-undo-list-pointer (evil-refresh-undo-step) (unless (or continue (null (car-safe buffer-undo-list))) (undo-boundary)) (setq evil-undo-list-pointer (or buffer-undo-list t))))) (defun evil-end-undo-step (&optional continue) "End a undo step started with `evil-start-undo-step'. Adds an undo boundary unless CONTINUE is specified." (when (and (listp buffer-undo-list) evil-undo-list-pointer (not evil-in-single-undo)) (evil-refresh-undo-step) (unless (or continue (null (car-safe buffer-undo-list))) (undo-boundary)) (setq evil-undo-list-pointer nil))) (defun evil-refresh-undo-step () "Refresh `buffer-undo-list' entries for current undo step. Undo boundaries until `evil-undo-list-pointer' are removed to make the entries undoable as a single action. See `evil-start-undo-step'." (when evil-undo-list-pointer (setq buffer-undo-list (evil-filter-list #'null buffer-undo-list evil-undo-list-pointer)) (setq evil-undo-list-pointer (or buffer-undo-list t)))) (defmacro evil-with-undo (&rest body) "Execute BODY with enabled undo. If undo is disabled in the current buffer, the undo information is stored in `evil-temporary-undo' instead of `buffer-undo-list'." (declare (indent defun) (debug t)) `(unwind-protect (let (buffer-undo-list) (unwind-protect (progn ,@body) (setq evil-temporary-undo buffer-undo-list) ;; ensure evil-temporary-undo starts with exactly one undo ;; boundary marker, i.e. nil (unless (null (car-safe evil-temporary-undo)) (push nil evil-temporary-undo)))) (unless (eq buffer-undo-list t) ;; undo is enabled, so update the global buffer undo list (setq buffer-undo-list ;; prepend new undos (if there are any) (if (cdr evil-temporary-undo) (nconc evil-temporary-undo buffer-undo-list) buffer-undo-list) evil-temporary-undo nil)))) (defmacro evil-with-single-undo (&rest body) "Execute BODY as a single undo step." (declare (indent defun) (debug t)) `(let (evil-undo-list-pointer) (evil-with-undo (unwind-protect (progn (evil-start-undo-step) (let ((evil-in-single-undo t)) ,@body)) (evil-end-undo-step))))) (defun evil-undo-pop () "Undo the last buffer change. Removes the last undo information from `buffer-undo-list'. If undo is disabled in the current buffer, use the information in `evil-temporary-undo' instead." (let ((paste-undo (list nil))) (let ((undo-list (if (eq buffer-undo-list t) evil-temporary-undo buffer-undo-list))) (when (or (not undo-list) (car undo-list)) (user-error "Can't undo previous change")) (while (and undo-list (null (car undo-list))) (pop undo-list)) ; remove nil (while (and undo-list (car undo-list)) (push (pop undo-list) paste-undo)) (let ((buffer-undo-list (nreverse paste-undo))) (evil-save-echo-area (undo))) (if (eq buffer-undo-list t) (setq evil-temporary-undo nil) (setq buffer-undo-list undo-list))))) ;;; Search (defun evil-transform-regexp (regexp replacements-alist) (let ((pos 0) result) (replace-regexp-in-string "\\\\+[^\\\\]" #'(lambda (txt) (let* ((b (match-beginning 0)) (e (match-end 0)) (ch (aref txt (1- e))) (repl (assoc ch replacements-alist))) (if (and repl (zerop (mod (length txt) 2))) (concat (substring txt b (- e 2)) (cdr repl)) txt))) regexp nil t))) (defun evil-transform-magic (str magic quote transform &optional start) "Transforms STR with magic characters. MAGIC is a regexp that matches all potential magic characters. Each occurence of CHAR as magic character within str is replaced by the result of calling the associated TRANSFORM function. TRANSFORM is a function taking two arguments, the character to be transformed and the rest of string after the character. The function should return a triple (REPLACEMENT REST . STOP) where REPLACEMENT is the replacement and REST is the rest of the string that has not been transformed. If STOP is non-nil then the substitution stops immediately. The replacement starts at position START, everything before that position is returned literally. The result is a pair (RESULT . REST). RESULT is a list containing the transformed parts in order. If two subsequents parts are both strings, they are concatenated. REST is the untransformed rest string (usually \"\" but may be more if TRANSFORM stopped the substitution). Which characters are considered as magic characters (i.e. the transformation happens if the character is NOT preceeded by a backslash) is determined by `evil-magic'. The special tokens \\v, \\V, \\m and \\M have always a special meaning (like in Vim) and should not be contained in TRANSFORMS, otherwise their meaning is overwritten. The parameter QUOTE is a quoting function applied to literal transformations, usually `regexp-quote' or `replace-quote'." (save-match-data (let ((regexp (concat "\\(?:\\`\\|[^\\]\\)\\(\\\\\\(?:\\(" magic "\\)\\|\\(.\\)\\)\\|\\(" magic "\\)\\)")) (magic-chars (evil-get-magic evil-magic)) (evil-magic evil-magic) (quote (or quote #'identity)) result stop) (while (and (not stop) str (string-match regexp str)) (unless (zerop (match-beginning 1)) (push (substring str 0 (match-beginning 1)) result)) (let ((char (or (match-string 2 str) (match-string 3 str) (match-string 4 str))) (rest (substring str (match-end 0)))) (cond ((match-beginning 4) ;; magic character without backslash (if (string-match magic-chars char) ;; magic, do transform (let ((trans (funcall transform (aref char 0) rest))) (push (car trans) result) (setq str (cadr trans) stop (nthcdr 2 trans))) ;; non-magic, literal transformation (push (funcall quote char) result) (setq str rest))) ((match-beginning 2) ;; magic character with backslash (if (not (string-match magic-chars char)) ;; non-magic, do transform (let ((trans (funcall transform (aref char 0) rest))) (push (car trans) result) (setq str (cadr trans) stop (nthcdr 2 trans))) ;; magic, literal transformation (push (funcall quote char) result) (setq str rest))) ((memq (aref char 0) '(?m ?M ?v ?V)) (setq evil-magic (cdr (assq (aref char 0) '((?m . t) (?M . nil) (?v . very-magic) (?V . very-nomagic))))) (setq magic-chars (evil-get-magic evil-magic)) (setq str rest)) (t ;; non-magic char with backslash, literal transformation (push (funcall quote char) result) (setq str rest))))) (cond ((and str (not stop)) (push str result) (setq str "")) ((not str) (setq str ""))) ;; concatenate subsequent strings ;; note that result is in reverse order (let (repl) (while result (cond ((and (stringp (car result)) (zerop (length (car result)))) (pop result)) ((and (stringp (car result)) (stringp (cadr result))) (setq result (cons (concat (cadr result) (car result)) (nthcdr 2 result)))) (t (push (pop result) repl)))) (cons repl str))))) (defconst evil-vim-regexp-replacements '((?n . "\n") (?r . "\r") (?t . "\t") (?b . "\b") (?s . "[[:space:]]") (?S . "[^[:space:]]") (?d . "[[:digit:]]") (?D . "[^[:digit:]]") (?x . "[[:xdigit:]]") (?X . "[^[:xdigit:]]") (?o . "[0-7]") (?O . "[^0-7]") (?a . "[[:alpha:]]") (?A . "[^[:alpha:]]") (?l . "[a-z]") (?L . "[^a-z]") (?u . "[A-Z]") (?U . "[^A-Z]") (?y . "\\s") (?Y . "\\S") (?\( . "\\(") (?\) . "\\)") (?{ . "\\{") (?} . "\\}") (?\[ . "[") (?\] . "]") (?< . "\\<") (?> . "\\>") (?_ . "\\_") (?* . "*") (?+ . "+") (?? . "?") (?= . "?") (?. . ".") (?` . "`") (?^ . "^") (?$ . "$") (?| . "\\|"))) (defconst evil-regexp-magic "[][(){}<>_dDsSxXoOaAlLuUwWyY.*+?=^$`|nrtb]") (defun evil-transform-vim-style-regexp (regexp) "Transforms vim-style backslash codes to Emacs regexp. This includes the backslash codes \\d, \\D, \\s, \\S, \\x, \\X, \\o, \\O, \\a, \\A, \\l, \\L, \\u, \\U and \\w, \\W. The new codes \\y and \\Y can be used instead of the Emacs code \\s and \\S which have a different meaning in Vim-style." (car (car (evil-transform-magic regexp evil-regexp-magic #'regexp-quote #'(lambda (char rest) (let ((repl (assoc char evil-vim-regexp-replacements))) (if repl (list (cdr repl) rest) (list (concat "\\" (char-to-string char)) rest)))))))) ;;; Substitute (defun evil-downcase-first (str) "Return STR with the first letter downcased." (if (zerop (length str)) str (concat (downcase (substring str 0 1)) (substring str 1)))) (defun evil-upcase-first (str) "Return STR with the first letter upcased." (if (zerop (length str)) str (concat (upcase (substring str 0 1)) (substring str 1)))) (defun evil-get-magic (magic) "Returns a regexp matching the magic characters according to MAGIC. Depending on the value of MAGIC the following characters are considered magic. t [][{}*+?.&~$^ nil [][{}*+?$^ 'very-magic not 0-9A-Za-z_ 'very-nomagic empty." (cond ((eq magic t) "[][}{*+?.&~$^]") ((eq magic 'very-magic) "[^0-9A-Za-z_]") ((eq magic 'very-nomagic) "\\\\") (t "[][}{*+?$^]"))) ;; TODO: support magic characters in patterns (defconst evil-replacement-magic "[eElLuU0-9&#,rnbt=]" "All magic characters in a replacement string") (defun evil-compile-subreplacement (to &optional start) "Convert a regexp replacement TO to Lisp from START until \\e or \\E. Returns a pair (RESULT . REST). RESULT is a list suitable for `perform-replace' if necessary, the original string if not. REST is the unparsed remainder of TO." (let ((result (evil-transform-magic to evil-replacement-magic #'replace-quote #'(lambda (char rest) (cond ((eq char ?#) (list '(number-to-string replace-count) rest)) ((eq char ?r) (list "\r" rest)) ((eq char ?n) (list "\n" rest)) ((eq char ?b) (list "\b" rest)) ((eq char ?t) (list "\t" rest)) ((memq char '(?e ?E)) `("" ,rest . t)) ((memq char '(?l ?L ?u ?U)) (let ((result (evil-compile-subreplacement rest)) (func (cdr (assoc char '((?l . evil-downcase-first) (?L . downcase) (?u . evil-upcase-first) (?U . upcase)))))) (list `(,func (replace-quote (evil-match-substitute-replacement ,(car result) (not case-replace)))) (cdr result)))) ((eq char ?=) (when (or (zerop (length rest)) (not (eq (aref rest 0) ?@))) (user-error "Expected @ after \\=")) (when (< (length rest) 2) (user-error "Expected register after \\=@")) (list (evil-get-register (aref rest 1)) (substring rest 2))) ((eq char ?,) (let* ((obj (read-from-string rest)) (result `(replace-quote ,(car obj))) (end ;; swallow a space after a symbol (if (and (or (symbolp (car obj)) ;; swallow a space after 'foo, ;; but not after (quote foo) (and (eq (car-safe (car obj)) 'quote) (not (= ?\( (aref rest 0))))) (eq (string-match " " rest (cdr obj)) (cdr obj))) (1+ (cdr obj)) (cdr obj)))) (list result (substring rest end)))) ((eq char ?0) (list "\\&" rest)) (t (list (concat "\\" (char-to-string char)) rest)))) start))) (let ((rest (cdr result)) (result (car result))) (replace-match-string-symbols result) (cons (if (cdr result) (cons 'concat result) (or (car result) "")) rest)))) (defun evil-compile-replacement (to) "Maybe convert a regexp replacement TO to Lisp. Returns a list suitable for `perform-replace' if necessary, the original string if not. Currently the following magic characters in replacements are supported: 0-9&#lLuUrnbt, The magic character , (comma) start an Emacs-lisp expression." (when (stringp to) (save-match-data (cons 'replace-eval-replacement (car (evil-compile-subreplacement to)))))) (defun evil-replace-match (replacement &optional fixedcase string) "Replace text match by last search with REPLACEMENT. If REPLACEMENT is an expression it will be evaluated to compute the replacement text, otherwise the function behaves as `replace-match'." (if (stringp replacement) (replace-match replacement fixedcase nil string) (replace-match (funcall (car replacement) (cdr replacement) 0) fixedcase nil string))) (defun evil-match-substitute-replacement (replacement &optional fixedcase string) "Return REPLACEMENT as it will be inserted by `evil-replace-match'." (if (stringp replacement) (match-substitute-replacement replacement fixedcase nil string) (match-substitute-replacement (funcall (car replacement) (cdr replacement) 0) fixedcase nil string))) ;;; Alignment (defun evil-justify-lines (beg end justify position) "Justifes all lines in a range. BEG and END specify the range of those lines to be justified. JUSTIFY is either 'left, 'right or 'center according to the justification type. POSITION is the maximal text width for right and center justification or the column at which the lines should be left-aligned for left justification." (let ((fill-column position) adaptive-fill-mode fill-prefix) (evil-with-restriction (save-excursion (goto-char beg) (line-beginning-position)) (save-excursion (goto-char end) (if (bolp) (line-end-position 0) (line-end-position))) (goto-char (point-min)) (while (progn (if (eq justify 'left) (indent-line-to position) (when (re-search-forward "^[[:space:]]*" nil t) (delete-region (match-beginning 0) (match-end 0))) (justify-current-line justify nil t)) (and (zerop (forward-line)) (bolp)))) (goto-char (point-min)) (back-to-indentation)))) ;;; View helper (defvar-local evil-list-view-select-action nil) (put 'evil-list-view-select-action 'permanent-local t) (define-derived-mode evil-list-view-mode tabulated-list-mode "Evil List View" (tabulated-list-init-header) (tabulated-list-print)) (defun evil-list-view-goto-entry () (interactive) (when (and evil-list-view-select-action (not (eobp))) (let* ((line (line-number-at-pos (point))) (entry (elt tabulated-list-entries (1- line)))) (funcall evil-list-view-select-action (nth 1 entry))))) (defun evil-list-view-quit () (interactive) (quit-window 'kill)) (define-key evil-list-view-mode-map (kbd "q") #'evil-list-view-quit) (define-key evil-list-view-mode-map [follow-link] nil) ;; allows mouse-1 to be activated (define-key evil-list-view-mode-map [mouse-1] #'evil-list-view-goto-entry) (define-key evil-list-view-mode-map [return] #'evil-list-view-goto-entry) (defmacro evil-with-view-list (&rest properties) "Opens new list view buffer. PROPERTIES is a property-list which supports the following properties: :name (required) The name of the buffer. :mode-name (required) The name for the mode line. :format (required) The value for `tabulated-list-format'. :entries (required) The value for `tabulated-list-entries'. :select-action (optional) A function for row selection. It takes in a single parameter, which is the selected row's vector value that is passed into `:entries'. " (declare (indent defun) (debug t)) `(let ((bufname (concat "*" ,(plist-get properties :name) "*")) (inhibit-read-only t)) (and (get-buffer bufname) (kill-buffer bufname)) (let ((buf (get-buffer-create bufname))) (with-current-buffer buf (setq tabulated-list-format ,(plist-get properties :format)) (setq tabulated-list-entries ,(plist-get properties :entries)) (setq evil-list-view-select-action ,(plist-get properties :select-action)) (evil-list-view-mode) (setq mode-name ,(plist-get properties :mode-name)) (evil-motion-state)) (switch-to-buffer-other-window buf)))) (provide 'evil-common) ;;; evil-common.el ends here evil-1.12.17/evil-core.el000066400000000000000000001556201360703323200150410ustar00rootroot00000000000000;;; evil-core.el --- Core functionality ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . ;;; Commentary: ;; Evil is defined as a globalized minor mode, enabled with the toggle ;; function `evil-mode'. This in turn enables `evil-local-mode' in ;; every buffer, which sets up the buffer's state. ;; ;; Each state has its own keymaps, and these keymaps have status as ;; "emulation keymaps" with priority over regular keymaps. Emacs ;; maintains the following keymap hierarchy (highest priority first): ;; ;; * Overriding keymaps/overlay keymaps... ;; * Emulation mode keymaps... ;; - Evil keymaps... ;; * Minor mode keymaps... ;; * Local keymap (`local-set-key') ;; * Global keymap (`global-set-key') ;; ;; Within this hierarchy, Evil arranges the keymaps for the current ;; state as shown below: ;; ;; * Intercept keymaps... ;; * Local state keymap ;; * Minor-mode keymaps... ;; * Auxiliary keymaps... ;; * Overriding keymaps... ;; * Global state keymap ;; * Keymaps for other states... ;; ;; These keymaps are listed in `evil-mode-map-alist', which is listed ;; in `emulation-mode-map-alist'. ;; ;; Most of the key bindings for a state are stored in its global ;; keymap, which has a name such as `evil-normal-state-map'. (See the ;; file evil-maps.el, which contains all the default key bindings.) A ;; state also has a local keymap (`evil-normal-state-local-map'), ;; which may contain user customizations for the current buffer. ;; Furthermore, any Emacs mode may be assigned state bindings of its ;; own by passing the mode's keymap to the function `evil-define-key' ;; or `evil-define-minor-mode-key'. The former uses a specific map to ;; define the key in while the latter associates the key with a ;; particular mode. These mode-specific bindings are ultimately stored ;; in so-called auxiliary and minor-mode keymaps respectively, which ;; are sandwiched between the local keymap and the global keymap. ;; Finally, the state may also activate the keymaps of other states ;; (e.g., Normal state inherits bindings from Motion state). ;; ;; For integration purposes, a regular Emacs keymap may be "elevated" ;; to emulation status by passing it to `evil-make-intercept-map' or ;; `evil-make-overriding-map'. An "intercept" keymap has priority over ;; all other Evil keymaps. (Evil uses this facility when debugging and ;; for handling the "ESC" key in the terminal.) More common is the ;; "overriding" keymap, which only has priority over the global state ;; keymap. (This is useful for adapting key-heavy modes such as Dired, ;; where all but a few keys should be left as-is and should not be ;; shadowed by Evil's default bindings.) ;; ;; States are defined with the macro `evil-define-state', which ;; creates a command for switching to the state. This command, ;; for example `evil-normal-state' for Normal state, performs ;; the following tasks: ;; ;; * Setting `evil-state' to the new state. ;; * Refreshing the keymaps in `evil-mode-map-alist'. ;; * Updating the mode line. ;; - Normal state depends on `evil-normal-state-tag'. ;; * Adjusting the cursor's appearance. ;; - Normal state depends on `evil-normal-state-cursor'. ;; * Displaying a message in the echo area. ;; - Normal state depends on `evil-normal-state-message'. ;; * Running hooks. ;; - Normal state runs `evil-normal-state-entry-hook' when ;; entering, and `evil-normal-state-exit-hook' when exiting. ;; ;; The various properties of a state can be accessed through their ;; respective variables, or by passing a keyword and the state's name ;; to the `evil-state-property' function. Evil defines the states ;; Normal state ("normal"), Insert state ("insert"), Visual state ;; ("visual"), Replace state ("replace"), Operator-Pending state ;; ("operator"), Motion state ("motion") and Emacs state ("emacs"). (require 'evil-common) ;;; Code: (declare-function evil-emacs-state-p "evil-states") (declare-function evil-ex-p "evil-ex") (defvar evil-mode-buffers) (define-minor-mode evil-local-mode "Minor mode for setting up Evil in a single buffer." :init-value nil (cond ((evil-disabled-buffer-p) ;; Don't leave the mode variable on in buffers where evil disabled, because ;; functions that check this variable will get an incorrect result (e.g., ;; evil-refresh-cursor). (setq evil-local-mode nil)) (evil-local-mode (setq emulation-mode-map-alists (evil-concat-lists '(evil-mode-map-alist) emulation-mode-map-alists)) (evil-initialize-local-keymaps) ;; restore the proper value of `major-mode' in Fundamental buffers (when (eq major-mode 'turn-on-evil-mode) (setq major-mode 'fundamental-mode)) (when (minibufferp) (setq-local evil-default-state 'insert) (setq-local evil-echo-state nil)) ;; The initial state is usually setup by `evil-initialize' when ;; the major-mode in a buffer changes. This preliminary ;; initialization is only for the case when `evil-local-mode' is ;; called directly for the first time in a buffer. (unless evil-state (evil-initialize-state)) (add-hook 'input-method-activate-hook 'evil-activate-input-method t t) (add-hook 'input-method-deactivate-hook 'evil-deactivate-input-method t t) (add-hook 'activate-mark-hook 'evil-visual-activate-hook nil t) (add-hook 'pre-command-hook 'evil-repeat-pre-hook) (add-hook 'post-command-hook 'evil-repeat-post-hook)) (t (evil-refresh-mode-line) (remove-hook 'activate-mark-hook 'evil-visual-activate-hook t) (remove-hook 'input-method-activate-hook 'evil-activate-input-method t) (remove-hook 'input-method-deactivate-hook 'evil-deactivate-input-method t) (evil-change-state nil)))) ;; Make the variable permanent local. This is particular useful in ;; conjunction with nXhtml/mumamo because mumamo does not touch these ;; variables. (put 'evil-local-mode 'permanent-local t) (defun turn-on-evil-mode (&optional arg) "Turn on Evil in the current buffer." (interactive) (evil-local-mode (or arg 1))) (defun turn-off-evil-mode (&optional arg) "Turn off Evil in the current buffer." (interactive) (evil-local-mode (or arg -1))) ;; The function `evil-initialize' should only be used to initialize ;; `evil-local-mode' from the globalized minor-mode `evil-mode'. It is ;; called whenever evil is enabled in a buffer for the first time or ;; when evil is active and the major-mode of the buffer changes. In ;; addition to enabling `evil-local-mode' it also sets the initial ;; evil-state according to the major-mode. (defun evil-initialize () "Enable Evil in the current buffer, if appropriate. To enable Evil globally, do (evil-mode 1)." (unless (and (minibufferp) (not evil-want-minibuffer)) (evil-local-mode 1) (evil-initialize-state))) ;;;###autoload (autoload 'evil-mode "evil" nil t) (define-globalized-minor-mode evil-mode evil-local-mode evil-initialize) ;; No hooks are run in Fundamental buffers, so other measures are ;; necessary to initialize Evil in these buffers. When Evil is ;; enabled globally, the default value of `major-mode' is set to ;; `turn-on-evil-mode', so that Evil is enabled in Fundamental ;; buffers as well. Then, the buffer-local value of `major-mode' is ;; changed back to `fundamental-mode'. (Since the `evil-mode' function ;; is created by a macro, we use `defadvice' to augment it.) (defadvice evil-mode (after start-evil activate) "Enable Evil in Fundamental mode." (if evil-mode (progn (when (eq (default-value 'major-mode) 'fundamental-mode) ;; changed back by `evil-local-mode' (setq-default major-mode 'turn-on-evil-mode)) (ad-enable-regexp "^evil") (ad-activate-regexp "^evil") (with-no-warnings (evil-esc-mode 1))) (when (eq (default-value 'major-mode) 'turn-on-evil-mode) (setq-default major-mode 'fundamental-mode)) (ad-disable-regexp "^evil") (ad-update-regexp "^evil") (with-no-warnings (evil-esc-mode -1)))) (defun evil-change-state (state &optional message) "Change the state to STATE. If STATE is nil, disable all states." (let ((func (evil-state-property (or state evil-state) :toggle))) (when (and (functionp func) (or message (not (eq state evil-state)))) (funcall func (if state (and message 1) -1))))) (defmacro evil-save-state (&rest body) "Save the current state; execute BODY; restore the state." (declare (indent defun) (debug t)) `(let* ((evil-state evil-state) (evil-previous-state evil-previous-state) (evil-previous-state-alist (copy-tree evil-previous-state-alist)) (evil-next-state evil-next-state) (old-state evil-state) (inhibit-quit t) (buf (current-buffer))) (unwind-protect (progn ,@body) (when (buffer-live-p buf) (with-current-buffer buf (evil-change-state old-state)))))) (defmacro evil-with-state (state &rest body) "Change to STATE and execute BODY without refreshing the display. Restore the previous state afterwards." (declare (indent defun) (debug t)) `(evil-without-display (evil-save-state (evil-change-state ',state) ,@body))) (defun evil-initializing-p (&optional buffer) "Whether Evil is in the process of being initialized." (memq (or buffer (current-buffer)) evil-mode-buffers)) (defun evil-initialize-state (&optional state buffer) "Set up the initial state for BUFFER. BUFFER defaults to the current buffer. Uses STATE if specified, or calls `evil-initial-state-for-buffer'. See also `evil-set-initial-state'." (with-current-buffer (or buffer (current-buffer)) (if state (evil-change-state state) (evil-change-to-initial-state buffer)))) (put 'evil-initialize-state 'permanent-local-hook t) (defun evil-initial-state-for-buffer-name (&optional name default) "Return the initial Evil state to use for a buffer with name NAME. Matches the name against the regular expressions in `evil-buffer-regexps'. If none matches, returns DEFAULT." (let ((name (if (stringp name) name (buffer-name name))) regexp state) (when (stringp name) (catch 'done (dolist (entry evil-buffer-regexps default) (setq regexp (car entry) state (cdr entry)) (when (string-match regexp name) (throw 'done state))))))) (defun evil-disabled-buffer-p (&optional buffer) "Whether Evil should be disabled in BUFFER." (null (evil-initial-state-for-buffer-name buffer 'undefined))) (defun evil-initial-state-for-buffer (&optional buffer default) "Return the initial Evil state to use for BUFFER. BUFFER defaults to the current buffer. Returns DEFAULT if no initial state is associated with BUFFER. See also `evil-initial-state'." (with-current-buffer (or buffer (current-buffer)) (or (evil-initial-state-for-buffer-name (buffer-name)) (catch 'done (dolist (mode minor-mode-map-alist) (setq mode (car-safe mode)) (when (and (boundp mode) (symbol-value mode)) (when (setq mode (evil-initial-state mode)) (throw 'done mode))))) (evil-initial-state major-mode nil t) default))) (defun evil-initial-state (mode &optional default follow-parent checked-modes) "Return the Evil state to use for MODE or its alias. Returns DEFAULT if no initial state is associated with MODE. The initial state for a mode can be set with `evil-set-initial-state'. If FOLLOW-PARENT is non-nil, also check parent modes of MODE and its alias. CHECKED-MODES is used internally and should not be set initially." (cond ((and mode (symbolp mode) (memq mode checked-modes)) (error "Circular reference detected in ancestors of %s\n%s" major-mode checked-modes)) ((and mode (symbolp mode)) (let ((mode-alias (let ((func (symbol-function mode))) (when (symbolp func) func))) state modes) (or (catch 'done (dolist (entry (evil-state-property t :modes) default) (setq state (car entry) modes (symbol-value (cdr entry))) (when (or (memq mode modes) (and mode-alias (memq mode-alias modes))) (throw 'done state)))) (when follow-parent (evil-initial-state (get mode 'derived-mode-parent) nil t (cons mode checked-modes))) (when follow-parent (evil-initial-state (get mode-alias 'derived-mode-parent) nil t (cons mode-alias checked-modes)))))))) (defun evil-set-initial-state (mode state) "Set the initial state for major mode MODE to STATE. This is the state the buffer comes up in." (dolist (modes (evil-state-property t :modes)) (setq modes (cdr-safe modes)) (set modes (delq mode (symbol-value modes)))) (when state (add-to-list (evil-state-property state :modes) mode))) (evil-define-command evil-change-to-initial-state (&optional buffer message) "Change the state of BUFFER to its initial state. This is the state the buffer came up in. If Evil is not activated then this function does nothing." :keep-visual t :suppress-operator t (with-current-buffer (or buffer (current-buffer)) (when evil-local-mode (evil-change-state (evil-initial-state-for-buffer buffer (or evil-default-state 'normal)) message)))) (evil-define-command evil-change-to-previous-state (&optional buffer message) "Change the state of BUFFER to its previous state." :keep-visual t :repeat abort :suppress-operator t (with-current-buffer (or buffer (current-buffer)) (let ((prev-state evil-previous-state) (prev-prev-state (cdr-safe (assoc evil-previous-state evil-previous-state-alist)))) (evil-change-state nil) (when prev-prev-state (setq evil-previous-state prev-prev-state)) (evil-change-state (or prev-state evil-default-state 'normal) message)))) ;; When a buffer is created in a low-level way, it is invisible to ;; Evil (as well as other globalized minor modes) because no hooks are ;; run. This is appropriate since many buffers are used for throwaway ;; purposes. Passing the buffer to `set-window-buffer' indicates ;; otherwise, though, so advise this function to initialize Evil. (defadvice set-window-buffer (before evil) "Initialize Evil in the displayed buffer." (when evil-mode (when (get-buffer (ad-get-arg 1)) (with-current-buffer (ad-get-arg 1) (unless evil-local-mode (evil-local-mode 1)))))) ;; Refresh cursor color. ;; Cursor color can only be set for each frame but not for each buffer. (add-hook 'window-configuration-change-hook 'evil-refresh-cursor) (defadvice select-window (after evil activate) (evil-refresh-cursor)) (defun evil-generate-mode-line-tag (&optional state) "Generate the evil mode-line tag for STATE." (let ((tag (evil-state-property state :tag t))) ;; prepare mode-line: add tooltip (if (stringp tag) (propertize tag 'help-echo (evil-state-property state :name) 'mouse-face 'mode-line-highlight) tag))) (defun evil-refresh-mode-line (&optional state) "Refresh mode line tag." (when (listp mode-line-format) (setq evil-mode-line-tag (evil-generate-mode-line-tag state)) ;; refresh mode line data structure ;; first remove evil from mode-line (setq mode-line-format (delq 'evil-mode-line-tag mode-line-format)) (let ((mlpos mode-line-format) pred which where) ;; determine before/after which symbol the tag should be placed (cond ((eq evil-mode-line-format 'before) (setq where 'after which 'mode-line-position)) ((eq evil-mode-line-format 'after) (setq where 'after which 'mode-line-modes)) ((consp evil-mode-line-format) (setq where (car evil-mode-line-format) which (cdr evil-mode-line-format)))) ;; find the cons-cell of the symbol before/after which the tag ;; should be placed (while (and mlpos (let ((sym (or (car-safe (car mlpos)) (car mlpos)))) (not (eq which sym)))) (setq pred mlpos mlpos (cdr mlpos))) ;; put evil tag at the right position in the mode line (cond ((not mlpos)) ;; position not found, so do not add the tag ((eq where 'before) (if pred (setcdr pred (cons 'evil-mode-line-tag mlpos)) (setq mode-line-format (cons 'evil-mode-line-tag mode-line-format)))) ((eq where 'after) (setcdr mlpos (cons 'evil-mode-line-tag (cdr mlpos))))) (force-mode-line-update)))) ;; input methods should be disabled in non-insertion states (defun evil-activate-input-method () "Enable input method in states with :input-method non-nil." (let (input-method-activate-hook input-method-deactivate-hook) (when (and evil-local-mode evil-state) (setq evil-input-method current-input-method) (unless (evil-state-property evil-state :input-method) (deactivate-input-method))))) (put 'evil-activate-input-method 'permanent-local-hook t) (defun evil-deactivate-input-method () "Disable input method in all states." (let (input-method-activate-hook input-method-deactivate-hook) (when (and evil-local-mode evil-state) (setq evil-input-method nil)))) (put 'evil-deactivate-input-method 'permanent-local-hook t) (defmacro evil-without-input-method-hooks (&rest body) "Execute body with evil's activate/deactivate-input-method hooks deactivated. This allows input methods to be used in normal-state." `(unwind-protect (progn (remove-hook 'input-method-activate-hook 'evil-activate-input-method t) (remove-hook 'input-method-deactivate-hook 'evil-deactivate-input-method t) ,@body) (progn (add-hook 'input-method-activate-hook 'evil-activate-input-method nil t) (add-hook 'input-method-deactivate-hook 'evil-deactivate-input-method nil t)))) (defadvice toggle-input-method (around evil) "Refresh `evil-input-method'." (cond ((not evil-local-mode) ad-do-it) ((evil-state-property evil-state :input-method) ad-do-it) (t (let ((current-input-method evil-input-method)) ad-do-it)))) ;; Local keymaps are implemented using buffer-local variables. ;; However, unless a buffer-local value already exists, ;; `define-key' acts on the variable's default (global) value. ;; So we need to initialize the variable whenever we enter a ;; new buffer or when the buffer-local values are reset. (defun evil-initialize-local-keymaps () "Initialize a buffer-local value for local keymaps as necessary. The initial value is that of `make-sparse-keymap'." (dolist (entry evil-local-keymaps-alist) (let ((mode (car entry)) (map (cdr entry))) (unless (and (keymapp (symbol-value map)) (local-variable-p map)) (set map (make-sparse-keymap)))))) (defun evil-make-overriding-map (keymap &optional state copy) "Give KEYMAP precedence over the global keymap of STATE. The keymap will have lower precedence than custom STATE bindings. If STATE is nil, give it precedence over all states. If COPY is t, create a copy of KEYMAP and give that higher precedence. See also `evil-make-intercept-map'." (let ((key [override-state])) (if (not copy) (define-key keymap key (or state 'all)) (unless (keymapp copy) (setq copy (assq-delete-all 'menu-bar (copy-keymap keymap)))) (define-key copy key (or state 'all)) (define-key keymap key copy)))) (defun evil-make-intercept-map (keymap &optional state aux) "Give KEYMAP precedence over all Evil keymaps in STATE. If STATE is nil, give it precedence over all states. If AUX is non-nil, make the auxiliary keymap corresponding to KEYMAP in STATE an intercept keymap instead of KEYMAP itself. See also `evil-make-overriding-map'." (let ((key [intercept-state]) (keymap (if aux (evil-get-auxiliary-keymap keymap state t t) keymap))) (define-key keymap key (or state 'all)))) (defmacro evil-define-keymap (keymap doc &rest body) "Define a keymap KEYMAP listed in `evil-mode-map-alist'. That means it will have precedence over regular keymaps. DOC is the documentation for the variable. BODY, if specified, is executed after toggling the mode. Optional keyword arguments may be specified before the body code: :mode VAR Mode variable. If unspecified, the variable is based on the keymap name. :local BOOLEAN Whether the keymap should be buffer-local, that is, reinitialized for each buffer. :func BOOLEAN Create a toggle function even if BODY is empty. \(fn KEYMAP DOC [[KEY VAL]...] BODY...)" (declare (indent defun) (doc-string 2) (debug (&define name [&optional stringp] [&rest [keywordp sexp]] def-body))) (let ((func t) arg intercept key local mode overriding) (while (keywordp (car-safe body)) (setq key (pop body) arg (pop body)) (cond ((eq key :mode) (setq mode arg)) ((eq key :local) (setq local arg)) ((eq key :func) (setq func arg)) ((eq key :intercept) (setq intercept arg)) ((eq key :overriding) (setq overriding arg)))) (setq mode (or mode (intern (replace-regexp-in-string "\\(?:-\\(?:mode-\\)?\\(?:key\\)?map\\)?$" "-mode" (symbol-name keymap))))) `(progn (defvar ,keymap ,(unless local '(make-sparse-keymap))) (unless (get ',keymap 'variable-documentation) (put ',keymap 'variable-documentation ,doc)) (defvar ,mode nil) (unless (get ',mode 'variable-documentation) (put ',mode 'variable-documentation ,doc)) (make-variable-buffer-local ',mode) (put ',mode 'permanent-local t) (when ,intercept (evil-make-intercept-map ,keymap)) (when ,overriding (evil-make-overriding-map ,keymap)) ,@(if local `((make-variable-buffer-local ',keymap) (put ',keymap 'permanent-local t) (evil-add-to-alist 'evil-local-keymaps-alist ',mode ',keymap)) `((evil-add-to-alist 'evil-global-keymaps-alist ',mode ',keymap) (evil-add-to-alist 'evil-mode-map-alist ',mode ,keymap))) ,(when (or body func) `(defun ,mode (&optional arg) ,@(when doc `(,doc)) (interactive) (cond ((numberp arg) (setq ,mode (> arg 0))) (t (setq ,mode (not ,mode)))) ,@body)) ',keymap))) ;; The ESC -> escape translation code has been provided by Stefan ;; Monnier in the discussion of GNU Emacs bug #13793. (defun evil-esc-mode (&optional arg) "Toggle interception of \\e (escape). Enable with positive ARG and disable with negative ARG. When enabled, `evil-esc-mode' modifies the entry of \\e in `input-decode-map'. If such an event arrives, it is translated to a plain 'escape event if no further event occurs within `evil-esc-delay' seconds. Otherwise no translation happens and the ESC prefix map (i.e. the map originally bound to \\e in `input-decode-map`) is returned." (cond ((or (null arg) (eq arg 0)) (evil-esc-mode (if evil-esc-mode -1 +1))) ((> arg 0) (unless evil-esc-mode (setq evil-esc-mode t) (add-hook 'after-make-frame-functions #'evil-init-esc) (mapc #'evil-init-esc (frame-list)))) ((< arg 0) (when evil-esc-mode (remove-hook 'after-make-frame-functions #'evil-init-esc) (mapc #'evil-deinit-esc (frame-list)) (setq evil-esc-mode nil))))) (defun evil-init-esc (frame) "Update `input-decode-map' in terminal." (with-selected-frame frame (let ((term (frame-terminal frame))) (when (and (or (eq evil-intercept-esc 'always) (and evil-intercept-esc (eq (terminal-live-p term) t))) ; only patch tty (not (terminal-parameter term 'evil-esc-map))) (let ((evil-esc-map (lookup-key input-decode-map [?\e]))) (set-terminal-parameter term 'evil-esc-map evil-esc-map) (define-key input-decode-map [?\e] `(menu-item "" ,evil-esc-map :filter ,#'evil-esc))))))) (defun evil-deinit-esc (frame) "Restore `input-decode-map' in terminal." (with-selected-frame frame (let ((term (frame-terminal frame))) (when (terminal-live-p term) (let ((evil-esc-map (terminal-parameter term 'evil-esc-map))) (when evil-esc-map (define-key input-decode-map [?\e] evil-esc-map) (set-terminal-parameter term 'evil-esc-map nil))))))) (defun evil-esc (map) "Translate \\e to 'escape if no further event arrives. This function is used to translate a \\e event either to 'escape or to the standard ESC prefix translation map. If \\e arrives, this function waits for `evil-esc-delay' seconds for another event. If no other event arrives, the event is translated to 'escape, otherwise it is translated to the standard ESC prefix map stored in `input-decode-map'. If `evil-inhibit-esc' is non-nil or if evil is in emacs state, the event is always translated to the ESC prefix. The translation to 'escape happens only if the current command has indeed been triggered by \\e. In other words, this will only happen when the keymap is accessed from `read-key-sequence'. In particular, if it is access from `define-key' the returned mapping will always be the ESC prefix map." (if (and (not evil-inhibit-esc) (or evil-local-mode (evil-ex-p) (active-minibuffer-window)) (not (evil-emacs-state-p)) (let ((keys (this-single-command-keys))) (and (> (length keys) 0) (= (aref keys (1- (length keys))) ?\e))) (sit-for evil-esc-delay)) (prog1 [escape] (when defining-kbd-macro (end-kbd-macro) (setq last-kbd-macro (vconcat last-kbd-macro [escape])) (start-kbd-macro t t))) map)) (defun evil-state-p (sym) "Whether SYM is the name of a state." (assq sym evil-state-properties)) (defun evil-state-keymaps (state &rest excluded) "Return a keymap alist of keymaps activated by STATE. If STATE references other states in its :enable property, these states are recursively processed and added to the list. \(The EXCLUDED argument is an internal safeguard against infinite recursion, keeping track of processed states.)" (let* ((state (or state evil-state)) (enable (evil-state-property state :enable)) (map (cons (evil-state-property state :mode) (evil-state-property state :keymap t))) (local-map (cons (evil-state-property state :local) (evil-state-property state :local-keymap t))) (minor-mode-maps (evil-state-minor-mode-keymaps state)) (aux-maps (evil-state-auxiliary-keymaps state)) (overriding-maps (evil-state-overriding-keymaps state)) (intercept-maps (evil-state-intercept-keymaps state)) (result `(,intercept-maps)) (remove-duplicates (null excluded))) (unless (memq state enable) (setq enable (cons state enable))) ;; process STATE's :enable property (dolist (entry enable) (cond ((memq entry excluded)) ;; the keymaps for STATE ((eq entry state) (setq result `(,@result (,local-map) ,minor-mode-maps ,aux-maps ,overriding-maps (,map))) (push state excluded)) ;; the keymaps for another state: call `evil-state-keymaps' ;; recursively, but keep track of processed states ((evil-state-p entry) (setq result `(,@result ,(apply #'evil-state-keymaps entry excluded)))) ;; a single keymap ((or (keymapp entry) (and (keymapp (symbol-value entry)) (setq entry (symbol-value entry))) (setq entry (evil-keymap-for-mode entry))) (setq result `(,@result ((,(evil-mode-for-keymap entry t) . ,entry))))))) ;; postpone the expensive filtering of duplicates to the top level (if remove-duplicates (apply #'evil-concat-keymap-alists result) (apply #'append result)))) (defun evil-normalize-keymaps (&optional state) "Create a buffer-local value for `evil-mode-map-alist'. This is a keymap alist, determined by the current state \(or by STATE if specified)." (let ((state (or state evil-state)) (excluded '(nil t)) map mode temp) ;; initialize buffer-local keymaps as necessary (evil-initialize-local-keymaps) ;; deactivate keymaps of previous state (dolist (entry evil-mode-map-alist) (setq mode (car-safe entry) map (cdr-safe entry)) ;; don't deactivate overriding keymaps; ;; they are toggled by their associated mode (if (or (memq mode excluded) (evil-intercept-keymap-p map) (evil-overriding-keymap-p map) (evil-auxiliary-keymap-p map) (evil-minor-mode-keymap-p map)) (push mode excluded) (when (and (fboundp mode) (symbol-value mode)) (funcall mode -1)) (set mode nil))) (setq evil-mode-map-alist nil) ;; activate keymaps of current state (when state (setq temp (evil-state-keymaps state)) (dolist (entry temp) (setq mode (car entry) map (cdr entry)) (unless (or (and (boundp mode) (symbol-value mode)) ;; the minor-mode keymaps include modes that are not ;; necessarily active (evil-minor-mode-keymap-p map)) (when (fboundp mode) (funcall mode 1)) (set mode t)) ;; refresh the keymap in case it has changed ;; (e.g., `evil-operator-shortcut-map' is ;; reset on toggling) (if (or (memq mode excluded) (evil-intercept-keymap-p map) (evil-overriding-keymap-p map) (evil-auxiliary-keymap-p map) (evil-minor-mode-keymap-p map)) (push mode excluded) (setcdr entry (or (evil-keymap-for-mode mode) map)))) ;; update `evil-mode-map-alist' (setq evil-mode-map-alist temp)))) (defun evil-mode-for-keymap (keymap &optional default) "Return the minor mode associated with KEYMAP. Returns DEFAULT if no mode is found. See also `evil-keymap-for-mode'." (let ((map (if (keymapp keymap) keymap (symbol-value keymap))) (var (when (symbolp keymap) keymap))) ;; Check Evil variables first for speed purposes. ;; If all else fails, check `minor-mode-map-alist'. (or (when var (or (car (rassq var evil-global-keymaps-alist)) (car (rassq var evil-local-keymaps-alist)))) (car (rassq map (mapcar #'(lambda (e) ;; from (MODE-VAR . MAP-VAR) ;; to (MODE-VAR . MAP) (cons (car-safe e) (symbol-value (cdr-safe e)))) (append evil-global-keymaps-alist evil-local-keymaps-alist)))) (car (rassq map minor-mode-map-alist)) default))) (defun evil-keymap-for-mode (mode &optional variable) "Return the keymap associated with MODE. Return the keymap variable if VARIABLE is non-nil. See also `evil-mode-for-keymap'." (let* ((var (or (cdr (assq mode evil-global-keymaps-alist)) (cdr (assq mode evil-local-keymaps-alist)))) (map (or (symbol-value var) (cdr (assq mode minor-mode-map-alist))))) (if variable var map))) (defun evil-state-auxiliary-keymaps (state) "Return a keymap alist of auxiliary keymaps for STATE." (let ((state (or state evil-state)) aux result) (dolist (map (current-active-maps) result) (when (setq aux (evil-get-auxiliary-keymap map state)) (push (cons (evil-mode-for-keymap map t) aux) result))) (nreverse result))) (defun evil-state-minor-mode-keymaps (state) "Return a keymap alist of minor-mode keymaps for STATE." (let* ((state (or state evil-state)) (state-entry (assq state evil-minor-mode-keymaps-alist))) (when state-entry (cdr state-entry)))) (defun evil-state-overriding-keymaps (&optional state) "Return a keymap alist of overriding keymaps for STATE." (let* ((state (or state evil-state)) result) (dolist (map (current-active-maps)) (when (setq map (evil-overriding-keymap-p map state)) (push (cons (evil-mode-for-keymap map t) map) result))) (nreverse result))) (defun evil-state-intercept-keymaps (&optional state) "Return a keymap alist of intercept keymaps for STATE." (let* ((state (or state evil-state)) result) (dolist (map (current-active-maps)) (when (setq map (or (evil-intercept-keymap-p map state) (evil-intercept-keymap-p (evil-get-auxiliary-keymap map state) state))) (push (cons (evil-mode-for-keymap map t) map) result))) (setq result (nreverse result)) result)) (defun evil-set-auxiliary-keymap (map state &optional aux) "Set the auxiliary keymap for MAP in STATE to AUX. If AUX is nil, create a new auxiliary keymap." (unless (keymapp aux) (setq aux (make-sparse-keymap))) (unless (evil-auxiliary-keymap-p aux) (evil-set-keymap-prompt aux (format "Auxiliary keymap for %s" (or (evil-state-property state :name) (format "%s state" state))))) (define-key map (vconcat (list (intern (format "%s-state" state)))) aux) aux) (put 'evil-set-auxiliary-keymap 'lisp-indent-function 'defun) (defun evil-get-auxiliary-keymap (map state &optional create ignore-parent) "Get the auxiliary keymap for MAP in STATE. If CREATE is non-nil, create an auxiliary keymap if MAP does not have one. If CREATE and IGNORE-PARENT are non-nil then a new auxiliary keymap is created even if the parent of MAP has one already." (when state (let* ((key (vconcat (list (intern (format "%s-state" state))))) (parent-aux (when (and ignore-parent (keymap-parent map) state) (lookup-key (keymap-parent map) key))) (aux (if state (lookup-key map key) map))) (cond ((and ignore-parent (equal parent-aux aux) create) (evil-set-auxiliary-keymap map state)) ((evil-auxiliary-keymap-p aux) aux) (create (evil-set-auxiliary-keymap map state)))))) (defun evil-get-minor-mode-keymap (state mode) "Get the auxiliary keymap for MODE in STATE, creating one if it does not already exist." (let ((state-entry (assq state evil-minor-mode-keymaps-alist))) (if (and state-entry (assq mode state-entry)) (cdr (assq mode state-entry)) (let ((map (make-sparse-keymap))) (evil-set-keymap-prompt map (format "Minor-mode keymap for %s in %s" (symbol-name mode) (or (evil-state-property state :name) (format "%s state" state)))) (if state-entry (setcdr state-entry (append (list (cons mode map)) (cdr state-entry))) (push (cons state (list (cons mode map))) evil-minor-mode-keymaps-alist)) map)))) (defun evil-auxiliary-keymap-p (map) "Whether MAP is an auxiliary keymap." (and (keymapp map) (string-match-p "Auxiliary keymap" (or (keymap-prompt map) "")) t)) (defun evil-minor-mode-keymap-p (map) "Whether MAP is a minor-mode keymap." (and (keymapp map) (string-match-p "Minor-mode keymap" (or (keymap-prompt map) "")) t)) (defun evil-intercept-keymap-p (map &optional state) "Whether MAP is an intercept keymap for STATE. If STATE is nil, it means any state." (let ((entry (and (keymapp map) (lookup-key map [intercept-state])))) (cond ((null entry) nil) ((null state) map) ((eq entry state) map) ((eq entry 'all) map)))) (defun evil-overriding-keymap-p (map &optional state) "Whether MAP is an overriding keymap for STATE. If STATE is nil, it means any state." (let ((entry (and (keymapp map) (lookup-key map [override-state])))) (cond ((null entry) nil) ((keymapp entry) (evil-overriding-keymap-p entry state)) ((null state) map) ((eq entry state) map) ((eq entry 'all) map)))) (defun evil-intercept-keymap-state (map) "Return the state for the intercept keymap MAP. A return value of t means all states." (let ((state (lookup-key map [intercept-state] map))) (cond ((keymapp state) (evil-intercept-keymap-state state)) ((eq state 'all) t) (t state)))) (defun evil-overriding-keymap-state (map) "Return the state for the overriding keymap MAP. A return value of t means all states." (let ((state (lookup-key map [override-state] map))) (cond ((keymapp state) (evil-overriding-keymap-state state)) ((eq state 'all) t) (t state)))) (defun evil-send-leader () "Put symbol leader in `unread-command-events' to trigger any bindings." (interactive) (setq prefix-arg current-prefix-arg) (push '(t . leader) unread-command-events)) (defun evil-send-localleader () "Put symbol localleader in `unread-command-events' to trigger any bindings." (interactive) (setq prefix-arg current-prefix-arg) (push '(t. localleader) unread-command-events)) (defun evil-set-leader (state key &optional localleader) "Set KEY to trigger bindings in STATE. KEY should be in the form produced by `kbd'. STATE is one of `normal', `insert', `visual', `replace', `operator', `motion', `emacs', a list of one or more of these, or nil. nil means all of the above. If LOCAL is non-nil, set localleader instead." (let* ((all-states '(normal insert visual replace operator motion emacs)) (states (cond ((listp state) state) ((member state all-states) (list state)) ((null state) all-states) ;; Maybe throw error here (t (list state)))) (binding (if localleader 'evil-send-localleader 'evil-send-leader))) (dolist (state states) (evil-global-set-key state key binding)))) (defmacro evil-define-key (state keymap key def &rest bindings) "Create a STATE binding from KEY to DEF for KEYMAP. STATE is one of normal, insert, visual, replace, operator, motion, emacs, or a list of one or more of these. Omitting a state by using nil corresponds to a standard Emacs binding using `define-key'. The remaining arguments are like those of `define-key'. For example: (evil-define-key 'normal foo-map \"a\" 'bar) This creates a binding from \"a\" to bar in Normal state, which is active whenever foo-map is active. Using nil for the state, the following lead to identical bindings: (evil-define-key nil foo-map \"a\" 'bar) (define-key foo-map \"a\" 'bar) It is possible to specify multiple states and/or bindings at once: (evil-define-key '(normal visual) foo-map \"a\" 'bar \"b\" 'foo) If foo-map has not been initialized yet, this macro adds an entry to `after-load-functions', delaying execution as necessary. KEYMAP may also be a quoted symbol. If the symbol is global, the global evil keymap corresponding to the state(s) is used, meaning the following lead to identical bindings: (evil-define-key 'normal 'global \"a\" 'bar) (evil-global-set-key 'normal \"a\" 'bar) The symbol local may also be used, which corresponds to using `evil-local-set-key'. If a quoted symbol is used that is not global or local, it is assumed to be the name of a minor mode, in which case `evil-define-minor-mode-key' is used." (declare (indent defun)) (cond ((member keymap '('global 'local)) `(evil-define-key* ,state ,keymap ,key ,def ,@bindings)) ((and (consp keymap) (eq (car keymap) 'quote)) `(evil-define-minor-mode-key ,state ,keymap ,key ,def ,@bindings)) (t `(evil-delay ',(if (symbolp keymap) `(and (boundp ',keymap) (keymapp ,keymap)) `(keymapp ,keymap)) '(condition-case-unless-debug err (evil-define-key* ,state ,keymap ,key ,def ,@bindings) (error (message "error in evil-define-key: %s" (error-message-string err)))) 'after-load-functions t nil (format "evil-define-key-in-%s" ',(if (symbolp keymap) keymap 'keymap)))))) (defalias 'evil-declare-key 'evil-define-key) (defun evil-define-key* (state keymap key def &rest bindings) "Create a STATE binding from KEY to DEF for KEYMAP. STATE is one of normal, insert, visual, replace, operator, motion, emacs, or a list of one or more of these. Omitting a state by using nil corresponds to a standard Emacs binding using `define-key' The remaining arguments are like those of `define-key'. For example: (evil-define-key* 'normal foo-map \"a\" 'bar) This creates a binding from \"a\" to bar in Normal state, which is active whenever foo-map is active. Using nil for the state, the following are equivalent: (evil-define-key* nil foo-map \"a\" 'bar) (define-key foo-map \"a\" 'bar) It is possible to specify multiple states and/or bindings at once: (evil-define-key* '(normal visual) foo-map \"a\" 'bar \"b\" 'foo) KEYMAP may also be a quoted symbol. If the symbol is global, the global evil keymap corresponding to the state(s) is used, meaning the following are equivalent: (evil-define-key* 'normal 'global \"a\" 'bar) (evil-global-set-key 'normal \"a\" 'bar) The symbol local may also be used, which corresponds to using `evil-local-set-key'. The use is nearly identical to `evil-define-key' with the exception that this is a function and not a macro (and so will not be expanded when compiled which can have unintended consequences). `evil-define-key*' also does not defer any bindings like `evil-define-key' does using `evil-delay'. This allows errors in the bindings to be caught immediately, and makes its behavior more predictable." (let ((maps (if state (mapcar (lambda (st) (cond ((eq keymap 'global) (evil-state-property st :keymap t)) ((eq keymap 'local) (evil-state-property st :local-keymap t)) (t (evil-get-auxiliary-keymap keymap st t t)))) (if (listp state) state (list state))) (list (cond ((eq keymap 'global) global-map) ((eq keymap 'local) ;; see `local-set-key' (or (current-local-map) (let ((map (make-sparse-keymap))) (use-local-map map) map))) (t keymap)))))) (while key (dolist (map maps) (define-key map key def)) (setq key (pop bindings) def (pop bindings))) ;; ensure the prompt string comes first (dolist (map maps) (evil-set-keymap-prompt map (keymap-prompt map))))) (defun evil-define-minor-mode-key (state mode key def &rest bindings) "Similar to `evil-define-key' but the bindings are associated with the minor-mode symbol MODE instead of a particular map. Associating bindings with a mode symbol instead of a map allows evil to use Emacs' built-in mechanisms to enable the bindings automatically when MODE is active without relying on calling `evil-normalize-keymaps'. Another less significant difference is that the bindings can be created immediately, because this function only uses the symbol MODE and does not rely on its value. See `evil-define-key' for the usage of STATE, KEY, DEF and BINDINGS." (declare (indent defun)) (let ((maps (mapcar (lambda (st) (evil-get-minor-mode-keymap st mode)) (if (listp state) state (list state))))) (while key (dolist (map maps) (define-key map key def)) (setq key (pop bindings) def (pop bindings))))) (defmacro evil-add-hjkl-bindings (keymap &optional state &rest bindings) "Add \"h\", \"j\", \"k\", \"l\" bindings to KEYMAP in STATE. Add additional BINDINGS if specified." (declare (indent defun)) `(evil-define-key ,state ,keymap "h" (lookup-key evil-motion-state-map "h") "j" (lookup-key evil-motion-state-map "j") "k" (lookup-key evil-motion-state-map "k") "l" (lookup-key evil-motion-state-map "l") ":" (lookup-key evil-motion-state-map ":") ,@bindings)) ;; may be useful for programmatic purposes (defun evil-global-set-key (state key def) "Bind KEY to DEF in STATE." (define-key (evil-state-property state :keymap t) key def)) (defun evil-local-set-key (state key def) "Bind KEY to DEF in STATE in the current buffer." (define-key (evil-state-property state :local-keymap t) key def)) ;; Advise these functions as they may activate an overriding keymap or ;; a keymap with state bindings; if so, refresh `evil-mode-map-alist'. (defadvice use-global-map (after evil activate) "Refresh Evil keymaps." (evil-normalize-keymaps)) (defadvice use-local-map (after evil activate) "Refresh Evil keymaps." (evil-normalize-keymaps)) (defmacro evil-define-state (state doc &rest body) "Define an Evil state STATE. DOC is a general description and shows up in all docstrings; the first line of the string should be the full name of the state. Then follows one or more optional keywords: :tag STRING Mode line indicator. :message STRING Echo area message when changing to STATE. :cursor SPEC Cursor to use in STATE. :entry-hook LIST Hooks run when changing to STATE. :exit-hook LIST Hooks run when changing from STATE. :enable LIST List of other states and modes enabled by STATE. :suppress-keymap FLAG If FLAG is non-nil, makes `evil-suppress-map' the parent of the global map of STATE, effectively disabling bindings to `self-insert-command'. Following the keywords is optional code to be executed each time the state is enabled or disabled. For example: (evil-define-state test \"Test state.\" :tag \" \" (setq test-var t)) The global keymap of this state will be `evil-test-state-map', the local keymap will be `evil-test-state-local-map', and so on. \(fn STATE DOC [[KEY VAL]...] BODY...)" (declare (indent defun) (doc-string 2) (debug (&define name [&optional stringp] [&rest [keywordp sexp]] def-body))) (let* ((name (and (string-match "^\\(.+\\)\\(\\(?:.\\|\n\\)*\\)" doc) (match-string 1 doc))) (doc (match-string 2 doc)) (name (and (string-match "^\\(.+?\\)\\.?$" name) (match-string 1 name))) (doc (if (or (null doc) (string= doc "")) "" (format "\n%s" doc))) (toggle (intern (format "evil-%s-state" state))) (mode (intern (format "%s-minor-mode" toggle))) (keymap (intern (format "%s-map" toggle))) (local (intern (format "%s-local-minor-mode" toggle))) (local-keymap (intern (format "%s-local-map" toggle))) (tag (intern (format "%s-tag" toggle))) (message (intern (format "%s-message" toggle))) (cursor (intern (format "%s-cursor" toggle))) (entry-hook (intern (format "%s-entry-hook" toggle))) (exit-hook (intern (format "%s-exit-hook" toggle))) (modes (intern (format "%s-modes" toggle))) (predicate (intern (format "%s-p" toggle))) arg cursor-value enable entry-hook-value exit-hook-value input-method key message-value suppress-keymap tag-value) ;; collect keywords (while (keywordp (car-safe body)) (setq key (pop body) arg (pop body)) (cond ((eq key :tag) (setq tag-value arg)) ((eq key :message) (setq message-value arg)) ((eq key :cursor) (setq cursor-value arg)) ((eq key :entry-hook) (setq entry-hook-value arg) (unless (listp entry-hook-value) (setq entry-hook-value (list entry-hook-value)))) ((eq key :exit-hook) (setq exit-hook-value arg) (unless (listp exit-hook-value) (setq exit-hook-value (list entry-hook-value)))) ((eq key :enable) (setq enable arg)) ((eq key :input-method) (setq input-method arg)) ((eq key :suppress-keymap) (setq suppress-keymap arg)))) ;; macro expansion `(progn ;; Save the state's properties in `evil-state-properties' for ;; runtime lookup. Among other things, this information is used ;; to determine what keymaps should be activated by the state ;; (and, when processing :enable, what keymaps are activated by ;; other states). We cannot know this at compile time because ;; it depends on the current buffer and its active keymaps ;; (to which we may have assigned state bindings), as well as ;; states whose definitions may not have been processed yet. (evil-put-property 'evil-state-properties ',state :name ',name :toggle ',toggle :mode (defvar ,mode nil ,(format "Non-nil if %s is enabled. Use the command `%s' to change this variable." name toggle)) :keymap (defvar ,keymap (make-sparse-keymap) ,(format "Keymap for %s." name)) :local (defvar ,local nil ,(format "Non-nil if %s is enabled. Use the command `%s' to change this variable." name toggle)) :local-keymap (defvar ,local-keymap nil ,(format "Buffer-local keymap for %s." name)) :tag (defvar ,tag ,tag-value ,(format "Mode line tag for %s." name)) :message (defvar ,message ,message-value ,(format "Echo area message for %s." name)) :cursor (defvar ,cursor ',cursor-value ,(format "Cursor for %s. May be a cursor type as per `cursor-type', a color string as passed to `set-cursor-color', a zero-argument function for changing the cursor, or a list of the above." name)) :entry-hook (defvar ,entry-hook nil ,(format "Hooks to run when entering %s." name)) :exit-hook (defvar ,exit-hook nil ,(format "Hooks to run when exiting %s." name)) :modes (defvar ,modes nil ,(format "Modes that should come up in %s." name)) :input-method ',input-method :predicate ',predicate :enable ',enable) ,@(when suppress-keymap `((set-keymap-parent ,keymap evil-suppress-map))) (dolist (func ',entry-hook-value) (add-hook ',entry-hook func)) (dolist (func ',exit-hook-value) (add-hook ',exit-hook func)) (defun ,predicate (&optional state) ,(format "Whether the current state is %s. \(That is, whether `evil-state' is `%s'.)" name state) (and evil-local-mode (eq (or state evil-state) ',state))) ;; define state function (defun ,toggle (&optional arg) ,(format "Enable %s. Disable with negative ARG. If ARG is nil, don't display a message in the echo area.%s" name doc) (interactive) (cond ((and (numberp arg) (< arg 1)) (setq evil-previous-state evil-state evil-state nil) (let ((evil-state ',state)) (run-hooks ',exit-hook) (setq evil-state nil) (evil-normalize-keymaps) ,@body)) (t (unless evil-local-mode (evil-local-mode 1)) (let ((evil-next-state ',state) input-method-activate-hook input-method-deactivate-hook) (evil-change-state nil) (setq evil-state ',state) (evil-add-to-alist 'evil-previous-state-alist ',state evil-previous-state) (let ((evil-state ',state)) (evil-normalize-keymaps) (if ',input-method (activate-input-method evil-input-method) ;; BUG #475: Deactivate the current input method only ;; if there is a function to deactivate it, otherwise ;; an error would be raised. This strange situation ;; should not arise in general and there should ;; probably be a better way to handle this situation. (if deactivate-current-input-method-function (deactivate-input-method))) (unless evil-no-display (evil-refresh-cursor ',state) (evil-refresh-mode-line ',state) (when (called-interactively-p 'any) (redisplay))) ,@body (run-hooks ',entry-hook) (when (and evil-echo-state arg (not evil-no-display) ,message) (if (functionp ,message) (funcall ,message) (evil-echo "%s" ,message)))))))) (evil-set-command-property ',toggle :keep-visual t) (evil-set-command-property ',toggle :suppress-operator t) (evil-define-keymap ,keymap nil :mode ,mode :func nil) (evil-define-keymap ,local-keymap nil :mode ,local :local t :func nil) ',state))) (provide 'evil-core) ;;; evil-core.el ends here evil-1.12.17/evil-development.el000066400000000000000000000031001360703323200164140ustar00rootroot00000000000000;;; evil-development.el --- Useful features for Evil developers ;; Author: Justin Burkett ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . ;;; Code: ;;; Teach imenu about evil macros (with-eval-after-load 'lisp-mode (when (boundp 'lisp-imenu-generic-expression) (dolist (macro '("interactive-code" "type" "text-object" "motion" "command" "operator")) (let ((macro-name (format "evil-%s" macro))) (unless (assoc macro-name lisp-imenu-generic-expression) (push (list macro-name (format "^\\s-*(evil-define-%s\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" macro) 1) lisp-imenu-generic-expression)))))) (provide 'evil-development) ;;; evil-development.el ends here evil-1.12.17/evil-digraphs.el000066400000000000000000001221121360703323200157000ustar00rootroot00000000000000;;; evil-digraphs.el --- Digraphs ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . (require 'evil-vars) ;;; Code: (defgroup evil-digraphs nil "Digraph support based on RFC 1345." :group 'evil :prefix "evil-digraph-") (defcustom evil-digraphs-table-user nil "List of user-defined digraphs. Entries have the form ((?CHAR1 ?CHAR2) . ?DIGRAPH). That is, a cons cell of the digraph and its character replacement, where the digraph is a list of two characters. See also `evil-digraphs-table'." :type '(alist :key-type (list character character) :value-type character) :require 'evil-digraphs :group 'evil-digraphs) (defconst evil-digraphs-table '(((?N ?U) . ?\x00) ((?S ?H) . ?\x01) ((?S ?X) . ?\x02) ((?E ?X) . ?\x03) ((?E ?T) . ?\x04) ((?E ?Q) . ?\x05) ((?A ?K) . ?\x06) ((?B ?L) . ?\x07) ((?B ?S) . ?\x08) ((?H ?T) . ?\x09) ((?L ?F) . ?\x0a) ((?V ?T) . ?\x0b) ((?F ?F) . ?\x0c) ((?C ?R) . ?\x0d) ((?S ?O) . ?\x0e) ((?S ?I) . ?\x0f) ((?D ?L) . ?\x10) ((?D ?1) . ?\x11) ((?D ?2) . ?\x12) ((?D ?3) . ?\x13) ((?D ?4) . ?\x14) ((?N ?K) . ?\x15) ((?S ?Y) . ?\x16) ((?E ?B) . ?\x17) ((?C ?N) . ?\x18) ((?E ?M) . ?\x19) ((?S ?B) . ?\x1a) ((?E ?C) . ?\x1b) ((?F ?S) . ?\x1c) ((?G ?S) . ?\x1d) ((?R ?S) . ?\x1e) ((?U ?S) . ?\x1f) ((?S ?P) . ?\x20) ((?N ?b) . ?\x23) ((?D ?O) . ?\x24) ((?A ?t) . ?\x40) ((?< ?\() . ?\x5b) ((?/ ?/) . ?\x5c) ((?\) ?>) . ?\x5d) ((?' ?>) . ?\x5e) ((?' ?!) . ?\x60) ((?\( ?!) . ?\x7b) ((?! ?!) . ?\x7c) ((?! ?\)) . ?\x7d) ((?' ??) . ?\x7e) ((?D ?T) . ?\x7f) ((?P ?A) . ?\x80) ((?H ?O) . ?\x81) ((?B ?H) . ?\x82) ((?N ?H) . ?\x83) ((?I ?N) . ?\x84) ((?N ?L) . ?\x85) ((?S ?A) . ?\x86) ((?E ?S) . ?\x87) ((?H ?S) . ?\x88) ((?H ?J) . ?\x89) ((?V ?S) . ?\x8a) ((?P ?D) . ?\x8b) ((?P ?U) . ?\x8c) ((?R ?I) . ?\x8d) ((?S ?2) . ?\x8e) ((?S ?3) . ?\x8f) ((?D ?C) . ?\x90) ((?P ?1) . ?\x91) ((?P ?2) . ?\x92) ((?T ?S) . ?\x93) ((?C ?C) . ?\x94) ((?M ?W) . ?\x95) ((?S ?G) . ?\x96) ((?E ?G) . ?\x97) ((?S ?S) . ?\x98) ((?G ?C) . ?\x99) ((?S ?C) . ?\x9a) ((?C ?I) . ?\x9b) ((?S ?T) . ?\x9c) ((?O ?C) . ?\x9d) ((?P ?M) . ?\x9e) ((?A ?C) . ?\x9f) ((?N ?S) . ?\xa0) ((?! ?I) . ?\xa1) ((?C ?t) . ?\xa2) ((?P ?d) . ?\xa3) ((?C ?u) . ?\xa4) ((?Y ?e) . ?\xa5) ((?B ?B) . ?\xa6) ((?S ?E) . ?\xa7) ((?' ?:) . ?\xa8) ((?C ?o) . ?\xa9) ((?- ?a) . ?\xaa) ((?< ?<) . ?\xab) ((?N ?O) . ?\xac) ((?- ?-) . ?\xad) ((?R ?g) . ?\xae) ((?' ?m) . ?\xaf) ((?D ?G) . ?\xb0) ((?+ ?-) . ?\xb1) ((?2 ?S) . ?\xb2) ((?3 ?S) . ?\xb3) ((?' ?') . ?\xb4) ((?M ?y) . ?\xb5) ((?P ?I) . ?\xb6) ((?. ?M) . ?\xb7) ((?' ?,) . ?\xb8) ((?1 ?S) . ?\xb9) ((?- ?o) . ?\xba) ((?> ?>) . ?\xbb) ((?1 ?4) . ?\xbc) ((?1 ?2) . ?\xbd) ((?3 ?4) . ?\xbe) ((?? ?I) . ?\xbf) ((?A ?!) . ?\xc0) ((?A ?') . ?\xc1) ((?A ?>) . ?\xc2) ((?A ??) . ?\xc3) ((?A ?:) . ?\xc4) ((?A ?A) . ?\xc5) ((?A ?E) . ?\xc6) ((?C ?,) . ?\xc7) ((?E ?!) . ?\xc8) ((?E ?') . ?\xc9) ((?E ?>) . ?\xca) ((?E ?:) . ?\xcb) ((?I ?!) . ?\xcc) ((?I ?') . ?\xcd) ((?I ?>) . ?\xce) ((?I ?:) . ?\xcf) ((?D ?-) . ?\xd0) ((?N ??) . ?\xd1) ((?O ?!) . ?\xd2) ((?O ?') . ?\xd3) ((?O ?>) . ?\xd4) ((?O ??) . ?\xd5) ((?O ?:) . ?\xd6) ((?* ?X) . ?\xd7) ((?O ?/) . ?\xd8) ((?U ?!) . ?\xd9) ((?U ?') . ?\xda) ((?U ?>) . ?\xdb) ((?U ?:) . ?\xdc) ((?Y ?') . ?\xdd) ((?T ?H) . ?\xde) ((?s ?s) . ?\xdf) ((?a ?!) . ?\xe0) ((?a ?') . ?\xe1) ((?a ?>) . ?\xe2) ((?a ??) . ?\xe3) ((?a ?:) . ?\xe4) ((?a ?a) . ?\xe5) ((?a ?e) . ?\xe6) ((?c ?,) . ?\xe7) ((?e ?!) . ?\xe8) ((?e ?') . ?\xe9) ((?e ?>) . ?\xea) ((?e ?:) . ?\xeb) ((?i ?!) . ?\xec) ((?i ?') . ?\xed) ((?i ?>) . ?\xee) ((?i ?:) . ?\xef) ((?d ?-) . ?\xf0) ((?n ??) . ?\xf1) ((?o ?!) . ?\xf2) ((?o ?') . ?\xf3) ((?o ?>) . ?\xf4) ((?o ??) . ?\xf5) ((?o ?:) . ?\xf6) ((?- ?:) . ?\xf7) ((?o ?/) . ?\xf8) ((?u ?!) . ?\xf9) ((?u ?') . ?\xfa) ((?u ?>) . ?\xfb) ((?u ?:) . ?\xfc) ((?y ?') . ?\xfd) ((?t ?h) . ?\xfe) ((?y ?:) . ?\xff) ((?A ?-) . ?\x0100) ((?a ?-) . ?\x0101) ((?A ?\() . ?\x0102) ((?a ?\() . ?\x0103) ((?A ?\;) . ?\x0104) ((?a ?\;) . ?\x0105) ((?C ?') . ?\x0106) ((?c ?') . ?\x0107) ((?C ?>) . ?\x0108) ((?c ?>) . ?\x0109) ((?C ?.) . ?\x010a) ((?c ?.) . ?\x010b) ((?C ?<) . ?\x010c) ((?c ?<) . ?\x010d) ((?D ?<) . ?\x010e) ((?d ?<) . ?\x010f) ((?D ?/) . ?\x0110) ((?d ?/) . ?\x0111) ((?E ?-) . ?\x0112) ((?e ?-) . ?\x0113) ((?E ?\() . ?\x0114) ((?e ?\() . ?\x0115) ((?E ?.) . ?\x0116) ((?e ?.) . ?\x0117) ((?E ?\;) . ?\x0118) ((?e ?\;) . ?\x0119) ((?E ?<) . ?\x011a) ((?e ?<) . ?\x011b) ((?G ?>) . ?\x011c) ((?g ?>) . ?\x011d) ((?G ?\() . ?\x011e) ((?g ?\() . ?\x011f) ((?G ?.) . ?\x0120) ((?g ?.) . ?\x0121) ((?G ?,) . ?\x0122) ((?g ?,) . ?\x0123) ((?H ?>) . ?\x0124) ((?h ?>) . ?\x0125) ((?H ?/) . ?\x0126) ((?h ?/) . ?\x0127) ((?I ??) . ?\x0128) ((?i ??) . ?\x0129) ((?I ?-) . ?\x012a) ((?i ?-) . ?\x012b) ((?I ?\() . ?\x012c) ((?i ?\() . ?\x012d) ((?I ?\;) . ?\x012e) ((?i ?\;) . ?\x012f) ((?I ?.) . ?\x0130) ((?i ?.) . ?\x0131) ((?I ?J) . ?\x0132) ((?i ?j) . ?\x0133) ((?J ?>) . ?\x0134) ((?j ?>) . ?\x0135) ((?K ?,) . ?\x0136) ((?k ?,) . ?\x0137) ((?k ?k) . ?\x0138) ((?L ?') . ?\x0139) ((?l ?') . ?\x013a) ((?L ?,) . ?\x013b) ((?l ?,) . ?\x013c) ((?L ?<) . ?\x013d) ((?l ?<) . ?\x013e) ((?L ?.) . ?\x013f) ((?l ?.) . ?\x0140) ((?L ?/) . ?\x0141) ((?l ?/) . ?\x0142) ((?N ?') . ?\x0143) ((?n ?') . ?\x0144) ((?N ?,) . ?\x0145) ((?n ?,) . ?\x0146) ((?N ?<) . ?\x0147) ((?n ?<) . ?\x0148) ((?' ?n) . ?\x0149) ((?N ?G) . ?\x014a) ((?n ?g) . ?\x014b) ((?O ?-) . ?\x014c) ((?o ?-) . ?\x014d) ((?O ?\() . ?\x014e) ((?o ?\() . ?\x014f) ((?O ?\") . ?\x0150) ((?o ?\") . ?\x0151) ((?O ?E) . ?\x0152) ((?o ?e) . ?\x0153) ((?R ?') . ?\x0154) ((?r ?') . ?\x0155) ((?R ?,) . ?\x0156) ((?r ?,) . ?\x0157) ((?R ?<) . ?\x0158) ((?r ?<) . ?\x0159) ((?S ?') . ?\x015a) ((?s ?') . ?\x015b) ((?S ?>) . ?\x015c) ((?s ?>) . ?\x015d) ((?S ?,) . ?\x015e) ((?s ?,) . ?\x015f) ((?S ?<) . ?\x0160) ((?s ?<) . ?\x0161) ((?T ?,) . ?\x0162) ((?t ?,) . ?\x0163) ((?T ?<) . ?\x0164) ((?t ?<) . ?\x0165) ((?T ?/) . ?\x0166) ((?t ?/) . ?\x0167) ((?U ??) . ?\x0168) ((?u ??) . ?\x0169) ((?U ?-) . ?\x016a) ((?u ?-) . ?\x016b) ((?U ?\() . ?\x016c) ((?u ?\() . ?\x016d) ((?U ?0) . ?\x016e) ((?u ?0) . ?\x016f) ((?U ?\") . ?\x0170) ((?u ?\") . ?\x0171) ((?U ?\;) . ?\x0172) ((?u ?\;) . ?\x0173) ((?W ?>) . ?\x0174) ((?w ?>) . ?\x0175) ((?Y ?>) . ?\x0176) ((?y ?>) . ?\x0177) ((?Y ?:) . ?\x0178) ((?Z ?') . ?\x0179) ((?z ?') . ?\x017a) ((?Z ?.) . ?\x017b) ((?z ?.) . ?\x017c) ((?Z ?<) . ?\x017d) ((?z ?<) . ?\x017e) ((?O ?9) . ?\x01a0) ((?o ?9) . ?\x01a1) ((?O ?I) . ?\x01a2) ((?o ?i) . ?\x01a3) ((?y ?r) . ?\x01a6) ((?U ?9) . ?\x01af) ((?u ?9) . ?\x01b0) ((?Z ?/) . ?\x01b5) ((?z ?/) . ?\x01b6) ((?E ?D) . ?\x01b7) ((?A ?<) . ?\x01cd) ((?a ?<) . ?\x01ce) ((?I ?<) . ?\x01cf) ((?i ?<) . ?\x01d0) ((?O ?<) . ?\x01d1) ((?o ?<) . ?\x01d2) ((?U ?<) . ?\x01d3) ((?u ?<) . ?\x01d4) ((?A ?1) . ?\x01de) ((?a ?1) . ?\x01df) ((?A ?7) . ?\x01e0) ((?a ?7) . ?\x01e1) ((?A ?3) . ?\x01e2) ((?a ?3) . ?\x01e3) ((?G ?/) . ?\x01e4) ((?g ?/) . ?\x01e5) ((?G ?<) . ?\x01e6) ((?g ?<) . ?\x01e7) ((?K ?<) . ?\x01e8) ((?k ?<) . ?\x01e9) ((?O ?\;) . ?\x01ea) ((?o ?\;) . ?\x01eb) ((?O ?1) . ?\x01ec) ((?o ?1) . ?\x01ed) ((?E ?Z) . ?\x01ee) ((?e ?z) . ?\x01ef) ((?j ?<) . ?\x01f0) ((?G ?') . ?\x01f4) ((?g ?') . ?\x01f5) ((?\; ?S) . ?\x02bf) ((?' ?<) . ?\x02c7) ((?' ?\() . ?\x02d8) ((?' ?.) . ?\x02d9) ((?' ?0) . ?\x02da) ((?' ?\;) . ?\x02db) ((?' ?\") . ?\x02dd) ((?A ?%) . ?\x0386) ((?E ?%) . ?\x0388) ((?Y ?%) . ?\x0389) ((?I ?%) . ?\x038a) ((?O ?%) . ?\x038c) ((?U ?%) . ?\x038e) ((?W ?%) . ?\x038f) ((?i ?3) . ?\x0390) ((?A ?*) . ?\x0391) ((?B ?*) . ?\x0392) ((?G ?*) . ?\x0393) ((?D ?*) . ?\x0394) ((?E ?*) . ?\x0395) ((?Z ?*) . ?\x0396) ((?Y ?*) . ?\x0397) ((?H ?*) . ?\x0398) ((?I ?*) . ?\x0399) ((?K ?*) . ?\x039a) ((?L ?*) . ?\x039b) ((?M ?*) . ?\x039c) ((?N ?*) . ?\x039d) ((?C ?*) . ?\x039e) ((?O ?*) . ?\x039f) ((?P ?*) . ?\x03a0) ((?R ?*) . ?\x03a1) ((?S ?*) . ?\x03a3) ((?T ?*) . ?\x03a4) ((?U ?*) . ?\x03a5) ((?F ?*) . ?\x03a6) ((?X ?*) . ?\x03a7) ((?Q ?*) . ?\x03a8) ((?W ?*) . ?\x03a9) ((?J ?*) . ?\x03aa) ((?V ?*) . ?\x03ab) ((?a ?%) . ?\x03ac) ((?e ?%) . ?\x03ad) ((?y ?%) . ?\x03ae) ((?i ?%) . ?\x03af) ((?u ?3) . ?\x03b0) ((?a ?*) . ?\x03b1) ((?b ?*) . ?\x03b2) ((?g ?*) . ?\x03b3) ((?d ?*) . ?\x03b4) ((?e ?*) . ?\x03b5) ((?z ?*) . ?\x03b6) ((?y ?*) . ?\x03b7) ((?h ?*) . ?\x03b8) ((?i ?*) . ?\x03b9) ((?k ?*) . ?\x03ba) ((?l ?*) . ?\x03bb) ((?m ?*) . ?\x03bc) ((?n ?*) . ?\x03bd) ((?c ?*) . ?\x03be) ((?o ?*) . ?\x03bf) ((?p ?*) . ?\x03c0) ((?r ?*) . ?\x03c1) ((?* ?s) . ?\x03c2) ((?s ?*) . ?\x03c3) ((?t ?*) . ?\x03c4) ((?u ?*) . ?\x03c5) ((?f ?*) . ?\x03c6) ((?x ?*) . ?\x03c7) ((?q ?*) . ?\x03c8) ((?w ?*) . ?\x03c9) ((?j ?*) . ?\x03ca) ((?v ?*) . ?\x03cb) ((?o ?%) . ?\x03cc) ((?u ?%) . ?\x03cd) ((?w ?%) . ?\x03ce) ((?' ?G) . ?\x03d8) ((?, ?G) . ?\x03d9) ((?T ?3) . ?\x03da) ((?t ?3) . ?\x03db) ((?M ?3) . ?\x03dc) ((?m ?3) . ?\x03dd) ((?K ?3) . ?\x03de) ((?k ?3) . ?\x03df) ((?P ?3) . ?\x03e0) ((?p ?3) . ?\x03e1) ((?' ?%) . ?\x03f4) ((?j ?3) . ?\x03f5) ((?I ?O) . ?\x0401) ((?D ?%) . ?\x0402) ((?G ?%) . ?\x0403) ((?I ?E) . ?\x0404) ((?D ?S) . ?\x0405) ((?I ?I) . ?\x0406) ((?Y ?I) . ?\x0407) ((?J ?%) . ?\x0408) ((?L ?J) . ?\x0409) ((?N ?J) . ?\x040a) ((?T ?s) . ?\x040b) ((?K ?J) . ?\x040c) ((?V ?%) . ?\x040e) ((?D ?Z) . ?\x040f) ((?A ?=) . ?\x0410) ((?B ?=) . ?\x0411) ((?V ?=) . ?\x0412) ((?G ?=) . ?\x0413) ((?D ?=) . ?\x0414) ((?E ?=) . ?\x0415) ((?Z ?%) . ?\x0416) ((?Z ?=) . ?\x0417) ((?I ?=) . ?\x0418) ((?J ?=) . ?\x0419) ((?K ?=) . ?\x041a) ((?L ?=) . ?\x041b) ((?M ?=) . ?\x041c) ((?N ?=) . ?\x041d) ((?O ?=) . ?\x041e) ((?P ?=) . ?\x041f) ((?R ?=) . ?\x0420) ((?S ?=) . ?\x0421) ((?T ?=) . ?\x0422) ((?U ?=) . ?\x0423) ((?F ?=) . ?\x0424) ((?H ?=) . ?\x0425) ((?C ?=) . ?\x0426) ((?C ?%) . ?\x0427) ((?S ?%) . ?\x0428) ((?S ?c) . ?\x0429) ((?= ?\") . ?\x042a) ((?Y ?=) . ?\x042b) ((?% ?\") . ?\x042c) ((?J ?E) . ?\x042d) ((?J ?U) . ?\x042e) ((?J ?A) . ?\x042f) ((?a ?=) . ?\x0430) ((?b ?=) . ?\x0431) ((?v ?=) . ?\x0432) ((?g ?=) . ?\x0433) ((?d ?=) . ?\x0434) ((?e ?=) . ?\x0435) ((?z ?%) . ?\x0436) ((?z ?=) . ?\x0437) ((?i ?=) . ?\x0438) ((?j ?=) . ?\x0439) ((?k ?=) . ?\x043a) ((?l ?=) . ?\x043b) ((?m ?=) . ?\x043c) ((?n ?=) . ?\x043d) ((?o ?=) . ?\x043e) ((?p ?=) . ?\x043f) ((?r ?=) . ?\x0440) ((?s ?=) . ?\x0441) ((?t ?=) . ?\x0442) ((?u ?=) . ?\x0443) ((?f ?=) . ?\x0444) ((?h ?=) . ?\x0445) ((?c ?=) . ?\x0446) ((?c ?%) . ?\x0447) ((?s ?%) . ?\x0448) ((?s ?c) . ?\x0449) ((?= ?') . ?\x044a) ((?y ?=) . ?\x044b) ((?% ?') . ?\x044c) ((?j ?e) . ?\x044d) ((?j ?u) . ?\x044e) ((?j ?a) . ?\x044f) ((?i ?o) . ?\x0451) ((?d ?%) . ?\x0452) ((?g ?%) . ?\x0453) ((?i ?e) . ?\x0454) ((?d ?s) . ?\x0455) ((?i ?i) . ?\x0456) ((?y ?i) . ?\x0457) ((?j ?%) . ?\x0458) ((?l ?j) . ?\x0459) ((?n ?j) . ?\x045a) ((?t ?s) . ?\x045b) ((?k ?j) . ?\x045c) ((?v ?%) . ?\x045e) ((?d ?z) . ?\x045f) ((?Y ?3) . ?\x0462) ((?y ?3) . ?\x0463) ((?O ?3) . ?\x046a) ((?o ?3) . ?\x046b) ((?F ?3) . ?\x0472) ((?f ?3) . ?\x0473) ((?V ?3) . ?\x0474) ((?v ?3) . ?\x0475) ((?C ?3) . ?\x0480) ((?c ?3) . ?\x0481) ((?G ?3) . ?\x0490) ((?g ?3) . ?\x0491) ((?A ?+) . ?\x05d0) ((?B ?+) . ?\x05d1) ((?G ?+) . ?\x05d2) ((?D ?+) . ?\x05d3) ((?H ?+) . ?\x05d4) ((?W ?+) . ?\x05d5) ((?Z ?+) . ?\x05d6) ((?X ?+) . ?\x05d7) ((?T ?j) . ?\x05d8) ((?J ?+) . ?\x05d9) ((?K ?%) . ?\x05da) ((?K ?+) . ?\x05db) ((?L ?+) . ?\x05dc) ((?M ?%) . ?\x05dd) ((?M ?+) . ?\x05de) ((?N ?%) . ?\x05df) ((?N ?+) . ?\x05e0) ((?S ?+) . ?\x05e1) ((?E ?+) . ?\x05e2) ((?P ?%) . ?\x05e3) ((?P ?+) . ?\x05e4) ((?Z ?j) . ?\x05e5) ((?Z ?J) . ?\x05e6) ((?Q ?+) . ?\x05e7) ((?R ?+) . ?\x05e8) ((?S ?h) . ?\x05e9) ((?T ?+) . ?\x05ea) ((?, ?+) . ?\x060c) ((?\; ?+) . ?\x061b) ((?? ?+) . ?\x061f) ((?H ?') . ?\x0621) ((?a ?M) . ?\x0622) ((?a ?H) . ?\x0623) ((?w ?H) . ?\x0624) ((?a ?h) . ?\x0625) ((?y ?H) . ?\x0626) ((?a ?+) . ?\x0627) ((?b ?+) . ?\x0628) ((?t ?m) . ?\x0629) ((?t ?+) . ?\x062a) ((?t ?k) . ?\x062b) ((?g ?+) . ?\x062c) ((?h ?k) . ?\x062d) ((?x ?+) . ?\x062e) ((?d ?+) . ?\x062f) ((?d ?k) . ?\x0630) ((?r ?+) . ?\x0631) ((?z ?+) . ?\x0632) ((?s ?+) . ?\x0633) ((?s ?n) . ?\x0634) ((?c ?+) . ?\x0635) ((?d ?d) . ?\x0636) ((?t ?j) . ?\x0637) ((?z ?H) . ?\x0638) ((?e ?+) . ?\x0639) ((?i ?+) . ?\x063a) ((?+ ?+) . ?\x0640) ((?f ?+) . ?\x0641) ((?q ?+) . ?\x0642) ((?k ?+) . ?\x0643) ((?l ?+) . ?\x0644) ((?m ?+) . ?\x0645) ((?n ?+) . ?\x0646) ((?h ?+) . ?\x0647) ((?w ?+) . ?\x0648) ((?j ?+) . ?\x0649) ((?y ?+) . ?\x064a) ((?: ?+) . ?\x064b) ((?\" ?+) . ?\x064c) ((?= ?+) . ?\x064d) ((?/ ?+) . ?\x064e) ((?' ?+) . ?\x064f) ((?1 ?+) . ?\x0650) ((?3 ?+) . ?\x0651) ((?0 ?+) . ?\x0652) ((?a ?S) . ?\x0670) ((?p ?+) . ?\x067e) ((?v ?+) . ?\x06a4) ((?g ?f) . ?\x06af) ((?0 ?a) . ?\x06f0) ((?1 ?a) . ?\x06f1) ((?2 ?a) . ?\x06f2) ((?3 ?a) . ?\x06f3) ((?4 ?a) . ?\x06f4) ((?5 ?a) . ?\x06f5) ((?6 ?a) . ?\x06f6) ((?7 ?a) . ?\x06f7) ((?8 ?a) . ?\x06f8) ((?9 ?a) . ?\x06f9) ((?B ?.) . ?\x1e02) ((?b ?.) . ?\x1e03) ((?B ?_) . ?\x1e06) ((?b ?_) . ?\x1e07) ((?D ?.) . ?\x1e0a) ((?d ?.) . ?\x1e0b) ((?D ?_) . ?\x1e0e) ((?d ?_) . ?\x1e0f) ((?D ?,) . ?\x1e10) ((?d ?,) . ?\x1e11) ((?F ?.) . ?\x1e1e) ((?f ?.) . ?\x1e1f) ((?G ?-) . ?\x1e20) ((?g ?-) . ?\x1e21) ((?H ?.) . ?\x1e22) ((?h ?.) . ?\x1e23) ((?H ?:) . ?\x1e26) ((?h ?:) . ?\x1e27) ((?H ?,) . ?\x1e28) ((?h ?,) . ?\x1e29) ((?K ?') . ?\x1e30) ((?k ?') . ?\x1e31) ((?K ?_) . ?\x1e34) ((?k ?_) . ?\x1e35) ((?L ?_) . ?\x1e3a) ((?l ?_) . ?\x1e3b) ((?M ?') . ?\x1e3e) ((?m ?') . ?\x1e3f) ((?M ?.) . ?\x1e40) ((?m ?.) . ?\x1e41) ((?N ?.) . ?\x1e44) ((?n ?.) . ?\x1e45) ((?N ?_) . ?\x1e48) ((?n ?_) . ?\x1e49) ((?P ?') . ?\x1e54) ((?p ?') . ?\x1e55) ((?P ?.) . ?\x1e56) ((?p ?.) . ?\x1e57) ((?R ?.) . ?\x1e58) ((?r ?.) . ?\x1e59) ((?R ?_) . ?\x1e5e) ((?r ?_) . ?\x1e5f) ((?S ?.) . ?\x1e60) ((?s ?.) . ?\x1e61) ((?T ?.) . ?\x1e6a) ((?t ?.) . ?\x1e6b) ((?T ?_) . ?\x1e6e) ((?t ?_) . ?\x1e6f) ((?V ??) . ?\x1e7c) ((?v ??) . ?\x1e7d) ((?W ?!) . ?\x1e80) ((?w ?!) . ?\x1e81) ((?W ?') . ?\x1e82) ((?w ?') . ?\x1e83) ((?W ?:) . ?\x1e84) ((?w ?:) . ?\x1e85) ((?W ?.) . ?\x1e86) ((?w ?.) . ?\x1e87) ((?X ?.) . ?\x1e8a) ((?x ?.) . ?\x1e8b) ((?X ?:) . ?\x1e8c) ((?x ?:) . ?\x1e8d) ((?Y ?.) . ?\x1e8e) ((?y ?.) . ?\x1e8f) ((?Z ?>) . ?\x1e90) ((?z ?>) . ?\x1e91) ((?Z ?_) . ?\x1e94) ((?z ?_) . ?\x1e95) ((?h ?_) . ?\x1e96) ((?t ?:) . ?\x1e97) ((?w ?0) . ?\x1e98) ((?y ?0) . ?\x1e99) ((?A ?2) . ?\x1ea2) ((?a ?2) . ?\x1ea3) ((?E ?2) . ?\x1eba) ((?e ?2) . ?\x1ebb) ((?E ??) . ?\x1ebc) ((?e ??) . ?\x1ebd) ((?I ?2) . ?\x1ec8) ((?i ?2) . ?\x1ec9) ((?O ?2) . ?\x1ece) ((?o ?2) . ?\x1ecf) ((?U ?2) . ?\x1ee6) ((?u ?2) . ?\x1ee7) ((?Y ?!) . ?\x1ef2) ((?y ?!) . ?\x1ef3) ((?Y ?2) . ?\x1ef6) ((?y ?2) . ?\x1ef7) ((?Y ??) . ?\x1ef8) ((?y ??) . ?\x1ef9) ((?\; ?') . ?\x1f00) ((?, ?') . ?\x1f01) ((?\; ?!) . ?\x1f02) ((?, ?!) . ?\x1f03) ((?? ?\;) . ?\x1f04) ((?? ?,) . ?\x1f05) ((?! ?:) . ?\x1f06) ((?? ?:) . ?\x1f07) ((?1 ?N) . ?\x2002) ((?1 ?M) . ?\x2003) ((?3 ?M) . ?\x2004) ((?4 ?M) . ?\x2005) ((?6 ?M) . ?\x2006) ((?1 ?T) . ?\x2009) ((?1 ?H) . ?\x200a) ((?- ?1) . ?\x2010) ((?- ?N) . ?\x2013) ((?- ?M) . ?\x2014) ((?- ?3) . ?\x2015) ((?! ?2) . ?\x2016) ((?= ?2) . ?\x2017) ((?' ?6) . ?\x2018) ((?' ?9) . ?\x2019) ((?. ?9) . ?\x201a) ((?9 ?') . ?\x201b) ((?\" ?6) . ?\x201c) ((?\" ?9) . ?\x201d) ((?: ?9) . ?\x201e) ((?9 ?\") . ?\x201f) ((?/ ?-) . ?\x2020) ((?/ ?=) . ?\x2021) ((?. ?.) . ?\x2025) ((?% ?0) . ?\x2030) ((?1 ?') . ?\x2032) ((?2 ?') . ?\x2033) ((?3 ?') . ?\x2034) ((?1 ?\") . ?\x2035) ((?2 ?\") . ?\x2036) ((?3 ?\") . ?\x2037) ((?C ?a) . ?\x2038) ((?< ?1) . ?\x2039) ((?> ?1) . ?\x203a) ((?: ?X) . ?\x203b) ((?' ?-) . ?\x203e) ((?/ ?f) . ?\x2044) ((?0 ?S) . ?\x2070) ((?4 ?S) . ?\x2074) ((?5 ?S) . ?\x2075) ((?6 ?S) . ?\x2076) ((?7 ?S) . ?\x2077) ((?8 ?S) . ?\x2078) ((?9 ?S) . ?\x2079) ((?+ ?S) . ?\x207a) ((?- ?S) . ?\x207b) ((?= ?S) . ?\x207c) ((?\( ?S) . ?\x207d) ((?\) ?S) . ?\x207e) ((?n ?S) . ?\x207f) ((?0 ?s) . ?\x2080) ((?1 ?s) . ?\x2081) ((?2 ?s) . ?\x2082) ((?3 ?s) . ?\x2083) ((?4 ?s) . ?\x2084) ((?5 ?s) . ?\x2085) ((?6 ?s) . ?\x2086) ((?7 ?s) . ?\x2087) ((?8 ?s) . ?\x2088) ((?9 ?s) . ?\x2089) ((?+ ?s) . ?\x208a) ((?- ?s) . ?\x208b) ((?= ?s) . ?\x208c) ((?\( ?s) . ?\x208d) ((?\) ?s) . ?\x208e) ((?L ?i) . ?\x20a4) ((?P ?t) . ?\x20a7) ((?W ?=) . ?\x20a9) ((?= ?e) . ?\x20ac) ((?E ?u) . ?\x20ac) ((?o ?C) . ?\x2103) ((?c ?o) . ?\x2105) ((?o ?F) . ?\x2109) ((?N ?0) . ?\x2116) ((?P ?O) . ?\x2117) ((?R ?x) . ?\x211e) ((?S ?M) . ?\x2120) ((?T ?M) . ?\x2122) ((?O ?m) . ?\x2126) ((?A ?O) . ?\x212b) ((?1 ?3) . ?\x2153) ((?2 ?3) . ?\x2154) ((?1 ?5) . ?\x2155) ((?2 ?5) . ?\x2156) ((?3 ?5) . ?\x2157) ((?4 ?5) . ?\x2158) ((?1 ?6) . ?\x2159) ((?5 ?6) . ?\x215a) ((?1 ?8) . ?\x215b) ((?3 ?8) . ?\x215c) ((?5 ?8) . ?\x215d) ((?7 ?8) . ?\x215e) ((?1 ?R) . ?\x2160) ((?2 ?R) . ?\x2161) ((?3 ?R) . ?\x2162) ((?4 ?R) . ?\x2163) ((?5 ?R) . ?\x2164) ((?6 ?R) . ?\x2165) ((?7 ?R) . ?\x2166) ((?8 ?R) . ?\x2167) ((?9 ?R) . ?\x2168) ((?a ?R) . ?\x2169) ((?b ?R) . ?\x216a) ((?c ?R) . ?\x216b) ((?1 ?r) . ?\x2170) ((?2 ?r) . ?\x2171) ((?3 ?r) . ?\x2172) ((?4 ?r) . ?\x2173) ((?5 ?r) . ?\x2174) ((?6 ?r) . ?\x2175) ((?7 ?r) . ?\x2176) ((?8 ?r) . ?\x2177) ((?9 ?r) . ?\x2178) ((?a ?r) . ?\x2179) ((?b ?r) . ?\x217a) ((?c ?r) . ?\x217b) ((?< ?-) . ?\x2190) ((?- ?!) . ?\x2191) ((?- ?>) . ?\x2192) ((?- ?v) . ?\x2193) ((?< ?>) . ?\x2194) ((?U ?D) . ?\x2195) ((?< ?=) . ?\x21d0) ((?= ?>) . ?\x21d2) ((?= ?=) . ?\x21d4) ((?F ?A) . ?\x2200) ((?d ?P) . ?\x2202) ((?T ?E) . ?\x2203) ((?/ ?0) . ?\x2205) ((?D ?E) . ?\x2206) ((?N ?B) . ?\x2207) ((?\( ?-) . ?\x2208) ((?- ?\)) . ?\x220b) ((?* ?P) . ?\x220f) ((?+ ?Z) . ?\x2211) ((?- ?2) . ?\x2212) ((?- ?+) . ?\x2213) ((?* ?-) . ?\x2217) ((?O ?b) . ?\x2218) ((?S ?b) . ?\x2219) ((?R ?T) . ?\x221a) ((?0 ?\() . ?\x221d) ((?0 ?0) . ?\x221e) ((?- ?L) . ?\x221f) ((?- ?V) . ?\x2220) ((?P ?P) . ?\x2225) ((?A ?N) . ?\x2227) ((?O ?R) . ?\x2228) ((?\( ?U) . ?\x2229) ((?\) ?U) . ?\x222a) ((?I ?n) . ?\x222b) ((?D ?I) . ?\x222c) ((?I ?o) . ?\x222e) ((?. ?:) . ?\x2234) ((?: ?.) . ?\x2235) ((?: ?R) . ?\x2236) ((?: ?:) . ?\x2237) ((?? ?1) . ?\x223c) ((?C ?G) . ?\x223e) ((?? ?-) . ?\x2243) ((?? ?=) . ?\x2245) ((?? ?2) . ?\x2248) ((?= ??) . ?\x224c) ((?H ?I) . ?\x2253) ((?! ?=) . ?\x2260) ((?= ?3) . ?\x2261) ((?= ?<) . ?\x2264) ((?> ?=) . ?\x2265) ((?< ?*) . ?\x226a) ((?* ?>) . ?\x226b) ((?! ?<) . ?\x226e) ((?! ?>) . ?\x226f) ((?\( ?C) . ?\x2282) ((?\) ?C) . ?\x2283) ((?\( ?_) . ?\x2286) ((?\) ?_) . ?\x2287) ((?0 ?.) . ?\x2299) ((?0 ?2) . ?\x229a) ((?- ?T) . ?\x22a5) ((?. ?P) . ?\x22c5) ((?: ?3) . ?\x22ee) ((?. ?3) . ?\x22ef) ((?E ?h) . ?\x2302) ((?< ?7) . ?\x2308) ((?> ?7) . ?\x2309) ((?7 ?<) . ?\x230a) ((?7 ?>) . ?\x230b) ((?N ?I) . ?\x2310) ((?\( ?A) . ?\x2312) ((?T ?R) . ?\x2315) ((?I ?u) . ?\x2320) ((?I ?l) . ?\x2321) ((?< ?/) . ?\x2329) ((?/ ?>) . ?\x232a) ((?V ?s) . ?\x2423) ((?1 ?h) . ?\x2440) ((?3 ?h) . ?\x2441) ((?2 ?h) . ?\x2442) ((?4 ?h) . ?\x2443) ((?1 ?j) . ?\x2446) ((?2 ?j) . ?\x2447) ((?3 ?j) . ?\x2448) ((?4 ?j) . ?\x2449) ((?1 ?.) . ?\x2488) ((?2 ?.) . ?\x2489) ((?3 ?.) . ?\x248a) ((?4 ?.) . ?\x248b) ((?5 ?.) . ?\x248c) ((?6 ?.) . ?\x248d) ((?7 ?.) . ?\x248e) ((?8 ?.) . ?\x248f) ((?9 ?.) . ?\x2490) ((?h ?h) . ?\x2500) ((?H ?H) . ?\x2501) ((?v ?v) . ?\x2502) ((?V ?V) . ?\x2503) ((?3 ?-) . ?\x2504) ((?3 ?_) . ?\x2505) ((?3 ?!) . ?\x2506) ((?3 ?/) . ?\x2507) ((?4 ?-) . ?\x2508) ((?4 ?_) . ?\x2509) ((?4 ?!) . ?\x250a) ((?4 ?/) . ?\x250b) ((?d ?r) . ?\x250c) ((?d ?R) . ?\x250d) ((?D ?r) . ?\x250e) ((?D ?R) . ?\x250f) ((?d ?l) . ?\x2510) ((?d ?L) . ?\x2511) ((?D ?l) . ?\x2512) ((?L ?D) . ?\x2513) ((?u ?r) . ?\x2514) ((?u ?R) . ?\x2515) ((?U ?r) . ?\x2516) ((?U ?R) . ?\x2517) ((?u ?l) . ?\x2518) ((?u ?L) . ?\x2519) ((?U ?l) . ?\x251a) ((?U ?L) . ?\x251b) ((?v ?r) . ?\x251c) ((?v ?R) . ?\x251d) ((?V ?r) . ?\x2520) ((?V ?R) . ?\x2523) ((?v ?l) . ?\x2524) ((?v ?L) . ?\x2525) ((?V ?l) . ?\x2528) ((?V ?L) . ?\x252b) ((?d ?h) . ?\x252c) ((?d ?H) . ?\x252f) ((?D ?h) . ?\x2530) ((?D ?H) . ?\x2533) ((?u ?h) . ?\x2534) ((?u ?H) . ?\x2537) ((?U ?h) . ?\x2538) ((?U ?H) . ?\x253b) ((?v ?h) . ?\x253c) ((?v ?H) . ?\x253f) ((?V ?h) . ?\x2542) ((?V ?H) . ?\x254b) ((?F ?D) . ?\x2571) ((?B ?D) . ?\x2572) ((?T ?B) . ?\x2580) ((?L ?B) . ?\x2584) ((?F ?B) . ?\x2588) ((?l ?B) . ?\x258c) ((?R ?B) . ?\x2590) ((?. ?S) . ?\x2591) ((?: ?S) . ?\x2592) ((?? ?S) . ?\x2593) ((?f ?S) . ?\x25a0) ((?O ?S) . ?\x25a1) ((?R ?O) . ?\x25a2) ((?R ?r) . ?\x25a3) ((?R ?F) . ?\x25a4) ((?R ?Y) . ?\x25a5) ((?R ?H) . ?\x25a6) ((?R ?Z) . ?\x25a7) ((?R ?K) . ?\x25a8) ((?R ?X) . ?\x25a9) ((?s ?B) . ?\x25aa) ((?S ?R) . ?\x25ac) ((?O ?r) . ?\x25ad) ((?U ?T) . ?\x25b2) ((?u ?T) . ?\x25b3) ((?P ?R) . ?\x25b6) ((?T ?r) . ?\x25b7) ((?D ?t) . ?\x25bc) ((?d ?T) . ?\x25bd) ((?P ?L) . ?\x25c0) ((?T ?l) . ?\x25c1) ((?D ?b) . ?\x25c6) ((?D ?w) . ?\x25c7) ((?L ?Z) . ?\x25ca) ((?0 ?m) . ?\x25cb) ((?0 ?o) . ?\x25ce) ((?0 ?M) . ?\x25cf) ((?0 ?L) . ?\x25d0) ((?0 ?R) . ?\x25d1) ((?S ?n) . ?\x25d8) ((?I ?c) . ?\x25d9) ((?F ?d) . ?\x25e2) ((?B ?d) . ?\x25e3) ((?* ?2) . ?\x2605) ((?* ?1) . ?\x2606) ((?< ?H) . ?\x261c) ((?> ?H) . ?\x261e) ((?0 ?u) . ?\x263a) ((?0 ?U) . ?\x263b) ((?S ?U) . ?\x263c) ((?F ?m) . ?\x2640) ((?M ?l) . ?\x2642) ((?c ?S) . ?\x2660) ((?c ?H) . ?\x2661) ((?c ?D) . ?\x2662) ((?c ?C) . ?\x2663) ((?M ?d) . ?\x2669) ((?M ?8) . ?\x266a) ((?M ?2) . ?\x266b) ((?M ?b) . ?\x266d) ((?M ?x) . ?\x266e) ((?M ?X) . ?\x266f) ((?O ?K) . ?\x2713) ((?X ?X) . ?\x2717) ((?- ?X) . ?\x2720) ((?I ?S) . ?\x3000) ((?, ?_) . ?\x3001) ((?. ?_) . ?\x3002) ((?+ ?\") . ?\x3003) ((?+ ?_) . ?\x3004) ((?* ?_) . ?\x3005) ((?\; ?_) . ?\x3006) ((?0 ?_) . ?\x3007) ((?< ?+) . ?\x300a) ((?> ?+) . ?\x300b) ((?< ?') . ?\x300c) ((?> ?') . ?\x300d) ((?< ?\") . ?\x300e) ((?> ?\") . ?\x300f) ((?\( ?\") . ?\x3010) ((?\) ?\") . ?\x3011) ((?= ?T) . ?\x3012) ((?= ?_) . ?\x3013) ((?\( ?') . ?\x3014) ((?\) ?') . ?\x3015) ((?\( ?I) . ?\x3016) ((?\) ?I) . ?\x3017) ((?- ??) . ?\x301c) ((?A ?5) . ?\x3041) ((?a ?5) . ?\x3042) ((?I ?5) . ?\x3043) ((?i ?5) . ?\x3044) ((?U ?5) . ?\x3045) ((?u ?5) . ?\x3046) ((?E ?5) . ?\x3047) ((?e ?5) . ?\x3048) ((?O ?5) . ?\x3049) ((?o ?5) . ?\x304a) ((?k ?a) . ?\x304b) ((?g ?a) . ?\x304c) ((?k ?i) . ?\x304d) ((?g ?i) . ?\x304e) ((?k ?u) . ?\x304f) ((?g ?u) . ?\x3050) ((?k ?e) . ?\x3051) ((?g ?e) . ?\x3052) ((?k ?o) . ?\x3053) ((?g ?o) . ?\x3054) ((?s ?a) . ?\x3055) ((?z ?a) . ?\x3056) ((?s ?i) . ?\x3057) ((?z ?i) . ?\x3058) ((?s ?u) . ?\x3059) ((?z ?u) . ?\x305a) ((?s ?e) . ?\x305b) ((?z ?e) . ?\x305c) ((?s ?o) . ?\x305d) ((?z ?o) . ?\x305e) ((?t ?a) . ?\x305f) ((?d ?a) . ?\x3060) ((?t ?i) . ?\x3061) ((?d ?i) . ?\x3062) ((?t ?U) . ?\x3063) ((?t ?u) . ?\x3064) ((?d ?u) . ?\x3065) ((?t ?e) . ?\x3066) ((?d ?e) . ?\x3067) ((?t ?o) . ?\x3068) ((?d ?o) . ?\x3069) ((?n ?a) . ?\x306a) ((?n ?i) . ?\x306b) ((?n ?u) . ?\x306c) ((?n ?e) . ?\x306d) ((?n ?o) . ?\x306e) ((?h ?a) . ?\x306f) ((?b ?a) . ?\x3070) ((?p ?a) . ?\x3071) ((?h ?i) . ?\x3072) ((?b ?i) . ?\x3073) ((?p ?i) . ?\x3074) ((?h ?u) . ?\x3075) ((?b ?u) . ?\x3076) ((?p ?u) . ?\x3077) ((?h ?e) . ?\x3078) ((?b ?e) . ?\x3079) ((?p ?e) . ?\x307a) ((?h ?o) . ?\x307b) ((?b ?o) . ?\x307c) ((?p ?o) . ?\x307d) ((?m ?a) . ?\x307e) ((?m ?i) . ?\x307f) ((?m ?u) . ?\x3080) ((?m ?e) . ?\x3081) ((?m ?o) . ?\x3082) ((?y ?A) . ?\x3083) ((?y ?a) . ?\x3084) ((?y ?U) . ?\x3085) ((?y ?u) . ?\x3086) ((?y ?O) . ?\x3087) ((?y ?o) . ?\x3088) ((?r ?a) . ?\x3089) ((?r ?i) . ?\x308a) ((?r ?u) . ?\x308b) ((?r ?e) . ?\x308c) ((?r ?o) . ?\x308d) ((?w ?A) . ?\x308e) ((?w ?a) . ?\x308f) ((?w ?i) . ?\x3090) ((?w ?e) . ?\x3091) ((?w ?o) . ?\x3092) ((?n ?5) . ?\x3093) ((?v ?u) . ?\x3094) ((?\" ?5) . ?\x309b) ((?0 ?5) . ?\x309c) ((?* ?5) . ?\x309d) ((?+ ?5) . ?\x309e) ((?a ?6) . ?\x30a1) ((?A ?6) . ?\x30a2) ((?i ?6) . ?\x30a3) ((?I ?6) . ?\x30a4) ((?u ?6) . ?\x30a5) ((?U ?6) . ?\x30a6) ((?e ?6) . ?\x30a7) ((?E ?6) . ?\x30a8) ((?o ?6) . ?\x30a9) ((?O ?6) . ?\x30aa) ((?K ?a) . ?\x30ab) ((?G ?a) . ?\x30ac) ((?K ?i) . ?\x30ad) ((?G ?i) . ?\x30ae) ((?K ?u) . ?\x30af) ((?G ?u) . ?\x30b0) ((?K ?e) . ?\x30b1) ((?G ?e) . ?\x30b2) ((?K ?o) . ?\x30b3) ((?G ?o) . ?\x30b4) ((?S ?a) . ?\x30b5) ((?Z ?a) . ?\x30b6) ((?S ?i) . ?\x30b7) ((?Z ?i) . ?\x30b8) ((?S ?u) . ?\x30b9) ((?Z ?u) . ?\x30ba) ((?S ?e) . ?\x30bb) ((?Z ?e) . ?\x30bc) ((?S ?o) . ?\x30bd) ((?Z ?o) . ?\x30be) ((?T ?a) . ?\x30bf) ((?D ?a) . ?\x30c0) ((?T ?i) . ?\x30c1) ((?D ?i) . ?\x30c2) ((?T ?U) . ?\x30c3) ((?T ?u) . ?\x30c4) ((?D ?u) . ?\x30c5) ((?T ?e) . ?\x30c6) ((?D ?e) . ?\x30c7) ((?T ?o) . ?\x30c8) ((?D ?o) . ?\x30c9) ((?N ?a) . ?\x30ca) ((?N ?i) . ?\x30cb) ((?N ?u) . ?\x30cc) ((?N ?e) . ?\x30cd) ((?N ?o) . ?\x30ce) ((?H ?a) . ?\x30cf) ((?B ?a) . ?\x30d0) ((?P ?a) . ?\x30d1) ((?H ?i) . ?\x30d2) ((?B ?i) . ?\x30d3) ((?P ?i) . ?\x30d4) ((?H ?u) . ?\x30d5) ((?B ?u) . ?\x30d6) ((?P ?u) . ?\x30d7) ((?H ?e) . ?\x30d8) ((?B ?e) . ?\x30d9) ((?P ?e) . ?\x30da) ((?H ?o) . ?\x30db) ((?B ?o) . ?\x30dc) ((?P ?o) . ?\x30dd) ((?u ?R) . ?\x2515) ((?U ?r) . ?\x2516) ((?U ?R) . ?\x2517) ((?u ?l) . ?\x2518) ((?u ?L) . ?\x2519) ((?U ?l) . ?\x251a) ((?U ?L) . ?\x251b) ((?v ?r) . ?\x251c) ((?v ?R) . ?\x251d) ((?V ?r) . ?\x2520) ((?V ?R) . ?\x2523) ((?v ?l) . ?\x2524) ((?v ?L) . ?\x2525) ((?V ?l) . ?\x2528) ((?V ?L) . ?\x252b) ((?d ?h) . ?\x252c) ((?d ?H) . ?\x252f) ((?D ?h) . ?\x2530) ((?D ?H) . ?\x2533) ((?u ?h) . ?\x2534) ((?u ?H) . ?\x2537) ((?U ?h) . ?\x2538) ((?U ?H) . ?\x253b) ((?v ?h) . ?\x253c) ((?v ?H) . ?\x253f) ((?V ?h) . ?\x2542) ((?V ?H) . ?\x254b) ((?F ?D) . ?\x2571) ((?B ?D) . ?\x2572) ((?T ?B) . ?\x2580) ((?L ?B) . ?\x2584) ((?F ?B) . ?\x2588) ((?l ?B) . ?\x258c) ((?R ?B) . ?\x2590) ((?. ?S) . ?\x2591) ((?: ?S) . ?\x2592) ((?? ?S) . ?\x2593) ((?f ?S) . ?\x25a0) ((?O ?S) . ?\x25a1) ((?R ?O) . ?\x25a2) ((?R ?r) . ?\x25a3) ((?R ?F) . ?\x25a4) ((?R ?Y) . ?\x25a5) ((?R ?H) . ?\x25a6) ((?R ?Z) . ?\x25a7) ((?R ?K) . ?\x25a8) ((?R ?X) . ?\x25a9) ((?s ?B) . ?\x25aa) ((?S ?R) . ?\x25ac) ((?O ?r) . ?\x25ad) ((?U ?T) . ?\x25b2) ((?u ?T) . ?\x25b3) ((?P ?R) . ?\x25b6) ((?T ?r) . ?\x25b7) ((?D ?t) . ?\x25bc) ((?d ?T) . ?\x25bd) ((?P ?L) . ?\x25c0) ((?T ?l) . ?\x25c1) ((?D ?b) . ?\x25c6) ((?D ?w) . ?\x25c7) ((?L ?Z) . ?\x25ca) ((?0 ?m) . ?\x25cb) ((?0 ?o) . ?\x25ce) ((?0 ?M) . ?\x25cf) ((?0 ?L) . ?\x25d0) ((?0 ?R) . ?\x25d1) ((?S ?n) . ?\x25d8) ((?I ?c) . ?\x25d9) ((?F ?d) . ?\x25e2) ((?B ?d) . ?\x25e3) ((?* ?2) . ?\x2605) ((?* ?1) . ?\x2606) ((?< ?H) . ?\x261c) ((?> ?H) . ?\x261e) ((?0 ?u) . ?\x263a) ((?0 ?U) . ?\x263b) ((?S ?U) . ?\x263c) ((?F ?m) . ?\x2640) ((?M ?l) . ?\x2642) ((?c ?S) . ?\x2660) ((?c ?H) . ?\x2661) ((?c ?D) . ?\x2662) ((?c ?C) . ?\x2663) ((?M ?d) . ?\x2669) ((?M ?8) . ?\x266a) ((?M ?2) . ?\x266b) ((?M ?b) . ?\x266d) ((?M ?x) . ?\x266e) ((?M ?X) . ?\x266f) ((?O ?K) . ?\x2713) ((?X ?X) . ?\x2717) ((?- ?X) . ?\x2720) ((?I ?S) . ?\x3000) ((?, ?_) . ?\x3001) ((?. ?_) . ?\x3002) ((?+ ?\") . ?\x3003) ((?+ ?_) . ?\x3004) ((?* ?_) . ?\x3005) ((?\; ?_) . ?\x3006) ((?0 ?_) . ?\x3007) ((?< ?+) . ?\x300a) ((?> ?+) . ?\x300b) ((?< ?') . ?\x300c) ((?> ?') . ?\x300d) ((?< ?\") . ?\x300e) ((?> ?\") . ?\x300f) ((?\( ?\") . ?\x3010) ((?\) ?\") . ?\x3011) ((?= ?T) . ?\x3012) ((?= ?_) . ?\x3013) ((?\( ?') . ?\x3014) ((?\) ?') . ?\x3015) ((?\( ?I) . ?\x3016) ((?\) ?I) . ?\x3017) ((?- ??) . ?\x301c) ((?A ?5) . ?\x3041) ((?a ?5) . ?\x3042) ((?I ?5) . ?\x3043) ((?i ?5) . ?\x3044) ((?U ?5) . ?\x3045) ((?u ?5) . ?\x3046) ((?E ?5) . ?\x3047) ((?e ?5) . ?\x3048) ((?O ?5) . ?\x3049) ((?o ?5) . ?\x304a) ((?k ?a) . ?\x304b) ((?g ?a) . ?\x304c) ((?k ?i) . ?\x304d) ((?g ?i) . ?\x304e) ((?k ?u) . ?\x304f) ((?g ?u) . ?\x3050) ((?k ?e) . ?\x3051) ((?g ?e) . ?\x3052) ((?k ?o) . ?\x3053) ((?g ?o) . ?\x3054) ((?s ?a) . ?\x3055) ((?z ?a) . ?\x3056) ((?s ?i) . ?\x3057) ((?z ?i) . ?\x3058) ((?s ?u) . ?\x3059) ((?z ?u) . ?\x305a) ((?s ?e) . ?\x305b) ((?z ?e) . ?\x305c) ((?s ?o) . ?\x305d) ((?z ?o) . ?\x305e) ((?t ?a) . ?\x305f) ((?d ?a) . ?\x3060) ((?t ?i) . ?\x3061) ((?d ?i) . ?\x3062) ((?t ?U) . ?\x3063) ((?t ?u) . ?\x3064) ((?d ?u) . ?\x3065) ((?t ?e) . ?\x3066) ((?d ?e) . ?\x3067) ((?t ?o) . ?\x3068) ((?d ?o) . ?\x3069) ((?n ?a) . ?\x306a) ((?n ?i) . ?\x306b) ((?n ?u) . ?\x306c) ((?n ?e) . ?\x306d) ((?n ?o) . ?\x306e) ((?h ?a) . ?\x306f) ((?b ?a) . ?\x3070) ((?p ?a) . ?\x3071) ((?h ?i) . ?\x3072) ((?b ?i) . ?\x3073) ((?p ?i) . ?\x3074) ((?h ?u) . ?\x3075) ((?b ?u) . ?\x3076) ((?p ?u) . ?\x3077) ((?h ?e) . ?\x3078) ((?b ?e) . ?\x3079) ((?p ?e) . ?\x307a) ((?h ?o) . ?\x307b) ((?b ?o) . ?\x307c) ((?p ?o) . ?\x307d) ((?m ?a) . ?\x307e) ((?m ?i) . ?\x307f) ((?m ?u) . ?\x3080) ((?m ?e) . ?\x3081) ((?m ?o) . ?\x3082) ((?y ?A) . ?\x3083) ((?y ?a) . ?\x3084) ((?y ?U) . ?\x3085) ((?y ?u) . ?\x3086) ((?y ?O) . ?\x3087) ((?y ?o) . ?\x3088) ((?r ?a) . ?\x3089) ((?r ?i) . ?\x308a) ((?r ?u) . ?\x308b) ((?r ?e) . ?\x308c) ((?r ?o) . ?\x308d) ((?w ?A) . ?\x308e) ((?w ?a) . ?\x308f) ((?w ?i) . ?\x3090) ((?w ?e) . ?\x3091) ((?w ?o) . ?\x3092) ((?n ?5) . ?\x3093) ((?v ?u) . ?\x3094) ((?\" ?5) . ?\x309b) ((?0 ?5) . ?\x309c) ((?* ?5) . ?\x309d) ((?+ ?5) . ?\x309e) ((?a ?6) . ?\x30a1) ((?A ?6) . ?\x30a2) ((?i ?6) . ?\x30a3) ((?I ?6) . ?\x30a4) ((?u ?6) . ?\x30a5) ((?U ?6) . ?\x30a6) ((?e ?6) . ?\x30a7) ((?E ?6) . ?\x30a8) ((?o ?6) . ?\x30a9) ((?O ?6) . ?\x30aa) ((?K ?a) . ?\x30ab) ((?G ?a) . ?\x30ac) ((?K ?i) . ?\x30ad) ((?G ?i) . ?\x30ae) ((?K ?u) . ?\x30af) ((?G ?u) . ?\x30b0) ((?K ?e) . ?\x30b1) ((?G ?e) . ?\x30b2) ((?K ?o) . ?\x30b3) ((?G ?o) . ?\x30b4) ((?S ?a) . ?\x30b5) ((?Z ?a) . ?\x30b6) ((?S ?i) . ?\x30b7) ((?Z ?i) . ?\x30b8) ((?S ?u) . ?\x30b9) ((?Z ?u) . ?\x30ba) ((?S ?e) . ?\x30bb) ((?Z ?e) . ?\x30bc) ((?S ?o) . ?\x30bd) ((?Z ?o) . ?\x30be) ((?T ?a) . ?\x30bf) ((?D ?a) . ?\x30c0) ((?T ?i) . ?\x30c1) ((?D ?i) . ?\x30c2) ((?T ?U) . ?\x30c3) ((?T ?u) . ?\x30c4) ((?D ?u) . ?\x30c5) ((?T ?e) . ?\x30c6) ((?D ?e) . ?\x30c7) ((?T ?o) . ?\x30c8) ((?D ?o) . ?\x30c9) ((?N ?a) . ?\x30ca) ((?N ?i) . ?\x30cb) ((?N ?u) . ?\x30cc) ((?N ?e) . ?\x30cd) ((?N ?o) . ?\x30ce) ((?H ?a) . ?\x30cf) ((?B ?a) . ?\x30d0) ((?P ?a) . ?\x30d1) ((?H ?i) . ?\x30d2) ((?B ?i) . ?\x30d3) ((?P ?i) . ?\x30d4) ((?H ?u) . ?\x30d5) ((?B ?u) . ?\x30d6) ((?P ?u) . ?\x30d7) ((?H ?e) . ?\x30d8) ((?B ?e) . ?\x30d9) ((?P ?e) . ?\x30da) ((?H ?o) . ?\x30db) ((?B ?o) . ?\x30dc) ((?P ?o) . ?\x30dd) ((?M ?a) . ?\x30de) ((?M ?i) . ?\x30df) ((?M ?u) . ?\x30e0) ((?M ?e) . ?\x30e1) ((?M ?o) . ?\x30e2) ((?Y ?A) . ?\x30e3) ((?Y ?a) . ?\x30e4) ((?Y ?U) . ?\x30e5) ((?Y ?u) . ?\x30e6) ((?Y ?O) . ?\x30e7) ((?Y ?o) . ?\x30e8) ((?R ?a) . ?\x30e9) ((?R ?i) . ?\x30ea) ((?R ?u) . ?\x30eb) ((?R ?e) . ?\x30ec) ((?R ?o) . ?\x30ed) ((?W ?A) . ?\x30ee) ((?W ?a) . ?\x30ef) ((?W ?i) . ?\x30f0) ((?W ?e) . ?\x30f1) ((?W ?o) . ?\x30f2) ((?N ?6) . ?\x30f3) ((?V ?u) . ?\x30f4) ((?K ?A) . ?\x30f5) ((?K ?E) . ?\x30f6) ((?V ?a) . ?\x30f7) ((?V ?i) . ?\x30f8) ((?V ?e) . ?\x30f9) ((?V ?o) . ?\x30fa) ((?. ?6) . ?\x30fb) ((?- ?6) . ?\x30fc) ((?* ?6) . ?\x30fd) ((?+ ?6) . ?\x30fe) ((?b ?4) . ?\x3105) ((?p ?4) . ?\x3106) ((?m ?4) . ?\x3107) ((?f ?4) . ?\x3108) ((?d ?4) . ?\x3109) ((?t ?4) . ?\x310a) ((?n ?4) . ?\x310b) ((?l ?4) . ?\x310c) ((?g ?4) . ?\x310d) ((?k ?4) . ?\x310e) ((?h ?4) . ?\x310f) ((?j ?4) . ?\x3110) ((?q ?4) . ?\x3111) ((?x ?4) . ?\x3112) ((?z ?h) . ?\x3113) ((?c ?h) . ?\x3114) ((?s ?h) . ?\x3115) ((?r ?4) . ?\x3116) ((?z ?4) . ?\x3117) ((?c ?4) . ?\x3118) ((?s ?4) . ?\x3119) ((?a ?4) . ?\x311a) ((?o ?4) . ?\x311b) ((?e ?4) . ?\x311c) ((?a ?i) . ?\x311e) ((?e ?i) . ?\x311f) ((?a ?u) . ?\x3120) ((?o ?u) . ?\x3121) ((?a ?n) . ?\x3122) ((?e ?n) . ?\x3123) ((?a ?N) . ?\x3124) ((?e ?N) . ?\x3125) ((?e ?r) . ?\x3126) ((?i ?4) . ?\x3127) ((?u ?4) . ?\x3128) ((?i ?u) . ?\x3129) ((?v ?4) . ?\x312a) ((?n ?G) . ?\x312b) ((?g ?n) . ?\x312c) ((?1 ?c) . ?\x3220) ((?2 ?c) . ?\x3221) ((?3 ?c) . ?\x3222) ((?4 ?c) . ?\x3223) ((?5 ?c) . ?\x3224) ((?6 ?c) . ?\x3225) ((?7 ?c) . ?\x3226) ((?8 ?c) . ?\x3227) ((?9 ?c) . ?\x3228) ((?\s ?\s) . ?\xe000) ((?/ ?c) . ?\xe001) ((?U ?A) . ?\xe002) ((?U ?B) . ?\xe003) ((?\" ?3) . ?\xe004) ((?\" ?1) . ?\xe005) ((?\" ?!) . ?\xe006) ((?\" ?') . ?\xe007) ((?\" ?>) . ?\xe008) ((?\" ??) . ?\xe009) ((?\" ?-) . ?\xe00a) ((?\" ?\() . ?\xe00b) ((?\" ?.) . ?\xe00c) ((?\" ?:) . ?\xe00d) ((?\" ?0) . ?\xe00e) ((?\" ?\") . ?\xe00f) ((?\" ?<) . ?\xe010) ((?\" ?,) . ?\xe011) ((?\" ?\;) . ?\xe012) ((?\" ?_) . ?\xe013) ((?\" ?=) . ?\xe014) ((?\" ?/) . ?\xe015) ((?\" ?i) . ?\xe016) ((?\" ?d) . ?\xe017) ((?\" ?p) . ?\xe018) ((?\; ?\;) . ?\xe019) ((?, ?,) . ?\xe01a) ((?b ?3) . ?\xe01b) ((?C ?i) . ?\xe01c) ((?f ?\() . ?\xe01d) ((?e ?d) . ?\xe01e) ((?a ?m) . ?\xe01f) ((?p ?m) . ?\xe020) ((?F ?l) . ?\xe023) ((?G ?F) . ?\xe024) ((?> ?V) . ?\xe025) ((?! ?*) . ?\xe026) ((?? ?*) . ?\xe027) ((?J ?<) . ?\xe028) ((?f ?f) . ?\xfb00) ((?f ?i) . ?\xfb01) ((?f ?l) . ?\xfb02) ((?f ?t) . ?\xfb05) ((?s ?t) . ?\xfb06) ((?~ ?!) . ?\x00a1) ((?c ?|) . ?\x00a2) ((?$ ?$) . ?\x00a3) ((?o ?x) . ?\x00a4) ((?Y ?-) . ?\x00a5) ((?| ?|) . ?\x00a6) ((?c ?O) . ?\x00a9) ((?- ?,) . ?\x00ac) ((?- ?=) . ?\x00af) ((?~ ?o) . ?\x00b0) ((?2 ?2) . ?\x00b2) ((?3 ?3) . ?\x00b3) ((?p ?p) . ?\x00b6) ((?~ ?.) . ?\x00b7) ((?1 ?1) . ?\x00b9) ((?~ ??) . ?\x00bf) ((?A ?`) . ?\x00c0) ((?A ?^) . ?\x00c2) ((?A ?~) . ?\x00c3) ((?A ?\") . ?\x00c4) ((?A ?@) . ?\x00c5) ((?E ?`) . ?\x00c8) ((?E ?^) . ?\x00ca) ((?E ?\") . ?\x00cb) ((?I ?`) . ?\x00cc) ((?I ?^) . ?\x00ce) ((?I ?\") . ?\x00cf) ((?N ?~) . ?\x00d1) ((?O ?`) . ?\x00d2) ((?O ?^) . ?\x00d4) ((?O ?~) . ?\x00d5) ((?/ ?\\) . ?\x00d7) ((?U ?`) . ?\x00d9) ((?U ?^) . ?\x00db) ((?I ?p) . ?\x00de) ((?a ?`) . ?\x00e0) ((?a ?^) . ?\x00e2) ((?a ?~) . ?\x00e3) ((?a ?\") . ?\x00e4) ((?a ?@) . ?\x00e5) ((?e ?`) . ?\x00e8) ((?e ?^) . ?\x00ea) ((?e ?\") . ?\x00eb) ((?i ?`) . ?\x00ec) ((?i ?^) . ?\x00ee) ((?n ?~) . ?\x00f1) ((?o ?`) . ?\x00f2) ((?o ?^) . ?\x00f4) ((?o ?~) . ?\x00f5) ((?u ?`) . ?\x00f9) ((?u ?^) . ?\x00fb) ((?y ?\") . ?\x00ff)) "Table of default digraphs. This includes all digraphs defined in RFC 1345, as well as miscellaneous digraphs for multi-byte characters. See also `evil-digraphs-table-user'.") (defun evil-digraph (digraph) "Convert DIGRAPH to character or list representation. If DIGRAPH is a list (CHAR1 CHAR2), return the corresponding character; if DIGRAPH is a character, return the corresponding list. Searches in `evil-digraphs-table-user' and `evil-digraphs-table'." (if (listp digraph) (let* ((char1 (car digraph)) (char2 (cadr digraph))) (or (cdr (assoc (list char1 char2) evil-digraphs-table-user)) (cdr (assoc (list char1 char2) evil-digraphs-table)) (unless (eq char1 char2) (or (cdr (assoc (list char2 char1) evil-digraphs-table-user)) (cdr (assoc (list char2 char1) evil-digraphs-table)))))) (or (car (rassoc digraph evil-digraphs-table-user)) (car (rassoc digraph evil-digraphs-table))))) (provide 'evil-digraphs) ;;; evil-digraphs.el ends here evil-1.12.17/evil-ex.el000066400000000000000000001277021360703323200145250ustar00rootroot00000000000000;;; evil-ex.el --- Ex-mode ;; Author: Frank Fischer ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . ;;; Commentary: ;; Ex is implemented as an extensible minilanguage, whose grammar ;; is stored in `evil-ex-grammar'. Ex commands are defined with ;; `evil-ex-define-cmd', which creates a binding from a string ;; to an interactive function. It is also possible to define key ;; sequences which execute a command immediately when entered: ;; such shortcuts go in `evil-ex-map'. ;; ;; To provide buffer and filename completion, as well as interactive ;; feedback, Ex defines the concept of an argument handler, specified ;; with `evil-ex-define-argument-type'. In the case of the ;; substitution command (":s/foo/bar"), the handler incrementally ;; highlights matches in the buffer as the substitution is typed. (require 'evil-common) (require 'evil-states) (require 'shell) ;;; Code: (defconst evil-ex-grammar '((expression (count command argument #'evil-ex-call-command) ((\? range) command argument #'evil-ex-call-command) (line #'evil-goto-line) (sexp #'eval-expression)) (count number) (command #'evil-ex-parse-command) (binding "[~&*@<>=:]+\\|[[:alpha:]_]+\\|!") (emacs-binding "[[:alpha:]-][[:alnum:][:punct:]-]+") (bang (\? (! space) "!" #'$1)) (argument ((\? space) (\? "\\(?:.\\|\n\\)+") #'$2)) (range ("%" #'(evil-ex-full-range)) (line ";" line #'(let ((tmp1 $1)) (save-excursion (goto-line tmp1) (evil-ex-range tmp1 $3)))) (line "," line #'(evil-ex-range $1 $3)) (line #'(evil-ex-range $1 nil)) ("`" "[-a-zA-Z_<>']" ",`" "[-a-zA-Z_<>']" #'(evil-ex-char-marker-range $2 $4))) (line (base (\? offset) search (\? offset) #'(let ((tmp (evil-ex-line $1 $2))) (save-excursion (goto-line tmp) (evil-ex-line $3 $4)))) ((\? base) offset search (\? offset) #'(let ((tmp (evil-ex-line $1 $2))) (save-excursion (goto-line tmp) (evil-ex-line $3 $4)))) (base (\? offset) #'evil-ex-line) ((\? base) offset #'evil-ex-line)) (base number marker search ("\\^" #'(evil-ex-first-line)) ("\\$" #'(evil-ex-last-line)) ("\\." #'(evil-ex-current-line))) (offset (+ signed-number #'+)) (marker ("'" "[-a-zA-Z_<>']" #'(evil-ex-marker $2))) (search forward backward next prev subst) (forward ("/" "\\(?:[\\].\\|[^/,; ]\\)+" (! "/") #'(evil-ex-re-fwd $2)) ("/" "\\(?:[\\].\\|[^/]\\)+" "/" #'(evil-ex-re-fwd $2))) (backward ("\\?" "\\(?:[\\].\\|[^?,; ]\\)+" (! "\\?") #'(evil-ex-re-bwd $2)) ("\\?" "\\(?:[\\].\\|[^?]\\)+" "\\?" #'(evil-ex-re-bwd $2))) (next "\\\\/" #'(evil-ex-prev-search)) (prev "\\\\\\?" #'(evil-ex-prev-search)) (subst "\\\\&" #'(evil-ex-prev-search)) (signed-number (sign (\? number) #'evil-ex-signed-number)) (sign "\\+\\|-" #'intern) (number "[0-9]+" #'string-to-number) (space "[ ]+") (sexp "(.*)" #'(car-safe (read-from-string $1)))) "Grammar for Ex. An association list of syntactic symbols and their definitions. The first entry is the start symbol. A symbol's definition may reference other symbols, but the grammar cannot contain left recursion. See `evil-parser' for a detailed explanation of the syntax.") (defvar evil-ex-echo-overlay nil "Overlay used for displaying info messages during ex.") (defun evil-ex-p () "Whether Ex is currently active." (and evil-ex-current-buffer t)) (evil-define-command evil-ex (&optional initial-input) "Enter an Ex command. The ex command line is initialized with the value of INITIAL-INPUT. If the command is called interactively the initial input depends on the current state. If the current state is normal state and no count argument is given then the initial input is empty. If a prefix count is given the initial input is .,.+count. If the current state is visual state then the initial input is the visual region '<,'> or `<,`>. If the value of the global variable `evil-ex-initial-input' is non-nil, its content is appended to the line." :keep-visual t :repeat abort (interactive (list (let ((s (concat (cond ((and (evil-visual-state-p) evil-ex-visual-char-range (memq (evil-visual-type) '(inclusive exclusive))) "`<,`>") ((evil-visual-state-p) "'<,'>") (current-prefix-arg (let ((arg (prefix-numeric-value current-prefix-arg))) (cond ((< arg 0) (setq arg (1+ arg))) ((> arg 0) (setq arg (1- arg)))) (if (= arg 0) "." (format ".,.%+d" arg))))) evil-ex-initial-input))) (and (> (length s) 0) s)))) (let ((evil-ex-current-buffer (current-buffer)) (evil-ex-previous-command (unless initial-input (car-safe evil-ex-history))) evil-ex-argument-handler evil-ex-info-string result) (minibuffer-with-setup-hook (if initial-input #'evil-ex-setup-and-update #'evil-ex-setup) (setq result (read-from-minibuffer ":" (or initial-input (and evil-ex-previous-command (propertize evil-ex-previous-command 'face 'shadow))) evil-ex-completion-map nil 'evil-ex-history evil-ex-previous-command t))) (evil-ex-execute result))) (defun evil-ex-execute (result) "Execute RESULT as an ex command on `evil-ex-current-buffer'." ;; empty input means repeating the previous command (when (zerop (length result)) (setq result evil-ex-previous-command)) ;; parse data (evil-ex-update nil nil nil result) ;; execute command (unless (zerop (length result)) (if evil-ex-expression (eval evil-ex-expression) (user-error "Ex: syntax error")))) (defun evil-ex-delete-backward-char () "Close the minibuffer if it is empty. Otherwise behaves like `delete-backward-char'." (interactive) (call-interactively (if (zerop (length (minibuffer-contents))) #'abort-recursive-edit #'delete-backward-char))) (defun evil-ex-abort () "Cancel ex state when another buffer is selected." (unless (minibufferp) (abort-recursive-edit))) (defun evil-ex-setup () "Initialize Ex minibuffer. This function registers several hooks that are used for the interactive actions during ex state." (add-hook 'post-command-hook #'evil-ex-abort) (add-hook 'after-change-functions #'evil-ex-update nil t) (add-hook 'minibuffer-exit-hook #'evil-ex-teardown nil t) (when evil-ex-previous-command (add-hook 'pre-command-hook #'evil-ex-remove-default)) (remove-hook 'minibuffer-setup-hook #'evil-ex-setup) (with-no-warnings (make-variable-buffer-local 'completion-at-point-functions)) (setq completion-at-point-functions '(evil-ex-command-completion-at-point evil-ex-argument-completion-at-point))) (put 'evil-ex-setup 'permanent-local-hook t) (defun evil-ex-setup-and-update () "Initialize Ex minibuffer with `evil-ex-setup', then call `evil-ex-update'." (evil-ex-setup) (evil-ex-update)) (defun evil-ex-teardown () "Deinitialize Ex minibuffer. Clean up everything set up by `evil-ex-setup'." (remove-hook 'post-command-hook #'evil-ex-abort) (remove-hook 'minibuffer-exit-hook #'evil-ex-teardown t) (remove-hook 'after-change-functions #'evil-ex-update t) (when evil-ex-argument-handler (let ((runner (evil-ex-argument-handler-runner evil-ex-argument-handler))) (when runner (funcall runner 'stop))))) (put 'evil-ex-teardown 'permanent-local-hook t) (defun evil-ex-remove-default () "Remove the default text shown in the ex minibuffer. When ex starts, the previous command is shown enclosed in parenthesis. This function removes this text when the first key is pressed." (when (and (not (eq this-command 'exit-minibuffer)) (/= (minibuffer-prompt-end) (point-max))) (if (eq this-command 'evil-ex-delete-backward-char) (setq this-command 'ignore)) (delete-minibuffer-contents)) (remove-hook 'pre-command-hook #'evil-ex-remove-default)) (put 'evil-ex-remove-default 'permanent-local-hook t) (defun evil-ex-update (&optional beg end len string) "Update Ex variables when the minibuffer changes. This function is usually called from `after-change-functions' hook. If BEG is non-nil (which is the case when called from `after-change-functions'), then an error description is shown in case of incomplete or unknown commands." (let* ((prompt (minibuffer-prompt-end)) (string (or string (buffer-substring prompt (point-max)))) arg bang cmd count expr func handler range tree type) (cond ((and (eq this-command #'self-insert-command) (commandp (setq cmd (lookup-key evil-ex-map string)))) (setq evil-ex-expression `(call-interactively #',cmd)) (when (minibufferp) (exit-minibuffer))) (t (setq cmd nil) ;; store the buffer position of each character ;; as the `ex-index' text property (dotimes (i (length string)) (add-text-properties i (1+ i) (list 'ex-index (+ i prompt)) string)) (with-current-buffer evil-ex-current-buffer (setq tree (evil-ex-parse string t) expr (evil-ex-parse string)) (when (eq (car-safe expr) 'evil-ex-call-command) (setq count (eval (nth 1 expr)) cmd (eval (nth 2 expr)) arg (eval (nth 3 expr)) range (cond ((evil-range-p count) count) ((numberp count) (evil-ex-range count count))) bang (and (save-match-data (string-match ".!$" cmd)) t)))) (setq evil-ex-tree tree evil-ex-expression expr evil-ex-range range evil-ex-cmd cmd evil-ex-bang bang evil-ex-argument arg) ;; test the current command (when (and cmd (minibufferp)) (setq func (evil-ex-completed-binding cmd t)) (cond ;; update argument-handler (func (when (setq type (evil-get-command-property func :ex-arg)) (setq handler (cdr-safe (assoc type evil-ex-argument-types)))) (unless (eq handler evil-ex-argument-handler) (let ((runner (and evil-ex-argument-handler (evil-ex-argument-handler-runner evil-ex-argument-handler)))) (when runner (funcall runner 'stop))) (setq evil-ex-argument-handler handler) (let ((runner (and evil-ex-argument-handler (evil-ex-argument-handler-runner evil-ex-argument-handler)))) (when runner (funcall runner 'start evil-ex-argument)))) (let ((runner (and evil-ex-argument-handler (evil-ex-argument-handler-runner evil-ex-argument-handler)))) (when runner (funcall runner 'update evil-ex-argument)))) (beg ;; show error message only when called from `after-change-functions' (let ((n (length (all-completions cmd (evil-ex-completion-table))))) (cond ((> n 1) (evil-ex-echo "Incomplete command")) ((= n 0) (evil-ex-echo "Unknown command"))))))))))) (put 'evil-ex-update 'permanent-local-hook t) (defun evil-ex-echo (string &rest args) "Display a message after the current Ex command." (with-selected-window (minibuffer-window) (with-current-buffer (window-buffer (minibuffer-window)) (unless (or evil-no-display (zerop (length string))) (let ((string (format " [%s]" (apply #'format string args))) (ov (or evil-ex-echo-overlay (setq evil-ex-echo-overlay (make-overlay (point-min) (point-max) nil t t)))) after-change-functions before-change-functions) (put-text-property 0 (length string) 'face 'evil-ex-info string) ;; The following 'trick' causes point to be shown before the ;; message instead behind. It is shamelessly stolen from the ;; implementation of `minibuffer-message`. (put-text-property 0 1 'cursor t string) (move-overlay ov (point-max) (point-max)) (overlay-put ov 'after-string string) (add-hook 'pre-command-hook #'evil--ex-remove-echo-overlay nil t)))))) (defun evil--ex-remove-echo-overlay () "Remove echo overlay from ex minibuffer." (when evil-ex-echo-overlay (delete-overlay evil-ex-echo-overlay) (setq evil-ex-echo-overlay nil)) (remove-hook 'pre-command-hook 'evil--ex-remove-echo-overlay t)) (defun evil-ex-completion () "Completes the current ex command or argument." (interactive) (let (after-change-functions) (evil-ex-update) (completion-at-point) (remove-text-properties (minibuffer-prompt-end) (point-max) '(face nil evil)))) (defun evil-ex-command-completion-at-point () (let ((beg (or (get-text-property 0 'ex-index evil-ex-cmd) (point))) (end (point))) (list beg end (evil-ex-completion-table) :exclusive 'no))) (defun evil-ex-completion-table () (cond ((eq evil-ex-complete-emacs-commands nil) #'evil-ex-command-collection) ((eq evil-ex-complete-emacs-commands 'in-turn) (completion-table-in-turn #'evil-ex-command-collection #'(lambda (str pred flag) (completion-table-with-predicate obarray #'commandp t str pred flag)))) (t #'(lambda (str pred flag) (evil-completion-table-concat #'evil-ex-command-collection #'(lambda (str pred flag) (completion-table-with-predicate obarray #'commandp t str pred flag)) str pred flag))))) (defun evil-completion-table-concat (table1 table2 string pred flag) (cond ((eq flag nil) (let ((result1 (try-completion string table1 pred)) (result2 (try-completion string table2 pred))) (cond ((null result1) result2) ((null result2) result1) ((and (eq result1 t) (eq result2 t)) t) (t result1)))) ((eq flag t) (delete-dups (append (all-completions string table1 pred) (all-completions string table2 pred)))) ((eq flag 'lambda) (and (or (eq t (test-completion string table1 pred)) (eq t (test-completion string table2 pred))) t)) ((eq (car-safe flag) 'boundaries) (or (completion-boundaries string table1 pred (cdr flag)) (completion-boundaries string table2 pred (cdr flag)))) ((eq flag 'metadata) '(metadata (display-sort-function . evil-ex-sort-completions))))) (defun evil-ex-sort-completions (completions) (sort completions #'(lambda (str1 str2) (let ((p1 (eq 'evil-ex-commands (get-text-property 0 'face str1))) (p2 (eq 'evil-ex-commands (get-text-property 0 'face str2)))) (if (equal p1 p2) (string< str1 str2) p1))))) (defun evil-ex-command-collection (cmd predicate flag) "Called to complete a command." (let (commands) ;; append ! to all commands that may take a bang argument (dolist (cmd (mapcar #'car evil-ex-commands)) (push cmd commands) (if (evil-ex-command-force-p cmd) (push (concat cmd "!") commands))) (when (eq evil-ex-complete-emacs-commands t) (setq commands (mapcar #'(lambda (str) (propertize str 'face 'evil-ex-commands)) commands))) (cond ((eq flag nil) (try-completion cmd commands predicate)) ((eq flag t) (all-completions cmd commands predicate)) ((eq flag 'lambda) (test-completion cmd commands)) ((eq (car-safe flag) 'boundaries) `(boundaries 0 . ,(length (cdr flag))))))) (defun evil-ex-argument-completion-at-point () (let ((context (evil-ex-syntactic-context (1- (point))))) (when (memq 'argument context) ;; if it's an autoload, load the function; this allows external ;; packages to register autoloaded ex commands which will be ;; loaded when ex argument completion is triggered (let ((binding-definition (symbol-function (evil-ex-binding evil-ex-cmd)))) (when (autoloadp binding-definition) (autoload-do-load binding-definition))) (let* ((beg (or (and evil-ex-argument (get-text-property 0 'ex-index evil-ex-argument)) (point))) (end (1+ (or (and evil-ex-argument (get-text-property (1- (length evil-ex-argument)) 'ex-index evil-ex-argument)) (1- (point))))) (binding (evil-ex-completed-binding evil-ex-cmd)) (arg-type (evil-get-command-property binding :ex-arg)) (arg-handler (assoc arg-type evil-ex-argument-types)) (completer (and arg-handler (evil-ex-argument-handler-completer (cdr arg-handler))))) (when completer (if (eq (car completer) 'collection) (list beg end (cdr completer)) (save-restriction (narrow-to-region beg (point-max)) (funcall (cdr completer))))))))) (defun evil-ex-define-cmd (cmd function) "Binds the function FUNCTION to the command CMD." (save-match-data (if (string-match "^[^][]*\\(\\[\\(.*\\)\\]\\)[^][]*$" cmd) (let ((abbrev (replace-match "" nil t cmd 1)) (full (replace-match "\\2" nil nil cmd 1))) (evil-add-to-alist 'evil-ex-commands full function) (evil-add-to-alist 'evil-ex-commands abbrev full)) (evil-add-to-alist 'evil-ex-commands cmd function)))) (defun evil-ex-make-argument-handler (runner completer) (list runner completer)) (defun evil-ex-argument-handler-runner (arg-handler) (car arg-handler)) (defun evil-ex-argument-handler-completer (arg-handler) (cadr arg-handler)) (defmacro evil-ex-define-argument-type (arg-type doc &rest body) "Defines a new handler for argument-type ARG-TYPE. DOC is the documentation string. It is followed by a list of keywords and function: :collection COLLECTION A collection for completion as required by `all-completions'. :completion-at-point FUNC Function to be called to initialize a potential completion. FUNC must match the requirements as described for the variable `completion-at-point-functions'. When FUNC is called the minibuffer content is narrowed to exactly match the argument. :runner FUNC Function to be called when the type of the current argument changes or when the content of this argument changes. This function should take one obligatory argument FLAG followed by an optional argument ARG. FLAG is one of three symbol 'start, 'stop or 'update. When the argument type is recognized for the first time and this handler is started the FLAG is 'start. If the argument type changes to something else or ex state finished the handler FLAG is 'stop. If the content of the argument has changed FLAG is 'update. If FLAG is either 'start or 'update then ARG is the current value of this argument. If FLAG is 'stop then arg is nil." (declare (indent defun) (doc-string 2) (debug (&define name [&optional stringp] [&rest [keywordp function-form]]))) (unless (stringp doc) (push doc body)) (let (runner completer) (while (keywordp (car-safe body)) (let ((key (pop body)) (func (pop body))) (cond ((eq key :runner) (setq runner func)) ((eq key :collection) (setq completer (cons 'collection func))) ((eq key :completion-at-point) (setq completer (cons 'completion-at-point func)))))) `(eval-and-compile (evil-add-to-alist 'evil-ex-argument-types ',arg-type '(,runner ,completer))))) (evil-ex-define-argument-type file "Handles a file argument." :collection read-file-name-internal) (evil-ex-define-argument-type buffer "Called to complete a buffer name argument." :collection internal-complete-buffer) (declare-function shell-completion-vars "shell" ()) (defun evil-ex-init-shell-argument-completion (flag &optional arg) "Prepares the current minibuffer for completion of shell commands. This function must be called from the :runner function of some argument handler that requires shell completion." (when (and (eq flag 'start) (not evil-ex-shell-argument-initialized)) (set (make-local-variable 'evil-ex-shell-argument-initialized) t) (cond ;; Emacs 24 ((fboundp 'comint-completion-at-point) (shell-completion-vars)) (t (set (make-local-variable 'minibuffer-default-add-function) 'minibuffer-default-add-shell-commands))) (setq completion-at-point-functions '(evil-ex-command-completion-at-point evil-ex-argument-completion-at-point)))) (define-obsolete-function-alias 'evil-ex-shell-command-completion-at-point 'comint-completion-at-point) (evil-ex-define-argument-type shell "Shell argument type, supports completion." :completion-at-point comint-completion-at-point :runner evil-ex-init-shell-argument-completion) (defun evil-ex-file-or-shell-command-completion-at-point () (if (and (< (point-min) (point-max)) (= (char-after (point-min)) ?!)) (save-restriction (narrow-to-region (1+ (point-min)) (point-max)) (comint-completion-at-point)) (list (point-min) (point-max) #'read-file-name-internal))) (evil-ex-define-argument-type file-or-shell "File or shell argument type. If the current argument starts with a ! the rest of the argument is considered a shell command, otherwise a file-name. Completion works accordingly." :completion-at-point evil-ex-file-or-shell-command-completion-at-point :runner evil-ex-init-shell-argument-completion) (defun evil-ex-binding (command &optional noerror) "Returns the final binding of COMMAND." (save-match-data (let ((binding command)) (when binding (string-match "^\\(.+?\\)\\!?$" binding) (setq binding (match-string 1 binding)) (while (progn (setq binding (cdr (assoc binding evil-ex-commands))) (stringp binding))) (unless binding (setq binding (intern command))) (if (commandp binding) ;; check for remaps (or (command-remapping binding) binding) (unless noerror (user-error "Unknown command: `%s'" command))))))) (defun evil-ex-completed-binding (command &optional noerror) "Returns the final binding of the completion of COMMAND." (let ((completion (try-completion command evil-ex-commands))) (evil-ex-binding (if (eq completion t) command (or completion command)) noerror))) ;;; TODO: extensions likes :p :~ ... (defun evil-ex-replace-special-filenames (file-name) "Replace special symbols in FILE-NAME. Replaces % by the current file-name, Replaces # by the alternate file-name in FILE-NAME." (let ((remote (file-remote-p file-name)) (current-fname (buffer-file-name)) (alternate-fname (and (other-buffer) (buffer-file-name (other-buffer))))) (setq file-name (or (file-remote-p file-name 'localname) file-name)) (when current-fname (setq current-fname (or (file-remote-p current-fname 'localname) current-fname)) (setq file-name (replace-regexp-in-string "\\(^\\|[^\\\\]\\)\\(%\\)" current-fname file-name t t 2))) (when alternate-fname (setq alternate-fname (or (file-remote-p alternate-fname 'localname) alternate-fname)) (setq file-name (replace-regexp-in-string "\\(^\\|[^\\\\]\\)\\(#\\)" alternate-fname file-name t t 2))) (setq file-name (replace-regexp-in-string "\\\\\\([#%]\\)" "\\1" file-name t)) (setq file-name (concat remote file-name))) file-name) (defun evil-ex-file-arg () "Returns the current Ex argument as a file name. This function interprets special file names like # and %." (unless (zerop (length evil-ex-argument)) (evil-ex-replace-special-filenames evil-ex-argument))) (defun evil-ex-repeat (count) "Repeats the last ex command." (interactive "P") (when count (goto-char (point-min)) (forward-line (1- count))) (let ((evil-ex-current-buffer (current-buffer)) (hist evil-ex-history)) (while hist (let ((evil-ex-last-cmd (pop hist))) (when evil-ex-last-cmd (evil-ex-update nil nil nil evil-ex-last-cmd) (let ((binding (evil-ex-binding evil-ex-cmd))) (unless (eq binding #'evil-ex-repeat) (setq hist nil) (if evil-ex-expression (eval evil-ex-expression) (user-error "Ex: syntax error"))))))))) (defun evil-ex-call-command (range command argument) "Execute the given command COMMAND." (let* ((count (when (numberp range) range)) (range (when (evil-range-p range) range)) (bang (and (save-match-data (string-match ".!$" command)) t)) (evil-ex-point (point)) (evil-ex-range (or range (and count (evil-ex-range count count)))) (evil-ex-command (evil-ex-completed-binding command)) (evil-ex-bang (and bang t)) (evil-ex-argument (copy-sequence argument)) (evil-this-type (evil-type evil-ex-range)) (current-prefix-arg count) (prefix-arg current-prefix-arg)) (when (stringp evil-ex-argument) (set-text-properties 0 (length evil-ex-argument) nil evil-ex-argument)) (let ((buf (current-buffer))) (unwind-protect (cond ((not evil-ex-range) (setq this-command evil-ex-command) (run-hooks 'pre-command-hook) (call-interactively evil-ex-command) (run-hooks 'post-command-hook)) (t ;; set visual selection to match the region if an explicit ;; range has been specified (let ((ex-range (evil-copy-range evil-ex-range)) beg end) (evil-expand-range ex-range) (setq beg (evil-range-beginning ex-range) end (evil-range-end ex-range)) (evil-sort beg end) (setq this-command evil-ex-command) (run-hooks 'pre-command-hook) (set-mark end) (goto-char beg) (activate-mark) (call-interactively evil-ex-command) (run-hooks 'post-command-hook)))) (when (buffer-live-p buf) (with-current-buffer buf (deactivate-mark))))))) (defun evil-ex-line (base &optional offset) "Return the line number of BASE plus OFFSET." (+ (or base (line-number-at-pos)) (or offset 0))) (defun evil-ex-first-line () "Return the line number of the first line." (line-number-at-pos (point-min))) (defun evil-ex-current-line () "Return the line number of the current line." (line-number-at-pos (point))) (defun evil-ex-last-line () "Return the line number of the last line." (save-excursion (goto-char (point-max)) (when (bolp) (forward-line -1)) (line-number-at-pos))) (defun evil-ex-range (beg-line &optional end-line) "Returns the first and last position of the current range." (evil-range (evil-line-position beg-line) (evil-line-position (or end-line beg-line) -1) 'line :expanded t)) (defun evil-ex-full-range () "Return a range encompassing the whole buffer." (evil-range (point-min) (point-max) 'line)) (defun evil-ex-marker (marker) "Return MARKER's line number in the current buffer. Signal an error if MARKER is in a different buffer." (when (stringp marker) (setq marker (aref marker 0))) (setq marker (evil-get-marker marker)) (if (numberp marker) (line-number-at-pos marker) (user-error "Ex does not support markers in other files"))) (defun evil-ex-char-marker-range (beg end) (when (stringp beg) (setq beg (aref beg 0))) (when (stringp end) (setq end (aref end 0))) (setq beg (evil-get-marker beg) end (evil-get-marker end)) (if (and (numberp beg) (numberp end)) (evil-expand-range (evil-range beg end (if (evil-visual-state-p) (evil-visual-type) 'inclusive))) (user-error "Ex does not support markers in other files"))) (defun evil-ex-re-fwd (pattern) "Search forward for PATTERN. Returns the line number of the match." (condition-case err (save-match-data (save-excursion (set-text-properties 0 (length pattern) nil pattern) (evil-move-end-of-line) (and (re-search-forward pattern nil t) (line-number-at-pos (1- (match-end 0)))))) (invalid-regexp (evil-ex-echo (cadr err)) nil))) (defun evil-ex-re-bwd (pattern) "Search backward for PATTERN. Returns the line number of the match." (condition-case err (save-match-data (save-excursion (set-text-properties 0 (length pattern) nil pattern) (evil-move-beginning-of-line) (and (re-search-backward pattern nil t) (line-number-at-pos (match-beginning 0))))) (invalid-regexp (evil-ex-echo (cadr err)) nil))) (defun evil-ex-prev-search () (error "Previous search not yet implemented")) (defun evil-ex-signed-number (sign &optional number) "Return a signed number like -3 and +1. NUMBER defaults to 1." (funcall sign (or number 1))) ;; function `evil-ex-eval' has been superseded by `evil-ex-parse' plus `eval' (make-obsolete 'evil-ex-eval 'evil-ex-parse "1.2.14") (defun evil-ex-parse (string &optional syntax start) "Parse STRING as an Ex expression and return an evaluation tree. If SYNTAX is non-nil, return a syntax tree instead. START is the start symbol, which defaults to `expression'." (let* ((start (or start (car-safe (car-safe evil-ex-grammar)))) (match (evil-parser string start evil-ex-grammar t syntax))) (car-safe match))) (defun evil-ex-parse-command (string) "Parse STRING as an Ex binding." (let ((result (evil-parser string 'binding evil-ex-grammar)) bang command) (when result (setq command (car-safe result) string (cdr-safe result)) ;; check whether the parsed command is followed by a slash, dash ;; or number and either the part before is NOT known to be a binding, ;; or the complete string IS known to be a binding (when (and (> (length string) 0) (string-match-p "^[-/[:digit:]]" string) (or (evil-ex-binding (concat command string) t) (not (evil-ex-binding command t)))) (setq result (evil-parser (concat command string) 'emacs-binding evil-ex-grammar) command (car-safe result) string (cdr-safe result))) ;; parse a following "!" as bang only if ;; the command has the property :ex-bang t (when (evil-ex-command-force-p command) (setq result (evil-parser string 'bang evil-ex-grammar) bang (or (car-safe result) "") string (cdr-safe result) command (concat command bang))) (cons command string)))) (defun evil-ex-command-force-p (command) "Whether COMMAND accepts the bang argument." (let ((binding (evil-ex-completed-binding command t))) (when binding (evil-get-command-property binding :ex-bang)))) (defun evil-flatten-syntax-tree (tree) "Find all paths from the root of TREE to its leaves. TREE is a syntax tree, i.e., all its leave nodes are strings. The `nth' element in the result is the syntactic context for the corresponding string index (counted from zero)." (let* ((result nil) (traverse nil) (traverse #'(lambda (tree path) (if (stringp tree) (dotimes (char (length tree)) (push path result)) (let ((path (cons (car tree) path))) (dolist (subtree (cdr tree)) (funcall traverse subtree path))))))) (funcall traverse tree nil) (nreverse result))) (defun evil-ex-syntactic-context (&optional pos) "Return the syntactical context of the character at POS. POS defaults to the current position of point." (let* ((contexts (evil-flatten-syntax-tree evil-ex-tree)) (length (length contexts)) (pos (- (or pos (point)) (minibuffer-prompt-end)))) (when (>= pos length) (setq pos (1- length))) (when (< pos 0) (setq pos 0)) (when contexts (nth pos contexts)))) (defun evil-parser (string symbol grammar &optional greedy syntax) "Parse STRING as a SYMBOL in GRAMMAR. If GREEDY is non-nil, the whole of STRING must match. If the parse succeeds, the return value is a cons cell \(RESULT . TAIL), where RESULT is a parse tree and TAIL is the remainder of STRING. Otherwise, the return value is nil. GRAMMAR is an association list of symbols and their definitions. A definition is either a list of production rules, which are tried in succession, or a #'-quoted function, which is called to parse the input. A production rule can be one of the following: nil matches the empty string. A regular expression matches a substring. A symbol matches a production for that symbol. (X Y) matches X followed by Y. (\\? X) matches zero or one of X. (* X) matches zero or more of X. (+ X) matches one or more of X. (& X) matches X, but does not consume. (! X) matches anything but X, but does not consume. Thus, a simple grammar may look like: ((plus \"\\\\+\") ; plus <- \"+\" (minus \"-\") ; minus <- \"-\" (operator plus minus)) ; operator <- plus / minus All input-consuming rules have a value. A regular expression evaluates to the text matched, while a list evaluates to a list of values. The value of a list may be overridden with a semantic action, which is specified with a #'-quoted expression at the end: (X Y #'foo) The value of this rule is the result of calling foo with the values of X and Y as arguments. Alternatively, the function call may be specified explicitly: (X Y #'(foo $1 $2)) Here, $1 refers to X and $2 refers to Y. $0 refers to the whole list. Dollar expressions can also be used directly: (X Y #'$1) This matches X followed by Y, but ignores the value of Y; the value of the list is the same as the value of X. If the SYNTAX argument is non-nil, then all semantic actions are ignored, and a syntax tree is constructed instead. The syntax tree obeys the property that all the leave nodes are parts of the input string. Thus, by traversing the syntax tree, one can determine how each character was parsed. The following symbols have reserved meanings within a grammar: `\\?', `*', `+', `&', `!', `function', `alt', `seq' and nil." (let ((string (or string "")) func pair result rules tail) (cond ;; epsilon ((member symbol '("" nil)) (setq pair (cons (if syntax "" nil) string))) ;; token ((stringp symbol) (save-match-data (when (or (eq (string-match symbol string) 0) ;; ignore leading whitespace (and (eq (string-match "^[ \f\t\n\r\v]+" string) 0) (eq (match-end 0) (string-match symbol string (match-end 0))))) (setq result (match-string 0 string) tail (substring string (match-end 0)) pair (cons result tail)) (when (and syntax pair) (setq result (substring string 0 (- (length string) (length tail)))) (setcar pair result))))) ;; symbol ((symbolp symbol) (let ((context symbol)) (setq rules (cdr-safe (assq symbol grammar))) (setq pair (evil-parser string `(alt ,@rules) grammar greedy syntax)) (when (and syntax pair) (setq result (car pair)) (if (and (listp result) (sequencep (car result))) (setq result `(,symbol ,@result)) (setq result `(,symbol ,result))) (setcar pair result)))) ;; function ((eq (car-safe symbol) 'function) (setq symbol (cadr symbol) pair (funcall symbol string)) (when (and syntax pair) (setq tail (or (cdr pair) "") result (substring string 0 (- (length string) (length tail)))) (setcar pair result))) ;; list ((listp symbol) (setq rules symbol symbol (car-safe rules)) (if (memq symbol '(& ! \? * + alt seq)) (setq rules (cdr rules)) (setq symbol 'seq)) (when (and (memq symbol '(+ alt seq)) (> (length rules) 1)) (setq func (car (last rules))) (if (eq (car-safe func) 'function) (setq rules (delq func (copy-sequence rules)) func (cadr func)) (setq func nil))) (cond ;; positive lookahead ((eq symbol '&) (when (evil-parser string rules grammar greedy syntax) (setq pair (evil-parser string nil grammar nil syntax)))) ;; negative lookahead ((eq symbol '!) (unless (evil-parser string rules grammar greedy syntax) (setq pair (evil-parser string nil grammar nil syntax)))) ;; zero or one ((eq symbol '\?) (setq rules (if (> (length rules) 1) `(alt ,rules nil) `(alt ,@rules nil)) pair (evil-parser string rules grammar greedy syntax))) ;; zero or more ((eq symbol '*) (setq rules `(alt (+ ,@rules) nil) pair (evil-parser string rules grammar greedy syntax))) ;; one or more ((eq symbol '+) (let (current results) (catch 'done (while (setq current (evil-parser string rules grammar nil syntax)) (setq result (car-safe current) tail (or (cdr-safe current) "") results (append results (if syntax result (cdr-safe result)))) ;; stop if stuck (if (equal string tail) (throw 'done nil) (setq string tail)))) (when results (setq func (or func 'list) pair (cons results tail))))) ;; alternatives ((eq symbol 'alt) (catch 'done (dolist (rule rules) (when (setq pair (evil-parser string rule grammar greedy syntax)) (throw 'done pair))))) ;; sequence (t (setq func (or func 'list)) (let ((last (car-safe (last rules))) current results rule) (catch 'done (while rules (setq rule (pop rules) current (evil-parser string rule grammar (when greedy (null rules)) syntax)) (cond ((null current) (setq results nil) (throw 'done nil)) (t (setq result (car-safe current) tail (cdr-safe current)) (unless (memq (car-safe rule) '(& !)) (if (and syntax (or (null result) (and (listp result) (listp rule) ;; splice in single-element ;; (\? ...) expressions (not (and (eq (car-safe rule) '\?) (eq (length rule) 2)))))) (setq results (append results result)) (setq results (append results (list result))))) (setq string (or tail "")))))) (when results (setq pair (cons results tail)))))) ;; semantic action (when (and pair func (not syntax)) (setq result (car pair)) (let* ((dexp #'(lambda (obj) (when (symbolp obj) (let ((str (symbol-name obj))) (save-match-data (when (string-match "\\$\\([0-9]+\\)" str) (string-to-number (match-string 1 str)))))))) ;; traverse a tree for dollar expressions (dval nil) (dval #'(lambda (obj) (if (listp obj) (mapcar dval obj) (let ((num (funcall dexp obj))) (if num (if (not (listp result)) result (if (eq num 0) `(list ,@result) (nth (1- num) result))) obj)))))) (cond ((null func) (setq result nil)) ;; lambda function ((eq (car-safe func) 'lambda) (if (memq symbol '(+ seq)) (setq result `(funcall ,func ,@result)) (setq result `(funcall ,func ,result)))) ;; string replacement ((or (stringp func) (stringp (car-safe func))) (let* ((symbol (or (car-safe (cdr-safe func)) (and (boundp 'context) context) (car-safe (car-safe grammar)))) (string (if (stringp func) func (car-safe func)))) (setq result (car-safe (evil-parser string symbol grammar greedy syntax))))) ;; dollar expression ((funcall dexp func) (setq result (funcall dval func))) ;; function call ((listp func) (setq result (funcall dval func))) ;; symbol (t (if (memq symbol '(+ seq)) (setq result `(,func ,@result)) (setq result `(,func ,result)))))) (setcar pair result)))) ;; weed out incomplete matches (when pair (if (not greedy) pair (if (null (cdr pair)) pair ;; ignore trailing whitespace (when (save-match-data (string-match "^[ \f\t\n\r\v]*$" (cdr pair))) (unless syntax (setcdr pair nil)) pair)))))) (provide 'evil-ex) ;;; evil-ex.el ends here evil-1.12.17/evil-integration.el000066400000000000000000000457601360703323200164370ustar00rootroot00000000000000;;; evil-integration.el --- Integrate Evil with other modules ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . ;;; Commentary: ;; This provides evil integration for various emacs modes. ;; Additional keybindings (or default state) should go into evil-keybindings.el. ;;; Code: (require 'evil-maps) (require 'evil-core) (require 'evil-macros) (require 'evil-types) (require 'evil-repeat) ;;; Evilize some commands ;; unbound keys should be ignored (evil-declare-ignore-repeat 'undefined) (mapc #'(lambda (cmd) (evil-set-command-property cmd :keep-visual t) (evil-declare-not-repeat cmd)) '(digit-argument negative-argument universal-argument universal-argument-minus universal-argument-more universal-argument-other-key)) (mapc #'evil-declare-not-repeat '(what-cursor-position)) (mapc #'evil-declare-change-repeat '(dabbrev-expand hippie-expand quoted-insert)) (mapc #'evil-declare-abort-repeat '(balance-windows eval-expression execute-extended-command exit-minibuffer compile delete-window delete-other-windows find-file-at-point ffap-other-window recompile redo save-buffer split-window split-window-horizontally split-window-vertically undo undo-tree-redo undo-tree-undo)) (evil-set-type #'previous-line 'line) (evil-set-type #'next-line 'line) (dolist (cmd '(keyboard-quit keyboard-escape-quit)) (evil-set-command-property cmd :suppress-operator t)) ;;; Mouse (evil-declare-insert-at-point-repeat 'mouse-yank-primary) (evil-declare-insert-at-point-repeat 'mouse-yank-secondary) ;;; key-binding ;; Calling `keyboard-quit' should cancel repeat (defadvice keyboard-quit (before evil activate) (when (fboundp 'evil-repeat-abort) (evil-repeat-abort))) (eval-after-load 'wdired '(progn (add-hook 'wdired-mode-hook #'evil-change-to-initial-state) (defadvice wdired-change-to-dired-mode (after evil activate) (evil-change-to-initial-state nil t)))) ;;; Parentheses (defadvice show-paren-function (around evil disable) "Match parentheses in Normal state." (if (if (memq 'not evil-highlight-closing-paren-at-point-states) (memq evil-state evil-highlight-closing-paren-at-point-states) (not (memq evil-state evil-highlight-closing-paren-at-point-states))) ad-do-it (let ((pos (point)) syntax narrow) (setq pos (catch 'end (dotimes (var (1+ (* 2 evil-show-paren-range))) (if (zerop (mod var 2)) (setq pos (+ pos var)) (setq pos (- pos var))) (setq syntax (syntax-class (syntax-after pos))) (cond ((eq syntax 4) (setq narrow pos) (throw 'end pos)) ((eq syntax 5) (throw 'end (1+ pos))))))) (if pos (save-excursion (goto-char pos) (save-restriction (when narrow (narrow-to-region narrow (point-max))) ad-do-it)) ;; prevent the preceding pair from being highlighted (dolist (ov '(show-paren--overlay show-paren--overlay-1 show-paren-overlay show-paren-overlay-1)) (let ((ov (and (boundp ov) (symbol-value ov)))) (when (overlayp ov) (delete-overlay ov)))))))) ;;; Undo tree (when (and (require 'undo-tree nil t) (fboundp 'global-undo-tree-mode)) (global-undo-tree-mode 1)) (eval-after-load 'undo-tree '(with-no-warnings (defun evil-turn-on-undo-tree-mode () "Enable `undo-tree-mode' if evil is enabled. This function enables `undo-tree-mode' when Evil is activated in some buffer, but only if `global-undo-tree-mode' is also activated." (when (and (boundp 'global-undo-tree-mode) global-undo-tree-mode) (turn-on-undo-tree-mode))) (add-hook 'evil-local-mode-hook #'evil-turn-on-undo-tree-mode) (defadvice undo-tree-visualize (after evil activate) "Initialize Evil in the visualization buffer." (when evil-local-mode (evil-initialize-state))) (when (fboundp 'undo-tree-visualize) (evil-ex-define-cmd "undol[ist]" 'undo-tree-visualize) (evil-ex-define-cmd "ul" 'undo-tree-visualize)) (when (boundp 'undo-tree-visualizer-mode-map) (define-key undo-tree-visualizer-mode-map [remap evil-backward-char] 'undo-tree-visualize-switch-branch-left) (define-key undo-tree-visualizer-mode-map [remap evil-forward-char] 'undo-tree-visualize-switch-branch-right) (define-key undo-tree-visualizer-mode-map [remap evil-next-line] 'undo-tree-visualize-redo) (define-key undo-tree-visualizer-mode-map [remap evil-previous-line] 'undo-tree-visualize-undo) (define-key undo-tree-visualizer-mode-map [remap evil-ret] 'undo-tree-visualizer-set)) (when (boundp 'undo-tree-visualizer-selection-mode-map) (define-key undo-tree-visualizer-selection-mode-map [remap evil-backward-char] 'undo-tree-visualizer-select-left) (define-key undo-tree-visualizer-selection-mode-map [remap evil-forward-char] 'undo-tree-visualizer-select-right) (define-key undo-tree-visualizer-selection-mode-map [remap evil-next-line] 'undo-tree-visualizer-select-next) (define-key undo-tree-visualizer-selection-mode-map [remap evil-previous-line] 'undo-tree-visualizer-select-previous) (define-key undo-tree-visualizer-selection-mode-map [remap evil-ret] 'undo-tree-visualizer-set)))) ;;; Auto-complete (eval-after-load 'auto-complete '(progn (evil-add-command-properties 'auto-complete :repeat 'evil-ac-repeat) (evil-add-command-properties 'ac-complete :repeat 'evil-ac-repeat) (evil-add-command-properties 'ac-expand :repeat 'evil-ac-repeat) (evil-add-command-properties 'ac-next :repeat 'ignore) (evil-add-command-properties 'ac-previous :repeat 'ignore) (defvar evil-ac-prefix-len nil "The length of the prefix of the current item to be completed.") (defvar ac-prefix) (defun evil-ac-repeat (flag) "Record the changes for auto-completion." (cond ((eq flag 'pre) (setq evil-ac-prefix-len (length ac-prefix)) (evil-repeat-start-record-changes)) ((eq flag 'post) ;; Add change to remove the prefix (evil-repeat-record-change (- evil-ac-prefix-len) "" evil-ac-prefix-len) ;; Add change to insert the full completed text (evil-repeat-record-change (- evil-ac-prefix-len) (buffer-substring-no-properties (- evil-repeat-pos evil-ac-prefix-len) (point)) 0) ;; Finish repeation (evil-repeat-finish-record-changes)))))) ;;; Company (eval-after-load 'company '(progn (mapc #'evil-declare-change-repeat '(company-complete-mouse company-complete-number company-complete-selection company-complete-common)) (mapc #'evil-declare-ignore-repeat '(company-abort company-select-next company-select-previous company-select-next-or-abort company-select-previous-or-abort company-select-mouse company-show-doc-buffer company-show-location company-search-candidates company-filter-candidates)))) ;; Eval last sexp (cond ((version< emacs-version "25") (defadvice preceding-sexp (around evil activate) "In normal-state or motion-state, last sexp ends at point." (if (and (not evil-move-beyond-eol) (or (evil-normal-state-p) (evil-motion-state-p))) (save-excursion (unless (or (eobp) (eolp)) (forward-char)) ad-do-it) ad-do-it)) (defadvice pp-last-sexp (around evil activate) "In normal-state or motion-state, last sexp ends at point." (if (and (not evil-move-beyond-eol) (or (evil-normal-state-p) (evil-motion-state-p))) (save-excursion (unless (or (eobp) (eolp)) (forward-char)) ad-do-it) ad-do-it))) (t (defun evil--preceding-sexp (command &rest args) "In normal-state or motion-state, last sexp ends at point." (if (and (not evil-move-beyond-eol) (or (evil-normal-state-p) (evil-motion-state-p))) (save-excursion (unless (or (eobp) (eolp)) (forward-char)) (apply command args)) (apply command args))) (advice-add 'elisp--preceding-sexp :around 'evil--preceding-sexp '((name . evil))) (advice-add 'pp-last-sexp :around 'evil--preceding-sexp '((name . evil))))) ;; Show key (defadvice quail-show-key (around evil activate) "Temporarily go to Emacs state" (evil-with-state emacs ad-do-it)) (defadvice describe-char (around evil activate) "Temporarily go to Emacs state" (evil-with-state emacs ad-do-it)) ;; ace-jump-mode (declare-function ace-jump-char-mode "ext:ace-jump-mode") (declare-function ace-jump-word-mode "ext:ace-jump-mode") (declare-function ace-jump-line-mode "ext:ace-jump-mode") (defvar evil-ace-jump-active nil) (defmacro evil-enclose-ace-jump-for-motion (&rest body) "Enclose ace-jump to make it suitable for motions. This includes restricting `ace-jump-mode' to the current window in visual and operator state, deactivating visual updates, saving the mark and entering `recursive-edit'." (declare (indent defun) (debug t)) `(let ((old-mark (mark)) (ace-jump-mode-scope (if (and (not (memq evil-state '(visual operator))) (boundp 'ace-jump-mode-scope)) ace-jump-mode-scope 'window))) (remove-hook 'pre-command-hook #'evil-visual-pre-command t) (remove-hook 'post-command-hook #'evil-visual-post-command t) (unwind-protect (let ((evil-ace-jump-active 'prepare)) (add-hook 'ace-jump-mode-end-hook #'evil-ace-jump-exit-recursive-edit) ,@body (when evil-ace-jump-active (setq evil-ace-jump-active t) (recursive-edit))) (remove-hook 'post-command-hook #'evil-ace-jump-exit-recursive-edit) (remove-hook 'ace-jump-mode-end-hook #'evil-ace-jump-exit-recursive-edit) (if (evil-visual-state-p) (progn (add-hook 'pre-command-hook #'evil-visual-pre-command nil t) (add-hook 'post-command-hook #'evil-visual-post-command nil t) (set-mark old-mark)) (push-mark old-mark))))) (eval-after-load 'ace-jump-mode `(defadvice ace-jump-done (after evil activate) (when evil-ace-jump-active (add-hook 'post-command-hook #'evil-ace-jump-exit-recursive-edit)))) (defun evil-ace-jump-exit-recursive-edit () "Exit a recursive edit caused by an evil jump." (cond ((eq evil-ace-jump-active 'prepare) (setq evil-ace-jump-active nil)) (evil-ace-jump-active (remove-hook 'post-command-hook #'evil-ace-jump-exit-recursive-edit) (exit-recursive-edit)))) (evil-define-motion evil-ace-jump-char-mode (count) "Jump visually directly to a char using ace-jump." :type inclusive (evil-without-repeat (let ((pnt (point)) (buf (current-buffer))) (evil-enclose-ace-jump-for-motion (call-interactively 'ace-jump-char-mode)) ;; if we jump backwards, motion type is exclusive, analogously ;; to `evil-find-char-backward' (when (and (equal buf (current-buffer)) (< (point) pnt)) (setq evil-this-type (cond ((eq evil-this-type 'exclusive) 'inclusive) ((eq evil-this-type 'inclusive) 'exclusive))))))) (evil-define-motion evil-ace-jump-char-to-mode (count) "Jump visually to the char in front of a char using ace-jump." :type inclusive (evil-without-repeat (let ((pnt (point)) (buf (current-buffer))) (evil-enclose-ace-jump-for-motion (call-interactively 'ace-jump-char-mode)) (if (and (equal buf (current-buffer)) (< (point) pnt)) (progn (or (eobp) (forward-char)) (setq evil-this-type (cond ((eq evil-this-type 'exclusive) 'inclusive) ((eq evil-this-type 'inclusive) 'exclusive)))) (backward-char))))) (evil-define-motion evil-ace-jump-line-mode (count) "Jump visually to the beginning of a line using ace-jump." :type line :repeat abort (evil-without-repeat (evil-enclose-ace-jump-for-motion (call-interactively 'ace-jump-line-mode)))) (evil-define-motion evil-ace-jump-word-mode (count) "Jump visually to the beginning of a word using ace-jump." :type exclusive :repeat abort (evil-without-repeat (evil-enclose-ace-jump-for-motion (call-interactively 'ace-jump-word-mode)))) (define-key evil-motion-state-map [remap ace-jump-char-mode] #'evil-ace-jump-char-mode) (define-key evil-motion-state-map [remap ace-jump-line-mode] #'evil-ace-jump-line-mode) (define-key evil-motion-state-map [remap ace-jump-word-mode] #'evil-ace-jump-word-mode) ;;; avy (declare-function avy-goto-word-or-subword-1 "ext:avy") (declare-function avy-goto-line "ext:avy") (declare-function avy-goto-char "ext:avy") (declare-function avy-goto-char-2 "ext:avy") (declare-function avy-goto-char-2-above "ext:avy") (declare-function avy-goto-char-2-below "ext:avy") (declare-function avy-goto-char-in-line "ext:avy") (declare-function avy-goto-word-0 "ext:avy") (declare-function avy-goto-word-1 "ext:avy") (declare-function avy-goto-word-1-above "ext:avy") (declare-function avy-goto-word-1-below "ext:avy") (declare-function avy-goto-subword-0 "ext:avy") (declare-function avy-goto-subword-1 "ext:avy") (declare-function avy-goto-char-timer "ext:avy") (defmacro evil-enclose-avy-for-motion (&rest body) "Enclose avy to make it suitable for motions. Based on `evil-enclose-ace-jump-for-motion'." (declare (indent defun) (debug t)) `(let ((avy-all-windows (if (and (not (memq evil-state '(visual operator))) (boundp 'avy-all-windows)) avy-all-windows nil))) ,@body)) (defmacro evil-define-avy-motion (command type) (declare (indent defun) (debug t)) (let ((name (intern (format "evil-%s" command)))) `(evil-define-motion ,name (_count) ,(format "Evil motion for `%s'." command) :type ,type :jump t :repeat abort (evil-without-repeat (evil-enclose-avy-for-motion (call-interactively ',command)))))) ;; define evil-avy-* motion commands for avy-* commands (evil-define-avy-motion avy-goto-char inclusive) (evil-define-avy-motion avy-goto-char-2 inclusive) (evil-define-avy-motion avy-goto-char-2-above inclusive) (evil-define-avy-motion avy-goto-char-2-below inclusive) (evil-define-avy-motion avy-goto-char-in-line inclusive) (evil-define-avy-motion avy-goto-char-timer inclusive) (evil-define-avy-motion avy-goto-line line) (evil-define-avy-motion avy-goto-line-above line) (evil-define-avy-motion avy-goto-line-below line) (evil-define-avy-motion avy-goto-subword-0 exclusive) (evil-define-avy-motion avy-goto-subword-1 exclusive) (evil-define-avy-motion avy-goto-symbol-1 exclusive) (evil-define-avy-motion avy-goto-symbol-1-above exclusive) (evil-define-avy-motion avy-goto-symbol-1-below exclusive) (evil-define-avy-motion avy-goto-word-0 exclusive) (evil-define-avy-motion avy-goto-word-1 exclusive) (evil-define-avy-motion avy-goto-word-1-above exclusive) (evil-define-avy-motion avy-goto-word-1-below exclusive) (evil-define-avy-motion avy-goto-word-or-subword-1 exclusive) ;; remap avy-* commands to evil-avy-* commands (dolist (command '(avy-goto-char avy-goto-char-2 avy-goto-char-2-above avy-goto-char-2-below avy-goto-char-in-line avy-goto-char-timer avy-goto-line avy-goto-line-above avy-goto-line-below avy-goto-subword-0 avy-goto-subword-1 avy-goto-symbol-1 avy-goto-symbol-1-above avy-goto-symbol-1-below avy-goto-word-0 avy-goto-word-1 avy-goto-word-1-above avy-goto-word-1-below avy-goto-word-or-subword-1)) (define-key evil-motion-state-map (vector 'remap command) (intern-soft (format "evil-%s" command)))) ;;; nXhtml/mumamo ;; ensure that mumamo does not toggle evil through its globalized mode (eval-after-load 'mumamo '(with-no-warnings (push 'evil-mode-cmhh mumamo-change-major-mode-no-nos))) ;; visual-line-mode integration (when evil-respect-visual-line-mode (evil-define-command evil-digit-argument-or-evil-beginning-of-visual-line () :digit-argument-redirection evil-beginning-of-visual-line :keep-visual t :repeat nil (interactive) (cond (current-prefix-arg (setq this-command #'digit-argument) (call-interactively #'digit-argument)) (t (let ((target (or (command-remapping #'evil-beginning-of-visual-line) #'evil-beginning-of-visual-line))) (setq this-command 'evil-beginning-of-visual-line) (call-interactively 'evil-beginning-of-visual-line))))) (evil-define-minor-mode-key 'motion 'visual-line-mode "j" 'evil-next-visual-line "gj" 'evil-next-line "k" 'evil-previous-visual-line "gk" 'evil-previous-line "0" 'evil-digit-argument-or-evil-beginning-of-visual-line "g0" 'evil-beginning-of-line "$" 'evil-end-of-visual-line "g$" 'evil-end-of-line "V" 'evil-visual-screen-line)) ;;; abbrev.el (when evil-want-abbrev-expand-on-insert-exit (eval-after-load 'abbrev '(add-hook 'evil-insert-state-exit-hook 'expand-abbrev))) ;;; ElDoc (eval-after-load 'eldoc '(when (fboundp 'eldoc-add-command-completions) (eldoc-add-command-completions "evil-window-"))) (provide 'evil-integration) ;;; evil-integration.el ends here evil-1.12.17/evil-jumps.el000066400000000000000000000302641360703323200152430ustar00rootroot00000000000000;;; evil-jumps.el --- Jump list implementation ;; Author: Bailey Ling ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . (require 'cl-lib) (require 'evil-core) (require 'evil-states) ;;; Code: (defgroup evil-jumps nil "Evil jump list configuration options." :prefix "evil-jumps" :group 'evil) (defcustom evil-jumps-cross-buffers t "When non-nil, the jump commands can cross borders between buffers, otherwise the jump commands act only within the current buffer." :type 'boolean :group 'evil-jumps) (defcustom evil-jumps-max-length 100 "The maximum number of jumps to keep track of." :type 'integer :group 'evil-jumps) (defcustom evil-jumps-pre-jump-hook nil "Hooks to run just before jumping to a location in the jump list." :type 'hook :group 'evil-jumps) (defcustom evil-jumps-post-jump-hook nil "Hooks to run just after jumping to a location in the jump list." :type 'hook :group 'evil-jumps) (defcustom evil-jumps-ignored-file-patterns '("COMMIT_EDITMSG$" "TAGS$") "A list of pattern regexps to match on the file path to exclude from being included in the jump list." :type '(repeat string) :group 'evil-jumps) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defvar savehist-additional-variables) (defvar evil--jumps-jumping nil) (eval-when-compile (defvar evil--jumps-debug nil)) (defvar evil--jumps-buffer-targets "\\*\\(new\\|scratch\\)\\*" "Regexp to match against `buffer-name' to determine whether it's a valid jump target.") (defvar evil--jumps-window-jumps (make-hash-table) "Hashtable which stores all jumps on a per window basis.") (defvar evil-jumps-history nil "History of `evil-mode' jumps that are persisted with `savehist'.") (cl-defstruct evil-jumps-struct ring (idx -1)) (defmacro evil--jumps-message (format &rest args) (when evil--jumps-debug `(with-current-buffer (get-buffer-create "*evil-jumps*") (goto-char (point-max)) (insert (apply #'format ,format ',args) "\n")))) (defun evil--jumps-get-current (&optional window) (unless window (setq window (frame-selected-window))) (let* ((jump-struct (gethash window evil--jumps-window-jumps))) (unless jump-struct (setq jump-struct (make-evil-jumps-struct)) (puthash window jump-struct evil--jumps-window-jumps)) jump-struct)) (defun evil--jumps-get-jumps (struct) (let ((ring (evil-jumps-struct-ring struct))) (unless ring (setq ring (make-ring evil-jumps-max-length)) (setf (evil-jumps-struct-ring struct) ring)) ring)) (defun evil--jumps-get-window-jump-list () (let ((struct (evil--jumps-get-current))) (evil--jumps-get-jumps struct))) (defun evil--jumps-savehist-load () (add-to-list 'savehist-additional-variables 'evil-jumps-history) (let ((ring (make-ring evil-jumps-max-length))) (cl-loop for jump in (reverse evil-jumps-history) do (ring-insert ring jump)) (setf (evil-jumps-struct-ring (evil--jumps-get-current)) ring)) (add-hook 'savehist-save-hook #'evil--jumps-savehist-sync) (remove-hook 'savehist-mode-hook #'evil--jumps-savehist-load)) (defun evil--jumps-savehist-sync () "Updates the printable value of window jumps for `savehist'." (setq evil-jumps-history (cl-remove-if-not #'identity (mapcar #'(lambda (jump) (let* ((mark (car jump)) (pos (if (markerp mark) (marker-position mark) mark)) (file-name (cadr jump))) (if (and (not (file-remote-p file-name)) (file-exists-p file-name) pos) (list pos file-name) nil))) (ring-elements (evil--jumps-get-window-jump-list)))))) (defun evil--jumps-jump (idx shift) (let ((target-list (evil--jumps-get-window-jump-list))) (evil--jumps-message "jumping from %s by %s" idx shift) (evil--jumps-message "target list = %s" target-list) (setq idx (+ idx shift)) (let* ((current-file-name (or (buffer-file-name) (buffer-name))) (size (ring-length target-list))) (unless evil-jumps-cross-buffers ;; skip jump marks pointing to other buffers (while (and (< idx size) (>= idx 0) (not (string= current-file-name (let* ((place (ring-ref target-list idx)) (pos (car place))) (cadr place))))) (setq idx (+ idx shift)))) (when (and (< idx size) (>= idx 0)) ;; actual jump (run-hooks 'evil-jumps-pre-jump-hook) (let* ((place (ring-ref target-list idx)) (pos (car place)) (file-name (cadr place))) (setq evil--jumps-jumping t) (if (string-match-p evil--jumps-buffer-targets file-name) (switch-to-buffer file-name) (find-file file-name)) (setq evil--jumps-jumping nil) (goto-char pos) (setf (evil-jumps-struct-idx (evil--jumps-get-current)) idx) (run-hooks 'evil-jumps-post-jump-hook)))))) (defun evil--jumps-push () "Pushes the current cursor/file position to the jump list." (let ((target-list (evil--jumps-get-window-jump-list))) (let ((file-name (buffer-file-name)) (buffer-name (buffer-name)) (current-pos (point-marker)) (first-pos nil) (first-file-name nil) (excluded nil)) (when (and (not file-name) (string-match-p evil--jumps-buffer-targets buffer-name)) (setq file-name buffer-name)) (when file-name (dolist (pattern evil-jumps-ignored-file-patterns) (when (string-match-p pattern file-name) (setq excluded t))) (unless excluded (unless (ring-empty-p target-list) (setq first-pos (car (ring-ref target-list 0))) (setq first-file-name (car (cdr (ring-ref target-list 0))))) (unless (and (equal first-pos current-pos) (equal first-file-name file-name)) (evil--jumps-message "pushing %s on %s" current-pos file-name) (ring-insert target-list `(,current-pos ,file-name)))))) (evil--jumps-message "%s %s" (selected-window) (and (not (ring-empty-p target-list)) (ring-ref target-list 0))))) (evil-define-command evil-show-jumps () "Display the contents of the jump list." :repeat nil (evil-with-view-list :name "evil-jumps" :mode "Evil Jump List" :format [("Jump" 5 nil) ("Marker" 8 nil) ("File/text" 1000 t)] :entries (let* ((jumps (evil--jumps-savehist-sync)) (count 0)) (cl-loop for jump in jumps collect `(nil [,(number-to-string (cl-incf count)) ,(number-to-string (car jump)) (,(cadr jump))]))) :select-action #'evil--show-jumps-select-action)) (defun evil--show-jumps-select-action (jump) (let ((position (string-to-number (elt jump 1))) (file (car (elt jump 2)))) (kill-buffer) (switch-to-buffer (find-file file)) (goto-char position))) (defun evil-set-jump (&optional pos) "Set jump point at POS. POS defaults to point." (unless (or (region-active-p) (evil-visual-state-p)) (push-mark pos t)) (unless evil--jumps-jumping ;; clear out intermediary jumps when a new one is set (let* ((struct (evil--jumps-get-current)) (target-list (evil--jumps-get-jumps struct)) (idx (evil-jumps-struct-idx struct))) (cl-loop repeat idx do (ring-remove target-list)) (setf (evil-jumps-struct-idx struct) -1)) (save-excursion (when pos (goto-char pos)) (evil--jumps-push)))) (defun evil--jump-backward (count) (let ((count (or count 1))) (evil-motion-loop (nil count) (let* ((struct (evil--jumps-get-current)) (idx (evil-jumps-struct-idx struct))) (evil--jumps-message "jumping back %s" idx) (when (= idx -1) (setq idx 0) (setf (evil-jumps-struct-idx struct) 0) (evil--jumps-push)) (evil--jumps-jump idx 1))))) (defun evil--jump-forward (count) (let ((count (or count 1))) (evil-motion-loop (nil count) (let* ((struct (evil--jumps-get-current)) (idx (evil-jumps-struct-idx struct))) (when (= idx -1) (setq idx 0) (setf (evil-jumps-struct-idx struct) 0) (evil--jumps-push)) (evil--jumps-jump idx -1))))) (defun evil--jumps-window-configuration-hook (&rest args) (let* ((window-list (window-list-1 nil nil t)) (existing-window (selected-window)) (new-window (previous-window))) (when (and (not (eq existing-window new-window)) (> (length window-list) 1)) (let* ((target-jump-struct (evil--jumps-get-current new-window)) (target-jump-count (ring-length (evil--jumps-get-jumps target-jump-struct)))) (if (not (ring-empty-p (evil--jumps-get-jumps target-jump-struct))) (evil--jumps-message "target window %s already has %s jumps" new-window target-jump-count) (evil--jumps-message "new target window detected; copying %s to %s" existing-window new-window) (let* ((source-jump-struct (evil--jumps-get-current existing-window)) (source-list (evil--jumps-get-jumps source-jump-struct))) (when (= (ring-length (evil--jumps-get-jumps target-jump-struct)) 0) (setf (evil-jumps-struct-idx target-jump-struct) (evil-jumps-struct-idx source-jump-struct)) (setf (evil-jumps-struct-ring target-jump-struct) (ring-copy source-list))))))) ;; delete obsolete windows (maphash (lambda (key val) (unless (member key window-list) (evil--jumps-message "removing %s" key) (remhash key evil--jumps-window-jumps))) evil--jumps-window-jumps))) (defun evil--jump-hook (&optional command) "Set jump point if COMMAND has a non-nil :jump property." (setq command (or command this-command)) (when (evil-get-command-property command :jump) (evil-set-jump))) (defadvice switch-to-buffer (before evil-jumps activate) (evil-set-jump)) (defadvice split-window-internal (before evil-jumps activate) (evil-set-jump)) (eval-after-load 'etags '(defadvice find-tag-noselect (before evil-jumps activate) (evil-set-jump))) (if (bound-and-true-p savehist-loaded) (evil--jumps-savehist-load) (add-hook 'savehist-mode-hook #'evil--jumps-savehist-load)) (add-hook 'evil-local-mode-hook (lambda () (if evil-local-mode (progn (add-hook 'pre-command-hook #'evil--jump-hook nil t) (add-hook 'next-error-hook #'evil-set-jump nil t) (add-hook 'window-configuration-change-hook #'evil--jumps-window-configuration-hook nil t)) (progn (remove-hook 'pre-command-hook #'evil--jump-hook t) (remove-hook 'next-error-hook #'evil-set-jump t) (remove-hook 'window-configuration-change-hook #'evil--jumps-window-configuration-hook t))))) (provide 'evil-jumps) ;;; evil-jumps.el ends here evil-1.12.17/evil-keybindings.el000066400000000000000000000064311360703323200164120ustar00rootroot00000000000000;;; evil-keybindings.el --- Add some Evil keybindings to other modules ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . ;;; Commentary: ;; This provides a set of keybindings for other emacs modes. This also includes ;; setting up the initial evil state of those other modes. ;;; Code: (require 'evil-maps) (require 'evil-core) (require 'evil-macros) (require 'evil-types) (require 'evil-repeat) ;; etags-select ;; FIXME: probably etags-select should be recomended in docs (eval-after-load 'etags-select '(progn (define-key evil-motion-state-map "g]" 'etags-select-find-tag-at-point))) ;;; Buffer-menu (evil-add-hjkl-bindings Buffer-menu-mode-map 'motion) ;; dictionary.el (evil-add-hjkl-bindings dictionary-mode-map 'motion "?" 'dictionary-help ; "h" "C-o" 'dictionary-previous) ; "l" ;;; Dired (eval-after-load 'dired '(progn ;; use the standard Dired bindings as a base (defvar dired-mode-map) (evil-make-overriding-map dired-mode-map 'normal) (evil-add-hjkl-bindings dired-mode-map 'normal "J" 'dired-goto-file ; "j" "K" 'dired-do-kill-lines ; "k" "r" 'dired-do-redisplay ; "l" ;; ":d", ":v", ":s", ":e" ";" (lookup-key dired-mode-map ":")))) ;;; ERT (evil-add-hjkl-bindings ert-results-mode-map 'motion) ;;; Info (evil-add-hjkl-bindings Info-mode-map 'motion "0" 'evil-digit-argument-or-evil-beginning-of-line (kbd "\M-h") 'Info-help ; "h" "\C-t" 'Info-history-back ; "l" "\C-o" 'Info-history-back " " 'Info-scroll-up "\C-]" 'Info-follow-nearest-node (kbd "DEL") 'Info-scroll-down) ;;; Speedbar (evil-add-hjkl-bindings speedbar-key-map 'motion "h" 'backward-char "j" 'speedbar-next "k" 'speedbar-prev "l" 'forward-char "i" 'speedbar-item-info "r" 'speedbar-refresh "u" 'speedbar-up-directory "o" 'speedbar-toggle-line-expansion (kbd "RET") 'speedbar-edit-line) ;; Ibuffer (eval-after-load 'ibuffer '(progn (defvar ibuffer-mode-map) (evil-make-overriding-map ibuffer-mode-map 'normal) (evil-define-key 'normal ibuffer-mode-map "j" 'evil-next-line "k" 'evil-previous-line "RET" 'ibuffer-visit-buffer))) ;;; ag.el (eval-after-load 'ag '(progn (defvar ag-mode-map) (add-to-list 'evil-motion-state-modes 'ag-mode) (evil-add-hjkl-bindings ag-mode-map 'motion))) ;;; ELP (eval-after-load 'elp '(defadvice elp-results (after evil activate) (evil-motion-state))) (provide 'evil-keybindings) ;;; evil-keybindings.el ends here evil-1.12.17/evil-macros.el000066400000000000000000000756321360703323200154010ustar00rootroot00000000000000;;; evil-macros.el --- Macros ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . (require 'evil-common) (require 'evil-states) (require 'evil-repeat) ;;; Code: (declare-function evil-ex-p "evil-ex") ;; set some error codes (put 'beginning-of-line 'error-conditions '(beginning-of-line error)) (put 'beginning-of-line 'error-message "Beginning of line") (put 'end-of-line 'error-conditions '(end-of-line error)) (put 'end-of-line 'error-message "End of line") (defun evil-motion-range (motion &optional count type) "Execute a motion and return the buffer positions. The return value is a list (BEG END TYPE)." (let ((opoint (point)) (omark (mark t)) (omactive (and (boundp 'mark-active) mark-active)) (obuffer (current-buffer)) (evil-motion-marker (move-marker (make-marker) (point))) range) (evil-with-transient-mark-mode (evil-narrow-to-field (unwind-protect (let ((current-prefix-arg count) ;; Store type in global variable `evil-this-type'. ;; If necessary, motions can change their type ;; during execution by setting this variable. (evil-this-type (or type (evil-type motion 'exclusive)))) (condition-case err (let ((repeat-type (evil-repeat-type motion t))) (if (functionp repeat-type) (funcall repeat-type 'pre)) (unless (with-local-quit (setq range (call-interactively motion)) t) (evil-repeat-abort) (setq quit-flag t)) (if (functionp repeat-type) (funcall repeat-type 'post))) (error (prog1 nil (evil-repeat-abort) ;; some operators depend on succeeding ;; motions, in particular for ;; `evil-forward-char' (e.g., used by ;; `evil-substitute'), therefore we let ;; end-of-line and end-of-buffer pass (if (not (memq (car err) '(end-of-line end-of-buffer))) (signal (car err) (cdr err)) (message (error-message-string err)))))) (cond ;; the motion returned a range ((evil-range-p range)) ;; the motion made a Visual selection ((evil-visual-state-p) (setq range (evil-visual-range))) ;; the motion made an active region ((region-active-p) (setq range (evil-range (region-beginning) (region-end) evil-this-type))) ;; default: range from previous position to current (t (setq range (evil-expand-range (evil-normalize evil-motion-marker (point) evil-this-type))))) (unless (or (null type) (eq (evil-type range) type)) (evil-set-type range type) (evil-expand-range range)) (evil-set-range-properties range nil) range) ;; restore point and mark like `save-excursion', ;; but only if the motion hasn't disabled the operator (unless evil-inhibit-operator (set-buffer obuffer) (evil-move-mark omark) (goto-char opoint)) ;; delete marker so it doesn't slow down editing (move-marker evil-motion-marker nil)))))) (defmacro evil-define-motion (motion args &rest body) "Define an motion command MOTION. \(fn MOTION (COUNT ARGS...) DOC [[KEY VALUE]...] BODY...)" (declare (indent defun) (doc-string 3) (debug (&define name lambda-list [&optional stringp] [&rest keywordp sexp] [&optional ("interactive" [&rest form])] def-body))) (let (arg doc interactive key keys type) (when args (setq args `(&optional ,@(delq '&optional args)) ;; the count is either numerical or nil interactive '(""))) ;; collect docstring (when (and (> (length body) 1) (or (eq (car-safe (car-safe body)) 'format) (stringp (car-safe body)))) (setq doc (pop body))) ;; collect keywords (setq keys (plist-put keys :repeat 'motion)) (while (keywordp (car-safe body)) (setq key (pop body) arg (pop body) keys (plist-put keys key arg))) ;; collect `interactive' specification (when (eq (car-safe (car-safe body)) 'interactive) (setq interactive (cdr (pop body)))) ;; macro expansion `(progn ;; refresh echo area in Eldoc mode (when ',motion (eval-after-load 'eldoc '(and (fboundp 'eldoc-add-command) (eldoc-add-command ',motion)))) (evil-define-command ,motion (,@args) ,@(when doc `(,doc)) ; avoid nil before `interactive' ,@keys :keep-visual t (interactive ,@interactive) ,@body)))) (defmacro evil-narrow-to-line (&rest body) "Narrow BODY to the current line. BODY will signal the errors 'beginning-of-line or 'end-of-line upon reaching the beginning or end of the current line. \(fn [[KEY VAL]...] BODY...)" (declare (indent defun) (debug t)) `(let* ((range (evil-expand (point) (point) 'line)) (beg (evil-range-beginning range)) (end (evil-range-end range)) (min (point-min)) (max (point-max))) (when (save-excursion (goto-char end) (bolp)) (setq end (max beg (1- end)))) ;; don't include the newline in Normal state (when (and (not evil-move-beyond-eol) (not (evil-visual-state-p)) (not (evil-operator-state-p))) (setq end (max beg (1- end)))) (evil-with-restriction beg end (evil-signal-without-movement (condition-case err (progn ,@body) (beginning-of-buffer (if (= beg min) (signal (car err) (cdr err)) (signal 'beginning-of-line nil))) (end-of-buffer (if (= end max) (signal (car err) (cdr err)) (signal 'end-of-line nil)))))))) ;; we don't want line boundaries to trigger the debugger ;; when `debug-on-error' is t (add-to-list 'debug-ignored-errors "^Beginning of line$") (add-to-list 'debug-ignored-errors "^End of line$") (defun evil-eobp (&optional pos) "Whether point is at end-of-buffer with regard to end-of-line." (save-excursion (when pos (goto-char pos)) (cond ((eobp)) ;; the rest only pertains to Normal state ((not (evil-normal-state-p)) nil) ;; at the end of the last line ((eolp) (forward-char) (eobp)) ;; at the last character of the last line (t (forward-char) (cond ((eobp)) ((eolp) (forward-char) (eobp))))))) (defun evil-move-beginning (count forward &optional backward) "Move to the beginning of the COUNT next object. If COUNT is negative, move to the COUNT previous object. FORWARD is a function which moves to the end of the object, and BACKWARD is a function which moves to the beginning. If one is unspecified, the other is used with a negative argument." (let* ((count (or count 1)) (backward (or backward #'(lambda (count) (funcall forward (- count))))) (forward (or forward #'(lambda (count) (funcall backward (- count))))) (opoint (point))) (cond ((< count 0) (when (bobp) (signal 'beginning-of-buffer nil)) (unwind-protect (evil-motion-loop (nil count count) (funcall backward 1)) (unless (zerop count) (goto-char (point-min))))) ((> count 0) (when (evil-eobp) (signal 'end-of-buffer nil)) ;; Do we need to move past the current object? (when (<= (save-excursion (funcall forward 1) (funcall backward 1) (point)) opoint) (setq count (1+ count))) (unwind-protect (evil-motion-loop (nil count count) (funcall forward 1)) (if (zerop count) ;; go back to beginning of object (funcall backward 1) (goto-char (point-max))))) (t count)))) (defun evil-move-end (count forward &optional backward inclusive) "Move to the end of the COUNT next object. If COUNT is negative, move to the COUNT previous object. FORWARD is a function which moves to the end of the object, and BACKWARD is a function which moves to the beginning. If one is unspecified, the other is used with a negative argument. If INCLUSIVE is non-nil, then point is placed at the last character of the object; otherwise it is placed at the end of the object." (let* ((count (or count 1)) (backward (or backward #'(lambda (count) (funcall forward (- count))))) (forward (or forward #'(lambda (count) (funcall backward (- count))))) (opoint (point))) (cond ((< count 0) (when (bobp) (signal 'beginning-of-buffer nil)) ;; Do we need to move past the current object? (when (>= (save-excursion (funcall backward 1) (funcall forward 1) (point)) (if inclusive (1+ opoint) opoint)) (setq count (1- count))) (unwind-protect (evil-motion-loop (nil count count) (funcall backward 1)) (if (not (zerop count)) (goto-char (point-min)) ;; go to end of object (funcall forward 1) (when inclusive (unless (bobp) (backward-char))) (when (or (evil-normal-state-p) (evil-motion-state-p)) (evil-adjust-cursor))))) ((> count 0) (when (evil-eobp) (signal 'end-of-buffer nil)) (when inclusive (forward-char)) (unwind-protect (evil-motion-loop (nil count count) (funcall forward 1)) (if (not (zerop count)) (goto-char (point-max)) (when inclusive (unless (bobp) (backward-char))) (when (or (evil-normal-state-p) (evil-motion-state-p)) (evil-adjust-cursor))))) (t count)))) (defun evil-text-object-make-linewise (range) "Turn the text object selection RANGE to linewise. The selection is adjusted in a sensible way so that the selected lines match the user intent. In particular, whitespace-only parts at the first and last lines are omitted. This function returns the new range." ;; Bug #607 ;; If new type is linewise and the selection of the ;; first line consists of whitespace only, the ;; beginning is moved to the start of the next line. If ;; the selections of the last line consists of ;; whitespace only, the end is moved to the end of the ;; previous line. (if (eq (evil-type range) 'line) range (let ((expanded (plist-get (evil-range-properties range) :expanded)) (newrange (evil-expand-range range t))) (save-excursion ;; skip whitespace at the beginning (goto-char (evil-range-beginning newrange)) (skip-chars-forward " \t") (when (and (not (bolp)) (eolp)) (evil-set-range-beginning newrange (1+ (point)))) ;; skip whitepsace at the end (goto-char (evil-range-end newrange)) (skip-chars-backward " \t") (when (and (not (eolp)) (bolp)) (evil-set-range-end newrange (1- (point)))) ;; only modify range if result is not empty (if (> (evil-range-beginning newrange) (evil-range-end newrange)) range (unless expanded (evil-contract-range newrange)) newrange))))) (defmacro evil-define-text-object (object args &rest body) "Define a text object command OBJECT. BODY should return a range (BEG END) to the right of point if COUNT is positive, and to the left of it if negative. \(fn OBJECT (COUNT) DOC [[KEY VALUE]...] BODY...)" (declare (indent defun) (doc-string 3) (debug (&define name lambda-list [&optional stringp] [&rest keywordp sexp] def-body))) (let* ((args (delq '&optional args)) (count (or (pop args) 'count)) (args (when args `(&optional ,@args))) (interactive '((interactive ""))) arg doc key keys) ;; collect docstring (when (stringp (car-safe body)) (setq doc (pop body))) ;; collect keywords (setq keys (plist-put keys :extend-selection t)) (while (keywordp (car-safe body)) (setq key (pop body) arg (pop body) keys (plist-put keys key arg))) ;; interactive (when (eq (car-safe (car-safe body)) 'interactive) (setq interactive (list (pop body)))) ;; macro expansion `(evil-define-motion ,object (,count ,@args) ,@(when doc `(,doc)) ,@keys ,@interactive (setq ,count (or ,count 1)) (when (/= ,count 0) (let ((type (evil-type ',object evil-visual-char)) (extend (and (evil-visual-state-p) (evil-get-command-property ',object :extend-selection ',(plist-get keys :extend-selection)))) (dir evil-visual-direction) mark point range selection) (cond ;; Visual state: extend the current selection ((and (evil-visual-state-p) (called-interactively-p 'any)) ;; if we are at the beginning of the Visual selection, ;; go to the left (negative COUNT); if at the end, ;; go to the right (positive COUNT) (setq dir evil-visual-direction ,count (* ,count dir)) (setq range (progn ,@body)) (when (evil-range-p range) (setq range (evil-expand-range range)) (evil-set-type range (evil-type range type)) (setq range (evil-contract-range range)) ;; the beginning is mark and the end is point ;; unless the selection goes the other way (setq mark (evil-range-beginning range) point (evil-range-end range) type (evil-type (if evil-text-object-change-visual-type range (evil-visual-range)))) (when (and (eq type 'line) (not (eq type (evil-type range)))) (let ((newrange (evil-text-object-make-linewise range))) (setq mark (evil-range-beginning newrange) point (evil-range-end newrange)))) (when (< dir 0) (evil-swap mark point)) ;; select the union (evil-visual-make-selection mark point type))) ;; not Visual state: return a pair of buffer positions (t (setq range (progn ,@body)) (unless (evil-range-p range) (setq ,count (- ,count) range (progn ,@body))) (when (evil-range-p range) (setq selection (evil-range (point) (point) type)) (if extend (setq range (evil-range-union range selection)) (evil-set-type range (evil-type range type))) ;; possibly convert to linewise (when (eq evil-this-type-modified 'line) (setq range (evil-text-object-make-linewise range))) (evil-set-range-properties range nil) range)))))))) (defmacro evil-define-operator (operator args &rest body) "Define an operator command OPERATOR. \(fn OPERATOR (BEG END ARGS...) DOC [[KEY VALUE]...] BODY...)" (declare (indent defun) (doc-string 3) (debug (&define name lambda-list [&optional stringp] [&rest keywordp sexp] [&optional ("interactive" [&rest form])] def-body))) (let* ((args (delq '&optional args)) (interactive (if (> (length args) 2) '("") '(""))) (args (if (> (length args) 2) `(,(nth 0 args) ,(nth 1 args) &optional ,@(nthcdr 2 args)) args)) arg doc key keys visual) ;; collect docstring (when (and (> (length body) 1) (or (eq (car-safe (car-safe body)) 'format) (stringp (car-safe body)))) (setq doc (pop body))) ;; collect keywords (setq keys (plist-put keys :move-point t)) (while (keywordp (car-safe body)) (setq key (pop body) arg (pop body)) (cond ((eq key :keep-visual) (setq visual arg)) (t (setq keys (plist-put keys key arg))))) ;; collect `interactive' specification (when (eq (car-safe (car-safe body)) 'interactive) (setq interactive (cdr-safe (pop body)))) ;; transform extended interactive specs (setq interactive (apply #'evil-interactive-form interactive)) (setq keys (evil-concat-plists keys (cdr-safe interactive)) interactive (car-safe interactive)) ;; macro expansion `(evil-define-command ,operator ,args ,@(when doc `(,doc)) ,@keys :keep-visual t :suppress-operator t (interactive (let* ((evil-operator-range-motion (when (evil-has-command-property-p ',operator :motion) ;; :motion nil is equivalent to :motion undefined (or (evil-get-command-property ',operator :motion) #'undefined))) (evil-operator-range-type (evil-get-command-property ',operator :type)) (orig (point)) evil-operator-range-beginning evil-operator-range-end evil-inhibit-operator) (setq evil-inhibit-operator-value nil evil-this-operator this-command) (prog1 ,interactive (setq orig (point) evil-inhibit-operator-value evil-inhibit-operator) (if ,visual (when (evil-visual-state-p) (evil-visual-expand-region)) (when (or (evil-visual-state-p) (region-active-p)) (setq deactivate-mark t))) (cond ((evil-visual-state-p) (evil-visual-rotate 'upper-left)) ((evil-get-command-property ',operator :move-point) (goto-char (or evil-operator-range-beginning orig))) (t (goto-char orig)))))) (unwind-protect (let ((evil-inhibit-operator evil-inhibit-operator-value)) (unless (and evil-inhibit-operator (called-interactively-p 'any)) ,@body)) (setq evil-inhibit-operator-value nil))))) ;; this is used in the `interactive' specification of an operator command (defun evil-operator-range (&optional return-type) "Read a motion from the keyboard and return its buffer positions. The return value is a list (BEG END), or (BEG END TYPE) if RETURN-TYPE is non-nil." (let* ((evil-ex-p (and (not (minibufferp)) (evil-ex-p))) (motion (or evil-operator-range-motion (when evil-ex-p 'evil-line))) (type evil-operator-range-type) (range (evil-range (point) (point))) command count modifier) (setq evil-this-type-modified nil) (evil-save-echo-area (cond ;; Ex mode ((and evil-ex-p evil-ex-range) (setq range evil-ex-range)) ;; Visual selection ((and (not evil-ex-p) (evil-visual-state-p)) (setq range (evil-visual-range))) ;; active region ((and (not evil-ex-p) (region-active-p)) (setq range (evil-range (region-beginning) (region-end) (or evil-this-type 'exclusive)))) (t ;; motion (evil-save-state (unless motion (evil-change-state 'operator) ;; Make linewise operator shortcuts. E.g., "d" yields the ;; shortcut "dd", and "g?" yields shortcuts "g??" and "g?g?". (let ((keys (nth 2 (evil-extract-count (this-command-keys))))) (setq keys (listify-key-sequence keys)) (dotimes (var (length keys)) (define-key evil-operator-shortcut-map (vconcat (nthcdr var keys)) 'evil-line-or-visual-line))) ;; read motion from keyboard (setq command (evil-read-motion motion) motion (nth 0 command) count (nth 1 command) type (or type (nth 2 command)))) (cond ((eq motion #'undefined) (setq range (if return-type '(nil nil nil) '(nil nil)) motion nil)) ((or (null motion) ; keyboard-quit (evil-get-command-property motion :suppress-operator)) (when (fboundp 'evil-repeat-abort) (evil-repeat-abort)) (setq quit-flag t motion nil)) (evil-repeat-count (setq count evil-repeat-count ;; only the first operator's count is overwritten evil-repeat-count nil)) ((or count current-prefix-arg) ;; multiply operator count and motion count together (setq count (* (prefix-numeric-value count) (prefix-numeric-value current-prefix-arg))))) (when motion (let ((evil-state 'operator) mark-active) ;; calculate motion range (setq range (evil-motion-range motion count type)))) ;; update global variables (setq evil-this-motion motion evil-this-motion-count count type (evil-type range type) evil-this-type type)))) (when (evil-range-p range) (unless (or (null type) (eq (evil-type range) type)) (evil-contract-range range) (evil-set-type range type) (evil-expand-range range)) (evil-set-range-properties range nil) (unless return-type (evil-set-type range nil)) (setq evil-operator-range-beginning (evil-range-beginning range) evil-operator-range-end (evil-range-end range) evil-operator-range-type (evil-type range))) range))) (defmacro evil-define-type (type doc &rest body) "Define type TYPE. DOC is a general description and shows up in all docstrings. It is followed by a list of keywords and functions: :expand FUNC Expansion function. This function should accept two positions in the current buffer, BEG and END, and return a pair of expanded buffer positions. :contract FUNC The opposite of :expand, optional. :one-to-one BOOL Whether expansion is one-to-one. This means that :expand followed by :contract always returns the original range. :normalize FUNC Normalization function, optional. This function should accept two unexpanded positions and adjust them before expansion. May be used to deal with buffer boundaries. :string FUNC Description function. This takes two buffer positions and returns a human-readable string, for example, \"2 lines\". If further keywords and functions are specified, they are assumed to be transformations on buffer positions, like :expand and :contract. \(fn TYPE DOC [[KEY FUNC]...])" (declare (indent defun) (doc-string 2) (debug (&define name [&optional stringp] [&rest [keywordp function-form]]))) (let (args defun-forms func key name plist string sym val) ;; standard values (setq plist (plist-put plist :one-to-one t)) ;; keywords (while (keywordp (car-safe body)) (setq key (pop body) val (pop body)) (if (plist-member plist key) ; not a function (setq plist (plist-put plist key val)) (setq func val sym (intern (replace-regexp-in-string "^:" "" (symbol-name key))) name (intern (format "evil-%s-%s" type sym)) args (car (cdr-safe func)) string (car (cdr (cdr-safe func))) string (if (stringp string) (format "%s\n\n" string) "") plist (plist-put plist key `',name)) (add-to-list 'defun-forms (cond ((eq key :string) `(defun ,name (beg end &rest properties) ,(format "Return size of %s from BEG to END \ with PROPERTIES.\n\n%s%s" type string doc) (let ((beg (evil-normalize-position beg)) (end (evil-normalize-position end)) (type ',type) plist range) (when (and beg end) (save-excursion (evil-sort beg end) (unless (plist-get properties :expanded) (setq range (apply #'evil-expand beg end type properties) beg (evil-range-beginning range) end (evil-range-end range) type (evil-type range type) plist (evil-range-properties range)) (setq properties (evil-concat-plists properties plist))) (or (apply #',func beg end (when ,(> (length args) 2) properties)) "")))))) (t `(defun ,name (beg end &rest properties) ,(format "Perform %s transformation on %s from BEG to END \ with PROPERTIES.\n\n%s%s" sym type string doc) (let ((beg (evil-normalize-position beg)) (end (evil-normalize-position end)) (type ',type) plist range) (when (and beg end) (save-excursion (evil-sort beg end) (when (memq ,key '(:expand :contract)) (setq properties (plist-put properties :expanded ,(eq key :expand)))) (setq range (or (apply #',func beg end (when ,(> (length args) 2) properties)) (apply #'evil-range beg end type properties)) beg (evil-range-beginning range) end (evil-range-end range) type (evil-type range type) plist (evil-range-properties range)) (setq properties (evil-concat-plists properties plist)) (apply #'evil-range beg end type properties))))))) t))) ;; :one-to-one requires both or neither of :expand and :contract (when (plist-get plist :expand) (setq plist (plist-put plist :one-to-one (and (plist-get plist :contract) (plist-get plist :one-to-one))))) `(progn (evil-put-property 'evil-type-properties ',type ,@plist) ,@defun-forms ',type))) (defmacro evil-define-interactive-code (code &rest body) "Define an interactive code. PROMPT, if given, is the remainder of the interactive string up to the next newline. Command properties may be specified via KEY-VALUE pairs. BODY should evaluate to a list of values. \(fn CODE (PROMPT) [[KEY VALUE]...] BODY...)" (declare (indent defun)) (let* ((args (when (and (> (length body) 1) (listp (car-safe body))) (pop body))) (doc (when (stringp (car-safe body)) (pop body))) func properties) (while (keywordp (car-safe body)) (setq properties (append properties (list (pop body) (pop body))))) (cond (args (setq func `(lambda ,args ,@(when doc `(,doc)) ,@body))) ((> (length body) 1) (setq func `(progn ,@body))) (t (setq func (car body)))) `(eval-and-compile (let* ((code ,code) (entry (assoc code evil-interactive-alist)) (value (cons ',func ',properties))) (if entry (setcdr entry value) (push (cons code value) evil-interactive-alist)) code)))) ;;; Highlighting (when (fboundp 'font-lock-add-keywords) (font-lock-add-keywords 'emacs-lisp-mode ;; Match all `evil-define-' forms except `evil-define-key'. ;; (In the interests of speed, this expression is incomplete ;; and does not match all three-letter words.) '(("(\\(evil-\\(?:ex-\\)?define-\ \\(?:[^ k][^ e][^ y]\\|[-[:word:]]\\{4,\\}\\)\\)\ \\>[ \f\t\n\r\v]*\\(\\(?:\\sw\\|\\s_\\)+\\)?" (1 font-lock-keyword-face) (2 font-lock-function-name-face nil t)) ("(\\(evil-\\(?:delay\\|narrow\\|signal\\|save\\|with\\(?:out\\)?\\)\ \\(?:-[-[:word:]]+\\)?\\)\\>\[ \f\t\n\r\v]+" 1 font-lock-keyword-face) ("(\\(evil-\\(?:[-[:word:]]\\)*loop\\)\\>[ \f\t\n\r\v]+" 1 font-lock-keyword-face)))) (provide 'evil-macros) ;;; evil-macros.el ends here evil-1.12.17/evil-maps.el000066400000000000000000000703011360703323200150410ustar00rootroot00000000000000;;; evil-maps.el --- Default keymaps ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . (require 'evil-states) (require 'evil-ex) (require 'evil-commands) (require 'evil-command-window) (require 'evil-common) ;;; Code: ;;; Normal state (define-key evil-normal-state-map "a" 'evil-append) (define-key evil-normal-state-map "A" 'evil-append-line) (define-key evil-normal-state-map "c" 'evil-change) (define-key evil-normal-state-map "C" 'evil-change-line) (define-key evil-normal-state-map "d" 'evil-delete) (define-key evil-normal-state-map "D" 'evil-delete-line) (define-key evil-normal-state-map "i" 'evil-insert) (define-key evil-normal-state-map (kbd "") 'evil-insert) (define-key evil-normal-state-map (kbd "") 'evil-insert) (define-key evil-normal-state-map "I" 'evil-insert-line) (define-key evil-normal-state-map "J" 'evil-join) (define-key evil-normal-state-map "m" 'evil-set-marker) (define-key evil-normal-state-map "o" 'evil-open-below) (define-key evil-normal-state-map "O" 'evil-open-above) (define-key evil-normal-state-map "p" 'evil-paste-after) (define-key evil-normal-state-map "P" 'evil-paste-before) (define-key evil-normal-state-map "q" 'evil-record-macro) (define-key evil-normal-state-map "r" 'evil-replace) (define-key evil-normal-state-map "R" 'evil-replace-state) (define-key evil-normal-state-map "s" 'evil-substitute) (define-key evil-normal-state-map "S" 'evil-change-whole-line) (define-key evil-normal-state-map "x" 'evil-delete-char) (define-key evil-normal-state-map "X" 'evil-delete-backward-char) (define-key evil-normal-state-map [deletechar] 'evil-delete-char) (define-key evil-normal-state-map "y" 'evil-yank) (define-key evil-normal-state-map "Y" 'evil-yank-line) (define-key evil-normal-state-map "&" 'evil-ex-repeat-substitute) (define-key evil-normal-state-map "g&" 'evil-ex-repeat-global-substitute) (define-key evil-normal-state-map "g8" 'what-cursor-position) (define-key evil-normal-state-map "ga" 'what-cursor-position) (define-key evil-normal-state-map "gi" 'evil-insert-resume) (define-key evil-normal-state-map "gJ" 'evil-join-whitespace) (define-key evil-normal-state-map "gq" 'evil-fill-and-move) (define-key evil-normal-state-map "gw" 'evil-fill) (define-key evil-normal-state-map "gu" 'evil-downcase) (define-key evil-normal-state-map "gU" 'evil-upcase) (define-key evil-normal-state-map "gf" 'find-file-at-point) (define-key evil-normal-state-map "gF" 'evil-find-file-at-point-with-line) (define-key evil-normal-state-map "gx" 'browse-url-at-point) (define-key evil-normal-state-map "g?" 'evil-rot13) (define-key evil-normal-state-map "g~" 'evil-invert-case) (define-key evil-normal-state-map "zo" 'evil-open-fold) (define-key evil-normal-state-map "zO" 'evil-open-fold-rec) (define-key evil-normal-state-map "zc" 'evil-close-fold) (define-key evil-normal-state-map "za" 'evil-toggle-fold) (define-key evil-normal-state-map "zr" 'evil-open-folds) (define-key evil-normal-state-map "zm" 'evil-close-folds) (define-key evil-normal-state-map "z=" 'ispell-word) (define-key evil-normal-state-map "\C-n" 'evil-paste-pop-next) (define-key evil-normal-state-map "\C-p" 'evil-paste-pop) (define-key evil-normal-state-map "\C-t" 'pop-tag-mark) (define-key evil-normal-state-map (kbd "C-.") 'evil-repeat-pop) (define-key evil-normal-state-map (kbd "M-.") 'evil-repeat-pop-next) (define-key evil-normal-state-map "." 'evil-repeat) (define-key evil-normal-state-map "@" 'evil-execute-macro) (define-key evil-normal-state-map "\"" 'evil-use-register) (define-key evil-normal-state-map "~" 'evil-invert-char) (define-key evil-normal-state-map "=" 'evil-indent) (define-key evil-normal-state-map "<" 'evil-shift-left) (define-key evil-normal-state-map ">" 'evil-shift-right) (define-key evil-normal-state-map "ZZ" 'evil-save-modified-and-close) (define-key evil-normal-state-map "ZQ" 'evil-quit) (define-key evil-normal-state-map (kbd "DEL") 'evil-backward-char) (define-key evil-normal-state-map [escape] 'evil-force-normal-state) (define-key evil-normal-state-map [remap cua-paste-pop] 'evil-paste-pop) (define-key evil-normal-state-map [remap yank-pop] 'evil-paste-pop) (when (featurep 'tab-bar) (define-key evil-normal-state-map "gt" 'tab-bar-switch-to-next-tab) (define-key evil-normal-state-map "gT" 'tab-bar-switch-to-prev-tab)) ;; go to last change (define-key evil-normal-state-map "g;" 'goto-last-change) (define-key evil-normal-state-map "g," 'goto-last-change-reverse) ;; undo (define-key evil-normal-state-map "u" 'undo) (define-key evil-normal-state-map "\C-r" 'redo) ;; window commands (define-prefix-command 'evil-window-map) (define-key evil-window-map "b" 'evil-window-bottom-right) (define-key evil-window-map "c" 'evil-window-delete) (define-key evil-window-map "h" 'evil-window-left) (define-key evil-window-map "H" 'evil-window-move-far-left) (define-key evil-window-map "j" 'evil-window-down) (define-key evil-window-map "J" 'evil-window-move-very-bottom) (define-key evil-window-map "k" 'evil-window-up) (define-key evil-window-map "K" 'evil-window-move-very-top) (define-key evil-window-map "l" 'evil-window-right) (define-key evil-window-map "L" 'evil-window-move-far-right) (define-key evil-window-map "n" 'evil-window-new) (define-key evil-window-map "o" 'delete-other-windows) (define-key evil-window-map "p" 'evil-window-mru) (define-key evil-window-map "q" 'evil-quit) (define-key evil-window-map "r" 'evil-window-rotate-downwards) (define-key evil-window-map "R" 'evil-window-rotate-upwards) (define-key evil-window-map "s" 'evil-window-split) (define-key evil-window-map "S" 'evil-window-split) (define-key evil-window-map "t" 'evil-window-top-left) (define-key evil-window-map "v" 'evil-window-vsplit) (define-key evil-window-map "w" 'evil-window-next) (define-key evil-window-map "W" 'evil-window-prev) (define-key evil-window-map "+" 'evil-window-increase-height) (define-key evil-window-map "-" 'evil-window-decrease-height) (define-key evil-window-map "_" 'evil-window-set-height) (define-key evil-window-map "<" 'evil-window-decrease-width) (define-key evil-window-map ">" 'evil-window-increase-width) (define-key evil-window-map "=" 'balance-windows) (define-key evil-window-map "|" 'evil-window-set-width) (define-key evil-window-map "\C-b" 'evil-window-bottom-right) (define-key evil-window-map "\C-c" 'evil-window-delete) (define-key evil-window-map (kbd "C-S-h") 'evil-window-move-far-left) (define-key evil-window-map (kbd "C-S-j") 'evil-window-move-very-bottom) (define-key evil-window-map (kbd "C-S-k") 'evil-window-move-very-top) (define-key evil-window-map (kbd "C-S-l") 'evil-window-move-far-right) (define-key evil-window-map "\C-n" 'evil-window-new) (define-key evil-window-map "\C-o" 'delete-other-windows) (define-key evil-window-map "\C-p" 'evil-window-mru) (define-key evil-window-map "\C-r" 'evil-window-rotate-downwards) (define-key evil-window-map (kbd "C-S-r") 'evil-window-rotate-upwards) (define-key evil-window-map "\C-s" 'evil-window-split) (define-key evil-window-map (kbd "C-S-s") 'evil-window-split) (define-key evil-window-map "\C-t" 'evil-window-top-left) (define-key evil-window-map "\C-v" 'evil-window-vsplit) (define-key evil-window-map "\C-w" 'evil-window-next) (define-key evil-window-map (kbd "C-S-W") 'evil-window-prev) (define-key evil-window-map "\C-_" 'evil-window-set-height) (define-key evil-window-map "\C-f" 'ffap-other-window) ;;; Motion state ;; "0" is a special command when called first (evil-redirect-digit-argument evil-motion-state-map "0" 'evil-beginning-of-line) (define-key evil-motion-state-map "1" 'digit-argument) (define-key evil-motion-state-map "2" 'digit-argument) (define-key evil-motion-state-map "3" 'digit-argument) (define-key evil-motion-state-map "4" 'digit-argument) (define-key evil-motion-state-map "5" 'digit-argument) (define-key evil-motion-state-map "6" 'digit-argument) (define-key evil-motion-state-map "7" 'digit-argument) (define-key evil-motion-state-map "8" 'digit-argument) (define-key evil-motion-state-map "9" 'digit-argument) (define-key evil-motion-state-map "b" 'evil-backward-word-begin) (define-key evil-motion-state-map "B" 'evil-backward-WORD-begin) (define-key evil-motion-state-map "e" 'evil-forward-word-end) (define-key evil-motion-state-map "E" 'evil-forward-WORD-end) (define-key evil-motion-state-map "f" 'evil-find-char) (define-key evil-motion-state-map "F" 'evil-find-char-backward) (define-key evil-motion-state-map "G" 'evil-goto-line) (define-key evil-motion-state-map "h" 'evil-backward-char) (define-key evil-motion-state-map "H" 'evil-window-top) (define-key evil-motion-state-map "j" 'evil-next-line) (define-key evil-motion-state-map "k" 'evil-previous-line) (define-key evil-motion-state-map "l" 'evil-forward-char) (define-key evil-motion-state-map " " 'evil-forward-char) (define-key evil-motion-state-map "K" 'evil-lookup) (define-key evil-motion-state-map "L" 'evil-window-bottom) (define-key evil-motion-state-map "M" 'evil-window-middle) (define-key evil-motion-state-map "n" 'evil-search-next) (define-key evil-motion-state-map "N" 'evil-search-previous) (define-key evil-motion-state-map "t" 'evil-find-char-to) (define-key evil-motion-state-map "T" 'evil-find-char-to-backward) (define-key evil-motion-state-map "w" 'evil-forward-word-begin) (define-key evil-motion-state-map "W" 'evil-forward-WORD-begin) (define-key evil-motion-state-map "y" 'evil-yank) (define-key evil-motion-state-map "Y" 'evil-yank-line) (define-key evil-motion-state-map "gd" 'evil-goto-definition) (define-key evil-motion-state-map "ge" 'evil-backward-word-end) (define-key evil-motion-state-map "gE" 'evil-backward-WORD-end) (define-key evil-motion-state-map "gg" 'evil-goto-first-line) (define-key evil-motion-state-map "gj" 'evil-next-visual-line) (define-key evil-motion-state-map "gk" 'evil-previous-visual-line) (define-key evil-motion-state-map "g0" 'evil-beginning-of-visual-line) (define-key evil-motion-state-map "g_" 'evil-last-non-blank) (define-key evil-motion-state-map "g^" 'evil-first-non-blank-of-visual-line) (define-key evil-motion-state-map "gm" 'evil-middle-of-visual-line) (define-key evil-motion-state-map "g$" 'evil-end-of-visual-line) (define-key evil-motion-state-map "g\C-]" 'evil-jump-to-tag) (define-key evil-motion-state-map "{" 'evil-backward-paragraph) (define-key evil-motion-state-map "}" 'evil-forward-paragraph) (define-key evil-motion-state-map "#" 'evil-search-word-backward) (define-key evil-motion-state-map "g#" 'evil-search-unbounded-word-backward) (define-key evil-motion-state-map "$" 'evil-end-of-line) (define-key evil-motion-state-map "%" 'evil-jump-item) (define-key evil-motion-state-map "`" 'evil-goto-mark) (define-key evil-motion-state-map "'" 'evil-goto-mark-line) (define-key evil-motion-state-map "(" 'evil-backward-sentence-begin) (define-key evil-motion-state-map ")" 'evil-forward-sentence-begin) (define-key evil-motion-state-map "]]" 'evil-forward-section-begin) (define-key evil-motion-state-map "][" 'evil-forward-section-end) (define-key evil-motion-state-map "[[" 'evil-backward-section-begin) (define-key evil-motion-state-map "[]" 'evil-backward-section-end) (define-key evil-motion-state-map "[(" 'evil-previous-open-paren) (define-key evil-motion-state-map "])" 'evil-next-close-paren) (define-key evil-motion-state-map "[{" 'evil-previous-open-brace) (define-key evil-motion-state-map "]}" 'evil-next-close-brace) (define-key evil-motion-state-map "]s" 'evil-next-flyspell-error) (define-key evil-motion-state-map "[s" 'evil-prev-flyspell-error) (define-key evil-motion-state-map "*" 'evil-search-word-forward) (define-key evil-motion-state-map "g*" 'evil-search-unbounded-word-forward) (define-key evil-motion-state-map "," 'evil-repeat-find-char-reverse) (define-key evil-motion-state-map "/" 'evil-search-forward) (define-key evil-motion-state-map ";" 'evil-repeat-find-char) (define-key evil-motion-state-map "?" 'evil-search-backward) (define-key evil-motion-state-map "|" 'evil-goto-column) (define-key evil-motion-state-map "^" 'evil-first-non-blank) (define-key evil-motion-state-map "+" 'evil-next-line-first-non-blank) (define-key evil-motion-state-map "_" 'evil-next-line-1-first-non-blank) (define-key evil-motion-state-map "-" 'evil-previous-line-first-non-blank) (define-key evil-motion-state-map "\C-w" 'evil-window-map) (define-key evil-motion-state-map (kbd "C-6") 'evil-switch-to-windows-last-buffer) (define-key evil-motion-state-map "\C-]" 'evil-jump-to-tag) (define-key evil-motion-state-map (kbd "C-b") 'evil-scroll-page-up) (define-key evil-motion-state-map (kbd "C-e") 'evil-scroll-line-down) (define-key evil-motion-state-map (kbd "C-f") 'evil-scroll-page-down) (define-key evil-motion-state-map (kbd "C-o") 'evil-jump-backward) (define-key evil-motion-state-map (kbd "C-y") 'evil-scroll-line-up) (define-key evil-motion-state-map (kbd "RET") 'evil-ret) (define-key evil-motion-state-map "\\" 'evil-execute-in-emacs-state) (define-key evil-motion-state-map "z^" 'evil-scroll-top-line-to-bottom) (define-key evil-motion-state-map "z+" 'evil-scroll-bottom-line-to-top) (define-key evil-motion-state-map "zt" 'evil-scroll-line-to-top) ;; TODO: z RET has an advanced form taking an count before the RET ;; but this requires again a special state with a single command ;; bound to RET (define-key evil-motion-state-map (vconcat "z" [return]) "zt^") (define-key evil-motion-state-map (kbd "z RET") (vconcat "z" [return])) (define-key evil-motion-state-map "zz" 'evil-scroll-line-to-center) (define-key evil-motion-state-map "z." "zz^") (define-key evil-motion-state-map "zb" 'evil-scroll-line-to-bottom) (define-key evil-motion-state-map "z-" "zb^") (define-key evil-motion-state-map "v" 'evil-visual-char) (define-key evil-motion-state-map "V" 'evil-visual-line) (define-key evil-motion-state-map "\C-v" 'evil-visual-block) (define-key evil-motion-state-map "gv" 'evil-visual-restore) (define-key evil-motion-state-map (kbd "C-^") 'evil-buffer) (define-key evil-motion-state-map [left] 'evil-backward-char) (define-key evil-motion-state-map [right] 'evil-forward-char) (define-key evil-motion-state-map [up] 'evil-previous-line) (define-key evil-motion-state-map [down] 'evil-next-line) (define-key evil-motion-state-map "zl" 'evil-scroll-column-right) (define-key evil-motion-state-map [?z right] "zl") (define-key evil-motion-state-map "zh" 'evil-scroll-column-left) (define-key evil-motion-state-map [?z left] "zh") (define-key evil-motion-state-map "zL" 'evil-scroll-right) (define-key evil-motion-state-map "zH" 'evil-scroll-left) (define-key evil-motion-state-map (read-kbd-macro evil-toggle-key) 'evil-emacs-state) ;; text objects (define-key evil-outer-text-objects-map "w" 'evil-a-word) (define-key evil-outer-text-objects-map "W" 'evil-a-WORD) (define-key evil-outer-text-objects-map "s" 'evil-a-sentence) (define-key evil-outer-text-objects-map "p" 'evil-a-paragraph) (define-key evil-outer-text-objects-map "b" 'evil-a-paren) (define-key evil-outer-text-objects-map "(" 'evil-a-paren) (define-key evil-outer-text-objects-map ")" 'evil-a-paren) (define-key evil-outer-text-objects-map "[" 'evil-a-bracket) (define-key evil-outer-text-objects-map "]" 'evil-a-bracket) (define-key evil-outer-text-objects-map "B" 'evil-a-curly) (define-key evil-outer-text-objects-map "{" 'evil-a-curly) (define-key evil-outer-text-objects-map "}" 'evil-a-curly) (define-key evil-outer-text-objects-map "<" 'evil-an-angle) (define-key evil-outer-text-objects-map ">" 'evil-an-angle) (define-key evil-outer-text-objects-map "'" 'evil-a-single-quote) (define-key evil-outer-text-objects-map "\"" 'evil-a-double-quote) (define-key evil-outer-text-objects-map "`" 'evil-a-back-quote) (define-key evil-outer-text-objects-map "t" 'evil-a-tag) (define-key evil-outer-text-objects-map "o" 'evil-a-symbol) (define-key evil-inner-text-objects-map "w" 'evil-inner-word) (define-key evil-inner-text-objects-map "W" 'evil-inner-WORD) (define-key evil-inner-text-objects-map "s" 'evil-inner-sentence) (define-key evil-inner-text-objects-map "p" 'evil-inner-paragraph) (define-key evil-inner-text-objects-map "b" 'evil-inner-paren) (define-key evil-inner-text-objects-map "(" 'evil-inner-paren) (define-key evil-inner-text-objects-map ")" 'evil-inner-paren) (define-key evil-inner-text-objects-map "[" 'evil-inner-bracket) (define-key evil-inner-text-objects-map "]" 'evil-inner-bracket) (define-key evil-inner-text-objects-map "B" 'evil-inner-curly) (define-key evil-inner-text-objects-map "{" 'evil-inner-curly) (define-key evil-inner-text-objects-map "}" 'evil-inner-curly) (define-key evil-inner-text-objects-map "<" 'evil-inner-angle) (define-key evil-inner-text-objects-map ">" 'evil-inner-angle) (define-key evil-inner-text-objects-map "'" 'evil-inner-single-quote) (define-key evil-inner-text-objects-map "\"" 'evil-inner-double-quote) (define-key evil-inner-text-objects-map "`" 'evil-inner-back-quote) (define-key evil-inner-text-objects-map "t" 'evil-inner-tag) (define-key evil-inner-text-objects-map "o" 'evil-inner-symbol) (define-key evil-motion-state-map "gn" 'evil-next-match) (define-key evil-motion-state-map "gN" 'evil-previous-match) (when evil-want-C-i-jump (define-key evil-motion-state-map (kbd "C-i") 'evil-jump-forward)) (when evil-want-C-u-scroll (define-key evil-motion-state-map (kbd "C-u") 'evil-scroll-up)) (when evil-want-C-d-scroll (define-key evil-motion-state-map (kbd "C-d") 'evil-scroll-down)) ;;; Visual state (define-key evil-visual-state-map "A" 'evil-append) (define-key evil-visual-state-map "I" 'evil-insert) (define-key evil-visual-state-map "o" 'exchange-point-and-mark) (define-key evil-visual-state-map "O" 'evil-visual-exchange-corners) (define-key evil-visual-state-map "R" 'evil-change) (define-key evil-visual-state-map "u" 'evil-downcase) (define-key evil-visual-state-map "U" 'evil-upcase) (define-key evil-visual-state-map "z=" 'ispell-word) (define-key evil-visual-state-map "a" evil-outer-text-objects-map) (define-key evil-visual-state-map "i" evil-inner-text-objects-map) (define-key evil-visual-state-map (kbd "") 'undefined) (define-key evil-visual-state-map (kbd "") 'undefined) (define-key evil-visual-state-map [remap evil-repeat] 'undefined) (define-key evil-visual-state-map [escape] 'evil-exit-visual-state) ;;; Operator-Pending state (define-key evil-operator-state-map "a" evil-outer-text-objects-map) (define-key evil-operator-state-map "i" evil-inner-text-objects-map) ;; (define-key evil-operator-state-map [escape] 'keyboard-quit) ;;; Insert state (defvar evil-insert-state-bindings `(("\C-v" . quoted-insert) ("\C-k" . evil-insert-digraph) ("\C-o" . evil-execute-in-normal-state) ("\C-r" . evil-paste-from-register) ("\C-y" . evil-copy-from-above) ("\C-e" . evil-copy-from-below) ("\C-n" . evil-complete-next) ("\C-p" . evil-complete-previous) ("\C-x\C-n" . evil-complete-next-line) ("\C-x\C-p" . evil-complete-previous-line) ("\C-t" . evil-shift-right-line) ("\C-d" . evil-shift-left-line) ("\C-a" . evil-paste-last-insertion) ([remap delete-backward-char] . evil-delete-backward-char-and-join) ,(if evil-want-C-w-delete '("\C-w" . evil-delete-backward-word) '("\C-w" . evil-window-map)) ([mouse-2] . mouse-yank-primary)) "Evil's bindings for insert state (for `evil-insert-state-map'), excluding , , and `evil-toggle-key'.") (defun evil-update-insert-state-bindings (&optional _option-name remove force) "Update bindings in `evil-insert-state-map'. If no arguments are given add the bindings specified in `evil-insert-state-bindings'. If REMOVE is non nil, remove only these bindings. Unless FORCE is non nil, this will not overwriting existing bindings, which means bindings will not be added if one already exists for a key and only default bindings are removed. Note that , and `evil-toggle-key' are not included in `evil-insert-state-bindings' by default." (interactive) (dolist (binding evil-insert-state-bindings) (cond ((and remove (or force ;; Only remove if the default binding has not changed (eq (evil-lookup-key evil-insert-state-map (car binding)) (cdr binding)))) (define-key evil-insert-state-map (car binding) nil)) ((and (null remove) (or force ;; Check to see that nothing is bound here before adding (not (evil-lookup-key evil-insert-state-map (car binding))))) (define-key evil-insert-state-map (car binding) (cdr binding)))))) (define-key evil-insert-state-map [delete] 'delete-char) (define-key evil-insert-state-map [escape] 'evil-normal-state) (define-key evil-insert-state-map (read-kbd-macro evil-toggle-key) 'evil-emacs-state) ;;; Replace state (define-key evil-replace-state-map (kbd "DEL") 'evil-replace-backspace) (define-key evil-replace-state-map [escape] 'evil-normal-state) ;;; Emacs state (define-key evil-emacs-state-map (read-kbd-macro evil-toggle-key) 'evil-exit-emacs-state) (when evil-want-C-w-in-emacs-state (define-key evil-emacs-state-map "\C-w" 'evil-window-map)) ;;; Mouse (define-key evil-motion-state-map [down-mouse-1] 'evil-mouse-drag-region) (define-key evil-visual-state-map [mouse-2] 'evil-exit-visual-and-repeat) (define-key evil-normal-state-map [mouse-2] 'mouse-yank-primary) ;; Ex (define-key evil-motion-state-map ":" 'evil-ex) (define-key evil-motion-state-map "!" 'evil-shell-command) (evil-ex-define-cmd "e[dit]" 'evil-edit) (evil-ex-define-cmd "w[rite]" 'evil-write) (evil-ex-define-cmd "wa[ll]" 'evil-write-all) (evil-ex-define-cmd "sav[eas]" 'evil-save) (evil-ex-define-cmd "r[ead]" 'evil-read) (evil-ex-define-cmd "b[uffer]" 'evil-buffer) (evil-ex-define-cmd "bn[ext]" 'evil-next-buffer) (evil-ex-define-cmd "bp[revious]" 'evil-prev-buffer) (evil-ex-define-cmd "bN[ext]" "bprevious") (evil-ex-define-cmd "sb[uffer]" 'evil-split-buffer) (evil-ex-define-cmd "sbn[ext]" 'evil-split-next-buffer) (evil-ex-define-cmd "sbp[revious]" 'evil-split-prev-buffer) (evil-ex-define-cmd "sbN[ext]" "sbprevious") (evil-ex-define-cmd "buffers" 'buffer-menu) (evil-ex-define-cmd "files" 'evil-show-files) (evil-ex-define-cmd "ls" "buffers") (evil-ex-define-cmd "c[hange]" 'evil-change) (evil-ex-define-cmd "co[py]" 'evil-copy) (evil-ex-define-cmd "t" "copy") (evil-ex-define-cmd "m[ove]" 'evil-move) (evil-ex-define-cmd "d[elete]" 'evil-ex-delete) (evil-ex-define-cmd "y[ank]" 'evil-ex-yank) (evil-ex-define-cmd "go[to]" 'evil-goto-char) (evil-ex-define-cmd "j[oin]" 'evil-ex-join) (evil-ex-define-cmd "le[ft]" 'evil-align-left) (evil-ex-define-cmd "ri[ght]" 'evil-align-right) (evil-ex-define-cmd "ce[nter]" 'evil-align-center) (evil-ex-define-cmd "sp[lit]" 'evil-window-split) (evil-ex-define-cmd "vs[plit]" 'evil-window-vsplit) (evil-ex-define-cmd "new" 'evil-window-new) (evil-ex-define-cmd "ene[w]" 'evil-buffer-new) (evil-ex-define-cmd "vne[w]" 'evil-window-vnew) (evil-ex-define-cmd "clo[se]" 'evil-window-delete) (evil-ex-define-cmd "on[ly]" 'delete-other-windows) (evil-ex-define-cmd "q[uit]" 'evil-quit) (evil-ex-define-cmd "wq" 'evil-save-and-close) (evil-ex-define-cmd "quita[ll]" 'evil-quit-all) (evil-ex-define-cmd "qa[ll]" "quitall") (evil-ex-define-cmd "cq[uit]" 'evil-quit-all-with-error-code) (evil-ex-define-cmd "wqa[ll]" 'evil-save-and-quit) (evil-ex-define-cmd "xa[ll]" "wqall") (evil-ex-define-cmd "x[it]" 'evil-save-modified-and-close) (evil-ex-define-cmd "exi[t]" 'evil-save-modified-and-close) (evil-ex-define-cmd "bd[elete]" 'evil-delete-buffer) (evil-ex-define-cmd "bw[ipeout]" 'evil-delete-buffer) (evil-ex-define-cmd "g[lobal]" 'evil-ex-global) (evil-ex-define-cmd "v[global]" 'evil-ex-global-inverted) (evil-ex-define-cmd "norm[al]" 'evil-ex-normal) (evil-ex-define-cmd "s[ubstitute]" 'evil-ex-substitute) (evil-ex-define-cmd "&" 'evil-ex-repeat-substitute) (evil-ex-define-cmd "&&" 'evil-ex-repeat-substitute-with-flags) (evil-ex-define-cmd "~" 'evil-ex-repeat-substitute-with-search) (evil-ex-define-cmd "~&" 'evil-ex-repeat-substitute-with-search-and-flags) (evil-ex-define-cmd "registers" 'evil-show-registers) (evil-ex-define-cmd "marks" 'evil-show-marks) (evil-ex-define-cmd "delm[arks]" 'evil-delete-marks) (evil-ex-define-cmd "ju[mps]" 'evil-show-jumps) (evil-ex-define-cmd "noh[lsearch]" 'evil-ex-nohighlight) (evil-ex-define-cmd "f[ile]" 'evil-show-file-info) (evil-ex-define-cmd "<" 'evil-shift-left) (evil-ex-define-cmd ">" 'evil-shift-right) (evil-ex-define-cmd "=" 'evil-ex-line-number) (evil-ex-define-cmd "!" 'evil-shell-command) (evil-ex-define-cmd "@:" 'evil-ex-repeat) (evil-ex-define-cmd "mak[e]" 'evil-make) (evil-ex-define-cmd "cc" 'evil-goto-error) (evil-ex-define-cmd "cfir[st]" 'first-error) (evil-ex-define-cmd "cr[ewind]" 'first-error) (evil-ex-define-cmd "cn[ext]" 'next-error) (evil-ex-define-cmd "cp[revious]" 'previous-error) (evil-ex-define-cmd "set-initial-state" 'evil-ex-set-initial-state) (evil-ex-define-cmd "show-digraphs" 'evil-ex-show-digraphs) (evil-ex-define-cmd "sor[t]" 'evil-ex-sort) (evil-ex-define-cmd "res[ize]" 'evil-ex-resize) (when (featurep 'tab-bar) (evil-ex-define-cmd "tabnew" 'tab-bar-new-tab) (evil-ex-define-cmd "tabn[ext]" 'tab-bar-switch-to-next-tab) (evil-ex-define-cmd "tabp[revious]" 'tab-bar-switch-to-prev-tab)) ;; search command line (define-key evil-ex-search-keymap "\d" #'evil-ex-delete-backward-char) (define-key evil-ex-search-keymap "\C-r" 'evil-paste-from-register) (define-key evil-ex-search-keymap "\C-n" 'next-history-element) (define-key evil-ex-search-keymap "\C-p" 'previous-history-element) ;; ex command line (define-key evil-ex-completion-map "\d" #'evil-ex-delete-backward-char) (define-key evil-ex-completion-map "\t" #'evil-ex-completion) (define-key evil-ex-completion-map [tab] #'evil-ex-completion) (define-key evil-ex-completion-map [remap completion-at-point] #'evil-ex-completion) (define-key evil-ex-completion-map "\C-a" 'evil-ex-completion) (define-key evil-ex-completion-map "\C-b" 'move-beginning-of-line) (define-key evil-ex-completion-map "\C-c" 'abort-recursive-edit) (define-key evil-ex-completion-map "\C-d" 'evil-ex-completion) (define-key evil-ex-completion-map "\C-g" 'abort-recursive-edit) (define-key evil-ex-completion-map "\C-k" 'evil-insert-digraph) (define-key evil-ex-completion-map "\C-l" 'evil-ex-completion) (define-key evil-ex-completion-map "\C-p" #'previous-complete-history-element) (define-key evil-ex-completion-map "\C-r" 'evil-paste-from-register) (define-key evil-ex-completion-map "\C-n" #'next-complete-history-element) (define-key evil-ex-completion-map "\C-u" 'evil-delete-whole-line) (define-key evil-ex-completion-map "\C-v" #'quoted-insert) (define-key evil-ex-completion-map "\C-w" 'backward-kill-word) (define-key evil-ex-completion-map [escape] 'abort-recursive-edit) (define-key evil-ex-completion-map [S-left] 'backward-word) (define-key evil-ex-completion-map [S-right] 'forward-word) (define-key evil-ex-completion-map [up] 'previous-complete-history-element) (define-key evil-ex-completion-map [down] 'next-complete-history-element) (define-key evil-ex-completion-map [prior] 'previous-history-element) (define-key evil-ex-completion-map [next] 'next-history-element) (define-key evil-ex-completion-map [return] 'exit-minibuffer) (define-key evil-ex-completion-map (kbd "RET") 'exit-minibuffer) ;; evil-read-key (define-key evil-read-key-map (kbd "ESC") #'keyboard-quit) (define-key evil-read-key-map (kbd "C-]") #'keyboard-quit) (define-key evil-read-key-map (kbd "C-g") #'keyboard-quit) (define-key evil-read-key-map (kbd "C-q") #'evil-read-quoted-char) (define-key evil-read-key-map (kbd "C-v") #'evil-read-quoted-char) (define-key evil-read-key-map (kbd "C-k") #'evil-read-digraph-char) (define-key evil-read-key-map "\r" "\n") ;; command line window (evil-define-key 'normal evil-command-window-mode-map (kbd "RET") 'evil-command-window-execute) (evil-define-key 'insert evil-command-window-mode-map (kbd "RET") 'evil-command-window-execute) (provide 'evil-maps) ;;; evil-maps.el ends here evil-1.12.17/evil-pkg.el000066400000000000000000000002351360703323200146610ustar00rootroot00000000000000(define-package "evil" "1.12.17" "Extensible Vi layer for Emacs." '((emacs "24.1") (undo-tree "0.6.3") (goto-chg "1.6") (cl-lib "0.5"))) evil-1.12.17/evil-repeat.el000066400000000000000000000620001360703323200153560ustar00rootroot00000000000000;;; evil-repeat.el --- Repeat system ;; Author: Frank Fischer ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . ;;; Commentary: ;; A repeat begins when leaving Normal state; it ends when re-entering ;; Normal state. The diagram below shows possible routes between ;; Normal state (N), Insert state (I), Visual state (V), ;; Operator-Pending state (O) and Replace state (R). (Emacs state ;; is an exception: nothing is repeated in that state.) ;; ___ ;; / \ ;; | R | ;; \___/ ;; ^ | ;; | | ;; ___ |___V ___ ;; / \ <------- / \ -------> / \ ;; | V | | N | | O | ;; \___/ -------> \___/ <------- \___/ ;; | | ^ | ;; | | | | ;; | V___| | ;; | / \ | ;; +--------> | I | <--------+ ;; \___/ ;; ;; The recording of a repeat is started in one of two cases: Either a ;; command is about being executed (in pre-command-hook) or normal ;; state is exited. The recording is stopped whenever a command has ;; being completed and evil is in normal state afterwards. Therefore, ;; a non-inserting command in normal-state is recorded as a single ;; repeat unit. In contrast, if the command leaves normal state and ;; starts insert-state, all commands that are executed until ;; insert-state is left and normal state is reactivated are recorded ;; together in one repeat unit. In other words, a repeat unit consists ;; of all commands that are executed starting and ending in normal ;; state. ;; ;; Not all commands are recorded. There are several commands that are ;; completely ignored and other commands that even abort the currently ;; active recording, e.g., commands that change the current buffer. ;; ;; During recording the repeat information is appended to the variable ;; `evil-repeat-info', which is cleared when the recording ;; starts. This accumulated repeat information is put into the ;; `evil-repeat-ring' when the recording is finished. The dot command, ;; `\[evil-repeat]' (`evil-repeat') replays the most recent entry in ;; the ring, preceeding repeats can be replayed using ;; `\[evil-repeat-pop]' (`evil-repeat-pop'). ;; ;; Repeat information can be stored in almost arbitrary form. How the ;; repeat information for each single command is recored is determined ;; by the :repeat property of the command. This property has the ;; following interpretation: ;; ;; t record commands by storing the key-sequence that invoked it ;; nil ignore this command completely ;; ignore synonym to nil ;; motion command is recorded by storing the key-sequence but only in ;; insert state, otherwise it is ignored. ;; abort stop recording of repeat information immediately ;; change record commands by storing buffer changes ;; SYMBOL if SYMBOL is contained as key in `evil-repeat-types' ;; call the corresponding (function-)value, otherwise ;; call the function associated with SYMBOL. In both ;; cases the function should take exactly one argument ;; which is either 'pre or 'post depending on whether ;; the function is called before or after the execution ;; of the command. ;; ;; Therefore, using a certain SYMBOL one can write specific repeation ;; functions for each command. ;; ;; Each value of ring `evil-repeat-info', i.e., each single repeat ;; information must be one of the following two possibilities: ;; If element is a sequence, it is regarded as a key-sequence to ;; be repeated. Otherwise the element must be a list ;; (FUNCTION PARAMS ...) which will be called using ;; (apply FUNCTION PARAMS) whenever this repeat is being executed. ;; ;; A user supplied repeat function can use the functions ;; `evil-record-repeat' to append further repeat-information of the ;; form described above to `evil-repeat-info'. See the implementation ;; of `evil-repeat-keystrokes' and `evil-repeat-changes' for examples. ;; Those functions are called in different situations before and after ;; the execution of a command. Each function should take one argument ;; which can be either 'pre, 'post, 'pre-operator or 'post-operator ;; specifying when the repeat function has been called. If the command ;; is a usual command the function is called with 'pre before the ;; command is executed and with 'post after the command has been ;; executed. ;; ;; The repeat information is executed with `evil-execute-repeat-info', ;; which passes key-sequence elements to `execute-kbd-macro' and ;; executes other elements as defined above. A special version is ;; `evil-execute-repeat-info-with-count'. This function works as ;; `evil-execute-repeat-info', but replaces the count of the first ;; command. This is done by parsing the key-sequence, ignoring all ;; calls to `digit-prefix-argument' and `negative-argument', and ;; prepending the count as a string to the vector of the remaining ;; key-sequence. (require 'evil-states) ;;; Code: (declare-function evil-visual-state-p "evil-visual") (declare-function evil-visual-range "evil-visual") (declare-function evil-visual-char "evil-visual") (declare-function evil-visual-line "evil-visual") (declare-function evil-visual-block "evil-visual") (defmacro evil-without-repeat (&rest body) (declare (indent defun) (debug t)) `(let ((pre-command-hook (remq 'evil-repeat-pre-hook pre-command-hook)) (post-command-hook (remq 'evil-repeat-post-hook post-command-hook))) ,@body (evil-repeat-abort))) (defsubst evil-repeat-recording-p () "Returns non-nil iff a recording is in progress." (eq evil-recording-repeat t)) (defun evil-repeat-start () "Start recording a new repeat into `evil-repeat-info'." (evil-repeat-reset t) (evil-repeat-record-buffer) (when (evil-visual-state-p) (let* ((range (evil-visual-range)) (beg (evil-range-beginning range)) (end (1- (evil-range-end range))) (nfwdlines (evil-count-lines beg end))) (evil-repeat-record (cond ((eq evil-visual-selection 'char) (list #'evil-repeat-visual-char nfwdlines (- end (if (zerop nfwdlines) beg (save-excursion (goto-char end) (line-beginning-position)))))) ((eq evil-visual-selection 'line) (list #'evil-repeat-visual-line nfwdlines)) ((eq evil-visual-selection 'block) (list #'evil-repeat-visual-block nfwdlines (abs (- (evil-column beg) (evil-column end)))))))))) (defun evil-repeat-stop () "Stop recording a repeat. Update `evil-repeat-ring' with the accumulated changes in `evil-repeat-info' and clear variables." (unwind-protect (when (evil-repeat-recording-p) (setq evil-repeat-info (evil-normalize-repeat-info evil-repeat-info)) (when (and evil-repeat-info evil-repeat-ring) (ring-insert evil-repeat-ring evil-repeat-info))) (evil-repeat-reset nil))) (defun evil-repeat-abort () "Abort current repeation." (evil-repeat-reset 'abort)) (defun evil-repeat-reset (flag) "Clear all repeat recording variables. Set `evil-recording-repeat' to FLAG." (setq evil-recording-repeat flag evil-repeat-info nil evil-repeat-buffer nil)) (defsubst evil-repeat-record-position (&optional pos) "Set `evil-repeat-pos' to POS or point." (setq evil-repeat-pos (or pos (point)))) (defun evil-repeat-record-buffer () "Set `evil-repeat-buffer' to the current buffer." (unless (minibufferp) (setq evil-repeat-buffer (current-buffer)))) (defmacro evil-save-repeat-info (&rest body) "Execute BODY, protecting the values of repeat variables." (declare (indent defun) (debug t)) `(let (evil-repeat-ring evil-recording-repeat evil-recording-current-command evil-repeat-info evil-repeat-changes evil-repeat-pos evil-repeat-keys evil-repeat-buffer this-command last-command) ,@body)) (defun evil-repeat-different-buffer-p (&optional strict) "Whether the buffer has changed in a repeat. If STRICT is non-nil, returns t if the previous buffer is unknown; otherwise returns t only if the previous buffer is known and different from the current buffer." (and (or (buffer-live-p evil-repeat-buffer) strict) (not (minibufferp)) (not (eq (current-buffer) evil-repeat-buffer)))) (defun evil-repeat-type (command &optional default) "Return the :repeat property of COMMAND. If COMMAND doesn't have this property, return DEFAULT." (when (functionp command) ; ignore keyboard macros (let* ((type (evil-get-command-property command :repeat default)) (repeat-type (assq type evil-repeat-types))) (if repeat-type (cdr repeat-type) type)))) (defun evil-repeat-force-abort-p (repeat-type) "Returns non-nil iff the current command should abort the recording of repeat information." (or (evil-repeat-different-buffer-p) ; ... buffer changed (eq repeat-type 'abort) ; ... explicitely forced (eq evil-recording-repeat 'abort) ; ... already aborted (evil-emacs-state-p) ; ... in Emacs state (and (evil-mouse-events-p (this-command-keys)) ; ... mouse events (eq repeat-type nil)) (minibufferp))) ; ... minibuffer activated (defun evil-repeat-record (info) "Add INFO to the end of `evil-repeat-info'." (when (evil-repeat-recording-p) (setq evil-repeat-info (nconc evil-repeat-info (list info))))) ;; called from `evil-normal-state-exit-hook' (defun evil-repeat-start-hook () "Record a new repeat when exiting Normal state. Does not record in Emacs state or if the current command has :repeat nil." (when (and (eq (evil-repeat-type this-command t) t) (not (evil-emacs-state-p))) (evil-repeat-start))) ;; called from `pre-command-hook' (defun evil-repeat-pre-hook () "Prepare the current command for recording the repeation." (when evil-local-mode (let ((repeat-type (evil-repeat-type this-command t))) (cond ;; abort the repeat ((evil-repeat-force-abort-p repeat-type) ;; We mark the current record as being aborted, because there ;; may be further pre-hooks following before the post-hook is ;; called. (evil-repeat-abort)) ;; ignore those commands completely ((or (null repeat-type) (evil-mouse-events-p (this-command-keys)))) ;; record command (t ;; In normal-state or visual state, each command is a single ;; repeation, therefore start a new repeation. (when (or (evil-normal-state-p) (evil-visual-state-p)) (evil-repeat-start)) (setq evil-recording-current-command t) (funcall repeat-type 'pre)))))) (put 'evil-repeat-pre-hook 'permanent-local-hook t) ;; called from `post-command-hook' (defun evil-repeat-post-hook () "Finish recording of repeat-information for the current-command." (when (and evil-local-mode evil-recording-repeat) (let ((repeat-type (evil-repeat-type this-command t))) (cond ;; abort the repeat ((evil-repeat-force-abort-p repeat-type) ;; The command has been aborted but is complete, so just reset ;; the recording state. (evil-repeat-reset nil)) ;; ignore if command should not be recorded or the current ;; command is not being recorded ((or (null repeat-type) (not evil-recording-current-command))) ;; record command (t (funcall repeat-type 'post) ;; In normal state, the repeat sequence is complete, so record it. (when (evil-normal-state-p) (evil-repeat-stop))))) ;; done with recording the current command (setq evil-recording-current-command nil))) (put 'evil-repeat-post-hook 'permanent-local-hook t) (defun evil-clear-command-keys () "Clear `this-command-keys' and all information about the current command keys. Calling this function prevents further recording of the keys that invoked the current command" (clear-this-command-keys t) (setq evil-repeat-keys "")) (defun evil-this-command-keys (&optional post-cmd) "Version of `this-command-keys' with finer control over prefix args." (let ((arg (if post-cmd current-prefix-arg prefix-arg))) (vconcat (when (and (numberp arg) ;; Only add prefix if no repeat info recorded yet (null evil-repeat-info)) (string-to-vector (number-to-string arg))) (this-single-command-keys)))) (defun evil-repeat-keystrokes (flag) "Repeation recording function for commands that are repeated by keystrokes." (cond ((eq flag 'pre) (when evil-this-register (evil-repeat-record `(set evil-this-register ,evil-this-register))) (setq evil-repeat-keys (evil-this-command-keys))) ((eq flag 'post) (evil-repeat-record (if (zerop (length (evil-this-command-keys t))) evil-repeat-keys (evil-this-command-keys t))) ;; erase commands keys to prevent double recording (evil-clear-command-keys)))) (defun evil-repeat-motion (flag) "Repeation for motions. Motions are recorded by keystroke but only in insert state." (when (memq evil-state '(insert replace)) (evil-repeat-keystrokes flag))) (defun evil-repeat-changes (flag) "Repeation recording function for commands that are repeated by buffer changes." (cond ((eq flag 'pre) (add-hook 'after-change-functions #'evil-repeat-change-hook nil t) (evil-repeat-start-record-changes)) ((eq flag 'post) (remove-hook 'after-change-functions #'evil-repeat-change-hook t) (evil-repeat-finish-record-changes)))) ;; called from the `after-change-functions' hook (defun evil-repeat-change-hook (beg end length) "Record change information for current command." (let ((repeat-type (evil-repeat-type this-command t))) (when (and (evil-repeat-recording-p) (eq repeat-type 'evil-repeat-changes) (not (evil-emacs-state-p)) (not (evil-repeat-different-buffer-p t)) evil-state) (unless (evil-repeat-recording-p) (evil-repeat-start)) (evil-repeat-record-change (- beg evil-repeat-pos) (buffer-substring beg end) length)))) (put 'evil-repeat-change-hook 'permanent-local-hook t) (defun evil-repeat-record-change (relpos ins ndel) "Record the current buffer changes during a repeat. If CHANGE is specified, it is added to `evil-repeat-changes'." (when (evil-repeat-recording-p) (setq evil-repeat-changes (nconc evil-repeat-changes (list (list relpos ins ndel)))))) (defun evil-repeat-start-record-changes () "Starts the recording of a new set of buffer changes." (setq evil-repeat-changes nil) (evil-repeat-record-position)) (defun evil-repeat-finish-record-changes () "Finishes the recording of buffer changes and records them as repeat." (when (evil-repeat-recording-p) (evil-repeat-record `(evil-execute-change ,evil-repeat-changes ,(- (point) evil-repeat-pos))) (setq evil-repeat-changes nil))) (defun evil-repeat-insert-at-point (flag) "Repeation recording function for commands that insert text in region. This records text insertion when a command inserts some text in a buffer between (point) and (mark)." (cond ((eq flag 'pre) (add-hook 'after-change-functions #'evil-repeat-insert-at-point-hook nil t)) ((eq flag 'post) (remove-hook 'after-change-functions #'evil-repeat-insert-at-point-hook t)))) (defun evil-repeat-insert-at-point-hook (beg end length) (let ((repeat-type (evil-repeat-type this-command t))) (when (and (evil-repeat-recording-p) (eq repeat-type 'evil-repeat-insert-at-point) (not (evil-emacs-state-p)) (not (evil-repeat-different-buffer-p t)) evil-state) (setq evil-repeat-pos beg) (evil-repeat-record (list 'insert (buffer-substring beg end)))))) (put 'evil-repeat-insert-at-point-hook 'permanent-local-hook t) (defun evil-normalize-repeat-info (repeat-info) "Concatenate consecutive arrays in REPEAT-INFO. Returns a single array." (let* ((result (cons nil nil)) (result-last result) cur cur-last) (dolist (rep repeat-info) (cond ((null rep)) ((arrayp rep) (setq rep (listify-key-sequence rep)) (cond (cur (setcdr cur-last (cons rep nil)) (setq cur-last (cdr cur-last))) (t (setq cur (cons rep nil)) (setq cur-last cur)))) (t (when cur (setcdr result-last (cons (apply #'vconcat cur) nil)) (setq result-last (cdr result-last)) (setq cur nil)) (setcdr result-last (cons rep nil)) (setq result-last (cdr result-last))))) (when cur (setcdr result-last (cons (apply #'vconcat cur) nil))) (cdr result))) (defun evil-repeat-visual-char (nfwdlines nfwdchars) "Restores a character visual selection. If the selection is in a single line, the restored visual selection covers the same number of characters. If the selection covers several lines, the restored selection covers the same number of lines and the same number of characters in the last line as the original selection." (evil-visual-char) (when (> nfwdlines 0) (forward-line nfwdlines)) (forward-char nfwdchars)) (defun evil-repeat-visual-line (nfwdlines) "Restores a character visual selection. If the selection is in a single line, the restored visual selection covers the same number of characters. If the selection covers several lines, the restored selection covers the same number of lines and the same number of characters in the last line as the original selection." (evil-visual-line) (forward-line nfwdlines)) (defun evil-repeat-visual-block (nfwdlines nfwdchars) "Restores a character visual selection. If the selection is in a single line, the restored visual selection covers the same number of characters. If the selection covers several lines, the restored selection covers the same number of lines and the same number of characters in the last line as the original selection." (evil-visual-block) (let ((col (current-column))) (forward-line nfwdlines) (move-to-column (+ col nfwdchars) t))) (defun evil-execute-change (changes rel-point) "Executes as list of changes. CHANGES is a list of triples (REL-BEG INSERT-TEXT NDEL). REL-BEG is the relative position (to point) where the change takes place. INSERT-TEXT is the text to be inserted at that position and NDEL the number of characters to be deleted at that position before insertion. REL-POINT is the relative position to point before the changed where point should be placed after all changes." (evil-save-repeat-info (let ((point (point))) (dolist (change changes) (goto-char (+ point (nth 0 change))) (delete-char (nth 2 change)) (insert (nth 1 change))) (goto-char (+ point rel-point))))) (defun evil-execute-repeat-info (repeat-info) "Executes a repeat-information REPEAT-INFO." (evil-save-repeat-info (dolist (rep repeat-info) (cond ((or (arrayp rep) (stringp rep)) (let ((input-method current-input-method) (evil-input-method nil)) (deactivate-input-method) (unwind-protect (execute-kbd-macro rep) (activate-input-method input-method)))) ((consp rep) (when (and (= 3 (length rep)) (eq (nth 0 rep) 'set) (eq (nth 1 rep) 'evil-this-register) (>= (nth 2 rep) ?0) (< (nth 2 rep) ?9)) (setcar (nthcdr 2 rep) (1+ (nth 2 rep)))) (apply (car rep) (cdr rep))) (t (error "Unexpected repeat-info: %S" rep)))))) ;; TODO: currently we prepend the replacing count before the ;; key-sequence that calls the command. Can we use direct ;; modification of prefix-arg instead? Does it work in ;; conjunction with `execute-kbd-macro'? (defun evil-execute-repeat-info-with-count (count repeat-info) "Repeat the repeat-information REPEAT-INFO with the count of the first command replaced by COUNT. The count is replaced if and only if COUNT is non-nil." (evil-save-repeat-info (cond ;; do nothing (zero repeating) ((and count (zerop count))) ;; replace count (count (let ((evil-repeat-count count) done) (while (and repeat-info (arrayp (car repeat-info)) (not done)) (let* ((count-and-cmd (evil-extract-count (pop repeat-info)))) (push (vconcat (number-to-string count) (nth 2 count-and-cmd) (nth 3 count-and-cmd)) repeat-info) (setq done t))) (evil-execute-repeat-info repeat-info))) ;; repeat with original count (t (evil-execute-repeat-info repeat-info))))) (evil-define-command evil-repeat (count &optional save-point) "Repeat the last editing command with count replaced by COUNT. If SAVE-POINT is non-nil, do not move point." :repeat ignore :suppress-operator t (interactive (list current-prefix-arg (not evil-repeat-move-cursor))) (cond ((null evil-repeat-ring) (error "Already executing repeat")) (save-point (save-excursion (evil-repeat count))) (t (unwind-protect (let ((confirm-kill-emacs t) (kill-buffer-hook (cons #'(lambda () (user-error "Cannot delete buffer in repeat command")) kill-buffer-hook)) (undo-pointer buffer-undo-list)) (evil-with-single-undo (setq evil-last-repeat (list (point) count undo-pointer)) (evil-execute-repeat-info-with-count count (ring-ref evil-repeat-ring 0)))) (evil-normal-state))))) ;; TODO: the same issue concering disabled undos as for `evil-paste-pop' (evil-define-command evil-repeat-pop (count &optional save-point) "Replace the just repeated command with a previously executed command. Only allowed after `evil-repeat', `evil-repeat-pop' or `evil-repeat-pop-next'. Uses the same repeat count that was used for the first repeat. The COUNT argument inserts the COUNT-th previous kill. If COUNT is negative, this is a more recent kill." :repeat nil :suppress-operator t (interactive (list (prefix-numeric-value current-prefix-arg) (not evil-repeat-move-cursor))) (cond ((not (and (eq last-command #'evil-repeat) evil-last-repeat)) (user-error "Previous command was not evil-repeat: %s" last-command)) (save-point (save-excursion (evil-repeat-pop count))) (t (unless (eq buffer-undo-list (nth 2 evil-last-repeat)) (evil-undo-pop)) (goto-char (car evil-last-repeat)) ;; rotate the repeat-ring (while (> count 0) (when evil-repeat-ring (ring-insert-at-beginning evil-repeat-ring (ring-remove evil-repeat-ring 0))) (setq count (1- count))) (while (< count 0) (when evil-repeat-ring (ring-insert evil-repeat-ring (ring-remove evil-repeat-ring))) (setq count (1+ count))) (setq this-command #'evil-repeat) (evil-repeat (cadr evil-last-repeat))))) (evil-define-command evil-repeat-pop-next (count &optional save-point) "Same as `evil-repeat-pop', but with negative COUNT." :repeat nil :suppress-operator t (interactive (list (prefix-numeric-value current-prefix-arg) (not evil-repeat-move-cursor))) (evil-repeat-pop (- count) save-point)) (defadvice read-key-sequence (before evil activate) "Record `this-command-keys' before it is reset." (when (and (evil-repeat-recording-p) evil-recording-current-command) (let ((repeat-type (evil-repeat-type this-command t))) (if (functionp repeat-type) (funcall repeat-type 'post))))) (provide 'evil-repeat) ;;; evil-repeat.el ends here evil-1.12.17/evil-search.el000066400000000000000000001536441360703323200153620ustar00rootroot00000000000000;;; evil-search.el --- Search and substitute ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . (require 'evil-core) (require 'evil-common) (require 'evil-ex) ;;; Code: (defun evil-select-search-module (option module) "Change the search module according to MODULE. If MODULE is `isearch', then Emacs' isearch module is used. If MODULE is `evil-search', then Evil's own interactive search module is used." (let ((search-functions '(forward backward word-forward word-backward unbounded-word-forward unbounded-word-backward next previous))) (dolist (fun search-functions) (let ((isearch (intern (format "evil-search-%s" fun))) (evil-search (intern (format "evil-ex-search-%s" fun)))) (if (eq module 'isearch) (substitute-key-definition evil-search isearch evil-motion-state-map) (substitute-key-definition isearch evil-search evil-motion-state-map))))) (set-default option module)) ;; this customization is here because it requires ;; the knowledge of `evil-select-search-mode' (defcustom evil-search-module 'isearch "The search module to be used." :type '(radio (const :tag "Emacs built-in isearch." :value isearch) (const :tag "Evil interactive search." :value evil-search)) :group 'evil :set 'evil-select-search-module :initialize 'evil-custom-initialize-pending-reset) (defun evil-push-search-history (string forward) "Push STRING into the appropriate search history (determined by FORWARD)." (let* ((history-var (if forward 'evil-search-forward-history 'evil-search-backward-history)) (history (symbol-value history-var))) (unless (equal (car-safe history) string) (set history-var (cons string history))))) (defun evil-search-incrementally (forward regexp-p) "Search incrementally for user-entered text." (let ((evil-search-prompt (evil-search-prompt forward)) (isearch-search-fun-function 'evil-isearch-function) (point (point)) search-nonincremental-instead) (setq isearch-forward forward) (evil-save-echo-area (evil-without-input-method-hooks ;; set the input method locally rather than globally to ensure that ;; isearch clears the input method when it's finished (setq current-input-method evil-input-method) (if forward (isearch-forward regexp-p) (isearch-backward regexp-p)) (evil-push-search-history isearch-string forward) (setq current-input-method nil)) (when (/= (point) point) ;; position the point at beginning of the match only if the call to ;; `isearch' has really moved the point. `isearch' doesn't move the ;; point only if "C-g" is hit twice to exit the search, in which case we ;; shouldn't move the point either. (when (and forward isearch-other-end) (goto-char isearch-other-end)) (when (and (eq point (point)) (not (string= isearch-string ""))) (if forward (isearch-repeat-forward) (isearch-repeat-backward)) (isearch-exit) (when (and forward isearch-other-end) (goto-char isearch-other-end))) (evil-flash-search-pattern (evil-search-message isearch-string forward)))))) (defun evil-flash-search-pattern (string &optional all) "Flash last search matches for duration of `evil-flash-delay'. If ALL is non-nil, flash all matches. STRING is a message to display in the echo area." (let ((lazy-highlight-initial-delay 0) (isearch-search-fun-function 'evil-isearch-function) (isearch-case-fold-search case-fold-search) (disable #'(lambda (&optional arg) (evil-flash-hook t)))) (when evil-flash-timer (cancel-timer evil-flash-timer)) (unless (or (null string) (string= string "")) (evil-echo-area-save) (evil-echo "%s" string) (isearch-highlight (match-beginning 0) (match-end 0)) (when all (setq isearch-lazy-highlight-wrapped nil isearch-lazy-highlight-start (point) isearch-lazy-highlight-end (point)) (isearch-lazy-highlight-new-loop) (unless isearch-lazy-highlight-overlays (isearch-lazy-highlight-update))) (add-hook 'pre-command-hook #'evil-flash-hook nil t) (add-hook 'evil-operator-state-exit-hook #'evil-flash-hook nil t) (add-hook 'pre-command-hook #'evil-clean-isearch-overlays nil t) (setq evil-flash-timer (run-at-time evil-flash-delay nil disable))))) (defun evil-clean-isearch-overlays () "Clean isearch overlays unless `this-command' is search." (remove-hook 'pre-command-hook #'evil-clean-isearch-overlays t) (unless (memq this-command '(evil-search-backward evil-search-forward evil-search-next evil-search-previous evil-search-word-backward evil-search-word-forward)) (isearch-clean-overlays))) (put 'evil-clean-isearch-overlays 'permanent-local-hook t) (defun evil-flash-hook (&optional force) "Disable hightlighting if `this-command' is not search. Disable anyway if FORCE is t." (when (or force ;; to avoid flicker, don't disable highlighting ;; if the next command is also a search command (not (memq this-command '(evil-search-backward evil-search-forward evil-search-next evil-search-previous evil-search-word-backward evil-search-word-forward)))) (evil-echo-area-restore) (isearch-dehighlight) (setq isearch-lazy-highlight-last-string nil) (lazy-highlight-cleanup t) (when evil-flash-timer (cancel-timer evil-flash-timer))) (remove-hook 'pre-command-hook #'evil-flash-hook t) (remove-hook 'evil-operator-state-exit-hook #'evil-flash-hook t)) (put 'evil-flash-hook 'permanent-local-hook t) (defun evil-search-function (&optional forward regexp-p wrap) "Return a search function. If FORWARD is nil, search backward, otherwise forward. If REGEXP-P is non-nil, the input is a regular expression. If WRAP is non-nil, the search wraps around the top or bottom of the buffer." `(lambda (string &optional bound noerror count) (let ((start (point)) (search-fun ',(if regexp-p (if forward 're-search-forward 're-search-backward) (if forward 'search-forward 'search-backward))) result) (setq result (funcall search-fun string bound ,(if wrap t 'noerror) count)) (when (and ,wrap (null result)) (goto-char ,(if forward '(point-min) '(point-max))) (unwind-protect (setq result (funcall search-fun string bound noerror count)) (unless result (goto-char start)))) result))) (defun evil-isearch-function () "Return a search function for use with isearch. Based on `isearch-regexp' and `isearch-forward'." (evil-search-function isearch-forward evil-regexp-search evil-search-wrap)) (defun evil-search (string forward &optional regexp-p start) "Search for STRING and highlight matches. If FORWARD is nil, search backward, otherwise forward. If REGEXP-P is non-nil, STRING is taken to be a regular expression. START is the position to search from; if unspecified, it is one more than the current position." (when (and (stringp string) (not (string= string ""))) (let* ((orig (point)) (start (or start (if forward (min (point-max) (1+ orig)) orig))) (isearch-regexp regexp-p) (isearch-forward forward) (case-fold-search (unless (and search-upper-case (not (isearch-no-upper-case-p string nil))) case-fold-search)) (search-func (evil-search-function forward regexp-p evil-search-wrap))) ;; no text properties, thank you very much (set-text-properties 0 (length string) nil string) ;; position to search from (goto-char start) (setq isearch-string string) (isearch-update-ring string regexp-p) (condition-case nil (funcall search-func string) (search-failed (goto-char orig) (user-error "\"%s\": %s not found" string (if regexp-p "pattern" "string")))) ;; handle opening and closing of invisible area (cond ((boundp 'isearch-filter-predicates) (dolist (pred isearch-filter-predicates) (funcall pred (match-beginning 0) (match-end 0)))) ((boundp 'isearch-filter-predicate) (funcall isearch-filter-predicate (match-beginning 0) (match-end 0)))) ;; always position point at the beginning of the match (goto-char (match-beginning 0)) ;; determine message for echo area (cond ((and forward (< (point) start)) (setq string "Search wrapped around BOTTOM of buffer")) ((and (not forward) (> (point) start)) (setq string "Search wrapped around TOP of buffer")) (t (setq string (evil-search-message string forward)))) (evil-flash-search-pattern string t)))) (defun evil-search-word (forward unbounded symbol) "Search for word near point. If FORWARD is nil, search backward, otherwise forward. If SYMBOL is non-nil then the functions searches for the symbol at point, otherwise for the word at point." (let ((string (car-safe regexp-search-ring)) (move (if forward #'forward-char #'backward-char)) (end (if forward #'eobp #'bobp))) (setq isearch-forward forward) (cond ((and (memq last-command '(evil-search-word-forward evil-search-word-backward)) (stringp string) (not (string= string ""))) (evil-search string forward t)) (t (setq string (evil-find-thing forward (if symbol 'symbol 'evil-word))) (cond ((null string) (user-error "No word under point")) (unbounded (setq string (regexp-quote string))) (t (setq string (format (if symbol "\\_<%s\\_>" "\\<%s\\>") (regexp-quote string))))) (evil-push-search-history string forward) (evil-search string forward t))))) (defun evil--find-thing (forward thing) "Return a cons of THING near point as a string and its position. THING should be a symbol understood by `thing-at-point', e.g. 'symbol or 'word. If FORWARD is nil, search backward, otherwise forward. Returns nil if nothing is found." (let ((move (if forward #'forward-char #'backward-char)) (end (if forward #'eobp #'bobp)) string) (save-excursion (setq string (thing-at-point thing)) ;; if there's nothing under point, go forwards ;; (or backwards) to find it (while (and (null string) (not (funcall end))) (funcall move) (setq string (thing-at-point thing))) (when (stringp string) (set-text-properties 0 (length string) nil string)) (when (> (length string) 0) (cons string (point)))))) (defun evil-find-thing (forward thing) "Return a THING near point as a string. THING should be a symbol understood by `thing-at-point', e.g. 'symbol or 'word. If FORWARD is nil, search backward, otherwise forward. Returns nil if nothing is found." (car (evil--find-thing forward thing))) (defun evil-find-word (forward) "Return word near point as a string. If FORWARD is nil, search backward, otherwise forward. Returns nil if nothing is found." (evil-find-thing forward 'word)) (defun evil-find-symbol (forward) "Return word near point as a string. If FORWARD is nil, search backward, otherwise forward. Returns nil if nothing is found." (evil-find-thing forward 'symbol)) (defun evil-search-prompt (forward) "Return the search prompt for the given direction." (if forward "/" "?")) (defun evil-search-message (string forward) "Prefix STRING with the search prompt." (format "%s%s" (evil-search-prompt forward) string)) (defadvice isearch-message-prefix (around evil activate) "Use `evil-search-prompt'." (if evil-search-prompt (setq ad-return-value evil-search-prompt) ad-do-it)) (defadvice isearch-delete-char (around evil activate) "Exit search if no search string." (cond ((and evil-search-prompt (string= isearch-string "")) (let (search-nonincremental-instead) (setq isearch-success nil) (isearch-exit))) (t ad-do-it))) (defadvice isearch-lazy-highlight-search (around evil activate) "Never wrap the search in this context." (let (evil-search-wrap) ad-do-it)) ;;; Ex search (defun evil-ex-regex-without-case (re) "Return the regular expression without all occurrences of \\c and \\C." (evil-transform-regexp re '((?c . "") (?C . "")))) (defun evil-ex-regex-case (re default-case) "Return the case as implied by \\c or \\C in regular expression RE. If \\c appears anywhere in the pattern, the pattern is case insensitive. If \\C appears, the pattern is case sensitive. Only the first occurrence of \\c or \\C is used, all others are ignored. If neither \\c nor \\C appears in the pattern, the case specified by DEFAULT-CASE is used. DEFAULT-CASE should be either `sensitive', `insensitive' or `smart'. In the latter case, the pattern will be case-sensitive if and only if it contains an upper-case letter, otherwise it will be case-insensitive." (cond ((string-match "\\(?:^\\|[^\\\\]\\)\\(?:\\\\\\\\\\)*\\\\\\([cC]\\)" re) (if (eq (aref (match-string 1 re) 0) ?c) 'insensitive 'sensitive)) ((eq default-case 'smart) (if (isearch-no-upper-case-p re t) 'insensitive 'sensitive)) (t default-case))) ;; a pattern (defun evil-ex-make-substitute-pattern (regexp flags) "Creates a PATTERN for substitution with FLAGS. This function respects the values of `evil-ex-substitute-case' and `evil-ex-substitute-global'." (evil-ex-make-pattern regexp (cond ((memq ?i flags) 'insensitive) ((memq ?I flags) 'sensitive) ((not evil-ex-substitute-case) evil-ex-search-case) (t evil-ex-substitute-case)) (or (and evil-ex-substitute-global (not (memq ?g flags))) (and (not evil-ex-substitute-global) (memq ?g flags))))) (defun evil-ex-make-search-pattern (regexp) "Creates a PATTERN for search. This function respects the values of `evil-ex-search-case'." (evil-ex-make-pattern regexp evil-ex-search-case t)) (defun evil-ex-make-pattern (regexp case whole-line) "Create a new search pattern. REGEXP is the regular expression to be searched for. CASE should be either 'sensitive, 'insensitive for case-sensitive and case-insensitive search, respectively, or anything else. In the latter case the pattern is smart-case, i.e. it is automatically sensitive of the pattern contains one upper case letter, otherwise it is insensitive. The input REGEXP is considered a Vim-style regular expression if `evil-ex-search-vim-style-regexp' is non-nil, in which case it is transformed to an Emacs style regular expression (i.e. certain backslash-codes are transformed. Otherwise REGEXP must be an Emacs style regular expression and is not transformed." (let ((re (evil-ex-regex-without-case regexp)) (ignore-case (eq (evil-ex-regex-case regexp case) 'insensitive))) ;; possibly transform regular expression from vim-style to ;; Emacs-style. (if evil-ex-search-vim-style-regexp (setq re (evil-transform-vim-style-regexp re)) ;; Even for Emacs regular expressions we translate certain ;; whitespace sequences (setq re (evil-transform-regexp re '((?t . "\t") (?n . "\n") (?r . "\r"))))) (list re ignore-case whole-line))) (defun evil-ex-pattern-regex (pattern) "Return the regular expression of a search PATTERN." (nth 0 pattern)) (defun evil-ex-pattern-ignore-case (pattern) "Return t if and only if PATTERN should ignore case." (nth 1 pattern)) (defun evil-ex-pattern-whole-line (pattern) "Return t if and only if PATTERN should match all occurences of a line. Otherwise PATTERN matches only the first occurence." (nth 2 pattern)) ;; Highlight (defun evil-ex-make-hl (name &rest args) "Create a new highlight object with name NAME and properties ARGS. The following properties are supported: :face The face to be used for the highlighting overlays. :win The window in which the highlighting should be shown. Note that the highlight will be visible in all windows showing the corresponding buffer, but only the matches visible in the specified window will actually be highlighted. If :win is nil, the matches in all windows will be highlighted. :min The minimal buffer position for highlighted matches. :max The maximal buffer position for highlighted matches. :match-hook A hook to be called once for each highlight. The hook must take two arguments, the highlight and the overlay for that highlight. :update-hook A hook called once after updating the highlighting with two arguments, the highlight and a message string describing the current match status." (unless (symbolp name) (user-error "Expected symbol as name of highlight")) (let ((face 'evil-ex-lazy-highlight) (win (selected-window)) min max match-hook update-hook) (while args (let ((key (pop args)) (val (pop args))) (cond ((eq key :face) (setq face val)) ((eq key :win) (setq win val)) ((eq key :min) (setq min val)) ((eq key :max) (setq max val)) ((eq key :match-hook) (setq match-hook val)) ((eq key :update-hook) (setq update-hook val)) (t (user-error "Unexpected keyword: %s" key))))) (when (assoc name evil-ex-active-highlights-alist) (evil-ex-delete-hl name)) (when (null evil-ex-active-highlights-alist) (add-hook 'window-scroll-functions #'evil-ex-hl-update-highlights-scroll nil t) (add-hook 'window-size-change-functions #'evil-ex-hl-update-highlights-resize nil)) (push (cons name (vector name nil face win min max match-hook update-hook nil)) evil-ex-active-highlights-alist))) (defun evil-ex-hl-name (hl) "Return the name of the highlight HL." (aref hl 0)) (defun evil-ex-hl-pattern (hl) "Return the pattern of the highlight HL." (aref hl 1)) (defun evil-ex-hl-set-pattern (hl pattern) "Set the pattern of the highlight HL to PATTERN." (aset hl 1 pattern)) (defun evil-ex-hl-face (hl) "Return the face of the highlight HL." (aref hl 2)) (defun evil-ex-hl-window (hl) "Return the window of the highlight HL." (aref hl 3)) (defun evil-ex-hl-min (hl) "Return the minimal buffer position of the highlight HL." (aref hl 4)) (defun evil-ex-hl-set-min (hl min) "Set the minimal buffer position of the highlight HL to MIN." (aset hl 4 min)) (defun evil-ex-hl-max (hl) "Return the maximal buffer position of the highlight HL." (aref hl 5)) (defun evil-ex-hl-set-max (hl max) "Set the minimal buffer position of the highlight HL to MAX." (aset hl 5 max)) (defun evil-ex-hl-match-hook (hl) "Return the match-hook of the highlight HL." (aref hl 6)) (defun evil-ex-hl-update-hook (hl) "Return the update-hook of the highlight HL." (aref hl 7)) (defun evil-ex-hl-overlays (hl) "Return the list of active overlays of the highlight HL." (aref hl 8)) (defun evil-ex-hl-set-overlays (hl overlays) "Set the list of active overlays of the highlight HL to OVERLAYS." (aset hl 8 overlays)) (defun evil-ex-delete-hl (name) "Remove the highlighting object with a certain NAME." (let ((hl (cdr-safe (assoc name evil-ex-active-highlights-alist)))) (when hl (mapc #'delete-overlay (evil-ex-hl-overlays hl)) (setq evil-ex-active-highlights-alist (assq-delete-all name evil-ex-active-highlights-alist)) (evil-ex-hl-update-highlights)) (when (null evil-ex-active-highlights-alist) (remove-hook 'window-scroll-functions #'evil-ex-hl-update-highlights-scroll t) (remove-hook 'window-size-change-functions #'evil-ex-hl-update-highlights-resize)))) (defun evil-ex-hl-active-p (name) "Whether the highlight with a certain NAME is active." (and (assoc name evil-ex-active-highlights-alist) t)) (defun evil-ex-hl-change (name pattern) "Set the regular expression of highlight NAME to PATTERN." (let ((hl (cdr-safe (assoc name evil-ex-active-highlights-alist)))) (when hl (evil-ex-hl-set-pattern hl (if (zerop (length pattern)) nil pattern)) (evil-ex-hl-idle-update)))) (defun evil-ex-hl-set-region (name beg end &optional type) "Set minimal and maximal position of highlight NAME to BEG and END." (let ((hl (cdr-safe (assoc name evil-ex-active-highlights-alist)))) (when hl (evil-ex-hl-set-min hl beg) (evil-ex-hl-set-max hl end) (evil-ex-hl-idle-update)))) (defun evil-ex-hl-get-max (name) "Return the maximal position of the highlight with name NAME." (let ((hl (cdr-safe (assoc name evil-ex-active-highlights-alist)))) (and hl (evil-ex-hl-max hl)))) (defun evil-ex-hl-update-highlights () "Update the overlays of all active highlights." (dolist (hl (mapcar #'cdr evil-ex-active-highlights-alist)) (let* ((old-ovs (evil-ex-hl-overlays hl)) new-ovs (pattern (evil-ex-hl-pattern hl)) (case-fold-search (evil-ex-pattern-ignore-case pattern)) (case-replace case-fold-search) (face (evil-ex-hl-face hl)) (match-hook (evil-ex-hl-match-hook hl)) result) (if pattern ;; collect all visible ranges (let (ranges sranges) (dolist (win (if (eq evil-ex-interactive-search-highlight 'all-windows) (get-buffer-window-list (current-buffer) nil t) (list (evil-ex-hl-window hl)))) (when (window-live-p win) (let ((beg (max (window-start win) (or (evil-ex-hl-min hl) (point-min)))) (end (min (window-end win) (or (evil-ex-hl-max hl) (point-max))))) (when (< beg end) (push (cons beg end) ranges))))) (setq ranges (sort ranges #'(lambda (r1 r2) (< (car r1) (car r2))))) (while ranges (let ((r1 (pop ranges)) (r2 (pop ranges))) (cond ;; last range ((null r2) (push r1 sranges)) ;; ranges overlap, union ((>= (cdr r1) (car r2)) (push (cons (car r1) (max (cdr r1) (cdr r2))) ranges)) ;; ranges distinct (t (push r1 sranges) (push r2 ranges))))) ;; run through all ranges (condition-case lossage (save-match-data (dolist (r sranges) (let ((beg (car r)) (end (cdr r))) (save-excursion (goto-char beg) ;; set the overlays for the current highlight, ;; reusing old overlays (if possible) (while (and (not (eobp)) (evil-ex-search-find-next-pattern pattern) (<= (match-end 0) end) (not (and (= (match-end 0) end) (string= (evil-ex-pattern-regex pattern) "^")))) (let ((ov (or (pop old-ovs) (make-overlay 0 0)))) (move-overlay ov (match-beginning 0) (match-end 0)) (overlay-put ov 'face face) (overlay-put ov 'evil-ex-hl (evil-ex-hl-name hl)) (overlay-put ov 'priority 1000) (push ov new-ovs) (when match-hook (funcall match-hook hl ov))) (cond ((and (not (evil-ex-pattern-whole-line pattern)) (not (string-match-p "\n" (buffer-substring-no-properties (match-beginning 0) (match-end 0))))) (forward-line)) ((= (match-beginning 0) (match-end 0)) (forward-char)) (t (goto-char (match-end 0)))))))) (mapc #'delete-overlay old-ovs) (evil-ex-hl-set-overlays hl new-ovs) (if (or (null pattern) new-ovs) (setq result t) ;; Maybe the match could just not be found somewhere else? (save-excursion (goto-char (or (evil-ex-hl-min hl) (point-min))) (if (and (evil-ex-search-find-next-pattern pattern) (< (match-end 0) (or (evil-ex-hl-max hl) (point-max)))) (setq result (format "Match in line %d" (line-number-at-pos (match-beginning 0)))) (setq result "No match"))))) (invalid-regexp (setq result (cadr lossage))) (search-failed (setq result (nth 2 lossage))) (error (setq result (format "%s" (cadr lossage)))) (user-error (setq result (format "%s" (cadr lossage)))))) ;; no pattern, remove all highlights (mapc #'delete-overlay old-ovs) (evil-ex-hl-set-overlays hl new-ovs)) (when (evil-ex-hl-update-hook hl) (funcall (evil-ex-hl-update-hook hl) hl result))))) (defun evil-ex-search-find-next-pattern (pattern &optional direction) "Look for the next occurrence of PATTERN in a certain DIRECTION. Note that this function ignores the whole-line property of PATTERN." (setq direction (or direction 'forward)) (let ((case-fold-search (evil-ex-pattern-ignore-case pattern))) (cond ((eq direction 'forward) (re-search-forward (evil-ex-pattern-regex pattern) nil t)) ((eq direction 'backward) (let* ((pnt (point)) (ret (re-search-backward (evil-ex-pattern-regex pattern) nil t)) (m (and ret (match-data)))) (if ret (forward-char) (goto-char (point-min))) (let ((fwdret (re-search-forward (evil-ex-pattern-regex pattern) nil t))) (cond ((and fwdret (< (match-beginning 0) pnt)) (setq ret fwdret) (goto-char (match-beginning 0))) (ret (set-match-data m) (goto-char (match-beginning 0))) (t (goto-char pnt) ret))))) (t (user-error "Unknown search direction: %s" direction))))) (defun evil-ex-hl-idle-update () "Triggers the timer to update the highlights in the current buffer." (when (and evil-ex-interactive-search-highlight evil-ex-active-highlights-alist) (when evil-ex-hl-update-timer (cancel-timer evil-ex-hl-update-timer)) (setq evil-ex-hl-update-timer (run-at-time evil-ex-hl-update-delay nil #'evil-ex-hl-do-update-highlight (current-buffer))))) (defun evil-ex-hl-do-update-highlight (&optional buffer) "Timer function for updating the highlights." (when (buffer-live-p buffer) (with-current-buffer buffer (evil-ex-hl-update-highlights))) (setq evil-ex-hl-update-timer nil)) (defun evil-ex-hl-update-highlights-scroll (win beg) "Update highlights after scrolling in some window." (with-current-buffer (window-buffer win) (evil-ex-hl-idle-update))) (put 'evil-ex-hl-update-highlights-scroll 'permanent-local-hook t) (defun evil-ex-hl-update-highlights-resize (frame) "Update highlights after resizing a window." (let ((buffers (delete-dups (mapcar #'window-buffer (window-list frame))))) (dolist (buf buffers) (with-current-buffer buf (evil-ex-hl-idle-update))))) (put 'evil-ex-hl-update-highlights-resize 'permanent-local-hook t) ;; interactive search (defun evil-ex-search-activate-highlight (pattern) "Activate highlighting of the search pattern set to PATTERN. This function does nothing if `evil-ex-search-interactive' or `evil-ex-search-highlight-all' is nil. " (when (and evil-ex-search-interactive evil-ex-search-highlight-all) (with-current-buffer (or evil-ex-current-buffer (current-buffer)) (unless (evil-ex-hl-active-p 'evil-ex-search) (evil-ex-make-hl 'evil-ex-search :win (minibuffer-selected-window))) (if pattern (evil-ex-hl-change 'evil-ex-search pattern))))) (defun evil-ex-search (&optional count) "Search forward or backward COUNT times for the current ex search pattern. The search pattern is determined by `evil-ex-search-pattern' and the direcion is determined by `evil-ex-search-direction'." (setq evil-ex-search-start-point (point) evil-ex-last-was-search t count (or count 1)) (let ((orig (point)) wrapped) (dotimes (i (or count 1)) (when (eq evil-ex-search-direction 'forward) (unless (eobp) (forward-char)) ;; maybe skip end-of-line (when (and (not evil-move-beyond-eol) (eolp) (not (eobp))) (forward-char))) (let ((res (evil-ex-find-next nil nil (not evil-search-wrap)))) (cond ((not res) (goto-char orig) (signal 'search-failed (list (evil-ex-pattern-regex evil-ex-search-pattern)))) ((eq res 'wrapped) (setq wrapped t))))) (if wrapped (let (message-log-max) (message "Search wrapped"))) (goto-char (match-beginning 0)) (setq evil-ex-search-match-beg (match-beginning 0) evil-ex-search-match-end (match-end 0)) (evil-ex-search-goto-offset evil-ex-search-offset) (evil-ex-search-activate-highlight evil-ex-search-pattern))) (defun evil-ex-find-next (&optional pattern direction nowrap) "Search for the next occurrence of the PATTERN in DIRECTION. PATTERN must be created using `evil-ex-make-pattern', DIRECTION is either 'forward or 'backward. If NOWRAP is non nil, the search does not wrap at buffer boundaries. Furthermore this function only searches invisible text if `search-invisible' is t. If PATTERN is not specified the current global pattern `evil-ex-search-pattern' and if DIRECTION is not specified the current global direction `evil-ex-search-direction' is used. This function returns t if the search was successful, nil if it was unsuccessful and 'wrapped if the search was successful but has been wrapped at the buffer boundaries." (setq pattern (or pattern evil-ex-search-pattern) direction (or direction evil-ex-search-direction)) (unless (and pattern (evil-ex-pattern-regex pattern)) (signal 'search-failed (list "No search pattern"))) (catch 'done (let (wrapped) (while t (let ((search-result (evil-ex-search-find-next-pattern pattern direction))) (cond ((and search-result (or (eq search-invisible t) (not (isearch-range-invisible (match-beginning 0) (match-end 0))))) ;; successful search and not invisible (throw 'done (if wrapped 'wrapped t))) ((not search-result) ;; unsuccessful search (if nowrap (throw 'done nil) (setq nowrap t wrapped t) (goto-char (if (eq direction 'forward) (point-min) (point-max))))))))))) (defun evil-ex-search-update (pattern offset beg end message) "Update the highlighting and info-message for the search pattern. PATTERN is the search pattern and OFFSET the associated offset. BEG and END specifiy the current match, MESSAGE is the info message to be shown. This function does nothing if `evil-ex-search-interactive' is nil." (when evil-ex-search-interactive (cond ((and beg end) ;; update overlay (if evil-ex-search-overlay (move-overlay evil-ex-search-overlay beg end) (setq evil-ex-search-overlay (make-overlay beg end)) (overlay-put evil-ex-search-overlay 'priority 1001) (overlay-put evil-ex-search-overlay 'face 'evil-ex-search)) ;; move point (goto-char beg) (evil-ex-search-goto-offset offset) ;; update highlights (when evil-ex-search-highlight-all (evil-ex-hl-change 'evil-ex-search pattern))) (t ;; no match (when evil-ex-search-overlay ;; remove overlay (delete-overlay evil-ex-search-overlay) (setq evil-ex-search-overlay nil)) ;; no highlights (when evil-ex-search-highlight-all (evil-ex-hl-change 'evil-ex-search nil)) ;; and go to initial position (goto-char evil-ex-search-start-point))) (when (stringp message) (evil-ex-echo "%s" message)))) (defun evil-ex-search-start-session () "Initialize Ex for interactive search." (remove-hook 'minibuffer-setup-hook #'evil-ex-search-start-session) (add-hook 'after-change-functions #'evil-ex-search-update-pattern nil t) (add-hook 'minibuffer-exit-hook #'evil-ex-search-stop-session) (evil-ex-search-activate-highlight nil)) (put 'evil-ex-search-start-session 'permanent-local-hook t) (defun evil-ex-search-stop-session () "Stop interactive search." (with-current-buffer evil-ex-current-buffer ;; TODO: This is a bad fix to remove duplicates. The duplicates ;; exist because `isearch-range-invisible' may add a single ;; overlay multiple times if we are in an unlucky situation ;; of overlapping overlays. This happens in our case because ;; of the overlays that are used for (lazy) highlighting. ;; Perhaps it would be better to disable those overlays ;; temporarily before calling `isearch-range-invisible'. (setq isearch-opened-overlays (delete-dups isearch-opened-overlays)) (isearch-clean-overlays)) (remove-hook 'minibuffer-exit-hook #'evil-ex-search-stop-session) (remove-hook 'after-change-functions #'evil-ex-search-update-pattern t) (when evil-ex-search-overlay (delete-overlay evil-ex-search-overlay) (setq evil-ex-search-overlay nil))) (put 'evil-ex-search-stop-session 'permanent-local-hook t) (defun evil-ex-split-search-pattern (pattern direction) "Split PATTERN in regexp, offset and next-pattern parts. Returns a triple (regexp offset next-search)." (save-match-data (if (or (and (eq direction 'forward) (string-match "\\(?:^\\|[^\\\\]\\)\\(?:\\\\\\\\\\)*\\(/\\([^;]*\\)\\(?:;\\([/?].*\\)?\\)?\\)?$" pattern)) (and (eq direction 'backward) (string-match "\\(?:^\\|[^\\\\]\\)\\(?:\\\\\\\\\\)*\\(\\?\\([^;]*\\)\\(?:;\\([/?].*\\)?\\)?\\)?$" pattern))) (list (substring pattern 0 (match-beginning 1)) (match-string 2 pattern) (match-string 3 pattern)) (list pattern nil nil)))) (defun evil-ex-search-full-pattern (pattern-string count direction) "Search for a full search pattern PATTERN-STRING in DIRECTION. This function split PATTERN-STRING in pattern/offset/;next-pattern parts and performs the search in DIRECTION which must be either 'forward or 'backward. The first search is repeated COUNT times. If the pattern part of PATTERN-STRING is empty, the last global pattern stored in `evil-ex-search-pattern' is used instead if in addition the offset part is nil (i.e. no pattern/offset separator), the last global offset stored in `evil-ex-search-offset' is used as offset. The current match data will correspond to the last successful match. This function returns a triple (RESULT PATTERN OFFSET) where RESULT is t the search has been successful without wrap 'wrap the search has been successful with wrap 'empty-pattern the last pattern has been empty nil the search has not been successful and PATTERN and OFFSET are the last pattern and offset this function searched for. Note that this function does not handle any error conditions." (setq count (or count 1)) (catch 'done (while t (let* ((res (evil-ex-split-search-pattern pattern-string direction)) (pat (pop res)) (offset (pop res)) (next-pat (pop res))) ;; use last pattern of no new pattern has been specified (if (not (zerop (length pat))) (setq pat (evil-ex-make-search-pattern pat)) (setq pat evil-ex-search-pattern offset (or offset evil-ex-search-offset))) (when (zerop (length pat)) (throw 'done (list 'empty-pattern pat offset))) (let (search-result) (while (> count 0) (let ((result (evil-ex-find-next pat direction (not evil-search-wrap)))) (if (not result) (setq search-result nil count 0) (setq search-result (if (or (eq result 'wrap) (eq search-result 'wrap)) 'wrap t) count (1- count))))) (cond ;; search failed ((not search-result) (throw 'done (list nil pat offset))) ;; no next pattern, search complete ((zerop (length next-pat)) (evil-ex-search-goto-offset offset) (throw 'done (list search-result pat offset))) ;; next pattern but empty ((= 1 (length next-pat)) (evil-ex-search-goto-offset offset) (throw 'done (list 'empty-pattern pat offset))) ;; next non-empty pattern, next search iteration (t (evil-ex-search-goto-offset offset) (setq count 1 pattern-string (substring next-pat 1) direction (if (= (aref next-pat 0) ?/) 'forward 'backward))))))))) (defun evil-ex-search-update-pattern (beg end range) "Update the current search pattern." (save-match-data (let ((pattern-string (minibuffer-contents))) (with-current-buffer evil-ex-current-buffer (with-selected-window (minibuffer-selected-window) (goto-char (1+ evil-ex-search-start-point)) (condition-case err (let* ((result (evil-ex-search-full-pattern pattern-string (or evil-ex-search-count 1) evil-ex-search-direction)) (success (pop result)) (pattern (pop result)) (offset (pop result))) (cond ((eq success 'wrap) (evil-ex-search-update pattern offset (match-beginning 0) (match-end 0) "Wrapped")) ((eq success 'empty-pattern) (evil-ex-search-update nil nil nil nil nil)) (success (evil-ex-search-update pattern offset (match-beginning 0) (match-end 0) nil)) (t (evil-ex-search-update nil nil nil nil "search failed")))) (invalid-regexp (evil-ex-search-update nil nil nil nil (cadr err))) (error (evil-ex-search-update nil nil nil nil (format "%s" err))))))))) (put 'evil-ex-search-update-pattern 'permanent-local-hook t) (defun evil-ex-search-exit () "Exit interactive search, keeping lazy highlighting active." (interactive) (evil-ex-search-stop-session) (exit-minibuffer)) (defun evil-ex-search-abort () "Abort interactive search, disabling lazy highlighting." (interactive) (evil-ex-search-stop-session) (evil-ex-delete-hl 'evil-ex-search) (abort-recursive-edit)) (defun evil-ex-search-goto-offset (offset) "Move point according to search OFFSET and set `evil-this-type' accordingly. This function assumes that the current match data represents the current search result." (unless (zerop (length offset)) (let ((beg (match-beginning 0)) (end (match-end 0))) (save-match-data (unless (string-match "^\\([esb]\\)?\\(\\([-+]\\)?\\([0-9]*\\)\\)$" offset) (user-error "Invalid search offset: %s" offset)) (let ((count (if (= (match-beginning 4) (match-end 4)) (cond ((not (match-beginning 3)) 0) ((= (aref offset (match-beginning 3)) ?+) +1) (t -1)) (string-to-number (match-string 2 offset))))) (cond ((not (match-beginning 1)) (setq evil-this-type 'line) (forward-line count)) ((= (aref offset (match-beginning 1)) ?e) (goto-char (+ end count -1)) (setq evil-this-type 'inclusive)) ((memq (aref offset (match-beginning 1)) '(?s ?b)) (goto-char (+ beg count)) (setq evil-this-type 'inclusive)))))))) (defun evil-ex-search-setup () "Hook to initialize the minibuffer for ex search." (add-hook 'pre-command-hook #'evil-ex-remove-default)) (defun evil-ex-start-search (direction count) "Start a new search in a certain DIRECTION." ;; store buffer and window where the search started (let ((evil-ex-current-buffer (current-buffer))) (setq evil-ex-search-count count evil-ex-search-direction direction evil-ex-search-start-point (point) evil-ex-last-was-search t) (progn ;; ensure minibuffer is initialized accordingly (add-hook 'minibuffer-setup-hook #'evil-ex-search-start-session) ;; read the search string (let* ((minibuffer-local-map evil-ex-search-keymap) (search-string (condition-case err (minibuffer-with-setup-hook #'evil-ex-search-setup (read-string (if (eq evil-ex-search-direction 'forward) "/" "?") (and evil-ex-search-history (propertize (car evil-ex-search-history) 'face 'shadow)) 'evil-ex-search-history)) (quit (evil-ex-search-stop-session) (evil-ex-delete-hl 'evil-ex-search) (goto-char evil-ex-search-start-point) (signal (car err) (cdr err)))))) ;; pattern entered successful (goto-char (1+ evil-ex-search-start-point)) (let* ((result (evil-ex-search-full-pattern search-string evil-ex-search-count evil-ex-search-direction)) (success (pop result)) (pattern (pop result)) (offset (pop result))) (setq evil-ex-search-pattern pattern evil-ex-search-offset offset) (cond ((memq success '(t wrap)) (goto-char (match-beginning 0)) (setq evil-ex-search-match-beg (match-beginning 0) evil-ex-search-match-end (match-end 0)) (evil-ex-search-goto-offset offset) (evil-push-search-history search-string (eq direction 'forward)) (unless evil-ex-search-persistent-highlight (evil-ex-delete-hl 'evil-ex-search))) (t (goto-char evil-ex-search-start-point) (evil-ex-delete-hl 'evil-ex-search) (signal 'search-failed (list search-string))))))))) (defun evil-ex-start-word-search (unbounded direction count &optional symbol) "Search for the symbol under point. The search matches the COUNT-th occurrence of the word. If the UNBOUNDED argument is nil, the search matches only at symbol boundaries, otherwise it matches anywhere. The DIRECTION argument should be either `forward' or `backward', determining the search direction. If SYMBOL is non-nil then the functions searches for the symbol at point, otherwise for the word at point." (let ((string (evil-find-thing (eq direction 'forward) (if symbol 'symbol 'word)))) (if (null string) (user-error "No word under point") (let ((regex (if unbounded (regexp-quote string) (format (if symbol "\\_<%s\\_>" "\\<%s\\>") (regexp-quote string))))) (setq evil-ex-search-count count evil-ex-search-direction direction evil-ex-search-pattern (evil-ex-make-search-pattern regex) evil-ex-search-offset nil evil-ex-last-was-search t) ;; update search history unless this pattern equals the ;; previous pattern (unless (equal (car-safe evil-ex-search-history) regex) (push regex evil-ex-search-history)) (evil-push-search-history regex (eq direction 'forward))) (evil-ex-delete-hl 'evil-ex-search) (when (fboundp 'evil-ex-search-next) (evil-ex-search-next count))))) ;; substitute (evil-ex-define-argument-type substitution "A substitution pattern argument /pattern/replacement/flags. This handler highlights the pattern of the current substitution." :runner (lambda (flag &optional arg) (with-selected-window (minibuffer-selected-window) (with-current-buffer evil-ex-current-buffer (cond ((eq flag 'start) (evil-ex-make-hl 'evil-ex-substitute :face 'evil-ex-substitute-matches :update-hook #'evil-ex-pattern-update-ex-info :match-hook (and evil-ex-substitute-interactive-replace #'evil-ex-pattern-update-replacement)) (setq flag 'update)) ((eq flag 'stop) (evil-ex-delete-hl 'evil-ex-substitute)))) (when (and (eq flag 'update) evil-ex-substitute-highlight-all (not (zerop (length arg)))) (condition-case lossage (let* ((result (evil-ex-get-substitute-info arg t)) (pattern (pop result)) (replacement (pop result)) (range (or (evil-copy-range evil-ex-range) (evil-range (line-beginning-position) (line-end-position) 'line :expanded t)))) (setq evil-ex-substitute-current-replacement replacement) (evil-expand-range range) (evil-ex-hl-set-region 'evil-ex-substitute (evil-range-beginning range) (evil-range-end range)) (evil-ex-hl-change 'evil-ex-substitute pattern)) (end-of-file (evil-ex-pattern-update-ex-info nil "incomplete replacement")) (user-error (evil-ex-pattern-update-ex-info nil (format "%s" lossage)))))))) (defun evil-ex-pattern-update-ex-info (hl result) "Update the Ex info string." (when (stringp result) (evil-ex-echo "%s" result))) (defun evil-ex-pattern-update-replacement (hl overlay) "Update the replacement display." (when (fboundp 'match-substitute-replacement) (let ((fixedcase (not case-replace)) repl) (setq repl (if evil-ex-substitute-current-replacement (evil-match-substitute-replacement evil-ex-substitute-current-replacement fixedcase) "")) (put-text-property 0 (length repl) 'face 'evil-ex-substitute-replacement repl) (overlay-put overlay 'after-string repl)))) (defun evil-ex-parse-global (string) "Parse STRING as a global argument." (let* ((pattern (nth 0 (evil-delimited-arguments string 2))) (command (and pattern (>= (- (length string) (length pattern)) 2) (substring string (+ (length pattern) 2))))) ;; use last pattern if none given (when (zerop (length pattern)) (setq pattern (cond ((and (eq evil-search-module 'evil-search) evil-ex-search-pattern) (evil-ex-pattern-regex evil-ex-search-pattern)) ((and (eq evil-search-module 'isearch) (not (zerop (length isearch-string)))) isearch-string) (t (user-error "No previous pattern"))))) (list pattern command))) (defun evil-ex-get-substitute-info (string &optional implicit-r) "Returns the substitution info of command line STRING. This function returns a three-element list \(PATTERN REPLACEMENT FLAGS) consisting of the substitution parts of STRING. PATTERN is a ex-pattern (see `evil-ex-make-pattern') and REPLACEMENT in a compiled replacement expression (see `evil-compile-replacement'). The information returned is the actual substitution information w.r.t. to special situations like empty patterns or repetition of previous substitution commands. If IMPLICIT-R is non-nil, then the flag 'r' is assumed, i.e. in the case of an empty pattern the last search pattern is used. This will be used when called from a :substitute command with arguments." (let (pattern replacement flags) (cond ((or (null string) (string-match "^[a-zA-Z]" string)) ;; starts with letter so there is no pattern because the ;; separator must not be a letter repeat last substitute (setq replacement evil-ex-substitute-replacement) ;; flags are everything that is not a white space (when (and string (string-match "[^[:space:]]+" string)) (setq flags (match-string 0 string)))) (t (let ((args (evil-delimited-arguments string 3))) (setq pattern (pop args) replacement (pop args) flags (pop args)) ;; if replacment equals "~" use previous replacement (if (equal replacement "~") (setq replacement evil-ex-substitute-replacement) (setq replacement (evil-compile-replacement replacement))) ;; append implicit "r" flag if required (when (and implicit-r (not (memq ?r (append flags nil)))) (setq flags (concat flags "r")))))) ;; if flags equals "&" add previous flags (if (and (not (zerop (length flags))) (= (aref flags 0) ?&)) (setq flags (append (substring flags 1) evil-ex-substitute-flags)) (setq flags (append flags nil))) ;; if no pattern, use previous pattern, either search or ;; substitute pattern depending on `evil-ex-last-was-search' and ;; the r flag (when (zerop (length pattern)) (setq pattern (if (eq evil-search-module 'evil-search) (if (and evil-ex-last-was-search (memq ?r flags)) (and evil-ex-search-pattern (evil-ex-pattern-regex evil-ex-search-pattern)) (and evil-ex-substitute-pattern (evil-ex-pattern-regex evil-ex-substitute-pattern))) (if (eq case-fold-search t) isearch-string (concat isearch-string "\\C"))) flags (remq ?r flags))) ;; generate pattern (when pattern (setq pattern (evil-ex-make-substitute-pattern pattern flags))) (list pattern replacement flags))) (defun evil-ex-nohighlight () "Disable the active search highlightings." (interactive) (evil-ex-delete-hl 'evil-ex-substitute) (evil-ex-delete-hl 'evil-ex-search)) (provide 'evil-search) ;;; evil-search.el ends here evil-1.12.17/evil-states.el000066400000000000000000001033231360703323200154050ustar00rootroot00000000000000;;; evil-states.el --- States ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . (require 'evil-core) ;;; Code: ;;; Normal state (evil-define-state normal "Normal state. AKA \"Command\" state." :tag " " :enable (motion) :exit-hook (evil-repeat-start-hook) (cond ((evil-normal-state-p) (overwrite-mode -1) (add-hook 'post-command-hook #'evil-normal-post-command nil t)) (t (remove-hook 'post-command-hook #'evil-normal-post-command t)))) (defun evil-normal-post-command (&optional command) "Reset command loop variables in Normal state. Also prevent point from reaching the end of the line. If the region is activated, enter Visual state." (unless (or (evil-initializing-p) (null this-command)) (setq command (or command this-command)) (when (evil-normal-state-p) (setq evil-this-type nil evil-this-operator nil evil-this-motion nil evil-this-motion-count nil evil-inhibit-operator nil evil-inhibit-operator-value nil) (unless (memq command '(evil-use-register digit-argument negative-argument universal-argument universal-argument-minus universal-argument-more universal-argument-other-key)) (setq evil-this-register nil)) (evil-adjust-cursor)))) (put 'evil-normal-post-command 'permanent-local-hook t) ;;; Insert state (defun evil-maybe-remove-spaces (&optional do-remove) "Remove space from newly opened empty line. This function removes (indentation) spaces that have been inserted by opening a new empty line. The behavior depends on the variable `evil-maybe-remove-spaces'. If this variable is nil the function does nothing. Otherwise the behavior depends on DO-REMOVE. If DO-REMOVE is non-nil the spaces are removed. Otherwise `evil-maybe-remove-spaces' is set to nil unless the last command opened yet another new line. This function should be added as a post-command-hook to track commands opening a new line." (cond ((not evil-maybe-remove-spaces) (remove-hook 'post-command-hook #'evil-maybe-remove-spaces)) (do-remove (when (save-excursion (beginning-of-line) (looking-at "^\\s-*$")) (delete-region (line-beginning-position) (line-end-position))) (setq evil-maybe-remove-spaces nil) (remove-hook 'post-command-hook #'evil-maybe-remove-spaces)) ((not (memq this-command '(evil-open-above evil-open-below evil-append evil-append-line newline newline-and-indent indent-and-newline))) (setq evil-maybe-remove-spaces nil) (remove-hook 'post-command-hook #'evil-maybe-remove-spaces)))) (evil-define-state insert "Insert state." :tag " " :cursor (bar . 2) :message "-- INSERT --" :entry-hook (evil-start-track-last-insertion) :exit-hook (evil-cleanup-insert-state evil-stop-track-last-insertion) :input-method t (cond ((evil-insert-state-p) (add-hook 'post-command-hook #'evil-maybe-remove-spaces) (add-hook 'pre-command-hook #'evil-insert-repeat-hook) (setq evil-maybe-remove-spaces t) (unless (eq evil-want-fine-undo t) (evil-start-undo-step))) (t (remove-hook 'post-command-hook #'evil-maybe-remove-spaces) (remove-hook 'pre-command-hook #'evil-insert-repeat-hook) (evil-maybe-remove-spaces t) (setq evil-insert-repeat-info evil-repeat-info) (evil-set-marker ?^ nil t) (unless (eq evil-want-fine-undo t) (evil-end-undo-step)) (when (or (evil-normal-state-p evil-next-state) (evil-motion-state-p evil-next-state)) (evil-move-cursor-back (and (eolp) (not evil-move-beyond-eol))))))) (defun evil-insert-repeat-hook () "Record insertion keys in `evil-insert-repeat-info'." (setq evil-insert-repeat-info (last evil-repeat-info)) (remove-hook 'pre-command-hook #'evil-insert-repeat-hook)) (put 'evil-insert-repeat-hook 'permanent-local-hook t) (defun evil-cleanup-insert-state () "Called when Insert state is about to be exited. Handles the repeat-count of the insertion command." (when evil-insert-count (dotimes (i (1- evil-insert-count)) (when evil-insert-lines (evil-insert-newline-below) (when evil-auto-indent (indent-according-to-mode))) (when (fboundp 'evil-execute-repeat-info) (evil-execute-repeat-info (cdr evil-insert-repeat-info))))) (when evil-insert-vcount (let ((buffer-invisibility-spec buffer-invisibility-spec)) ;; make all lines hidden by hideshow temporarily visible (when (listp buffer-invisibility-spec) (setq buffer-invisibility-spec (evil-filter-list #'(lambda (x) (or (eq x 'hs) (eq (car-safe x) 'hs))) buffer-invisibility-spec))) (let ((line (nth 0 evil-insert-vcount)) (col (nth 1 evil-insert-vcount)) (vcount (nth 2 evil-insert-vcount))) (save-excursion (dotimes (v (1- vcount)) (goto-char (point-min)) (forward-line (+ line v)) (when (or (not evil-insert-skip-empty-lines) (not (integerp col)) (save-excursion (evil-move-end-of-line) (>= (current-column) col))) (if (integerp col) (move-to-column col t) (funcall col)) (dotimes (i (or evil-insert-count 1)) (when (fboundp 'evil-execute-repeat-info) (evil-execute-repeat-info (cdr evil-insert-repeat-info))))))))))) ;;; Visual state ;; Visual selections are implemented in terms of types, and are ;; compatible with the Emacs region. This is achieved by "translating" ;; the region to the selected text right before a command is executed. ;; If the command is a motion, the translation is postponed until a ;; non-motion command is invoked (distinguished by the :keep-visual ;; command property). ;; ;; Visual state activates the region, enabling Transient Mark mode if ;; not already enabled. This is only temporay: if Transient Mark mode ;; was disabled before entering Visual state, it is disabled when ;; exiting Visual state. This allows Visual state to harness the ;; "transient" behavior of many commands without overriding the user's ;; preferences in other states. (defmacro evil-define-visual-selection (selection doc &rest body) "Define a Visual selection SELECTION. Creates a command evil-visual-SELECTION for enabling the selection. DOC is the function's documentation string. The following keywords may be specified in BODY: :message STRING Status message when enabling the selection. :type TYPE Type to use (defaults to SELECTION). Following the keywords is optional code which is executed each time the selection is enabled. \(fn SELECTION DOC [[KEY VAL]...] BODY...)" (declare (indent defun) (doc-string 2) (debug (&define name stringp [&rest keywordp sexp] def-body))) (let* ((name (intern (format "evil-visual-%s" selection))) (message (intern (format "%s-message" name))) (type selection) arg key string) ;; collect keywords (while (keywordp (car-safe body)) (setq key (pop body) arg (pop body)) (cond ((eq key :message) (setq string arg)) ((eq key :type) (setq type arg)))) ;; macro expansion `(progn (add-to-list 'evil-visual-alist (cons ',selection ',name)) (defvar ,name ',type ,(format "*%s" doc)) (defvar ,message ,string ,doc) (evil-define-command ,name (&optional mark point type message) ,@(when doc `(,doc)) :keep-visual t :repeat nil (interactive (list nil nil (if (and (evil-visual-state-p) (eq evil-visual-selection ',selection)) 'exit ,name) t)) (if (eq type 'exit) (evil-exit-visual-state) (setq type (or type ,name) evil-visual-selection ',selection) (evil-visual-make-region mark point type message) ,@body)) ',selection))) (evil-define-visual-selection char "Characterwise selection." :type inclusive :message "-- VISUAL --") (evil-define-visual-selection line "Linewise selection." :message "-- VISUAL LINE --") (evil-define-visual-selection screen-line "Linewise selection in `visual-line-mode'." :message "-- SCREEN LINE --") (evil-define-visual-selection block "Blockwise selection." :message "-- VISUAL BLOCK --" (evil-transient-mark -1) ;; refresh the :corner property (setq evil-visual-properties (plist-put evil-visual-properties :corner (evil-visual-block-corner 'upper-left)))) (evil-define-state visual "Visual state." :tag " " :enable (motion normal) :message 'evil-visual-message (cond ((evil-visual-state-p) (evil-save-transient-mark-mode) (setq select-active-regions nil) (cond ((region-active-p) (if (< (evil-visual-direction) 0) (evil-visual-select (region-beginning) (region-end) evil-visual-char (evil-visual-direction)) (evil-visual-make-selection (mark t) (point) evil-visual-char)) (evil-visual-highlight)) (t (evil-visual-make-region (point) (point) evil-visual-char))) (add-hook 'pre-command-hook #'evil-visual-pre-command nil t) (add-hook 'post-command-hook #'evil-visual-post-command nil t) (add-hook 'deactivate-mark-hook #'evil-visual-deactivate-hook nil t)) (t ;; Postpone deactivation of region if next state is Insert. ;; This gives certain insertion commands (auto-pairing characters, ;; for example) an opportunity to access the region. (if (and (eq evil-next-state 'insert) (eq evil-visual-selection 'char)) (add-hook 'evil-normal-state-entry-hook #'evil-visual-deactivate-hook nil t) (evil-visual-deactivate-hook)) (setq evil-visual-region-expanded nil) (remove-hook 'pre-command-hook #'evil-visual-pre-command t) (remove-hook 'post-command-hook #'evil-visual-post-command t) (remove-hook 'deactivate-mark-hook #'evil-visual-deactivate-hook t) (evil-visual-highlight -1)))) (defun evil-visual-pre-command (&optional command) "Run before each COMMAND in Visual state. Expand the region to the selection unless COMMAND is a motion." (when (evil-visual-state-p) (setq command (or command this-command)) (when evil-visual-x-select-timer (cancel-timer evil-visual-x-select-timer)) (unless (evil-get-command-property command :keep-visual) (evil-visual-update-x-selection) (evil-visual-expand-region ;; exclude final newline from linewise selection ;; unless the command has real need of it (and (eq (evil-visual-type) 'line) (evil-get-command-property command :exclude-newline)))))) (put 'evil-visual-pre-command 'permanent-local-hook t) (defun evil-visual-post-command (&optional command) "Run after each COMMAND in Visual state. If COMMAND is a motion, refresh the selection; otherwise exit Visual state." (when (evil-visual-state-p) (setq command (or command this-command)) (if (or quit-flag (eq command #'keyboard-quit) ;; Is `mark-active' nil for an unexpanded region? deactivate-mark (and (not evil-visual-region-expanded) (not (region-active-p)) (not (eq evil-visual-selection 'block)))) (progn (evil-exit-visual-state) (evil-adjust-cursor)) (if evil-visual-region-expanded (evil-visual-contract-region) (evil-visual-refresh)) (setq evil-visual-x-select-timer (run-with-idle-timer evil-visual-x-select-timeout nil #'evil-visual-update-x-selection (current-buffer))) (evil-visual-highlight)))) (put 'evil-visual-post-command 'permanent-local-hook t) (defun evil-visual-update-x-selection (&optional buffer) "Update the X selection with the current visual region." (let ((buf (or buffer (current-buffer)))) (when (buffer-live-p buf) (with-current-buffer buf (when (and (evil-visual-state-p) (display-selections-p) (not (eq evil-visual-selection 'block))) (evil-set-selection 'PRIMARY (buffer-substring-no-properties evil-visual-beginning evil-visual-end))))))) (defun evil-visual-activate-hook (&optional command) "Enable Visual state if the region is activated." (unless (evil-visual-state-p) (evil-delay nil ;; the activation may only be momentary, so re-check ;; in `post-command-hook' before entering Visual state '(unless (or (evil-visual-state-p) (evil-insert-state-p) (evil-emacs-state-p)) (when (and (region-active-p) (not deactivate-mark)) (evil-visual-state))) 'post-command-hook nil t "evil-activate-visual-state"))) (put 'evil-visual-activate-hook 'permanent-local-hook t) (defun evil-visual-deactivate-hook (&optional command) "Deactivate the region and restore Transient Mark mode." (setq command (or command this-command)) (remove-hook 'deactivate-mark-hook #'evil-visual-deactivate-hook t) (remove-hook 'evil-normal-state-entry-hook #'evil-visual-deactivate-hook t) (cond ((and (evil-visual-state-p) command (not (evil-get-command-property command :keep-visual))) (setq evil-visual-region-expanded nil) (evil-exit-visual-state)) ((not (evil-visual-state-p)) (evil-active-region -1) (evil-restore-transient-mark-mode)))) (put 'evil-visual-deactivate-hook 'permanent-local-hook t) (evil-define-command evil-exit-visual-state (&optional later buffer) "Exit from Visual state to the previous state. If LATER is non-nil, exit after the current command." :keep-visual t :repeat abort (with-current-buffer (or buffer (current-buffer)) (when (evil-visual-state-p) (if later (setq deactivate-mark t) (when evil-visual-region-expanded (evil-visual-contract-region)) (evil-change-to-previous-state))))) (defun evil-visual-message (&optional selection) "Create an echo area message for SELECTION. SELECTION is a kind of selection as defined by `evil-define-visual-selection', such as `char', `line' or `block'." (let (message) (setq selection (or selection evil-visual-selection)) (when selection (setq message (symbol-value (intern (format "evil-visual-%s-message" selection)))) (cond ((functionp message) (funcall message)) ((stringp message) (evil-echo "%s" message)))))) (defun evil-visual-select (beg end &optional type dir message) "Create a Visual selection of type TYPE from BEG to END. Point and mark are positioned so that the resulting selection has the specified boundaries. If DIR is negative, point precedes mark, otherwise it succedes it. To specify point and mark directly, use `evil-visual-make-selection'." (let* ((range (evil-contract beg end type)) (mark (evil-range-beginning range)) (point (evil-range-end range)) (dir (or dir 1))) (when (< dir 0) (evil-swap mark point)) (evil-visual-make-selection mark point type message))) (defun evil-visual-make-selection (mark point &optional type message) "Create a Visual selection with point at POINT and mark at MARK. The boundaries of the selection are inferred from these and the current TYPE. To specify the boundaries and infer mark and point, use `evil-visual-select' instead." (let* ((selection (evil-visual-selection-for-type type)) (func (evil-visual-selection-function selection)) (prev (and (evil-visual-state-p) evil-visual-selection)) (mark (evil-normalize-position mark)) (point (evil-normalize-position point)) (state evil-state)) (unless (evil-visual-state-p) (evil-visual-state)) (setq evil-visual-selection selection) (funcall func mark point type ;; signal a message when changing the selection (when (or (not (evil-visual-state-p state)) (not (eq selection prev))) message)))) (defun evil-visual-make-region (mark point &optional type message) "Create an active region from MARK to POINT. If TYPE is given, also set the Visual type. If MESSAGE is given, display it in the echo area." (interactive) (let* ((point (evil-normalize-position (or point (point)))) (mark (evil-normalize-position (or mark (when (or (evil-visual-state-p) (region-active-p)) (mark t)) point)))) (unless (evil-visual-state-p) (evil-visual-state)) (evil-active-region 1) (setq evil-visual-region-expanded nil) (evil-visual-refresh mark point type) (cond ((null evil-echo-state)) ((stringp message) (evil-echo "%s" message)) (message (cond ((stringp evil-visual-state-message) (evil-echo "%s" evil-visual-state-message)) ((functionp evil-visual-state-message) (funcall evil-visual-state-message))))))) (defun evil-visual-expand-region (&optional exclude-newline) "Expand the region to the Visual selection. If EXCLUDE-NEWLINE is non-nil and the selection ends with a newline, exclude that newline from the region." (when (and (evil-visual-state-p) (not evil-visual-region-expanded)) (let ((mark evil-visual-beginning) (point evil-visual-end)) (when (< evil-visual-direction 0) (evil-swap mark point)) (setq evil-visual-region-expanded t) (evil-visual-refresh mark point) (when (and exclude-newline (save-excursion (goto-char evil-visual-end) (and (bolp) (not (bobp))))) (if (< evil-visual-direction 0) (evil-move-mark (max point (1- (mark)))) (goto-char (max mark (1- (point))))))))) (defun evil-visual-contract-region () "The inverse of `evil-visual-expand-region'. Create a Visual selection that expands to the current region." (evil-visual-refresh) (setq evil-visual-region-expanded nil) (evil-visual-refresh evil-visual-mark evil-visual-point)) (defun evil-visual-refresh (&optional mark point type &rest properties) "Refresh point, mark and Visual variables. Refreshes `evil-visual-beginning', `evil-visual-end', `evil-visual-mark', `evil-visual-point', `evil-visual-selection', `evil-visual-direction', `evil-visual-properties' and `evil-this-type'." (let* ((point (or point (point))) (mark (or mark (mark t) point)) (dir (evil-visual-direction)) (type (or type (evil-visual-type evil-visual-selection) (evil-visual-type))) range) (evil-move-mark mark) (goto-char point) (setq evil-visual-beginning (or evil-visual-beginning (let ((marker (make-marker))) (move-marker marker (min point mark)))) evil-visual-end (or evil-visual-end (let ((marker (make-marker))) (set-marker-insertion-type marker t) (move-marker marker (max point mark)))) evil-visual-mark (or evil-visual-mark (let ((marker (make-marker))) (move-marker marker mark))) evil-visual-point (or evil-visual-point (let ((marker (make-marker))) (move-marker marker point)))) (setq evil-visual-properties (evil-concat-plists evil-visual-properties properties)) (cond (evil-visual-region-expanded (setq type (or (evil-visual-type) type)) (move-marker evil-visual-beginning (min point mark)) (move-marker evil-visual-end (max point mark)) ;; if the type is one-to-one, we can safely refresh ;; the unexpanded positions as well (when (evil-type-property type :one-to-one) (setq range (apply #'evil-contract point mark type evil-visual-properties) mark (evil-range-beginning range) point (evil-range-end range)) (when (< dir 0) (evil-swap mark point)) (move-marker evil-visual-mark mark) (move-marker evil-visual-point point))) (t (setq range (apply #'evil-expand point mark type evil-visual-properties) type (evil-type range type)) (move-marker evil-visual-beginning (evil-range-beginning range)) (move-marker evil-visual-end (evil-range-end range)) (move-marker evil-visual-mark mark) (move-marker evil-visual-point point))) (setq evil-visual-direction dir evil-this-type type))) (defun evil-visual-highlight (&optional arg) "Highlight Visual selection, depending on the Visual type. With negative ARG, disable highlighting." (cond ((and (numberp arg) (< arg 1)) (when evil-visual-overlay (delete-overlay evil-visual-overlay) (setq evil-visual-overlay nil)) (when evil-visual-block-overlays (mapc #'delete-overlay evil-visual-block-overlays) (setq evil-visual-block-overlays nil))) ((eq evil-visual-selection 'block) (when evil-visual-overlay (evil-visual-highlight -1)) (evil-visual-highlight-block evil-visual-beginning evil-visual-end)) (t (when evil-visual-block-overlays (evil-visual-highlight -1)) (if evil-visual-overlay (move-overlay evil-visual-overlay evil-visual-beginning evil-visual-end) (setq evil-visual-overlay (make-overlay evil-visual-beginning evil-visual-end))) (overlay-put evil-visual-overlay 'face 'region) (overlay-put evil-visual-overlay 'priority 99)))) (defun evil-visual-highlight-block (beg end &optional overlays) "Highlight rectangular region from BEG to END. Do this by putting an overlay on each line within the rectangle. Each overlay extends across all the columns of the rectangle. Reuse overlays where possible to prevent flicker." (let* ((point (point)) (mark (or (mark t) point)) (overlays (or overlays 'evil-visual-block-overlays)) (old (symbol-value overlays)) (eol-col (and (memq this-command '(next-line previous-line)) (numberp temporary-goal-column) (1+ (min (round temporary-goal-column) (1- most-positive-fixnum))))) beg-col end-col new nlines overlay window-beg window-end) (save-excursion ;; calculate the rectangular region represented by BEG and END, ;; but put BEG in the upper-left corner and END in the ;; lower-right if not already there (setq beg-col (evil-column beg) end-col (evil-column end)) (when (>= beg-col end-col) (if (= beg-col end-col) (setq end-col (1+ end-col)) (evil-sort beg-col end-col)) (setq beg (save-excursion (goto-char beg) (evil-move-to-column beg-col)) end (save-excursion (goto-char end) (evil-move-to-column end-col 1)))) ;; update end column with eol-col (extension to eol). (when (and eol-col (> eol-col end-col)) (setq end-col eol-col)) ;; force a redisplay so we can do reliable window ;; BEG/END calculations (sit-for 0) (setq window-beg (max (window-start) beg) window-end (min (window-end) (1+ end)) nlines (count-lines window-beg (min window-end (point-max)))) ;; iterate over those lines of the rectangle which are ;; visible in the currently selected window (goto-char window-beg) (dotimes (i nlines) (let (before after row-beg row-end) ;; beginning of row (evil-move-to-column beg-col) (when (< (current-column) beg-col) ;; prepend overlay with virtual spaces if unable to ;; move directly to the first column (setq before (propertize (make-string (- beg-col (current-column)) ?\s) 'face (or (get-text-property (1- (point)) 'face) 'default)))) (setq row-beg (point)) ;; end of row (evil-move-to-column end-col) (when (and (not (eolp)) (< (current-column) end-col)) ;; append overlay with virtual spaces if unable to ;; move directly to the last column (setq after (propertize (make-string (if (= (point) row-beg) (- end-col beg-col) (- end-col (current-column))) ?\s) 'face 'region)) ;; place cursor on one of the virtual spaces (if (= point row-beg) (put-text-property 0 (min (length after) 1) 'cursor t after) (put-text-property (max 0 (1- (length after))) (length after) 'cursor t after))) (setq row-end (min (point) (line-end-position))) ;; trim old leading overlays (while (and old (setq overlay (car old)) (< (overlay-start overlay) row-beg) (/= (overlay-end overlay) row-end)) (delete-overlay overlay) (setq old (cdr old))) ;; reuse an overlay if possible, otherwise create one (cond ((and old (setq overlay (car old)) (or (= (overlay-start overlay) row-beg) (= (overlay-end overlay) row-end))) (move-overlay overlay row-beg row-end) (overlay-put overlay 'before-string before) (overlay-put overlay 'after-string after) (setq new (cons overlay new) old (cdr old))) (t (setq overlay (make-overlay row-beg row-end)) (overlay-put overlay 'before-string before) (overlay-put overlay 'after-string after) (setq new (cons overlay new))))) (forward-line 1)) ;; display overlays (dolist (overlay new) (overlay-put overlay 'face 'region) (overlay-put overlay 'priority 99)) ;; trim old overlays (dolist (overlay old) (delete-overlay overlay)) (set overlays (nreverse new))))) (defun evil-visual-range () "Return the Visual selection as a range. This is a list (BEG END TYPE PROPERTIES...), where BEG is the beginning of the selection, END is the end of the selection, TYPE is the selection's type, and PROPERTIES is a property list of miscellaneous selection attributes." (apply #'evil-range evil-visual-beginning evil-visual-end (evil-visual-type) :expanded t evil-visual-properties)) (defun evil-visual-direction () "Return direction of Visual selection. The direction is -1 if point precedes mark and 1 otherwise. See also the variable `evil-visual-direction', which holds the direction of the last selection." (let* ((point (point)) (mark (or (mark t) point))) (if (< point mark) -1 1))) (defun evil-visual-type (&optional selection) "Return the type of the Visual selection. If SELECTION is specified, return the type of that instead." (if (and (null selection) (evil-visual-state-p)) (or evil-this-type (evil-visual-type evil-visual-selection)) (setq selection (or selection evil-visual-selection)) (symbol-value (cdr-safe (assq selection evil-visual-alist))))) (defun evil-visual-goto-end () "Go to the last line of the Visual selection. This position may differ from `evil-visual-end' depending on the selection type, and is contained in the selection." (let ((range (evil-contract-range (evil-visual-range)))) (goto-char (evil-range-end range)))) (defun evil-visual-alist () "Return an association list from types to selection symbols." (mapcar #'(lambda (e) (cons (symbol-value (cdr-safe e)) (cdr-safe e))) evil-visual-alist)) (defun evil-visual-selection-function (selection) "Return a selection function for TYPE. Default to `evil-visual-make-region'." (or (cdr-safe (assq selection evil-visual-alist)) ;; generic selection function 'evil-visual-make-region)) (defun evil-visual-selection-for-type (type) "Return a Visual selection for TYPE." (catch 'done (dolist (selection evil-visual-alist) (when (eq (symbol-value (cdr selection)) type) (throw 'done (car selection)))))) (defun evil-visual-block-corner (&optional corner point mark) "Block corner corresponding to POINT, with MARK in opposite corner. Depending on POINT and MARK, the return value is `upper-left', `upper-right', `lower-left' or `lower-right': upper-left +---+ upper-right | | lower-left +---+ lower-right One-column or one-row blocks are ambiguous. In such cases, the horizontal or vertical component of CORNER is used. CORNER defaults to `upper-left'." (let* ((point (or point (point))) (mark (or mark (mark t))) (corner (symbol-name (or corner (and (overlayp evil-visual-overlay) (overlay-get evil-visual-overlay :corner)) 'upper-left))) (point-col (evil-column point)) (mark-col (evil-column mark)) horizontal vertical) (cond ((= point-col mark-col) (setq horizontal (or (and (string-match "left\\|right" corner) (match-string 0 corner)) "left"))) ((< point-col mark-col) (setq horizontal "left")) ((> point-col mark-col) (setq horizontal "right"))) (cond ((= (line-number-at-pos point) (line-number-at-pos mark)) (setq vertical (or (and (string-match "upper\\|lower" corner) (match-string 0 corner)) "upper"))) ((< point mark) (setq vertical "upper")) ((> point mark) (setq vertical "lower"))) (intern (format "%s-%s" vertical horizontal)))) ;;; Operator-Pending state (evil-define-state operator "Operator-Pending state." :tag " " :cursor evil-half-cursor :enable (evil-operator-shortcut-map operator motion normal)) (evil-define-keymap evil-operator-shortcut-map "Keymap for Operator-Pending shortcuts like \"dd\" and \"gqq\"." :local t (setq evil-operator-shortcut-map (make-sparse-keymap)) (evil-initialize-local-keymaps)) ;; the half-height "Operator-Pending cursor" cannot be specified ;; as a static `cursor-type' value, since its height depends on ;; the current font size (defun evil-half-cursor () "Change cursor to a half-height box. \(This is really just a thick horizontal bar.)" (let ((height (/ (window-pixel-height) (* (window-height) 2)))) (setq cursor-type (cons 'hbar height)))) ;;; Replace state (evil-define-state replace "Replace state." :tag " " :cursor hbar :message "-- REPLACE --" :input-method t (cond ((evil-replace-state-p) (overwrite-mode 1) (add-hook 'pre-command-hook #'evil-replace-pre-command nil t) (unless (eq evil-want-fine-undo t) (evil-start-undo-step))) (t (overwrite-mode -1) (remove-hook 'pre-command-hook #'evil-replace-pre-command t) (unless (eq evil-want-fine-undo t) (evil-end-undo-step)) (evil-move-cursor-back))) (setq evil-replace-alist nil)) (defun evil-replace-pre-command () "Remember the character under point." (when (evil-replace-state-p) (unless (assq (point) evil-replace-alist) (add-to-list 'evil-replace-alist (cons (point) (unless (eolp) (char-after))))))) (put 'evil-replace-pre-command 'permanent-local-hook t) (defun evil-replace-backspace () "Restore character under cursor." (interactive) (let (char) (backward-char) (when (assq (point) evil-replace-alist) (setq char (cdr (assq (point) evil-replace-alist))) (save-excursion (delete-char 1) (when char (insert char)))))) ;;; Motion state (evil-define-state motion "Motion state." :tag " " :suppress-keymap t) ;;; Emacs state (evil-define-state emacs "Emacs state." :tag " " :message "-- EMACS --" :input-method t :intercept-esc nil) (provide 'evil-states) ;;; evil-states.el ends here evil-1.12.17/evil-test-helpers.el000066400000000000000000000426041360703323200165250ustar00rootroot00000000000000;;; evil-test-helpers.el --- unit test helpers for Evil -*- coding: utf-8 -*- ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Package-Requires: ((evil "1.12.17")) ;; Version: 1.12.17 ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . ;;; Commentary: ;; This file contains helper functions for writing tests for ;; evil-mode. These helpers can also be used by other packages which ;; extend evil-mode. ;; To write a test use `evil-test-buffer': ;; (require 'evil-test-helpers) ;; ;; (ert-deftest evil-test () ;; :tags '(evil) ;; (evil-test-buffer ;; "[T]his creates a test buffer." ; cursor on "T" ;; ("w") ; key sequence ;; "This [c]reates a test buffer."))) ; cursor moved to "c" ;; ;; The initial state, the cursor syntax, etc., can be changed ;; with keyword arguments. See the documentation string of ;; `evil-test-buffer' for more details. ;; ;; This file is NOT part of Evil itself. (require 'elp) (require 'ert) (require 'evil) ;;; Code: (when (fboundp 'font-lock-add-keywords) (font-lock-add-keywords 'emacs-lisp-mode '(("(\\(evil-test-buffer\\)\\>" 1 font-lock-keyword-face)))) (defvar evil-test-point nil "Marker for point.") (make-variable-buffer-local 'evil-test-point) (defvar evil-test-visual-start nil "Marker for Visual beginning.") (make-variable-buffer-local 'evil-test-visual-start) (defvar evil-test-visual-end nil "Marker for Visual end.") (make-variable-buffer-local 'evil-test-visual-end) (defmacro evil-test-buffer (&rest body) "Execute FORMS in a temporary buffer. The following optional keywords specify the buffer's properties: :state STATE The initial state, defaults to `normal'. :visual SELECTION The Visual selection, defaults to `char'. :point-start STRING String for matching beginning of point, defaults to \"[\". :point-end STRING String for matching end of point, defaults to \"]\". :visual-start STRING String for matching beginning of Visual selection, defaults to \"<\". :visual-end STRING String for matching end of Visual selection, defaults to \">\". Then follows one or more forms. If the first form is a string, it is taken to be a buffer description as passed to `evil-test-buffer-from-string', and initializes the buffer. Subsequent string forms validate the buffer. If a form is a list of strings or vectors, it is taken to be a key sequence and is passed to `execute-kbd-macro'. If the form is \(file FILENAME CONTENTS), then the test fails unless the contents of FILENAME equal CONTENTS. If the form is \(error SYMBOL ...) then the test fails unless an error of type SYMBOL is raised. Remaining forms are evaluated as-is. \(fn [[KEY VALUE]...] FORMS...)" (declare (indent defun)) (let ((state 'normal) arg key point-start point-end string visual visual-start visual-end) ;; collect keywords (while (keywordp (car-safe body)) (setq key (pop body) arg (pop body)) (cond ((eq key :point-start) (setq point-start (or arg ""))) ((eq key :point-end) (setq point-end (or arg ""))) ((eq key :state) (setq state arg)) ((eq key :visual) (setq visual arg)) ((eq key :visual-start) (setq visual-start (or arg ""))) ((eq key :visual-end) (setq visual-end (or arg ""))))) ;; collect buffer initialization (when (stringp (car-safe body)) (setq string (pop body))) ;; macro expansion `(let ((buffer (evil-test-buffer-from-string ,string ',state ,point-start ,point-end ',visual ,visual-start ,visual-end)) (kill-ring kill-ring) (kill-ring-yank-pointer kill-ring-yank-pointer) x-select-enable-clipboard message-log-max) (unwind-protect (save-window-excursion (with-current-buffer buffer ;; necessary for keyboard macros to work (switch-to-buffer-other-window (current-buffer)) (buffer-enable-undo) (undo-tree-mode 1) ;; parse remaining forms ,@(mapcar #'(lambda (form) (let (error-symbol) (when (and (listp form) (eq (car-safe form) 'error)) (setq error-symbol (car-safe (cdr-safe form)) form (cdr-safe (cdr-safe form)))) (let ((result (cond ((stringp form) `(evil-test-buffer-string ,form ',point-start ',point-end ',visual-start ',visual-end)) ((eq (car-safe form) 'file) `(evil-test-file-contents ,(cadr form) ,(car (cddr form)))) ((or (stringp (car-safe form)) (vectorp (car-safe form)) (memq (car-safe (car-safe form)) '(kbd vconcat))) ;; we need to execute everything as a single ;; sequence for command loop hooks to work `(execute-kbd-macro (apply #'vconcat (mapcar #'listify-key-sequence (mapcar #'eval ',form))))) ((memq (car-safe form) '(kbd vconcat)) `(execute-kbd-macro ,form)) (t form)))) (if error-symbol `(should-error ,result :type ',error-symbol) result)))) body))) (and (buffer-name buffer) (kill-buffer buffer)))))) (defmacro evil-test-selection (string &optional end-string before-predicate after-predicate) "Verify that the Visual selection contains STRING." (declare (indent defun)) `(progn (save-excursion (goto-char (or evil-visual-beginning (region-beginning))) (evil-test-text nil (or ,string ,end-string) ,before-predicate)) (save-excursion (goto-char (or evil-visual-end (region-end))) (evil-test-text (or ,end-string ,string) nil nil ,after-predicate)))) (defun evil-test-buffer-string (string &optional point-start point-end visual-start visual-end) "Validate the current buffer according to STRING. If STRING contains an occurrence of POINT-START immediately followed by POINT-END, that position is compared against point. If STRING contains an occurrence of VISUAL-START followed by VISUAL-END, those positions are compared against the Visual selection. POINT-START and POINT-END default to [ and ]. VISUAL-START and VISUAL-END default to < and >." (let ((actual-buffer (current-buffer)) (marker-buffer (evil-test-marker-buffer-from-string string point-start point-end visual-start visual-end)) before-point after-point string selection) (unwind-protect (with-current-buffer marker-buffer (setq string (buffer-string)) (when evil-test-point (setq before-point (buffer-substring (point-min) evil-test-point) after-point (buffer-substring evil-test-point (point-max)))) (when (and evil-test-visual-start evil-test-visual-end) (setq selection (buffer-substring evil-test-visual-start evil-test-visual-end))) (with-current-buffer actual-buffer (if (or before-point after-point) (evil-test-text before-point after-point) ;; if the cursor isn't specified, just test the whole buffer (save-excursion (goto-char (point-min)) (evil-test-text nil string #'bobp #'eobp))) (when selection (evil-test-selection selection)))) (kill-buffer marker-buffer)))) (defun evil-test-buffer-from-string (string &optional state point-start point-end visual visual-start visual-end) "Create a new buffer according to STRING. If STRING contains an occurrence of POINT-START immediately followed by POINT-END, then point is moved to that position. If STRING contains an occurrence of VISUAL-START followed by VISUAL-END, then a Visual selection is created with those boundaries. POINT-START and POINT-END default to [ and ]. VISUAL-START and VISUAL-END default to < and >. STATE is the initial state; it defaults to `normal'. VISUAL is the Visual selection: it defaults to `char'." (let ((type (evil-visual-type (or visual 'char))) (buffer (evil-test-marker-buffer-from-string string point-start point-end visual-start visual-end))) (with-current-buffer buffer (prog1 buffer (evil-change-state state) ;; let the buffer change its major mode without disabling Evil (add-hook 'after-change-major-mode-hook #'evil-initialize) (when (and (markerp evil-test-visual-start) (markerp evil-test-visual-end)) (evil-visual-select evil-test-visual-start evil-test-visual-end type) (when evil-test-point (goto-char evil-test-point) (evil-visual-refresh) (unless (and (= evil-visual-beginning evil-test-visual-start) (= evil-visual-end evil-test-visual-end)) (evil-visual-select evil-test-visual-start evil-test-visual-end type -1) (goto-char evil-test-point) (evil-visual-refresh)))) (when (markerp evil-test-point) (goto-char evil-test-point)))))) (defun evil-test-marker-buffer-from-string (string &optional point-start point-end visual-start visual-end) "Create a new marker buffer according to STRING. If STRING contains an occurrence of POINT-START immediately followed by POINT-END, that position is stored in the buffer-local variable `evil-test-point'. Similarly, if STRING contains an occurrence of VISUAL-START followed by VISUAL-END, those positions are stored in the variables `evil-test-visual-beginning' and `evil-test-visual-end'. POINT-START and POINT-END default to [ and ]. VISUAL-START and VISUAL-END default to < and >." (let ((string (or string "")) (point-start (regexp-quote (if (characterp point-start) (string point-start) (or point-start "[")))) (point-end (regexp-quote (if (characterp point-end) (string point-end) (or point-end "]")))) (visual-start (regexp-quote (if (characterp visual-start) (string visual-start) (or visual-start "<")))) (visual-end (regexp-quote (if (characterp visual-end) (string visual-end) (or visual-end ">"))))) (with-current-buffer (generate-new-buffer " *test*") (prog1 (current-buffer) (save-excursion (insert string)) (save-excursion (when (> (length point-start) 0) (if (> (length point-end) 0) (when (re-search-forward (format "\\(%s\\)[^%s]?\\(%s\\)" point-start point-end point-end) nil t) (goto-char (match-beginning 0)) (delete-region (match-beginning 2) (match-end 2)) (delete-region (match-beginning 1) (match-end 1)) (setq evil-test-point (move-marker (make-marker) (point)))) (when (re-search-forward point-start nil t) (goto-char (match-beginning 0)) (delete-region (match-beginning 0) (match-end 0)) (setq evil-test-point (move-marker (make-marker) (point))))))) (save-excursion (when (and (> (length visual-start) 0) (> (length visual-end) 0)) (when (re-search-forward visual-start nil t) (goto-char (match-beginning 0)) (delete-region (match-beginning 0) (match-end 0)) (setq evil-test-visual-start (move-marker (make-marker) (point)))) (when (re-search-forward visual-end nil t) (goto-char (match-beginning 0)) (delete-region (match-beginning 0) (match-end 0)) (setq evil-test-visual-end (move-marker (make-marker) (point)))))))))) (defun evil-test-text (before after &optional before-predicate after-predicate) "Verify the text around point. BEFORE is the expected text before point, and AFTER is the text after point. BEFORE-PREDICATE is a predicate function to execute at the beginning of the text, and AFTER-PREDICATE is executed at the end." (when before (if (functionp before) (setq before-predicate before before nil) (should (string= (buffer-substring (max (point-min) (- (point) (length before))) (point)) before)))) (when after (if (functionp after) (setq after-predicate after after nil) (should (string= (buffer-substring (point) (min (point-max) (+ (point) (length after)))) after)))) (when before-predicate (ert-info ((format "Expect `%s' at the beginning" before-predicate)) (save-excursion (backward-char (length before)) (should (funcall before-predicate))))) (when after-predicate (ert-info ((format "Expect `%s' at the end" after-predicate)) (save-excursion (forward-char (length after)) (should (funcall after-predicate)))))) (defmacro evil-test-region (string &optional end-string before-predicate after-predicate) "Verify that the region contains STRING." (declare (indent defun)) `(progn (save-excursion (goto-char (region-beginning)) (evil-test-text nil (or ,string ,end-string) ,before-predicate)) (save-excursion (goto-char (region-end)) (evil-test-text (or ,end-string ,string) nil nil ,after-predicate)))) (defmacro evil-test-overlay (overlay string &optional end-string before-predicate after-predicate) "Verify that OVERLAY contains STRING." (declare (indent defun)) `(progn (save-excursion (goto-char (overlay-start ,overlay)) (evil-test-text nil (or ,string ,end-string) ,before-predicate)) (save-excursion (goto-char (overlay-end ,overlay)) (evil-test-text (or ,end-string ,string) nil nil ,after-predicate)))) (defmacro evil-with-temp-file (file-var content &rest body) "Create a temp file with CONTENT and bind its name to FILE-VAR within BODY. FILE-VAR must be a symbol which contains the name of the temporary file within the macro body. CONTENT is either a string to be used as the content of the temporary file or a form to be executed with the temporary file's buffer as \(current-buffer), see `with-temp-file'. BODY contains the forms to be executed while the temporary file exists. The temporary file is deleted at the end of the execution of BODY." (declare (indent 2) (debug (symbolp form body))) `(let ((,file-var (make-temp-file "evil-test"))) (with-temp-file ,file-var ,(if (stringp content) `(insert ,content) content)) ,@body (delete-file ,file-var))) (defun evil-test-file-contents (name contents) "Ensure that the contents of file with NAME equal CONTENTS." (with-temp-buffer (insert-file-contents name) (should (string= (buffer-string) contents)))) (provide 'evil-test-helpers) ;;; evil-test-helpers.el ends here evil-1.12.17/evil-tests.el000066400000000000000000010367401360703323200152550ustar00rootroot00000000000000;; evil-tests.el --- unit tests for Evil -*- coding: utf-8 -*- ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . ;;; Commentary: ;; This file is for developers. It runs some tests on Evil. ;; To load it, run the Makefile target "make test" or add ;; the following lines to .emacs: ;; ;; (setq evil-tests-run nil) ; set to t to run tests immediately ;; (global-set-key [f12] 'evil-tests-run) ; hotkey ;; (require 'evil-tests) ;; ;; Loading this file enables profiling on Evil. The current numbers ;; can be displayed with `elp-results'. The Makefile target ;; "make profiler" shows profiling results in the terminal on the ;; basis of running all tests. ;; ;; To write a test, use `ert-deftest' and specify a :tags value of at ;; least '(evil). The test may inspect the output of functions given ;; certain input, or it may execute a key sequence in a temporary ;; buffer and investigate the results. For the latter approach, the ;; macro `evil-test-buffer' creates a temporary buffer in Normal ;; state. String descriptors initialize and match the contents of ;; the buffer: ;; ;; (ert-deftest evil-test () ;; :tags '(evil) ;; (evil-test-buffer ;; "[T]his creates a test buffer." ; cursor on "T" ;; ("w") ; key sequence ;; "This [c]reates a test buffer."))) ; cursor moved to "c" ;; ;; The initial state, the cursor syntax, etc., can be changed ;; with keyword arguments. See the documentation string of ;; `evil-test-buffer' for more details. ;; ;; This file is NOT part of Evil itself. (require 'cl-lib) (require 'elp) (require 'ert) (require 'evil) (require 'evil-test-helpers) ;;; Code: (defvar evil-tests-run nil "*Run Evil tests.") (defvar evil-tests-profiler nil "*Profile Evil tests.") (defun evil-tests-initialize (&optional tests profiler interactive) (setq profiler (or profiler evil-tests-profiler)) (when (listp profiler) (setq profiler (car profiler))) (when profiler (setq evil-tests-profiler t) (setq profiler (or (cdr (assq profiler '((call . elp-sort-by-call-count) (average . elp-sort-by-average-time) (total . elp-sort-by-total-time)))))) (setq elp-sort-by-function (or profiler 'elp-sort-by-call-count)) (elp-instrument-package "evil")) (if interactive (if (y-or-n-p-with-timeout "Run tests? " 2 t) (evil-tests-run tests interactive) (message "You can run the tests at any time \ with `M-x evil-tests-run'")) (evil-tests-run tests))) (defun evil-tests-run (&optional tests interactive) "Run Evil tests." (interactive '(nil t)) (let ((elp-use-standard-output (not interactive))) (setq tests (or (null tests) `(or ,@(mapcar #'(lambda (test) (or (null test) (and (memq test '(evil t)) t) `(or (tag ,test) ,(format "^%s$" test)))) tests)))) (cond (interactive (ert-run-tests-interactively tests) (when evil-tests-profiler (elp-results))) (evil-tests-profiler (ert-run-tests-batch tests) (elp-results)) (t ;; We would like to use `ert-run-tests-batch-and-exit' ;; Unfortunately it doesn't work outside of batch mode, and we ;; can't use batch mode because we have tests that need windows. ;; Instead, run the tests interactively, copy the results to a ;; text file, and then exit with an appropriate code. (setq attempt-stack-overflow-recovery nil attempt-orderly-shutdown-on-fatal-signal nil) (unwind-protect (progn (ert-run-tests-interactively tests) (with-current-buffer "*ert*" (append-to-file (point-min) (point-max) "test-results.txt") (kill-emacs (if (zerop (ert-stats-completed-unexpected ert--results-stats)) 0 1)))) (unwind-protect (progn (append-to-file "Error running tests\n" nil "test-results.txt") (append-to-file (backtrace-to-string (backtrace-get-frames 'backtrace)) nil "test-results.txt")) (kill-emacs 2))))))) (defun evil-tests-profiler (&optional force) "Profile Evil tests." (when (or evil-tests-profiler force) (setq evil-tests-profiler t) (elp-instrument-package "evil"))) ;;; States (defun evil-test-local-mode-enabled () "Verify that `evil-local-mode' is enabled properly" (ert-info ("Set the mode variable to t") (should (eq evil-local-mode t))) (ert-info ("Refresh `emulation-mode-map-alist'") (should (memq 'evil-mode-map-alist emulation-mode-map-alists))) (ert-info ("Create a buffer-local value for `evil-mode-map-alist'") (should (assq 'evil-mode-map-alist (buffer-local-variables)))) (ert-info ("Initialize buffer-local keymaps") (should (assq 'evil-normal-state-local-map (buffer-local-variables))) (should (keymapp evil-normal-state-local-map)) (should (assq 'evil-emacs-state-local-map (buffer-local-variables))) (should (keymapp evil-emacs-state-local-map))) (ert-info ("Don't add buffer-local entries to the default value") (should-not (rassq evil-normal-state-local-map (default-value 'evil-mode-map-alist))) (should-not (rassq evil-emacs-state-local-map (default-value 'evil-mode-map-alist))))) (defun evil-test-local-mode-disabled () "Verify that `evil-local-mode' is disabled properly" (ert-info ("Set the mode variable to nil") (should-not evil-local-mode)) (ert-info ("Disable all states") (evil-test-no-states))) (defun evil-test-no-states () "Verify that all states are disabled" (ert-info ("Set `evil-state' to nil") (should-not evil-state)) (ert-info ("Disable all state keymaps") (dolist (state (mapcar #'car evil-state-properties) t) (should-not (evil-state-property state :mode t)) (should-not (memq (evil-state-property state :keymap t) (current-active-maps))) (should-not (evil-state-property state :local t)) (should-not (memq (evil-state-property state :local-keymap t) (current-active-maps))) (dolist (map (evil-state-auxiliary-keymaps state)) (should-not (memq map (current-active-maps))))))) (ert-deftest evil-test-toggle-local-mode () "Toggle `evil-local-mode'" :tags '(evil state) (with-temp-buffer (ert-info ("Enable `evil-local-mode'") (evil-local-mode 1) (evil-test-local-mode-enabled)) (ert-info ("Disable `evil-local-mode'") (evil-local-mode -1) (evil-test-local-mode-disabled)))) (defun evil-test-change-state (state) "Change state to STATE and check keymaps" (let (mode keymap local-mode local-keymap tag) (evil-change-state state) (setq mode (evil-state-property state :mode) keymap (evil-state-property state :keymap t) local-mode (evil-state-property state :local) local-keymap (evil-state-property state :local-keymap t) tag (evil-state-property state :tag t)) (ert-info ("Update `evil-state'") (should (eq evil-state state))) (ert-info ("Ensure `evil-local-mode' is enabled") (evil-test-local-mode-enabled)) (ert-info ("Enable state modes") (should (symbol-value mode)) (should (symbol-value local-mode))) (ert-info ("Push state keymaps to the top") (evil-test-state-keymaps state)) (ert-info ("Refresh mode line tag") (should (equal evil-mode-line-tag tag))))) (defun evil-test-state-keymaps (state) "Verify that STATE's keymaps are pushed to the top" (let ((actual (evil-state-keymaps state)) (expected `((,(evil-state-property state :local) . , (evil-state-property state :local-keymap t)) (,(evil-state-property state :mode) . ,(evil-state-property state :keymap t))))) ;; additional keymaps inherited with :enable (cond ((eq state 'operator) (setq expected `((evil-operator-shortcut-mode . ,evil-operator-shortcut-map) (evil-operator-state-local-minor-mode . ,evil-operator-state-local-map) (evil-operator-state-minor-mode . ,evil-operator-state-map) (evil-motion-state-local-minor-mode . ,evil-motion-state-local-map) (evil-motion-state-minor-mode . ,evil-motion-state-map) (evil-normal-state-local-minor-mode . ,evil-normal-state-local-map) (evil-normal-state-minor-mode . ,evil-normal-state-map))))) (let ((actual (butlast actual (- (length actual) (length expected))))) (should (equal actual expected)) (dolist (map actual) (setq map (cdr-safe map)) (should (keymapp map)))))) (ert-deftest evil-test-exit-normal-state () "Enter Normal state and then disable all states" :tags '(evil state) (with-temp-buffer (evil-test-change-state 'normal) (evil-normal-state -1) (evil-test-no-states))) (ert-deftest evil-test-change-states () "Change between Normal state, Emacs state and Operator-Pending state" :tags '(evil state) (with-temp-buffer (evil-test-change-state 'normal) (evil-test-change-state 'emacs) (evil-test-change-state 'normal) (evil-test-change-state 'operator) (evil-test-change-state 'normal) (evil-test-change-state 'emacs) (evil-test-change-state 'replace) (evil-test-change-state 'normal))) (ert-deftest evil-test-change-to-previous-state () "Change to some state and back." :tags '(evil state) (with-temp-buffer (evil-test-change-state 'normal) (evil-test-change-state 'visual) (evil-test-change-state 'emacs) (evil-change-to-previous-state) (should (eq evil-state 'visual)) (evil-change-to-previous-state) (should (eq evil-state 'normal)))) (ert-deftest evil-test-enter-normal-state-disabled () "Enter Normal state even if `evil-local-mode' is disabled" :tags '(evil state) (with-temp-buffer (evil-local-mode -1) (evil-test-local-mode-disabled) (evil-test-change-state 'normal))) (ert-deftest evil-test-execute-in-normal-state () "Test `evil-execute-in-normal-state'." :tags '(evil) (ert-info ("Execute normal state command in insert state") (evil-test-buffer "[a]bcdef\n" ("I") (should (evil-insert-state-p)) ("\C-ox") (ert-info ("Should return to insert state") (should (evil-insert-state-p))) "[b]cdef\n" ("\C-oA") (ert-info ("Should return to insert state after insert state command") (should (evil-insert-state-p))) ("bcdef[]\n")))) (defun evil-test-suppress-keymap (state) "Verify that `self-insert-command' is suppressed in STATE" (evil-test-buffer ";; This buffer is for notes." (evil-test-change-state state) ;; TODO: this should be done better (ert-info ("Disable the state's own keymaps so that the suppression keymap comes first") (setq evil-operator-state-minor-mode nil evil-operator-state-local-minor-mode nil)) (should (eq (key-binding "Q") #'undefined)) (ert-info ("Don't insert text") ;; may or may not signal an error, depending on batch mode (condition-case nil (execute-kbd-macro "QQQ") (error nil)) (should (string= (buffer-substring 1 4) ";; "))))) (ert-deftest evil-test-emacs-state-suppress-keymap () "`self-insert-command' works in Emacs state" :tags '(evil state) (should-error (evil-test-suppress-keymap 'emacs))) (ert-deftest evil-test-normal-state-suppress-keymap () "No `self-insert-command' in Normal state" :tags '(evil state) (evil-test-suppress-keymap 'normal)) (ert-deftest evil-test-operator-state-suppress-keymap () "Operator-Pending state should inherit suppression of `self-insert-command' from Normal state" :tags '(evil state) (evil-test-suppress-keymap 'operator)) (ert-deftest evil-test-operator-state-shortcut-keymap () "Enable shortcut keymap in Operator-Pending state" :tags '(evil state) (evil-test-buffer (ert-info ("Activate `evil-operator-shortcut-map' in \ Operator-Pending state") (evil-test-change-state 'operator) (should (rassq evil-operator-shortcut-map (evil-state-keymaps 'operator))) (should (keymapp evil-operator-shortcut-map)) (should evil-operator-shortcut-mode) (should (memq evil-operator-shortcut-map (current-active-maps)))) (ert-info ("Deactivate `evil-operator-shortcut-map' \ outside Operator-Pending state") (evil-test-change-state 'emacs) (should-not evil-operator-shortcut-mode) (should-not (memq evil-operator-shortcut-map (current-active-maps)))) (ert-info ("Reset `evil-operator-shortcut-map' \ when entering Operator-Pending state") (define-key evil-operator-shortcut-map "f" 'foo) (should (eq (lookup-key evil-operator-shortcut-map "f") 'foo)) (evil-test-change-state 'operator) (should-not (eq (lookup-key evil-operator-shortcut-map "f") 'foo))) (ert-info ("Reset `evil-operator-shortcut-map' \ when exiting Operator-Pending state") (define-key evil-operator-shortcut-map "b" 'bar) (should (eq (lookup-key evil-operator-shortcut-map "b") 'bar)) (evil-test-change-state 'emacs) (should-not (eq (lookup-key evil-operator-shortcut-map "b") 'bar))))) (ert-deftest evil-test-auxiliary-maps () "Test auxiliary keymaps" :tags '(evil state) (let ((map (make-sparse-keymap)) aux) (ert-info ("Create a new auxiliary keymap") (evil-define-key 'normal map "f" 'foo) (setq aux (evil-get-auxiliary-keymap map 'normal)) (should (evil-auxiliary-keymap-p aux)) (should (eq (lookup-key aux "f") 'foo))) (ert-info ("Add to auxiliary keymap") (evil-define-key 'normal map "b" 'bar) (should (eq (lookup-key aux "f") 'foo)) (should (eq (lookup-key aux "b") 'bar))))) (ert-deftest evil-test-global-local-map-binding () "Test use of `evil-define-key' for binding in global maps." :tags '(evil state) (let ((evil-normal-state-map (copy-keymap evil-normal-state-map)) (evil-normal-state-local-map (when (keymapp evil-normal-state-local-map) (copy-keymap evil-normal-state-local-map))) (global-map (copy-keymap global-map)) (orig-local-map (when (keymapp (current-local-map)) (copy-keymap (current-local-map)))) (map (or (current-local-map) (make-sparse-keymap)))) (use-local-map map) (ert-info ("Bind in a global state map") (evil-define-key 'normal 'global "f" 'foo) (should (eq (lookup-key evil-normal-state-map "f") 'foo))) (ert-info ("Bind in a local state map") (evil-define-key 'normal 'local "f" 'foo) (should (eq (lookup-key evil-normal-state-local-map "f") 'foo))) (ert-info ("Bind in the global map") (evil-define-key nil 'global "b" 'bar) (should (eq (lookup-key global-map "b") 'bar))) (ert-info ("Bind in the local map") (evil-define-key nil 'local "b" 'bar) (should (eq (lookup-key (current-local-map) "b") 'bar))) (use-local-map orig-local-map))) ;;; Type system (ert-deftest evil-test-exclusive-type () "Expand and contract the `line' type" :tags '(evil type) (evil-test-buffer ";; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (let* ((first-line 1) (second-line (progn (forward-line) (point))) (third-line (progn (forward-line) (point)))) (ert-info ("Return the beginning and end unchanged \ if they are the same") (should (equal (evil-normalize 1 1 'exclusive) (list 1 1 'exclusive)))) (ert-info ("expand to `inclusive' if the end position \ is at the beginning of a line") (should (equal (evil-normalize (1+ first-line) second-line 'exclusive) (list (1+ first-line) (1- second-line) 'inclusive :expanded t)))) (ert-info ("expand to `line' if both the beginning and end \ are at the beginning of a line") (should (equal (evil-normalize first-line second-line 'exclusive) (list first-line second-line 'line :expanded t)))) (ert-info ("Measure as the strict difference between the end \ and the beginning") (should (string= (evil-describe 1 1 'exclusive) "0 characters")) (should (string= (evil-describe 1 2 'exclusive) "1 character")) (should (string= (evil-describe 5 2 'exclusive) "3 characters")))))) (ert-deftest evil-test-inclusive-type () "Expand and contract the `inclusive' type" :tags '(evil type) (evil-test-buffer ";; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (ert-info ("Include the ending character") (should (equal (evil-expand 1 1 'inclusive) '(1 2 inclusive :expanded t)))) (ert-info ("Don't mind if positions are in wrong order") (should (equal (evil-expand 5 2 'inclusive) '(2 6 inclusive :expanded t)))) (ert-info ("Exclude the ending character when contracting") (should (equal (evil-contract 1 2 'inclusive) '(1 1 inclusive :expanded nil)))) (ert-info ("Don't mind positions' order when contracting") (should (equal (evil-contract 6 2 'inclusive) '(2 5 inclusive :expanded nil)))) (ert-info ("Measure as one more than the difference") (should (string= (evil-describe 1 1 'inclusive) "1 character")) (should (string= (evil-describe 5 2 'inclusive) "4 characters"))))) (ert-deftest evil-test-line-type () "Expand the `line' type" :tags '(evil type) (evil-test-buffer ";; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (let* ((first-line 1) (second-line (progn (forward-line) (point))) (third-line (progn (forward-line) (point)))) (ert-info ("Expand to the whole first line") (should (equal (evil-expand first-line first-line 'line) (list first-line second-line 'line :expanded t))) (should (string= (evil-describe first-line first-line 'line) "1 line"))) (ert-info ("Expand to the two first lines") (should (equal (evil-expand first-line second-line 'line) (list first-line third-line 'line :expanded t))) (should (string= (evil-describe first-line second-line 'line) "2 lines")))))) (ert-deftest evil-test-block-type () "Expand and contract the `block' type" :tags '(evil type) (evil-test-buffer ";; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (let* ((first-line 1) (second-line (progn (forward-line) (point))) (third-line (progn (forward-line) (point)))) (ert-info ("Expand to a 1x1 block") (should (equal (evil-expand 1 1 'block) (list 1 2 'block :expanded t))) (should (string= (evil-describe 1 1 'block) "1 row and 1 column"))) (ert-info ("Expand to a 2x1 block") (should (equal (evil-expand first-line second-line 'block) (list first-line (1+ second-line) 'block :expanded t))) (should (string= (evil-describe first-line second-line 'block) "2 rows and 1 column"))) (ert-info ("Expand to a 3x2 block") (should (equal (evil-expand first-line (1+ third-line) 'block) (list first-line (1+ (1+ third-line)) 'block :expanded t))) (should (string= (evil-describe first-line (1+ third-line) 'block) "3 rows and 2 columns"))) (ert-info ("Contract to a 0x0 rectangle") (should (equal (evil-contract 1 2 'block) (list 1 1 'block :expanded nil)))) (ert-info ("Contract to a 2x0 rectangle") (should (equal (evil-contract first-line (1+ second-line) 'block) (list first-line second-line 'block :expanded nil)))) (ert-info ("Contract to a 3x1 rectangle") (should (equal (evil-contract first-line (1+ (1+ third-line)) 'block) (list first-line (1+ third-line) 'block :expanded nil))))))) (ert-deftest evil-test-type-transform () "Test `evil-transform'" :tags '(evil type) (evil-test-buffer ";; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (ert-info ("Return positions unchanged when passed nil \ for TYPE or TRANSFORM") (should (equal (evil-transform nil 1 2 'block) '(1 2 block))) (should (equal (evil-transform :expand 1 2 nil) '(1 2))) (should (equal (evil-transform nil 1 2 nil) '(1 2)))) (ert-info ("Accept markers, but return positions") (should (equal (evil-transform :expand (move-marker (make-marker) 1) 1 'inclusive) '(1 2 inclusive :expanded t))) (should (equal (evil-transform nil (move-marker (make-marker) 1) 2 nil) '(1 2)))))) (ert-deftest evil-test-type-modifiers () "Test type modifiers like \"dv}\"" :tags '(evil type) (ert-info ("Change `inclusive' motions to `exclusive'") (evil-test-buffer "[A]bove some line" ("dve") "[e] some line")) (ert-info ("Change `exclusive' motions to `inclusive'") (evil-test-buffer "Above [s]ome line Below some empty line" ("dv}") "Above[ ] Below some empty line")) (ert-info ("Change type to `line'") (evil-test-buffer "Above [s]ome line Below some empty line" ("dV}") "[B]elow some empty line"))) ;;; Insertion (ert-deftest evil-test-insert () "Test `evil-insert'" :tags '(evil insert) (evil-test-buffer ";; [T]his buffer is for notes you don't want to save" ("ievil rulz " [escape]) ";; evil rulz[ ]This buffer is for notes you don't want to save")) (ert-deftest evil-test-append () "Test `evil-append'" :tags '(evil insert) (evil-test-buffer ";; [T]his buffer is for notes you don't want to save" ("aevil rulz " [escape]) ";; Tevil rulz[ ]his buffer is for notes you don't want to save")) (ert-deftest evil-test-visual-append () "Test `evil-append' from visual state" :tags '(evil insert) (evil-test-buffer ";; [T]his buffer is for notes you don't want to save" ("veA_evil rulz " [escape]) ";; This_evil rulz[ ] buffer is for notes you don't want to save")) (ert-deftest evil-test-open-above () "Test `evil-open-above'" :tags '(evil insert) (evil-test-buffer ";; This buffer is for notes you don't want to save, \[;]; and for Lisp evaluation." ("Oabc\ndef" [escape]) ";; This buffer is for notes you don't want to save, abc de[f] ;; and for Lisp evaluation.") (ert-info ("Open empty line") (evil-test-buffer "(let (var)\n [t]est)\n" (emacs-lisp-mode) ("O" [escape]) "(let (var)\n[\n] test)\n")) (ert-info ("Open non-empty line") (evil-test-buffer "(let (var)\n [t]est)\n" (emacs-lisp-mode) ("Odo-it" [escape]) "(let (var)\n do-i[t]\n test)\n"))) (ert-deftest evil-test-open-below () "Test `evil-open-below'" :tags '(evil insert) (evil-test-buffer "[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("oabc\ndef" [escape]) ";; This buffer is for notes you don't want to save, abc de[f] ;; and for Lisp evaluation.") (ert-info ("Open empty line") (evil-test-buffer "[(]let (var)\n test)\n" (emacs-lisp-mode) ("o" [escape]) "(let (var)\n[\n] test)\n")) (ert-info ("Open non-empty line") (evil-test-buffer "[(]let (var)\n test)\n" (emacs-lisp-mode) ("odo-it" [escape]) "(let (var)\n do-i[t]\n test)\n")) (let ((evil-auto-indent t)) (ert-info ("With count") (evil-test-buffer "[(]and a\n c)\n" (emacs-lisp-mode) ("3ob" [escape]) "(and a\n b\n b\n [b]\n c)\n")))) (ert-deftest evil-test-open-below-folded () "Test `evil-open-below' on folded lines" :tags '(evil insert) (evil-test-buffer "[l]ine1\n\n(let ()\n var)\n\nlast line\n" (emacs-lisp-mode) (hs-minor-mode 1) ("zm2joABC" [escape]) "line1\n\n(let ()\n var)\nAB[C]\n\nlast line\n")) (ert-deftest evil-test-insert-line () "Test `evil-insert-line'" :tags '(evil insert) (evil-test-buffer ";; [T]his buffer is for notes you don't want to save" ("Ievil rulz " [escape]) "evil rulz[ ];; This buffer is for notes you don't want to save")) (ert-deftest evil-test-append-line () "Test `evil-append-line'" :tags '(evil insert) (evil-test-buffer ";; [T]his buffer is for notes you don't want to save" ("Aevil rulz " [escape]) ";; This buffer is for notes you don't want to saveevil rulz[ ]")) (ert-deftest evil-test-insert-digraph () "Test `evil-insert-digraph'" :tags '(evil insert) (ert-info ("Predefined digraph") (evil-test-buffer ("i\C-kae") "æ[]")) (ert-info ("Custom digraph") (let ((evil-digraphs-table-user '(((?a ?o) . ?å)))) (evil-test-buffer ("i\C-kao") "å[]")))) ;;; Repeat system (ert-deftest evil-test-normalize-repeat-info () "Test `evil-normalize-repeat-info'" :tags '(evil repeat) (ert-info ("Single array") (should (equal (evil-normalize-repeat-info '("abc")) '([?a ?b ?c]))) (should (equal (evil-normalize-repeat-info '("\M-f")) (list (kbd "M-f"))))) (ert-info ("Single symbol") (should (equal (evil-normalize-repeat-info '(SYM)) '(SYM)))) (ert-info ("Arrays only") (should (equal (evil-normalize-repeat-info '("abc" [XX YY] "def")) '([?a ?b ?c XX YY ?d ?e ?f])))) (ert-info ("Several symbols") (should (equal (evil-normalize-repeat-info '(BEG MID END)) '(BEG MID END)))) (ert-info ("Arrays with symbol at the beginning") (should (equal (evil-normalize-repeat-info '(BEG "abc" [XX YY] "def")) '(BEG [?a ?b ?c XX YY ?d ?e ?f])))) (ert-info ("Arrays with symbol at the end") (should (equal (evil-normalize-repeat-info '("abc" [XX YY] "def" END)) '([?a ?b ?c XX YY ?d ?e ?f] END)))) (ert-info ("Arrays with symbol in the middle") (should (equal (evil-normalize-repeat-info '("abc" [XX YY] MID "def" )) '([?a ?b ?c XX YY] MID [?d ?e ?f])))) (ert-info ("Concatenate arrays with several symbols") (should (equal (evil-normalize-repeat-info '(BEG "abc" [XX YY] MID "def" END)) '(BEG [?a ?b ?c XX YY] MID [?d ?e ?f] END))))) (defun evil-test-repeat-info (keys &optional recorded) "Execute a sequence of keys and verify that `evil-repeat-ring' records them correctly. KEYS is the sequence of keys to execute. RECORDED is the expected sequence of recorded events. If nil, KEYS is used." (execute-kbd-macro keys) (should (equal (evil-normalize-repeat-info (ring-ref evil-repeat-ring 0)) (list (vconcat (or recorded keys)))))) (ert-deftest evil-test-normal-repeat-info-simple-command () "Save key-sequence after simple editing command in Normal state" :tags '(evil repeat) (evil-test-buffer "[T]his is a test buffer" (ert-info ("Call simple command without count") (evil-test-repeat-info "x")) (ert-info ("Call simple command with count 3") (evil-test-repeat-info "3x")))) (ert-deftest evil-test-normal-repeat-info-char-command () "Save key-sequence after editing command with character in Normal state" :tags '(evil repeat) (evil-test-buffer "[T]his is a test buffer" (ert-info ("Call command with character argument without count") (evil-test-repeat-info "r5")) (ert-info ("Call command with character argument with count 12") (evil-test-repeat-info "12rX")))) (ert-deftest evil-test-insert-repeat-info () "Save key-sequence after Insert state" :tags '(evil repeat) (evil-test-buffer (ert-info ("Insert text without count") (evil-test-repeat-info (vconcat "iABC" [escape]))) (ert-info ("Insert text with count 42") (evil-test-repeat-info (vconcat "42iABC" [escape]))))) (ert-deftest evil-test-repeat () "Repeat several editing commands" :tags '(evil repeat) (ert-info ("Repeat replace") (evil-test-buffer "[;]; This buffer is for notes you don't want to save" ("rX") "[X]; This buffer is for notes you don't want to save" ([right right] ".") "X;[X]This buffer is for notes you don't want to save")) (ert-info ("Repeat replace with count") (evil-test-buffer "[;]; This buffer is for notes you don't want to save" ("2rX") "X[X] This buffer is for notes you don't want to save" ([right right] ".") "XX X[X]is buffer is for notes you don't want to save")) (ert-info ("Repeat replace without count with a new count") (evil-test-buffer "[;]; This buffer is for notes you don't want to save" ("rX") "[X]; This buffer is for notes you don't want to save" ([right right] "13.") "X;XXXXXXXXXXXX[X]is for notes you don't want to save")) (ert-info ("Repeat replace with count replacing original count") (evil-test-buffer "[;]; This buffer is for notes you don't want to save" ("10rX") "XXXXXXXXX[X]ffer is for notes you don't want to save" ([right right] "20.") "XXXXXXXXXXfXXXXXXXXXXXXXXXXXXX[X] don't want to save")) (ert-info ("Repeat movement in Insert state") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save" ("i(\M-f)" [escape]) ";; (This[)] buffer is for notes you don't want to save" ("w.") ";; (This) (buffer[)] is for notes you don't want to save"))) (ert-deftest evil-test-repeat-register () "Test repeating a register command." :tags '(evil repeat) (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4\n" ("\"addyy\"aP") "[l]ine 1\nline 2\nline 3\nline 4\n" (".") "[l]ine 1\nline 1\nline 2\nline 3\nline 4\n")) (ert-deftest evil-test-repeat-numeric-register () "Test repeating a command with a numeric register." :tags '(evil repeat) (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4\nline 5\n" ("dd...") "[l]ine 5\n" ("\"1P") "[l]ine 4\nline 5\n" (".") "[l]ine 3\nline 4\nline 5\n" (".") "[l]ine 2\nline 3\nline 4\nline 5\n" (".") "[l]ine 1\nline 2\nline 3\nline 4\nline 5\n")) (ert-deftest evil-test-cmd-replace-char () "Calling `evil-replace-char' should replace characters" :tags '(evil repeat) (evil-test-buffer "[;]; This buffer is for notes you don't want to save" ("r5") "[5]; This buffer is for notes you don't want to save" ("3rX") "XX[X]This buffer is for notes you don't want to save") (ert-info ("Replace digraph") (evil-test-buffer "[;]; This buffer is for notes you don't want to save" ("r e'") "[é]; This buffer is for notes you don't want to save" ("3r c*") "ξξ[ξ]This buffer is for notes you don't want to save")) (ert-info ("Replacing \\n should insert only one newline") (evil-test-buffer "(setq var xxx [y]yy zzz)\n" (emacs-lisp-mode) (setq indent-tabs-mode nil) ("2r\n") "(setq var xxx \n [y] zzz)\n"))) (ert-deftest evil-test-insert-with-count () "Test `evil-insert' with repeat count" :tags '(evil repeat) (evil-test-buffer ";; [T]his buffer is for notes" ("2ievil rulz " [escape]) ";; evil rulz evil rulz[ ]This buffer is for notes")) (ert-deftest evil-test-repeat-insert () "Test repeating of `evil-insert'" :tags '(evil repeat) (ert-info ("Repeat insert") (evil-test-buffer "[;]; This buffer is for notes" ("iABC" [escape]) "AB[C];; This buffer is for notes" ("..") "ABABAB[C]CC;; This buffer is for notes")) (ert-info ("Repeat insert with count") (evil-test-buffer "[;]; This buffer is for notes" ("2iABC" [escape]) "ABCAB[C];; This buffer is for notes" ("..") "ABCABABCABABCAB[C]CC;; This buffer is for notes")) (ert-info ("Repeat insert with repeat count") (evil-test-buffer "[;]; This buffer is for notes" ("iABC" [escape]) "AB[C];; This buffer is for notes" ("11.") "ABABCABCABCABCABCABCABCABCABCABCAB[C]C;; This buffer is for notes")) (ert-info ("Repeat insert with count with repeat with count") (evil-test-buffer "[;]; This buffer is for notes" ("10iABC" [escape]) "ABCABCABCABCABCABCABCABCABCAB[C];; This buffer is for notes" ("11.") "ABCABCABCABCABCABCABCABCABCABABCABCABCABCABCABCABCABCABCABCAB[C]C;; \ This buffer is for notes"))) (ert-deftest evil-test-repeat-error () "Test whether repeat returns to normal state in case of an error." (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4" ("ixxx" [down] [down] [left] [left] [left] "yyy" [escape]) "xxxline 1\nline 2\nyy[y]line 3\nline 4" (should-error (execute-kbd-macro "j^.")) (should (evil-normal-state-p)) ("^") "xxxline 1\nline 2\nyyyline 3\n[x]xxline 4")) (ert-deftest evil-test-repeat-quoted-insert () "Test whether `quoted-insert' can be repeated." (ert-info ("Insert C-v") (evil-test-buffer "lin[e] 1\nline 2\nline 3\n" ("i\C-v\C-v" [escape]) "lin[]e 1\nline 2\nline 3\n")) (ert-info ("Insert ESC") (evil-test-buffer "lin[e] 1\nline 2\nline 3\n" ("i\C-v" [escape escape]) "lin[]e 1\nline 2\nline 3\n")) (ert-info ("Block insert C-v") (evil-test-buffer "lin[e] 1\nline 2\nline 3\n" ("gg\C-vGI\C-v\C-v" [escape]) "[]line 1\nline 2\nline 3\n"))) (ert-deftest evil-test-insert-vcount () "Test `evil-insert' with vertical repeating" :tags '(evil repeat) (evil-test-buffer ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer. ;; Below the empty line." (define-key evil-normal-state-local-map "i" #'(lambda (count) (interactive "p") (evil-insert count 5))) ("2iABC" [escape]) "\ ;; ABCAB[C]This buffer is for notes you don't want to save. ;; ABCABCIf you want to create a file, visit that file with C-x C-f, ;; ABCABCthen enter the text in that file's own buffer. ABCABC ;; ABCABCBelow the empty line.")) (ert-deftest evil-test-append-with-count () "Test `evil-append' with repeat count" :tags '(evil repeat) (evil-test-buffer ";; [T]his buffer is for notes" ("2aevil rulz " [escape]) ";; Tevil rulz evil rulz[ ]his buffer is for notes")) (ert-deftest evil-test-repeat-append () "Test repeating of `evil-append'" :tags '(evil repeat) (ert-info ("Repeat insert") (evil-test-buffer "[;]; This buffer is for notes" ("aABC" [escape]) ";AB[C]; This buffer is for notes" ("..") ";ABCABCAB[C]; This buffer is for notes")) (ert-info ("Repeat insert with count") (evil-test-buffer "[;]; This buffer is for notes" ("2aABC" [escape]) ";ABCAB[C]; This buffer is for notes" ("..") ";ABCABCABCABCABCAB[C]; This buffer is for notes")) (ert-info ("Repeat insert with repeat count") (evil-test-buffer "[;]; This buffer is for notes" ("aABC" [escape]) ";AB[C]; This buffer is for notes" ("11.") ";ABCABCABCABCABCABCABCABCABCABCABCAB[C]; This buffer is for notes")) (ert-info ("Repeat insert with count with repeat with count") (evil-test-buffer "[;]; This buffer is for notes" ("10aABC" [escape]) ";ABCABCABCABCABCABCABCABCABCAB[C]; This buffer is for notes" ("11.") ";ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB[C]; \ This buffer is for notes"))) (ert-deftest evil-test-append-vcount () "Test `evil-append' with vertical repeating" :tags '(evil repeat) (evil-test-buffer ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer. ;; Below the empty line." (define-key evil-normal-state-local-map "a" #'(lambda (count) (interactive "p") (evil-append count 5))) ("2aABC" [escape]) "\ ;; TABCAB[C]his buffer is for notes you don't want to save. ;; IABCABCf you want to create a file, visit that file with C-x C-f, ;; tABCABChen enter the text in that file's own buffer. ABCABC ;; BABCABCelow the empty line.")) (ert-deftest evil-test-open-above-with-count () "Test `evil-open-above' with repeat count" :tags '(evil repeat) (evil-test-buffer ";; This buffer is for notes you don't want to save, \[;]; and for Lisp evaluation." ("2Oevil\nrulz" [escape]) ";; This buffer is for notes you don't want to save, evil\nrulz\nevil\nrul[z] ;; and for Lisp evaluation.")) (ert-deftest evil-test-repeat-open-above () "Test repeating of `evil-open-above'" :tags '(evil repeat) (ert-info ("Repeat insert") (evil-test-buffer "[;]; This buffer is for notes you don't want to save." ("Oevil\nrulz" [escape]) "evil\nrul[z] ;; This buffer is for notes you don't want to save." ("..") "evil\nevil\nevil\nrul[z]\nrulz\nrulz ;; This buffer is for notes you don't want to save.")) (ert-info ("Repeat insert with count") (evil-test-buffer ";; This buffer is for notes you don't want to save." ("2Oevil\nrulz" [escape]) "evil\nrulz\nevil\nrul[z] ;; This buffer is for notes you don't want to save." ("..") "evil\nrulz\nevil\nevil\nrulz\nevil\nevil\nrulz\nevil\nrul[z]\nrulz\nrulz ;; This buffer is for notes you don't want to save.")) (ert-info ("Repeat insert with repeat count") (evil-test-buffer ";; This buffer is for notes you don't want to save." ("Oevil\nrulz" [escape]) "evil\nrul[z]\n;; This buffer is for notes you don't want to save." ("2.") "evil\nevil\nrulz\nevil\nrul[z]\nrulz ;; This buffer is for notes you don't want to save.")) (ert-info ("Repeat insert with count with repeat with count") (evil-test-buffer ";; This buffer is for notes you don't want to save." ("2Oevil\nrulz" [escape]) "evil\nrulz\nevil\nrul[z] ;; This buffer is for notes you don't want to save." ("3.") "evil\nrulz\nevil\nevil\nrulz\nevil\nrulz\nevil\nrul[z]\nrulz ;; This buffer is for notes you don't want to save."))) (ert-deftest evil-test-open-below-with-count () "Test insertion of `evil-open-below' with repeat count" :tags '(evil repeat) (evil-test-buffer "[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("2oevil\nrulz" [escape]) ";; This buffer is for notes you don't want to save, evil\nrulz\nevil\nrul[z] ;; and for Lisp evaluation.")) (ert-deftest evil-test-repeat-open-below () "Test repeating `evil-open-below'" :tags '(evil repeat) (ert-info ("Repeat insert") (evil-test-buffer "[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("oevil\nrulz" [escape]) ";; This buffer is for notes you don't want to save, evil\nrul[z]\n;; and for Lisp evaluation." ("..") ";; This buffer is for notes you don't want to save, evil\nrulz\nevil\nrulz\nevil\nrul[z] ;; and for Lisp evaluation.")) (ert-info ("Repeat insert with count") (evil-test-buffer "[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("2oevil\nrulz" [escape]) ";; This buffer is for notes you don't want to save, evil\nrulz\nevil\nrul[z] ;; and for Lisp evaluation." ("..") ";; This buffer is for notes you don't want to save, evil\nrulz\nevil\nrulz\nevil\nrulz\nevil\nrulz\nevil\nrulz\nevil\nrul[z] ;; and for Lisp evaluation.")) (ert-info ("Repeat insert with repeat count") (evil-test-buffer "[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("oevil\nrulz" [escape]) ";; This buffer is for notes you don't want to save, evil\nrul[z]\n;; and for Lisp evaluation." ("2.") ";; This buffer is for notes you don't want to save, evil\nrulz\nevil\nrulz\nevil\nrul[z] ;; and for Lisp evaluation.")) (ert-info ("Repeat insert with count with repeat with count") (evil-test-buffer "[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("2oevil\nrulz" [escape]) ";; This buffer is for notes you don't want to save, evil\nrulz\nevil\nrul[z] ;; and for Lisp evaluation." ("3.") ";; This buffer is for notes you don't want to save, evil\nrulz\nevil\nrulz\nevil\nrulz\nevil\nrulz\nevil\nrul[z] ;; and for Lisp evaluation."))) (ert-deftest evil-test-insert-line-with-count () "Test `evil-insert-line' with repeat count" :tags '(evil repeat) (evil-test-buffer ";; [T]his buffer is for notes" ("2Ievil rulz " [escape]) "evil rulz evil rulz[ ];; This buffer is for notes")) (ert-deftest evil-test-repeat-insert-line () "Test repeating of `evil-insert-line'" :tags '(evil repeat) (ert-info ("Repeat insert") (evil-test-buffer ";; This buffer is for note[s]" ("IABC" [escape]) "AB[C];; This buffer is for notes" ("..") "AB[C]ABCABC;; This buffer is for notes")) (ert-info ("Repeat insert with count") (evil-test-buffer ";; This buffer is for note[s]" ("2IABC" [escape]) "ABCAB[C];; This buffer is for notes" ("..") "ABCAB[C]ABCABCABCABC;; This buffer is for notes")) (ert-info ("Repeat insert with repeat count") (evil-test-buffer ";; This buffer is for note[s]" ("IABC" [escape]) "AB[C];; This buffer is for notes" ("11.") "ABCABCABCABCABCABCABCABCABCABCAB[C]ABC;; This buffer is for notes")) (ert-info ("Repeat insert with count with repeat with count") (evil-test-buffer ";; This buffer is for note[s]" ("10IABC" [escape]) "ABCABCABCABCABCABCABCABCABCAB[C];; This buffer is for notes" ("11.") "ABCABCABCABCABCABCABCABCABCABCAB[C]ABCABCABCABCABCABCABCABCABCABC;; This buffer is for notes"))) (ert-deftest evil-test-insert-line-vcount () "Test `evil-insert-line' with vertical repeating" :tags '(evil repeat) (evil-test-buffer "int[ ]main(int argc, char** argv) { printf(\"Hello world\\n\"); return EXIT_SUCCESS; }" (define-key evil-normal-state-local-map "I" #'(lambda (count) (interactive "p") (evil-insert-line count 4))) ("2IABC" [escape]) "ABCABCint main(int argc, char** argv) ABCABC{ ABCABCprintf(\"Hello world\\n\"); ABCABCreturn EXIT_SUCCESS; }")) (ert-deftest evil-test-append-line-with-count () "Test `evil-append-line' with repeat count" :tags '(evil repeat) (evil-test-buffer ";; [T]his buffer is for notes." ("2Aevil rulz " [escape]) ";; This buffer is for notes.evil rulz evil rulz[ ]")) (ert-deftest evil-test-repeat-append-line () "Test repeating of `evil-append-line'" :tags '(evil repeat) (ert-info ("Repeat insert") (evil-test-buffer ";; [T]his buffer is for notes." ("AABC" [escape]) ";; This buffer is for notes.AB[C]" ("..") ";; This buffer is for notes.ABCABCAB[C]")) (ert-info ("Repeat insert with count") (evil-test-buffer ";; [T]his buffer is for notes." ("2AABC" [escape]) ";; This buffer is for notes.ABCAB[C]" ("..") ";; This buffer is for notes.ABCABCABCABCABCAB[C]")) (ert-info ("Repeat insert with repeat count") (evil-test-buffer ";; [T]his buffer is for notes." ("AABC" [escape]) ";; This buffer is for notes.ABC" ("11.") ";; This buffer is for notes.ABCABCABCABCABCABCABCABCABCABCABCAB[C]")) (ert-info ("Repeat insert with count with repeat with count") (evil-test-buffer ";; [T]his buffer is for notes." ("10AABC" [escape]) ";; This buffer is for notes.ABCABCABCABCABCABCABCABCABCAB[C]" ("11.") ";; This buffer is for notes.ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB[C]"))) (ert-deftest evil-test-append-line-vcount () "Test `evil-append-line' with vertical repeating" :tags '(evil repeat) (evil-test-buffer "int[ ]main(int argc, char** argv) { printf(\"Hello world\\n\"); return EXIT_SUCCESS; }" (define-key evil-normal-state-local-map "A" #'(lambda (count) (interactive "p") (evil-append-line count 4))) ("2AABC" [escape]) "int main(int argc, char** argv)ABCAB[C] {ABCABC printf(\"Hello world\\n\");ABCABC return EXIT_SUCCESS;ABCABC }")) (ert-deftest evil-test-repeat-by-change () "Test repeating by tracking changes for completion commands" :tags '(evil repeat) (let ((line-move-visual nil) (change (evil-define-command nil () :repeat change (interactive) (delete-char 5) (insert "BEGIN\n") (save-excursion (insert "\nEND\n"))))) (evil-test-buffer ";; [T]his buffer is for notes." (define-key evil-insert-state-local-map (kbd "C-c C-p") change) ("iABC " (kbd "C-c C-p") "BODY" [escape]) ";; ABC BEGIN BOD[Y] END buffer is for notes." (".") ";; ABC BEGIN BODABC BEGIN BOD[Y] END buffer is for notes."))) (ert-deftest evil-test-repeat-kill-buffer () "Test safe-guard preventing buffers from being deleted when repeating a command" :tags '(evil repeat) (ert-info ("Test killing works for direct calls \ to `evil-execute-repeat-info'") (evil-test-buffer "[;]; This buffer is for notes." (setq evil-repeat-ring (make-ring 10)) (ring-insert evil-repeat-ring '((kill-buffer nil))) (evil-execute-repeat-info (ring-ref evil-repeat-ring 0)) (should-not (looking-at ";; This")))) (ert-info ("Verify an error is raised when using \ the `evil-repeat' command") (evil-test-buffer "[;]; This buffer is for notes." (setq evil-repeat-ring (make-ring 10)) (ring-insert evil-repeat-ring '((kill-buffer nil))) (evil-execute-repeat-info (ring-ref evil-repeat-ring 0)) (should-error (call-interactively #'evil-repeat))))) (ert-deftest evil-test-repeat-pop () "Test `repeat-pop'." :tags '(evil repeat) (ert-info ("Test repeat-pop") (evil-test-buffer ";; [T]his buffer is for notes." (setq evil-repeat-ring (make-ring 10)) ("iABC" [escape] "aXYZ" [escape]) ";; ABCXY[Z]This buffer is for notes." (".") ";; ABCXYZXY[Z]This buffer is for notes.")) (ert-info ("Test repeat-pop") (evil-test-buffer ";; [T]his buffer is for notes." (setq evil-repeat-ring (make-ring 10)) ("iABC" [escape] "aXYZ" [escape]) ";; ABCXY[Z]This buffer is for notes." ("." (kbd "C-.")) ";; ABCXYAB[C]ZThis buffer is for notes.")) (ert-info ("Test repeat-pop-next") (evil-test-buffer ";; [T]his buffer is for notes." (setq evil-repeat-ring (make-ring 10)) ("iABC" [escape] "aXYZ" [escape]) ";; ABCXY[Z]This buffer is for notes." ("." (kbd "C-.") (kbd "M-.")) ";; ABCXYZXY[Z]This buffer is for notes.")) (ert-info ("Test repeat-pop after non-change") (evil-test-buffer ";; [T]his buffer is for notes." (setq evil-repeat-ring (make-ring 10)) ("iABC" [escape] "a" [escape] "aXYZ" [escape]) ";; ABCXY[Z]This buffer is for notes." ("." (kbd "C-.") (kbd "C-.")) ";; ABCXYAB[C]ZThis buffer is for notes."))) (ert-deftest evil-test-ESC-repeat-normal-state () "Test if ESC is not been recorded in normal state." :tags '(evil repeat) (ert-info ("Test normal ESC") (evil-test-buffer ";;[ ]This buffer is for notes." (setq evil-repeat-ring (make-ring 10)) (should (= (ring-length evil-repeat-ring) 0)) ("aABC" [escape]) ";; AB[C]This buffer is for notes." (should (= (ring-length evil-repeat-ring) 1)) (".") ";; ABCAB[C]This buffer is for notes." ([escape]) (should (= (ring-length evil-repeat-ring) 1)) (".") ";; ABCABCAB[C]This buffer is for notes."))) (ert-deftest evil-test-abort-operator-repeat () "Test if ESC in operator-state cancels recording of repeation." :tags '(evil repeat) (let ((inhibit-quit t)) (ert-info ("Test ESC") (evil-test-buffer ";;[ ]This buffer is for notes." (setq evil-repeat-ring (make-ring 10)) (should (= (ring-length evil-repeat-ring) 0)) ("aABC" [escape]) ";; AB[C]This buffer is for notes." (should (= (ring-length evil-repeat-ring) 1)) (".") ";; ABCAB[C]This buffer is for notes." ("d" [escape]) (should (= (ring-length evil-repeat-ring) 1)) (".") ";; ABCABCAB[C]This buffer is for notes.")))) (ert-deftest evil-test-repeat-visual-char () "Test repeat of character visual mode command." :tags '(evil repeat) (ert-info ("Test repeat on same line") (evil-test-buffer ";; [T]his buffer is for notes." ("v3lcABC" [escape]) ";; AB[C] buffer is for notes." ("ww.") ";; ABC buffer AB[C]or notes.")) (ert-info ("Test repeat on several lines") (evil-test-buffer ";; This [b]uffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer. " ("vj^eerX") ";; This XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXX[X] you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer. " ("2gg^3w.") ";; This XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXX you want XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXX[X]en enter the text in that file's own buffer. "))) (ert-deftest evil-test-repeat-visual-line () "Test repeat of linewise visual mode command." :tags '(evil repeat) (ert-info ("Test repeat on several lines") (evil-test-buffer ";; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter th[e] text in that file's own buffer. ;; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer. " ("VkcNew Text" [escape]) ";; This buffer is for notes you don't want to save. New Tex[t] ;; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer. " ("jj.") ";; This buffer is for notes you don't want to save. New Text New Tex[t] ;; then enter the text in that file's own buffer. "))) (ert-deftest evil-test-repeat-visual-block () "Test repeat of block visual mode command." :tags '(evil repeat) (ert-info ("Test repeat on several lines") (evil-test-buffer ";; This [b]uffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer. ;; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer. " ((kbd "C-v") "3j2lrQ") ";; This [Q]QQfer is for notes you don't want to save. ;; If yoQQQant to create a file, visit that file with C-x C-f, ;; then QQQer the text in that file's own buffer. ;; This QQQfer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer. " ("2j3w.") ";; This QQQfer is for notes you don't want to save. ;; If yoQQQant to create a file, visit that file with C-x C-f, ;; then QQQer the text [Q]QQthat file's own buffer. ;; This QQQfer is for nQQQs you don't want to save. ;; If you want to creatQQQ file, visit that file with C-x C-f, ;; then enter the text QQQthat file's own buffer. "))) (ert-deftest evil-visual-block-append () "Test appending in visual block." :tags '(evil visual insert) (ert-info ("Simple append") (evil-test-buffer "l[i]ne 1\nline 2\nline 3\n" ((kbd "C-v") "jjllAXXX" [escape]) "lineXX[X] 1\nlineXXX 2\nlineXXX 3\n")) (ert-info ("Append after empty lines") (evil-test-buffer "line 1l[i]ne 1\nline 2\nline 3line 3\n" (setq indent-tabs-mode nil) ((kbd "C-v") "jjllAXXX" [escape]) "line 1lineXX[X] 1\nline 2 XXX\nline 3lineXXX 3\n")) (ert-info ("Append after empty first line") (evil-test-buffer "l[i]ne 1line 1\nline 2\nline 3line 3line 3\n" (setq indent-tabs-mode nil) ((kbd "C-v") "jj3feAXXX" [escape]) "line 1line 1 XX[X]\nline 2 XXX\nline 3line 3lineXXX 3\n")) (ert-info ("Append after end of lines") (evil-test-buffer "line 1l[i]ne 1line 1\nline 2\nline 3line 3\n" (setq indent-tabs-mode nil) ((kbd "C-v") "jj$AXXX" [escape]) "line 1line 1line 1XX[X]\nline 2XXX\nline 3line 3XXX\n"))) (ert-deftest evil-test-repeat-digraph () "Test repeat of insertion of a digraph." :tags '(evil digraph repeat) (evil-test-buffer "Line with ['] several apostrophes ', yeah." ("s" (kbd "C-k") "'9" [escape]) "Line with [’] several apostrophes ', yeah." ("f'.") "Line with ’ several apostrophes [’], yeah.")) ;;; Operators (ert-deftest evil-test-keypress-parser () "Test `evil-keypress-parser'" :tags '(evil operator) (evil-test-buffer :state operator (ert-info ("Read from the keyboard unless INPUT is given") (evil-test-buffer :state operator (let ((unread-command-events '(?d))) (should (equal (evil-keypress-parser) '(evil-delete nil))) (should (equal (evil-keypress-parser '(?d)) '(evil-delete nil)))))) (ert-info ("Read remainder from the keyboard if INPUT is incomplete") (let ((unread-command-events '(?d))) (should (equal (evil-keypress-parser '(?2)) '(evil-delete 2))))) (ert-info ("Handle counts not starting with zero") (should (equal (evil-keypress-parser '(?2 ?d)) '(evil-delete 2))) (should (equal (evil-keypress-parser '(?2 ?0 ?d)) '(evil-delete 20))) (should (equal (evil-keypress-parser '(?2 ?0 ?2 ?d)) '(evil-delete 202))) (should (equal (evil-keypress-parser '(?4 ?0 ?4 ?g ??)) '(evil-rot13 404)))) (ert-info ("Treat 0 as a motion") (should (equal (evil-keypress-parser '(?0)) '(evil-digit-argument-or-evil-beginning-of-line nil)))) (ert-info ("Handle keyboard macros") (evil-test-buffer (define-key evil-motion-state-local-map (kbd "W") (kbd "w")) (should (equal (evil-keypress-parser '(?W)) '(evil-forward-word-begin nil))))))) (ert-deftest evil-test-invert-char () "Test `evil-invert-char'" :tags '(evil operator) (evil-test-buffer ";; [T]his buffer is for notes." ("~") ";; t[h]is buffer is for notes.") (evil-test-buffer ";; <[T]his> buffer is for notes." ("~") ";; [t]HIS buffer is for notes.") (evil-test-buffer :visual block ";; <[T]his buffer is for notes, ;; and >for Lisp evaluation." ("~") ";; [t]HIS buffer is for notes, ;; AND for Lisp evaluation.")) (ert-deftest evil-test-rot13 () "Test `evil-rot13'" :tags '(evil operator) (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." ("g?" [M-right]) ";; [G]uvf buffer is for notes you don't want to save.")) (ert-deftest evil-test-rot13-with-count () "Test `evil-rot13' with count argument" :tags '(evil operator) (ert-info ("Count before operator") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." ("2g?" [M-right]) ";; [G]uvf ohssre is for notes you don't want to save.")) (ert-info ("Count before motion") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." ("g?2" [M-right]) ";; [G]uvf ohssre is for notes you don't want to save.")) (ert-info ("Count before operator and motion") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." ("3g?2" [M-right]) ";; [G]uvf ohssre vf sbe abgrf lbh don't want to save.")) (ert-info ("Count exceeding buffer boundaries") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." ("g?200" [right]) ";; [G]uvf ohssre vf sbe abgrf lbh qba'g jnag gb fnir."))) (ert-deftest evil-test-rot13-repeat () "Test repeating of `evil-rot13'" :tags '(evil operator) (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." ("g?" [M-right] [M-right]) ";; Guvf[ ]buffer is for notes you don't want to save." (".") ";; Guvf[ ]ohssre is for notes you don't want to save.")) (ert-deftest evil-test-rot13-repeat-with-count () "Test repeating of `evil-rot13' with new count" :tags '(evil operator) (ert-info ("Count before operator") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." ("2g?" [M-right]) ";; [G]uvf ohssre is for notes you don't want to save." ("3.") ";; [T]his buffer vf for notes you don't want to save.")) (ert-info ("Count before motion") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." ("g?2" [M-right]) ";; [G]uvf ohssre is for notes you don't want to save." ("3.") ";; [T]his buffer vf for notes you don't want to save.")) (ert-info ("Count before operator and motion") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." ("3g?2" [M-right]) ";; [G]uvf ohssre vf sbe abgrf lbh don't want to save." ("4.") ";; [T]his buffer is for abgrf lbh don't want to save."))) (ert-deftest evil-test-operator-delete () "Test deleting text" :tags '(evil operator) (ert-info ("Delete characters") (evil-test-buffer ";; [T]his buffer is for notes." ("dl") ";; [h]is buffer is for notes." ("d1l") ";; [i]s buffer is for notes." ("1dl") ";; [s] buffer is for notes." ("1d1l") ";; [ ]buffer is for notes." ("d2l") ";; [u]ffer is for notes." ("2dl") ";; [f]er is for notes." ("d4l") ";; [i]s for notes." ("4dl") ";; [o]r notes." ("2d2l") ";; [o]tes.")) (ert-info ("Delete current line") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("dd") "[;]; and for Lisp evaluation.") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("d1d") "[;]; and for Lisp evaluation.") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("1dd") "[;]; and for Lisp evaluation.") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("1d1d") "[;]; and for Lisp evaluation.")) (ert-info ("Delete two lines") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("d2d") "[;]; then enter the text in that file's own buffer.") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("2dd") "[;]; then enter the text in that file's own buffer.") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("dj") "[;]; then enter the text in that file's own buffer.") (evil-test-buffer ";; This buffer is for notes you don't want to save. ;; [I]f you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("dk") "[;]; then enter the text in that file's own buffer."))) (evil-define-motion evil-test-square-motion (count) "Test motion for selecting a square." :type block (let ((column (current-column))) (forward-line (1- count)) (move-to-column (+ column count -1)))) (ert-deftest evil-test-yank () "Test `evil-yank'" :tags '(evil operator yank) (ert-info ("Yank characters") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." ("y2e") (should (string= (current-kill 0) "This buffer")))) (ert-info ("Yank lines") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("yj") (should (string= (current-kill 0) (buffer-substring (point-min) (1+ (line-end-position 2))))) (should (eq (car-safe (get-text-property 0 'yank-handler (current-kill 0))) 'evil-yank-line-handler))) (evil-test-buffer ";; This buffer is for notes you don't want to save. \[;]; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("y5j") (should (string= (current-kill 0) (concat (buffer-substring (line-beginning-position 1) (point-max)) "\n"))) (should (eq (car-safe (get-text-property 0 'yank-handler (current-kill 0))) 'evil-yank-line-handler)))) (ert-info ("Yank rectangle") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y3s") (should (string= (current-kill 0) "Thi\nIf \nthe")) (should (eq (car-safe (get-text-property 0 'yank-handler (current-kill 0))) 'evil-yank-block-handler)))) (ert-info (":yank, then paste") (evil-test-buffer "a\n[b]\nc\nd\n" (":yank" [return] "p") "a\nb\nb\nc\nd\n")) (ert-info (":yank with COUNT") (evil-test-buffer "a\n[b]\nc\nd\n" (":yank 2" [return] "p") "a\nb\nb\nc\nc\nd\n")) (ert-info (":yank with COUNT in visual state") (evil-test-buffer "a\n\nd\ne\nf\n" (":yank 3" [return] "p") "a\nb\nc\nd\ne\nc\nd\ne\nf\n")) (ert-info (":yank with REGISTER") (evil-test-buffer "a\n[b]\nc\nd\n" (":yank r") ;; yank into the 'r' register "a\nb\nc\nd\n" ;; check the 'r' register contains the yanked text (should (string= (substring-no-properties (evil-get-register ?r)) "b\n")))) (ert-info (":yank with REGISTER and COUNT") (evil-test-buffer "a\n[b]\nc\nd\ne\nf\n" (":yank r 3") "a\nb\nc\nd\ne\nf\n" (should (string= (substring-no-properties (evil-get-register ?r)) "b\nc\nd\n"))))) (ert-deftest evil-test-delete () "Test `evil-delete'" :tags '(evil operator delete) (ert-info ("Delete characters") (evil-test-buffer ";; This buffer is for notes you don't want to save[.]" ("x") ";; This buffer is for notes you don't want to sav[e]" (goto-char 4) ";; [T]his buffer is for notes you don't want to save" ("d2e") ";; [ ]is for notes you don't want to save" (should (string= (current-kill 0) "This buffer")) ("P") ";; This buffe[r] is for notes you don't want to save")) (ert-info ("Delete lines") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("2dd") "[;]; then enter the text in that file's own buffer." ("P") "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer.")) (ert-info ("Delete last line") (evil-test-buffer ";; This buffer is for notes you don't want to save. ;; [I]f you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("2dd") "[;]; This buffer is for notes you don't want to save.")) (ert-info ("Delete last empty line") (evil-test-buffer "line 1\nline 2\n\n[]" ("dd") "line 1\nline 2\n[]")) (ert-info ("Delete rectangle") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("d3s") "[T]his buffer is for notes you don't want to save. If you want to create a file, visit that file with C-x C-f, then enter the text in that file's own buffer.")) (ert-info (":delete") (evil-test-buffer "a\n[b]\nc\nd\n" (":delete") "a\nc\nd\n")) (ert-info (":delete with COUNT") (evil-test-buffer "a\n[b]\nc\nd\n" (":delete 2") "a\nd\n")) (ert-info (":delete with COUNT in visual state") (evil-test-buffer "a\n\nd\ne\nf\n" (":delete 3") "a\nb\nf\n")) (ert-info (":delete with REGISTER") (evil-test-buffer "a\n[b]\nc\nd\n" (":delete r") ;; delete into the 'r' register "a\nc\nd\n" ;; check the 'r' register contains the deleted text (should (string= (substring-no-properties (evil-get-register ?r)) "b\n")))) (ert-info (":delete with REGISTER and COUNT") (evil-test-buffer "a\n[b]\nc\nd\ne\nf\n" (":delete r 3") "a\ne\nf\n" (should (string= (substring-no-properties (evil-get-register ?r)) "b\nc\nd\n"))))) (ert-deftest evil-test-delete-line () "Test `evil-delete-line'" :tags '(evil operator) (ert-info ("Delete to end of line") (evil-test-buffer ";; This buffer is for notes[ ]you don't want to save." ("D") ";; This buffer is for note[s]")) (ert-info ("Act linewise on character selection") (evil-test-buffer ";; This is for notes, and for Lisp evaluation." ("D") "[a]nd for Lisp evaluation.")) (ert-info ("Act on each line of block selection") (evil-test-buffer :visual block ";; This buffer is for ." ("D") ";; This buffer is for[ ] ;; and for Lisp evalua")) (ert-info ("Yank full block with block selection") (evil-test-buffer :visual block "line1 le3 line3\n" ("D") "line1 [l]\nline2 l\nline3 l\n" ("0P") "ine1 line1 line1line1 l ine2 line2 l ine3 line3 line3 l\n"))) (ert-deftest evil-test-delete-folded () "Test `evil-delete' on folded lines." :tags '(evil operator) (ert-info ("Delete folded lines") (evil-test-buffer "[l]ine1\n\n(let ()\n var)\n\n(let ()\n var2)\n" (emacs-lisp-mode) (hs-minor-mode 1) ("zm2jdd") "line1\n\n[\n](let ()\n var2)\n")) (ert-info ("Delete folded lines with count") (evil-test-buffer "[l]ine1\n\n(let ()\n var)\n\n(let ()\n var2)\n\nlast line\n" (emacs-lisp-mode) (hs-minor-mode 1) ("zm2j3dd") "line1\n\n[\n]last line\n"))) (ert-deftest evil-test-delete-backward-word () "Test `evil-delete-backward-word' in insert state." :tags '(evil) (let ((evil-backspace-join-lines t)) (evil-test-buffer "abc def\n ghi j[k]l\n" ("i" (kbd "C-w")) "abc def\n ghi [k]l\n" ((kbd "C-w")) "abc def\n [k]l\n" ((kbd "C-w")) "abc def\n[k]l\n" ((kbd "C-w")) "abc def[k]l\n")) (let (evil-backspace-join-lines) (evil-test-buffer "abc def\n[k]l\n" (should-error (execute-kbd-macro (concat "i" (kbd "C-w")))) "abc def\n[k]l\n"))) (ert-deftest evil-test-change () "Test `evil-change'" :tags '(evil operator) (ert-info ("Change characters") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." ("c2eABC" [escape]) ";; AB[C] is for notes you don't want to save." (should (string= (current-kill 0) "This buffer")) ("p") ";; ABCThis buffe[r] is for notes you don't want to save.")) (ert-info ("Change lines") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("2ccABCLINE\nDEFLINE" [escape]) "ABCLINE DEFLIN[E] ;; then enter the text in that file's own buffer." ("p") "ABCLINE DEFLINE \[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer.")) (ert-info ("Change last line") (evil-test-buffer ";; This buffer is for notes you don't want to save. ;; [I]f you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("2ccABC" [escape]) ";; This buffer is for notes you don't want to save. AB[C]")) (ert-info ("Change rectangle") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("c3sABC" [escape]) "AB[C]This buffer is for notes you don't want to save. ABCIf you want to create a file, visit that file with C-x C-f, ABCthen enter the text in that file's own buffer."))) (ert-deftest evil-test-change-word () "Test changing words" :tags '(evil operator) (ert-info ("Non-word") (evil-test-buffer "[;]; This buffer is for notes." ("cwABC" [escape]) "AB[C] This buffer is for notes.")) (ert-info ("Word") (evil-test-buffer ";; [T]his buffer is for notes." ("cwABC" [escape]) ";; AB[C] buffer is for notes.")) (ert-info ("Single character") (evil-test-buffer "[;] This buffer is for notes." ("cwABC" [escape]) "AB[C] This buffer is for notes.")) (ert-info ("Whitespace") (evil-test-buffer "This[ ]is a test\n" ("cwABC" [escape]) "ThisAB[C]is a test\n"))) (ert-deftest evil-test-join () "Test `evil-join'" :tags '(evil join operator) (ert-info ("Simple") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f." ("J") ";; This buffer is for notes you don't want to save.[ ]\ ;; If you want to create a file, visit that file with C-x C-f.")) (ert-info ("Visual") (evil-test-buffer :visual line "<;; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f.>" ("J") ";; This buffer is for notes you don't want to save.[ ]\ ;; If you want to create a file, visit that file with C-x C-f.")) (ert-info ("Join with count") (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4" (":join 3") "line 1 line 2 line 3\nline 4")) (ert-info ("Join with bang and count") (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4" (":join! 3") "line 1line 2line 3\nline 4")) (ert-info ("Join with bang and count, exceeding end-of-buffer") (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4" (":join! 10") "line 1line 2line 3line 4")) (ert-info ("Join with count 1 should be the same as without count") (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4" (":join 1") "line 1 line 2\nline 3\nline 4")) (ert-info ("Join with count 2 should be the same as with count 1") (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4" (":join 2") "line 1 line 2\nline 3\nline 4")) (ert-info ("Join with count and single line range") (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4" (":2join 3") "line 1\nline 2 line 3 line 4")) (ert-info ("Join with count and range") (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4" (":1,2join 3") "line 1\nline 2 line 3 line 4")) (ert-info ("Join with count, range and bang") (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4" (":1,2join! 3") "line 1\nline 2line 3line 4")) (ert-info ("Join with range") (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4" (":1,3join") "line 1 line 2 line 3\nline 4")) ) (ert-deftest evil-test-substitute () "Test `evil-substitute'" :tags '(evil operator) (ert-info ("Simple") (evil-test-buffer ";; [T]his buffer is for notes." ("5sABC" [escape]) ";; AB[C]buffer is for notes.")) (ert-info ("On empty line") (evil-test-buffer "Above some line \[] Below some empty line" ("5sABC" [escape]) "Above some line AB[C] Below some empty line"))) (ert-deftest evil-test-shift () "Test `evil-shift-right' and `evil-shift-left'." :tags '(evil operator) (let ((evil-shift-width 4) indent-tabs-mode) (ert-info ("Shift linewise") (evil-test-buffer "[l]ine 1\nline 2\nline 3\n" ("Vj>") " [l]ine 1\n line 2\nline 3\n")) (ert-info ("Shift char selection on whole line") (evil-test-buffer "[l]ine 1\nline 2\nline 3\n" ("v$>") " [l]ine 1\nline 2\nline 3\n")) (ert-info ("Shift visual with count") (evil-test-buffer "[l]ine 1\nline 2\nline 3\n" ("Vj3>") " [l]ine 1\n line 2\nline 3\n" ("Vj2<") " [l]ine 1\n line 2\nline 3\n")) (ert-info ("Shift in insert state") (evil-test-buffer "line 1\nl[i]ne 2\nline 3\n" ("i\C-t\C-t") "line 1\n l[i]ne 2\nline 3\n" ("\C-d") "line 1\n l[i]ne 2\nline 3\n")))) ;;; Paste (ert-deftest evil-test-paste-before () "Test `evil-paste-before'" :tags '(evil paste) (ert-info ("Paste characters") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("y2ej0") ";; This buffer is for notes you don't want to save, \[;]; and for Lisp evaluation." ("P") ";; This buffer is for notes you don't want to save, This buffe[r];; and for Lisp evaluation.")) (ert-info ("Paste characters with count") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("y2ej0") ";; This buffer is for notes you don't want to save, \[;]; and for Lisp evaluation." ("3P") ";; This buffer is for notes you don't want to save, This bufferThis bufferThis buffe[r];; and for Lisp evaluation.")) (ert-info ("Paste characters at end-of-buffer") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("y2eG$") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation[.]" ("2P") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluationThis bufferThis buffe[r].")) (ert-info ("Paste lines") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("2yyP") "[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. ;; This buffer is for notes you don't want to save, ;; and for Lisp evaluation.")) (ert-info ("Paste lines with count") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("2yy2P") "[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. ;; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. ;; This buffer is for notes you don't want to save, ;; and for Lisp evaluation.")) (ert-info ("Paste lines at end-of-buffer") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("2yyG$") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation[.]" ("2P") ";; This buffer is for notes you don't want to save, \[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. ;; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. ;; and for Lisp evaluation.")) (ert-info ("Paste block") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("3ysP") "[;]; ;; This buffer is for notes you don't want to save. ;; ;; If you want to create a file, visit that file with C-x C-f, ;; ;; then enter the text in that file's own buffer.")) (ert-info ("Paste block with count") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("3ys2P") "[;]; ;; ;; This buffer is for notes you don't want to save. ;; ;; ;; If you want to create a file, visit that file with C-x C-f, ;; ;; ;; then enter the text in that file's own buffer.")) (ert-info ("Paste block with empty line") (evil-test-buffer "[;]; Above some line ;; Below some empty line" (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("3ys2P") "[;]; ;; ;; Above some line \n\ ;; ;; ;; Below some empty line")) (ert-info ("Paste block crossing end of buffer") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("3ysj") ";; This buffer is for notes you don't want to save. \[;]; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("P") ";; This buffer is for notes you don't want to save. \[;]; ;; If you want to create a file, visit that file with C-x C-f, ;; ;; then enter the text in that file's own buffer. ;;")) (ert-info ("Paste block at end-of-line") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("3ys$") ";; This buffer is for notes you don't want to save[.] ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("p") ";; This buffer is for notes you don't want to save.[;]; ;; If you want to create a file, visit that file wi;; th C-x C-f, ;; then enter the text in that file's own buffer. ;;"))) (ert-deftest evil-test-paste-after () "Test `evil-paste-after'" :tags '(evil paste) (ert-info ("Paste characters") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("y2ej0") ";; This buffer is for notes you don't want to save, \[;]; and for Lisp evaluation." ("p") ";; This buffer is for notes you don't want to save, ;This buffe[r]; and for Lisp evaluation.")) (ert-info ("Paste characters with count") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("y2ej0") ";; This buffer is for notes you don't want to save, \[;]; and for Lisp evaluation." ("3p") ";; This buffer is for notes you don't want to save, ;This bufferThis bufferThis buffe[r]; and for Lisp evaluation.")) (ert-info ("Paste characters at end-of-buffer") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("y2eG$") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation[.]" ("2p") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation.This bufferThis buffe[r]")) (ert-info ("Paste lines") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("2yyp") ";; This buffer is for notes you don't want to save, \[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. ;; and for Lisp evaluation.")) (ert-info ("Paste lines with count") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("2yy2p") ";; This buffer is for notes you don't want to save, \[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. ;; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. ;; and for Lisp evaluation.")) (ert-info ("Paste lines at end-of-buffer") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("2yyG$") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation[.]" ("2p") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. \[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. ;; This buffer is for notes you don't want to save, ;; and for Lisp evaluation.")) (ert-info ("Paste block") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("3ysp") ";[;]; ; This buffer is for notes you don't want to save. ;;; ; If you want to create a file, visit that file with C-x C-f, ;;; ; then enter the text in that file's own buffer.")) (ert-info ("Paste block with count") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("3ys2p") ";[;]; ;; ; This buffer is for notes you don't want to save. ;;; ;; ; If you want to create a file, visit that file with C-x C-f, ;;; ;; ; then enter the text in that file's own buffer.")) (ert-info ("Paste block with empty line") (evil-test-buffer "[;]; Above some line ;; Below some empty line" (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("3ys2p") ";;; ;; ; Above some line ;;; ;; ; Below some empty line")) (ert-info ("Paste block crossing end of buffer") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("3ysj") ";; This buffer is for notes you don't want to save. \[;]; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("p") ";; This buffer is for notes you don't want to save. ;;; ; If you want to create a file, visit that file with C-x C-f, ;;; ; then enter the text in that file's own buffer. ;;")) (ert-info ("Paste block at end-of-line") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("3ys$") ";; This buffer is for notes you don't want to save[.] ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("p") ";; This buffer is for notes you don't want to save.;; ;; If you want to create a file, visit that file wi;; th C-x C-f, ;; then enter the text in that file's own buffer. ;;")) (ert-info ("Paste preserves preceding text properties") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (put-text-property (point) (line-end-position) 'font-lock-face 'warning) ("yyp") ";; This buffer is for notes you don't want to save. [;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (should (equal (get-text-property (point-min) 'font-lock-face) 'warning))))) (ert-deftest evil-test-paste-pop-before () "Test `evil-paste-pop' after `evil-paste-before'" :tags '(evil paste) (ert-info ("Paste") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y2e2yyy3sj") ";; This buffer is for notes you don't want to save. \[;]; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("P") ";; This buffer is for notes you don't want to save. \[;]; ;; If you want to create a file, visit that file with C-x C-f, ;; ;; then enter the text in that file's own buffer. ;;")) (ert-info ("Single pop") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y2e2yyy3sjP\C-p") ";; This buffer is for notes you don't want to save. \[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer.")) (ert-info ("Two pops") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y2e2yyy3sjP\C-p\C-p") ";; This buffer is for notes you don't want to save. ;; Thi[s];; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer.")) (ert-info ("Pop with count") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y2e2yyy3sjP2\C-p") ";; This buffer is for notes you don't want to save. ;; Thi[s];; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer.")) (ert-info ("Single pop-next") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y2e2yyy3sjP2\C-p\C-n") ";; This buffer is for notes you don't want to save. \[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer.")) (ert-info ("Pop-next with count") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y2e2yyy3sjP\C-p\C-p2\C-n") ";; This buffer is for notes you don't want to save. \[;]; ;; If you want to create a file, visit that file with C-x C-f, ;; ;; then enter the text in that file's own buffer. ;;"))) (ert-deftest evil-test-paste-pop-after () "Test `evil-paste-pop' after `evil-paste-after'" :tags '(evil paste) (ert-info ("Paste") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y2e2yyy3sj") ";; This buffer is for notes you don't want to save. \[;]; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("p") ";; This buffer is for notes you don't want to save. ;[;]; ; If you want to create a file, visit that file with C-x C-f, ;;; ; then enter the text in that file's own buffer. ;;")) (ert-info ("Single pop") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y2e2yyy3sjp\C-p") ";; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, \[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer.")) (ert-info ("Two pops") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y2e2yyy3sjp\C-p\C-p") ";; This buffer is for notes you don't want to save. ;;; Thi[s]; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer.")) (ert-info ("Pop with count") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y2e2yyy3sjp2\C-p") ";; This buffer is for notes you don't want to save. ;;; Thi[s]; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer.")) (ert-info ("Single pop-next") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y2e2yyy3sjp2\C-p\C-n") ";; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, \[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer.")) (ert-info ("Pop-next with count") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y2e2yyy3sjp\C-p\C-p2\C-n") ";; This buffer is for notes you don't want to save. ;[;]; ; If you want to create a file, visit that file with C-x C-f, ;;; ; then enter the text in that file's own buffer. ;;"))) (ert-deftest evil-test-paste-pop-without-undo () "Test `evil-paste-pop' with undo disabled" :tags '(evil paste) (ert-info ("Pop-next with count without undo") (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (setq buffer-undo-list t) (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) ("y2e2yyy3sjP\C-p\C-p2\C-n") ";; This buffer is for notes you don't want to save. \[;]; ;; If you want to create a file, visit that file with C-x C-f, ;; ;; then enter the text in that file's own buffer. ;;"))) (ert-deftest evil-test-visual-paste () "Test `evil-paste-before' and `evil-paste-after' in Visual state" :tags '(evil paste) (evil-test-buffer ";; This buffer is for notes you don't want to save. ;; [I]f you want to create a file, visit that file with C-x C-f." ("yyk") ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f." ("VP") "[;]; If you want to create a file, visit that file with C-x C-f. ;; If you want to create a file, visit that file with C-x C-f.") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f." ("yyj") ";; This buffer is for notes you don't want to save. ;; [I]f you want to create a file, visit that file with C-x C-f." ("Vp") ";; This buffer is for notes you don't want to save. \[;]; This buffer is for notes you don't want to save.")) (ert-deftest evil-test-visual-paste-pop () "Test `evil-paste-pop' after visual paste." :tags '(evil paste) (ert-info ("Visual-char paste, char paste") (evil-test-buffer "[w]ord1a word1b word1c\nword2a word2b\nword3a word3b word3c word3d\n" ("yiwyywyiw^jw") "word1a word1b word1c\nword2a [w]ord2b\nword3a word3b word3c word3d\n" ("viwp") "word1a word1b word1c\nword2a word1[b]\nword3a word3b word3c word3d\n")) (ert-info ("Visual-char paste, char paste, line pop") (evil-test-buffer "[w]ord1a word1b word1c\nword2a word2b\nword3a word3b word3c word3d\n" ("yiwyywyiw^jw") "word1a word1b word1c\nword2a [w]ord2b\nword3a word3b word3c word3d\n" ("viwp\C-p") "word1a word1b word1c\nword2a \n[w]ord1a word1b word1c\n\nword3a word3b word3c word3d\n")) (ert-info ("Visual-char paste, char paste, line pop, char pop") (evil-test-buffer "[w]ord1a word1b word1c\nword2a word2b\nword3a word3b word3c word3d\n" ("yiwyywyiw^jw") "word1a word1b word1c\nword2a [w]ord2b\nword3a word3b word3c word3d\n" ("viwp\C-p\C-p") "word1a word1b word1c\nword2a word1[a]\nword3a word3b word3c word3d\n")) (ert-info ("Visual-line paste, char paste") (evil-test-buffer "[w]ord1a word1b word1c\nword2a word2b\nword3a word3b word3c word3d\n" ("yiwyywyiw^j") "word1a word1b word1c\n[w]ord2a word2b\nword3a word3b word3c word3d\n" ("Vp") "word1a word1b word1c\nword1[b]word3a word3b word3c word3d\n")) (ert-info ("Visual-line paste, char paste, line pop") (evil-test-buffer "[w]ord1a word1b word1c\nword2a word2b\nword3a word3b word3c word3d\n" ("yiwyywyiw^j") "word1a word1b word1c\n[w]ord2a word2b\nword3a word3b word3c word3d\n" ("Vp\C-p") "word1a word1b word1c\n[w]ord1a word1b word1c\nword3a word3b word3c word3d\n")) (ert-info ("Visual-line paste, char paste, line pop, char pop") (evil-test-buffer "[w]ord1a word1b word1c\nword2a word2b\nword3a word3b word3c word3d\n" ("yiwyywyiw^j") "word1a word1b word1c\n[w]ord2a word2b\nword3a word3b word3c word3d\n" ("Vp\C-p\C-p") "word1a word1b word1c\nword1[a]word3a word3b word3c word3d\n"))) (ert-deftest evil-test-register () "Test yanking and pasting to and from register." :tags '(evil yank paste) (ert-info ("simple lower case register") (evil-test-buffer "[f]oo\n" ("\"ayw\"aP") "fo[o]foo\n" ("\"ayy\"aP") "[f]oofoo\nfoofoo\n")) (ert-info ("upper case register") (evil-test-buffer "[f]oo\n" ("\"ayw\"Ayw\"aP") "foofo[o]foo\n" ("\"ayy\"Ayy\"aP") "[f]oofoofoo\nfoofoofoo\nfoofoofoo\n")) (ert-info ("upper case register and lines") (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4\n" ("\"a2Yjj\"A2Y\"aP") "line 1\nline 2\n[l]ine 1\nline 2\nline 3\nline 4\nline 3\nline 4\n" ("8G\"ap") "line 1\nline 2\nline 1\nline 2\nline 3\nline 4\nline 3\nline 4\n[l]ine 1\nline 2\nline 3\nline 4\n")) (ert-info ("yank with count") (evil-test-buffer "[l]ine 1\nline 2\nline 3\n" ("\"a2yw\"aP") "line [1]line 1\nline 2\nline 3\n" ("\"a2yy\"aP") "[l]ine 1line 1\nline 2\nline 1line 1\nline 2\nline 3\n")) (dolist (module '(evil-search isearch)) (evil-select-search-module 'evil-search-module module) (ert-info ((format "special register / (module: %s)" module)) (evil-test-buffer "[f]oo bar\n" ("/bar" [return] "0i\C-r/") "bar[f]oo bar\n"))) (ert-info ("special register :") (evil-test-buffer "[f]oo bar\n" (":noh\ni\C-r:")))) (ert-deftest evil-test-last-insert-register () "Test last insertion register." (evil-test-buffer "[l]ine 1\n" ("GiABC" [escape]) "line 1\nAB[C]" ("gg\".P") "AB[C]line 1\nABC")) (ert-deftest evil-test-zero-register () "\"0 contains the last text that was yanked without specificying a register." (evil-test-buffer "[l]ine 1\nline 2\n" ("yy\"0p") "line 1\n[l]ine 1\nline 2\n" ("j\"ayy\"0p") "line 1\nline 1\nline 2\n[l]ine 1\n" ; yanked line 2 to "a, so "0 is still line 1 ("kdd\"0p") "line 1\nline 1\nline 1\n[l]ine 1\n")) (ert-deftest evil-test-align () "Test `evil-align-left', `evil-align-right' and `evil-align-center'." :tags '(evil operator) (evil-without-display (let ((fill-column 70) indent-tabs-mode) (evil-test-buffer "before\n[l]ine 1\nthis is line number 2\nline number 3\nafter\n" (":.,+2ri" [return] (kbd "M-x") "untabify" [return]) "before\n [l]ine 1\n this is line number 2\n line number 3\nafter\n" (":.,+2ri 60" [return] (kbd "M-x") "untabify" [return]) "before\n [l]ine 1\n this is line number 2\n line number 3\nafter\n" (":.,+2le" [return] (kbd "M-x") "untabify" [return]) "before\n[l]ine 1\nthis is line number 2\nline number 3\nafter\n" (":.,+2le 10" [return]) "before\n [l]ine 1\n this is line number 2\n line number 3\nafter\n" (":.,+2ce" [return] (kbd "M-x") "untabify" [return]) "before\n [l]ine 1\n this is line number 2\n line number 3\nafter\n" (":.,+2ce 40" [return] (kbd "M-x") "untabify" [return]) "before\n [l]ine 1\n this is line number 2\n line number 3\nafter\n")))) ;;; Motions (ert-deftest evil-test-forward-char () "Test `evil-forward-char' motion" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer "[;]; This buffer is for notes." ("l") ";[;] This buffer is for notes.")) (ert-info ("End of line") (let ((evil-cross-lines t) (evil-move-beyond-eol nil)) (evil-test-buffer ";; This buffer is for notes[,] ;; and for Lisp evaluation." ("l") ";; This buffer is for notes, \[;]; and for Lisp evaluation."))) (ert-info ("With count") (evil-test-buffer "[;]; This buffer is for notes." ("12l") ";; This buff[e]r is for notes.")) (ert-info ("End of line") (evil-test-buffer ";; This buffer is for notes[.]" (should-error (execute-kbd-macro "l")) (should-error (execute-kbd-macro "10l")))) (ert-info ("Until end-of-line") (evil-test-buffer "[;]; This buffer is for notes." ("100l") ";; This buffer is for notes[.]")) (ert-info ("On empty line") (evil-test-buffer "Above some line \[] Below some empty line" (should-error (execute-kbd-macro "l")) (should-error (execute-kbd-macro "42l"))))) (ert-deftest evil-test-backward-char () "Test `evil-backward-char' motion" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer ";; This[ ]buffer is for notes." ("h") ";; Thi[s] buffer is for notes.")) (ert-info ("With count") (evil-test-buffer ";; This[ ]buffer is for notes." ("3h") ";; T[h]is buffer is for notes.")) (ert-info ("Beginning of line") (evil-test-buffer "[;]; This buffer is for notes." (should-error (execute-kbd-macro "h")) (should-error (execute-kbd-macro "10h")))) (ert-info ("Until beginning-of-line") (evil-test-buffer ";; This[ ]buffer is for notes." ("100h") "[;]; This buffer is for notes.")) (ert-info ("On empty line") (evil-test-buffer "Above some line \[] Below some empty line" (should-error (execute-kbd-macro "h")) (should-error (execute-kbd-macro "42h"))))) (ert-deftest evil-test-previous-line () "Test `evil-previous-line' motion" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer ";; This buffer is for notes you don't want to save, ;; [a]nd for Lisp evaluation." ("k") ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation.")) (ert-info ("With count") (evil-test-buffer ";; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; [t]hen enter the text in that file's own buffer." ("2k") ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer.")) (ert-info ("Until beginning of buffer") (evil-test-buffer ";; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; [t]hen enter the text in that file's own buffer." ("100k") ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer.")) (ert-info ("At beginning of buffer") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." (should-error (execute-kbd-macro "k")) (should-error (execute-kbd-macro "42k"))))) (ert-deftest evil-test-next-line () "Test `evil-next-line' motion" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("j") ";; This buffer is for notes you don't want to save, ;; [a]nd for Lisp evaluation.")) (ert-info ("With count") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("2j") ";; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; [t]hen enter the text in that file's own buffer.")) (ert-info ("Until end of buffer") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("100j") ";; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; [t]hen enter the text in that file's own buffer.")) (ert-info ("At end of buffer") (evil-test-buffer ";; This buffer is for notes you don't want to [s]ave." (should-error (execute-kbd-macro "j")) (should-error (execute-kbd-macro "42j"))))) (ert-deftest evil-test-preserve-column () "Test `evil-previous-line' and `evil-next-line' preserve the column." :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer "ab[c]\nabcdef\n\nabcd\n" ("j") "abc\nab[c]def\n\nabcd\n") (evil-test-buffer "ab[c]\nabcdef\n\nabcd\n" ("jj") "abc\nabcdef\n[\n]abcd\n") (evil-test-buffer "ab[c]\nabcdef\n\nabcd\n" ("jjj") "abc\nabcdef\n\nab[c]d\n") (evil-test-buffer "ab[c]\nabcdef\n\nabcd\n" ("jjjk") "abc\nabcdef\n[\n]abcd\n") (evil-test-buffer "ab[c]\nabcdef\n\nabcd\n" ("jjjkk") "abc\nab[c]def\n\nabcd\n"))) (ert-deftest evil-test-beginning-of-line () "Test `evil-beginning-of-line' motion" :tags '(evil motion) (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." ("0") "[;]; This buffer is for notes you don't want to save." ("0") "[;]; This buffer is for notes you don't want to save.")) (ert-deftest evil-test-end-of-line () "Test `evil-end-of-line' motion" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer ";; [T]his buffer is for notes you don't want to save." ("$") ";; This buffer is for notes you don't want to save[.]" ("$") ";; This buffer is for notes you don't want to save[.]")) (ert-info ("Don't delete blank lines") (evil-test-buffer "Above some line \[] Below some empty line" ("d$") "Above some line \[] Below some empty line"))) (ert-deftest evil-test-first-non-blank () "Test `evil-first-non-blank' motion" :tags '(evil motion) (evil-test-buffer "\ printf(\"Hello world\\n\")[;] return EXIT_SUCCESS;" ("^") "\ [p]rintf(\"Hello world\\n\"); return EXIT_SUCCESS;" ("j^") "\ printf(\"Hello world\\n\"); [r]eturn EXIT_SUCCESS;")) (ert-deftest evil-test-last-non-blank () "Test `evil-last-non-blank' motion" :tags '(evil motion) (evil-test-buffer "[i]nt main(int argc, char** argv) \n\ { printf(\"Hello world\\n\"); return EXIT_SUCCESS; }" ("g_") "int main(int argc, char** argv[)] \n\ { printf(\"Hello world\\n\"); return EXIT_SUCCESS; }" ("jjg_") "int main(int argc, char** argv) \n\ { printf(\"Hello world\\n\")[;] return EXIT_SUCCESS; }")) (ert-deftest evil-test-goto-first-line () "Test `evil-goto-first-line' motion" :tags '(evil motion) (evil-test-buffer "[i]nt main(int argc, char** argv) { printf(\"Hello world\\n\"); return EXIT_SUCCESS; }" ("3gg") "int main(int argc, char** argv) { [p]rintf(\"Hello world\\n\"); return EXIT_SUCCESS; }" ("gg") "[i]nt main(int argc, char** argv) { printf(\"Hello world\\n\"); return EXIT_SUCCESS; }" ("100gg") "int main(int argc, char** argv) { printf(\"Hello world\\n\"); return EXIT_SUCCESS; \[}]")) (ert-deftest evil-test-goto-line () "Test `evil-goto-line' motion" :tags '(evil motion) (evil-test-buffer "[i]nt main(int argc, char** argv) { printf(\"Hello world\\n\"); return EXIT_SUCCESS; }" ("G") "int main(int argc, char** argv) { printf(\"Hello world\\n\"); return EXIT_SUCCESS; \[}]" ("3G") "int main(int argc, char** argv) { [p]rintf(\"Hello world\\n\"); return EXIT_SUCCESS; }" ("100G") "int main(int argc, char** argv) { printf(\"Hello world\\n\"); return EXIT_SUCCESS; \[}]")) (ert-deftest evil-test-operator-0 () "Test motion \"0\" with an operator." :tags '(evil motion) (evil-test-buffer ";; [T]his buffer is for notes." ("d0") "[T]his buffer is for notes.")) (ert-deftest evil-test-forward-not-word () "Test `evil-forward-not-thing'" :tags '(evil motion) (evil-test-buffer "[ ] aa,," (evil-forward-not-thing 'evil-word) " [a]a,,")) ;; TODO: test Visual motions and window motions (ert-deftest evil-test-forward-word-begin () "Test `evil-forward-word-begin'" :tags '(evil motion) (ert-info ("Non-word") (evil-test-buffer "[;]; This buffer is for notes." ("w") ";; [T]his buffer is for notes.")) (ert-info ("Simple") (evil-test-buffer ";; [T]his buffer is for notes." ("w") ";; This [b]uffer is for notes.")) (ert-info ("With count") (evil-test-buffer ";; [T]his buffer is for notes." ("3w") ";; This buffer is [f]or notes.")) (ert-info ("With count on whitespace") (evil-test-buffer ";;[ ]This buffer is for notes." ("3w") ";; This buffer [i]s for notes.")) (ert-info ("Empty line") (evil-test-buffer "Above some line \[] Below some empty line" ("w") "Above some line \[B]elow some empty line") (evil-test-buffer "[A]bove Below some empty line" ("dw") "[] Below some empty line" ("dw") "[] Below some empty line" ("dw") "[B]elow some empty line") (evil-test-buffer "[A]bove Below some empty line with leading whitespace" ("dw") "[] Below some empty line with leading whitespace" ("dw") "[] Below some empty line with leading whitespace" ("dw") " [B]elow some empty line") (evil-test-buffer "Some line with trailing whitespace [ ] \n next line\n" ("dw") "Some line with trailing whitespace [ ]\n next line\n") (evil-test-buffer "[A]\n" ("dw") "[]\n")) (ert-info ("End of buffer") (evil-test-buffer ";; [T]his buffer is for notes." ("100w") ";; This buffer is for notes[.]" (should-error (execute-kbd-macro "w")) (should-error (execute-kbd-macro "10w")))) (ert-info ("Before last character in buffer") (evil-test-buffer "fo[o]." ("w") "foo[.]") (evil-test-buffer "fo[o] " ("w") "foo[ ]") (evil-test-buffer "[ ]e" ("w") " [e]"))) (ert-deftest evil-test-forward-word-end () "Test `evil-forward-word-end'" :tags '(evil motion) (ert-info ("Non-word") (evil-test-buffer "[;]; This buffer is for notes." ("e") ";[;] This buffer is for notes.")) (ert-info ("Simple") (evil-test-buffer ";; [T]his buffer is for notes." ("e") ";; Thi[s] buffer is for notes.")) (ert-info ("With count") (evil-test-buffer ";; [T]his buffer is for notes." ("3e") ";; This buffer i[s] for notes.")) (ert-info ("With count on whitespace") (evil-test-buffer ";;[ ]This buffer is for notes." ("3e") ";; This buffer i[s] for notes.")) (ert-info ("Delete") (evil-test-buffer ";; This[-]buffer-is-for-notes." ("de") ";; This[-]is-for-notes.")) (ert-info ("Empty line") (evil-test-buffer "Above some line \[] Below some empty line" ("e") "Above some line Belo[w] some empty line")) (ert-info ("End of buffer") (evil-test-buffer ";; [T]his buffer is for notes." ("100e") ";; This buffer is for notes[.]" (should-error (execute-kbd-macro "e")) (should-error (execute-kbd-macro "10e")))) ;; In Vim, "de" may delete two words rather than one ;; if the first word is only one letter. In Evil, ;; "de" always deletes one word. (ert-info ("Delete a single-letter word") (evil-test-buffer "a [b] c" ("de") "a [ ]c"))) (ert-deftest evil-test-backward-word-begin () "Test `evil-backward-word-begin'" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer ";; This buffer is for notes[.]" ("b") ";; This buffer is for [n]otes.")) (ert-info ("With count") (evil-test-buffer ";; This buffer is for notes[.]" ("2b") ";; This buffer is [f]or notes.")) (ert-info ("Empty line") (evil-test-buffer "Above some line \[] Below some empty line" ("b") "Above some [l]ine Below some empty line")) (ert-info ("With count on whitespace") (evil-test-buffer ";; This buffer is for[ ]notes." ("2b") ";; This buffer [i]s for notes.")) (ert-info ("Beginning of buffer") (evil-test-buffer ";; This buffer is for notes[.]" ("100b") "[;]; This buffer is for notes." (should-error (execute-kbd-macro "b")) (should-error (execute-kbd-macro "10b"))))) (ert-deftest evil-test-backward-word-end () "Test `evil-backward-word-end'" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer ";; This buffer is for notes[.]" ("ge") ";; This buffer is for note[s].")) (ert-info ("With count") (evil-test-buffer ";; This buffer is for notes[.]" ("2ge") ";; This buffer is fo[r] notes.")) (ert-info ("Empty line") (evil-test-buffer "Above some line \[] Below some empty line" ("ge") "Above some lin[e] Below some empty line")) (ert-info ("With count on whitespace") (evil-test-buffer ";; This buffer is for[ ]notes." ("2ge") ";; This buffer i[s] for notes.")) (ert-info ("Beginning of buffer") (evil-test-buffer ";; This buffer is for notes[.]" ("100ge") "[;]; This buffer is for notes." (should-error (execute-kbd-macro "ge")) (should-error (execute-kbd-macro "10ge"))))) (ert-deftest evil-test-forward-word-begin-cjk () "Test `evil-forward-word-begin' on CJK words" :tags '(evil motion cjk) (ert-info ("Latin / numeric") (evil-test-buffer "[a]bcd1234" ("w") "abcd123[4]")) (ert-info ("Latin / Kanji") (evil-test-buffer "[a]bcd漢字" ("w") "abcd[漢]字")) (ert-info ("Latin / Hiragana") (evil-test-buffer "[a]bcdひらがな" ("w") "abcd[ひ]らがな")) (ert-info ("Latin / Katakana") (evil-test-buffer "[a]bcdカタカナ" ("w") "abcd[カ]タカナ")) (ert-info ("Latin / half-width Katakana") (evil-test-buffer "[a]bcdカタカナ" ("w") "abcdカタカ[ナ]")) (ert-info ("Latin / full-width alphabet") (evil-test-buffer "[a]bcdABC" ("w") "abcdAB[C]")) (ert-info ("Latin / full-width numeric") (evil-test-buffer "[a]bcd123" ("w") "abcd12[3]")) (ert-info ("Latin / Hangul") (evil-test-buffer "[a]bcd한글" ("w") "abcd[한]글")) (ert-info ("numeric / Latin") (evil-test-buffer "[1]234abcd" ("w") "1234abc[d]")) (ert-info ("numeric / Kanji") (evil-test-buffer "[1]234漢字" ("w") "1234[漢]字")) (ert-info ("numeric / Hiragana") (evil-test-buffer "[1]234ひらがな" ("w") "1234[ひ]らがな")) (ert-info ("numeric / Katakana") (evil-test-buffer "[1]234カタカナ" ("w") "1234[カ]タカナ")) (ert-info ("numeric / half-width Katakana") (evil-test-buffer "[1]234カタカナ" ("w") "1234カタカ[ナ]")) (ert-info ("numeric / full-width alphabet") (evil-test-buffer "[1]234ABC" ("w") "1234AB[C]")) (ert-info ("numeric / full-width numeric") (evil-test-buffer "[1]234123" ("w") "123412[3]")) (ert-info ("numeric / Hangul") (evil-test-buffer "[1]234한글" ("w") "1234[한]글")) (ert-info ("Kanji / Latin") (evil-test-buffer "[漢]字abcd" ("w") "漢字[a]bcd")) (ert-info ("Kanji / numeric") (evil-test-buffer "[漢]字1234" ("w") "漢字[1]234")) (ert-info ("Kanji / Hiragana") (evil-test-buffer "[漢]字ひらがな" ("w") "漢字[ひ]らがな")) (ert-info ("Kanji / Katakana") (evil-test-buffer "[漢]字カタカナ" ("w") "漢字[カ]タカナ")) (ert-info ("Kanji / half-width Katakana") (evil-test-buffer "[漢]字カタカナ" ("w") "漢字[カ]タカナ")) (ert-info ("Kanji / full-width alphabet") (evil-test-buffer "[漢]字ABC" ("w") "漢字[A]BC")) (ert-info ("Kanji / full-width numeric") (evil-test-buffer "[漢]字123" ("w") "漢字[1]23")) (ert-info ("Kanji / Hangul") (evil-test-buffer "[漢]字한글" ("w") "漢字[한]글")) (ert-info ("Hiragana / Latin") (evil-test-buffer "[ひ]らがなabcd" ("w") "ひらがな[a]bcd")) (ert-info ("Hiragana / numeric") (evil-test-buffer "[ひ]らがな1234" ("w") "ひらがな[1]234")) (ert-info ("Hiragana / Kanji") (evil-test-buffer "[ひ]らがな漢字" ("w") "ひらがな[漢]字")) (ert-info ("Hiragana / Katakana") (evil-test-buffer "[ひ]らがなカタカナ" ("w") "ひらがな[カ]タカナ")) (ert-info ("Hiragana / half-width Katakana") (evil-test-buffer "[ひ]らがなカタカナ" ("w") "ひらがな[カ]タカナ")) (ert-info ("Hiragana / full-width alphabet") (evil-test-buffer "[ひ]らがなABC" ("w") "ひらがな[A]BC")) (ert-info ("Hiragana / full-width numeric") (evil-test-buffer "[ひ]らがな123" ("w") "ひらがな[1]23")) (ert-info ("Hiragana / Hangul") (evil-test-buffer "[ひ]らがな한글" ("w") "ひらがな[한]글")) (ert-info ("Katakana / Latin") (evil-test-buffer "[カ]タカナabcd" ("w") "カタカナ[a]bcd")) (ert-info ("Katakana / numeric") (evil-test-buffer "[カ]タカナ1234" ("w") "カタカナ[1]234")) (ert-info ("Katakana / Kanji") (evil-test-buffer "[カ]タカナ漢字" ("w") "カタカナ[漢]字")) (ert-info ("Katakana / Hiragana") (evil-test-buffer "[カ]タカナひらがな" ("w") "カタカナ[ひ]らがな")) (ert-info ("Katakana / half-width Katakana") (evil-test-buffer "[カ]タカナカタカナ" ("w") "カタカナ[カ]タカナ")) (ert-info ("Katakana / full-width alphabet") (evil-test-buffer "[カ]タカナABC" ("w") "カタカナ[A]BC")) (ert-info ("Katakana / full-width numeric") (evil-test-buffer "[カ]タカナ123" ("w") "カタカナ[1]23")) (ert-info ("Katakana / Hangul") (evil-test-buffer "[カ]タカナ한글" ("w") "カタカナ[한]글")) (ert-info ("half-width Katakana / Latin") (evil-test-buffer "[カ]タカナabcd" ("w") "カタカナabc[d]")) (ert-info ("half-width Katakana / numeric") (evil-test-buffer "[カ]タカナ1234" ("w") "カタカナ123[4]")) (ert-info ("half-width Katakana / Kanji") (evil-test-buffer "[カ]タカナ漢字" ("w") "カタカナ[漢]字")) (ert-info ("half-width Katakana / Hiragana") (evil-test-buffer "[カ]タカナひらがな" ("w") "カタカナ[ひ]らがな")) (ert-info ("half-width Katakana / Katakana") (evil-test-buffer "[カ]タカナカタカナ" ("w") "カタカナ[カ]タカナ")) (ert-info ("half-width Katakana / full-width alphabet") (evil-test-buffer "[カ]タカナABC" ("w") "カタカナAB[C]")) (ert-info ("half-width Katakana / full-width numeric") (evil-test-buffer "[カ]タカナ123" ("w") "カタカナ12[3]")) (ert-info ("half-width Katakana / Hangul") (evil-test-buffer "[カ]タカナ한글" ("w") "カタカナ[한]글")) (ert-info ("full-width alphabet / Latin") (evil-test-buffer "[A]BCabcd" ("w") "ABCabc[d]")) (ert-info ("full-width alphabet / numeric") (evil-test-buffer "[A]BC1234" ("w") "ABC123[4]")) (ert-info ("full-width alphabet / Kanji") (evil-test-buffer "[A]BC漢字" ("w") "ABC[漢]字")) (ert-info ("full-width alphabet / Hiragana") (evil-test-buffer "[A]BCひらがな" ("w") "ABC[ひ]らがな")) (ert-info ("full-width alphabet / Katakana") (evil-test-buffer "[A]BCカタカナ" ("w") "ABC[カ]タカナ")) (ert-info ("full-width alphabet / half-width Katakana") (evil-test-buffer "[A]BCカタカナ" ("w") "ABCカタカ[ナ]")) (ert-info ("full-width alphabet / full-width numeric") (evil-test-buffer "[A]BC123" ("w") "ABC12[3]")) (ert-info ("full-width alphabet / Hangul") (evil-test-buffer "[A]BC한글" ("w") "ABC[한]글")) (ert-info ("full-width numeric / Latin") (evil-test-buffer "[1]23abcd" ("w") "123abc[d]")) (ert-info ("full-width numeric / numeric") (evil-test-buffer "[1]231234" ("w") "123123[4]")) (ert-info ("full-width numeric / Kanji") (evil-test-buffer "[1]23漢字" ("w") "123[漢]字")) (ert-info ("full-width numeric / Hiragana") (evil-test-buffer "[1]23ひらがな" ("w") "123[ひ]らがな")) (ert-info ("full-width numeric / Katakana") (evil-test-buffer "[1]23カタカナ" ("w") "123[カ]タカナ")) (ert-info ("full-width numeric / half-width Katakana") (evil-test-buffer "[1]23カタカナ" ("w") "123カタカ[ナ]")) (ert-info ("full-width numeric / full-width alphabet") (evil-test-buffer "[1]23ABC" ("w") "123AB[C]")) (ert-info ("full-width numeric / Hangul") (evil-test-buffer "[1]23한글" ("w") "123[한]글")) (ert-info ("Hangul / Latin") (evil-test-buffer "[한]글abcd" ("w") "한글[a]bcd")) (ert-info ("Hangul / numeric") (evil-test-buffer "[한]글1234" ("w") "한글[1]234")) (ert-info ("Hangul / Kanji") (evil-test-buffer "[한]글漢字" ("w") "한글[漢]字")) (ert-info ("Hangul / Hiragana") (evil-test-buffer "[한]글ひらがな" ("w") "한글[ひ]らがな")) (ert-info ("Hangul / Katakana") (evil-test-buffer "[한]글カタカナ" ("w") "한글[カ]タカナ")) (ert-info ("Hangul / half-width Katakana") (evil-test-buffer "[한]글カタカナ" ("w") "한글[カ]タカナ")) (ert-info ("Hangul / full-width alphabet") (evil-test-buffer "[한]글ABC" ("w") "한글[A]BC")) (ert-info ("Hangul / full-width numeric") (evil-test-buffer "[한]글123" ("w") "한글[1]23"))) (ert-deftest evil-test-forward-word-end-cjk () "Test `evil-forward-word-end' on CJK words" :tags '(evil motion cjk) (ert-info ("Latin / numeric") (evil-test-buffer "[a]bcd1234" ("e") "abcd123[4]")) (ert-info ("Latin / Kanji") (evil-test-buffer "[a]bcd漢字" ("e") "abc[d]漢字")) (ert-info ("Latin / Hiragana") (evil-test-buffer "[a]bcdひらがな" ("e") "abc[d]ひらがな")) (ert-info ("Latin / Katakana") (evil-test-buffer "[a]bcdカタカナ" ("e") "abc[d]カタカナ")) (ert-info ("Latin / half-width Katakana") (evil-test-buffer "[a]bcdカタカナ" ("e") "abcdカタカ[ナ]")) (ert-info ("Latin / full-width alphabet") (evil-test-buffer "[a]bcdABC" ("e") "abcdAB[C]")) (ert-info ("Latin / full-width numeric") (evil-test-buffer "[a]bcd123" ("e") "abcd12[3]")) (ert-info ("Latin / Hangul") (evil-test-buffer "[a]bcd한글" ("e") "abc[d]한글")) (ert-info ("numeric / Latin") (evil-test-buffer "[1]234abcd" ("e") "1234abc[d]")) (ert-info ("numeric / Kanji") (evil-test-buffer "[1]234漢字" ("e") "123[4]漢字")) (ert-info ("numeric / Hiragana") (evil-test-buffer "[1]234ひらがな" ("e") "123[4]ひらがな")) (ert-info ("numeric / Katakana") (evil-test-buffer "[1]234カタカナ" ("e") "123[4]カタカナ")) (ert-info ("numeric / half-width Katakana") (evil-test-buffer "[1]234カタカナ" ("e") "1234カタカ[ナ]")) (ert-info ("numeric / full-width alphabet") (evil-test-buffer "[1]234ABC" ("e") "1234AB[C]")) (ert-info ("numeric / full-width numeric") (evil-test-buffer "[1]234123" ("e") "123412[3]")) (ert-info ("numeric / Hangul") (evil-test-buffer "[1]234한글" ("e") "123[4]한글")) (ert-info ("Kanji / Latin") (evil-test-buffer "[漢]字abcd" ("e") "漢[字]abcd")) (ert-info ("Kanji / numeric") (evil-test-buffer "[漢]字1234" ("e") "漢[字]1234")) (ert-info ("Kanji / Hiragana") (evil-test-buffer "[漢]字ひらがな" ("e") "漢[字]ひらがな")) (ert-info ("Kanji / Katakana") (evil-test-buffer "[漢]字カタカナ" ("e") "漢[字]カタカナ")) (ert-info ("Kanji / half-width Katakana") (evil-test-buffer "[漢]字カタカナ" ("e") "漢[字]カタカナ")) (ert-info ("Kanji / full-width alphabet") (evil-test-buffer "[漢]字ABC" ("e") "漢[字]ABC")) (ert-info ("Kanji / full-width numeric") (evil-test-buffer "[漢]字123" ("e") "漢[字]123")) (ert-info ("Kanji / Hangul") (evil-test-buffer "[漢]字한글" ("e") "漢[字]한글")) (ert-info ("Hiragana / Latin") (evil-test-buffer "[ひ]らがなabcd" ("e") "ひらが[な]abcd")) (ert-info ("Hiragana / numeric") (evil-test-buffer "[ひ]らがな1234" ("e") "ひらが[な]1234")) (ert-info ("Hiragana / Kanji") (evil-test-buffer "[ひ]らがな漢字" ("e") "ひらが[な]漢字")) (ert-info ("Hiragana / Katakana") (evil-test-buffer "[ひ]らがなカタカナ" ("e") "ひらが[な]カタカナ")) (ert-info ("Hiragana / half-width Katakana") (evil-test-buffer "[ひ]らがなカタカナ" ("e") "ひらが[な]カタカナ")) (ert-info ("Hiragana / full-width alphabet") (evil-test-buffer "[ひ]らがなABC" ("e") "ひらが[な]ABC")) (ert-info ("Hiragana / full-width numeric") (evil-test-buffer "[ひ]らがな123" ("e") "ひらが[な]123")) (ert-info ("Hiragana / Hangul") (evil-test-buffer "[ひ]らがな한글" ("e") "ひらが[な]한글")) (ert-info ("Katakana / Latin") (evil-test-buffer "[カ]タカナabcd" ("e") "カタカ[ナ]abcd")) (ert-info ("Katakana / numeric") (evil-test-buffer "[カ]タカナ1234" ("e") "カタカ[ナ]1234")) (ert-info ("Katakana / Kanji") (evil-test-buffer "[カ]タカナ漢字" ("e") "カタカ[ナ]漢字")) (ert-info ("Katakana / Hiragana") (evil-test-buffer "[カ]タカナひらがな" ("e") "カタカ[ナ]ひらがな")) (ert-info ("Katakana / half-width Katakana") (evil-test-buffer "[カ]タカナカタカナ" ("e") "カタカ[ナ]カタカナ")) (ert-info ("Katakana / full-width alphabet") (evil-test-buffer "[カ]タカナABC" ("e") "カタカ[ナ]ABC")) (ert-info ("Katakana / full-width numeric") (evil-test-buffer "[カ]タカナ123" ("e") "カタカ[ナ]123")) (ert-info ("Katakana / Hangul") (evil-test-buffer "[カ]タカナ한글" ("e") "カタカ[ナ]한글")) (ert-info ("half-width Katakana / Latin") (evil-test-buffer "[カ]タカナabcd" ("e") "カタカナabc[d]")) (ert-info ("half-width Katakana / numeric") (evil-test-buffer "[カ]タカナ1234" ("e") "カタカナ123[4]")) (ert-info ("half-width Katakana / Kanji") (evil-test-buffer "[カ]タカナ漢字" ("e") "カタカ[ナ]漢字")) (ert-info ("half-width Katakana / Hiragana") (evil-test-buffer "[カ]タカナひらがな" ("e") "カタカ[ナ]ひらがな")) (ert-info ("half-width Katakana / Katakana") (evil-test-buffer "[カ]タカナカタカナ" ("e") "カタカ[ナ]カタカナ")) (ert-info ("half-width Katakana / full-width alphabet") (evil-test-buffer "[カ]タカナABC" ("e") "カタカナAB[C]")) (ert-info ("half-width Katakana / full-width numeric") (evil-test-buffer "[カ]タカナ123" ("e") "カタカナ12[3]")) (ert-info ("half-width Katakana / Hangul") (evil-test-buffer "[カ]タカナ한글" ("e") "カタカ[ナ]한글")) (ert-info ("full-width alphabet / Latin") (evil-test-buffer "[A]BCabcd" ("e") "ABCabc[d]")) (ert-info ("full-width alphabet / numeric") (evil-test-buffer "[A]BC1234" ("e") "ABC123[4]")) (ert-info ("full-width alphabet / Kanji") (evil-test-buffer "[A]BC漢字" ("e") "AB[C]漢字")) (ert-info ("full-width alphabet / Hiragana") (evil-test-buffer "[A]BCひらがな" ("e") "AB[C]ひらがな")) (ert-info ("full-width alphabet / Katakana") (evil-test-buffer "[A]BCカタカナ" ("e") "AB[C]カタカナ")) (ert-info ("full-width alphabet / half-width Katakana") (evil-test-buffer "[A]BCカタカナ" ("e") "ABCカタカ[ナ]")) (ert-info ("full-width alphabet / full-width numeric") (evil-test-buffer "[A]BC123" ("e") "ABC12[3]")) (ert-info ("full-width alphabet / Hangul") (evil-test-buffer "[A]BC한글" ("e") "AB[C]한글")) (ert-info ("full-width numeric / Latin") (evil-test-buffer "[1]23abcd" ("e") "123abc[d]")) (ert-info ("full-width numeric / numeric") (evil-test-buffer "[1]231234" ("e") "123123[4]")) (ert-info ("full-width numeric / Kanji") (evil-test-buffer "[1]23漢字" ("e") "12[3]漢字")) (ert-info ("full-width numeric / Hiragana") (evil-test-buffer "[1]23ひらがな" ("e") "12[3]ひらがな")) (ert-info ("full-width numeric / Katakana") (evil-test-buffer "[1]23カタカナ" ("e") "12[3]カタカナ")) (ert-info ("full-width numeric / half-width Katakana") (evil-test-buffer "[1]23カタカナ" ("e") "123カタカ[ナ]")) (ert-info ("full-width numeric / full-width alphabet") (evil-test-buffer "[1]23ABC" ("e") "123AB[C]")) (ert-info ("full-width numeric / Hangul") (evil-test-buffer "[1]23한글" ("e") "12[3]한글")) (ert-info ("Hangul / Latin") (evil-test-buffer "[한]글abcd" ("e") "한[글]abcd")) (ert-info ("Hangul / numeric") (evil-test-buffer "[한]글1234" ("e") "한[글]1234")) (ert-info ("Hangul / Kanji") (evil-test-buffer "[한]글漢字" ("e") "한[글]漢字")) (ert-info ("Hangul / Hiragana") (evil-test-buffer "[한]글ひらがな" ("e") "한[글]ひらがな")) (ert-info ("Hangul / Katakana") (evil-test-buffer "[한]글カタカナ" ("e") "한[글]カタカナ")) (ert-info ("Hangul / half-width Katakana") (evil-test-buffer "[한]글カタカナ" ("e") "한[글]カタカナ")) (ert-info ("Hangul / full-width alphabet") (evil-test-buffer "[한]글ABC" ("e") "한[글]ABC")) (ert-info ("Hangul / full-width numeric") (evil-test-buffer "[한]글123" ("e") "한[글]123"))) (ert-deftest evil-test-backword-word-begin-cjk () "Test `evil-backward-word-begin' on CJK words" :tags '(evil motion cjk) (ert-info ("Latin / numeric") (evil-test-buffer "abcd123[4]" ("b") "[a]bcd1234")) (ert-info ("Latin / Kanji") (evil-test-buffer "abcd漢[字]" ("b") "abcd[漢]字")) (ert-info ("Latin / Hiragana") (evil-test-buffer "abcdひらが[な]" ("b") "abcd[ひ]らがな")) (ert-info ("Latin / Katakana") (evil-test-buffer "abcdカタカ[ナ]" ("b") "abcd[カ]タカナ")) (ert-info ("Latin / half-width Katakana") (evil-test-buffer "abcdカタカ[ナ]" ("b") "[a]bcdカタカナ")) (ert-info ("Latin / full-width alphabet") (evil-test-buffer "abcdAB[C]" ("b") "[a]bcdABC")) (ert-info ("Latin / full-width numeric") (evil-test-buffer "abcd12[3]" ("b") "[a]bcd123")) (ert-info ("Latin / Hangul") (evil-test-buffer "abcd한[글]" ("b") "abcd[한]글")) (ert-info ("numeric / Latin") (evil-test-buffer "1234abc[d]" ("b") "[1]234abcd")) (ert-info ("numeric / Kanji") (evil-test-buffer "1234漢[字]" ("b") "1234[漢]字")) (ert-info ("numeric / Hiragana") (evil-test-buffer "1234ひらが[な]" ("b") "1234[ひ]らがな")) (ert-info ("numeric / Katakana") (evil-test-buffer "1234カタカ[ナ]" ("b") "1234[カ]タカナ")) (ert-info ("numeric / half-width Katakana") (evil-test-buffer "1234カタカ[ナ]" ("b") "[1]234カタカナ")) (ert-info ("numeric / full-width alphabet") (evil-test-buffer "1234AB[C]" ("b") "[1]234ABC")) (ert-info ("numeric / full-width numeric") (evil-test-buffer "123412[3]" ("b") "[1]234123")) (ert-info ("numeric / Hangul") (evil-test-buffer "1234한[글]" ("b") "1234[한]글")) (ert-info ("Kanji / Latin") (evil-test-buffer "漢字abc[d]" ("b") "漢字[a]bcd")) (ert-info ("Kanji / numeric") (evil-test-buffer "漢字123[4]" ("b") "漢字[1]234")) (ert-info ("Kanji / Hiragana") (evil-test-buffer "漢字ひらが[な]" ("b") "漢字[ひ]らがな")) (ert-info ("Kanji / Katakana") (evil-test-buffer "漢字カタカ[ナ]" ("b") "漢字[カ]タカナ")) (ert-info ("Kanji / half-width Katakana") (evil-test-buffer "漢字カタカ[ナ]" ("b") "漢字[カ]タカナ")) (ert-info ("Kanji / full-width alphabet") (evil-test-buffer "漢字AB[C]" ("b") "漢字[A]BC")) (ert-info ("Kanji / full-width numeric") (evil-test-buffer "漢字12[3]" ("b") "漢字[1]23")) (ert-info ("Kanji / Hangul") (evil-test-buffer "漢字한[글]" ("b") "漢字[한]글")) (ert-info ("Hiragana / Latin") (evil-test-buffer "ひらがなabc[d]" ("b") "ひらがな[a]bcd")) (ert-info ("Hiragana / numeric") (evil-test-buffer "ひらがな123[4]" ("b") "ひらがな[1]234")) (ert-info ("Hiragana / Kanji") (evil-test-buffer "ひらがな漢[字]" ("b") "ひらがな[漢]字")) (ert-info ("Hiragana / Katakana") (evil-test-buffer "ひらがなカタカ[ナ]" ("b") "ひらがな[カ]タカナ")) (ert-info ("Hiragana / half-width Katakana") (evil-test-buffer "ひらがなカタカ[ナ]" ("b") "ひらがな[カ]タカナ")) (ert-info ("Hiragana / full-width alphabet") (evil-test-buffer "ひらがなAB[C]" ("b") "ひらがな[A]BC")) (ert-info ("Hiragana / full-width numeric") (evil-test-buffer "ひらがな12[3]" ("b") "ひらがな[1]23")) (ert-info ("Hiragana / Hangul") (evil-test-buffer "ひらがな한[글]" ("b") "ひらがな[한]글")) (ert-info ("Katakana / Latin") (evil-test-buffer "カタカナabc[d]" ("b") "カタカナ[a]bcd")) (ert-info ("Katakana / numeric") (evil-test-buffer "カタカナ123[4]" ("b") "カタカナ[1]234")) (ert-info ("Katakana / Kanji") (evil-test-buffer "カタカナ漢[字]" ("b") "カタカナ[漢]字")) (ert-info ("Katakana / Hiragana") (evil-test-buffer "カタカナひらが[な]" ("b") "カタカナ[ひ]らがな")) (ert-info ("Katakana / half-width Katakana") (evil-test-buffer "カタカナカタカ[ナ]" ("b") "カタカナ[カ]タカナ")) (ert-info ("Katakana / full-width alphabet") (evil-test-buffer "カタカナAB[C]" ("b") "カタカナ[A]BC")) (ert-info ("Katakana / full-width numeric") (evil-test-buffer "カタカナ12[3]" ("b") "カタカナ[1]23")) (ert-info ("Katakana / Hangul") (evil-test-buffer "カタカナ한[글]" ("b") "カタカナ[한]글")) (ert-info ("half-width Katakana / Latin") (evil-test-buffer "カタカナabc[d]" ("b") "[カ]タカナabcd")) (ert-info ("half-width Katakana / numeric") (evil-test-buffer "カタカナ123[4]" ("b") "[カ]タカナ1234")) (ert-info ("half-width Katakana / Kanji") (evil-test-buffer "カタカナ漢[字]" ("b") "カタカナ[漢]字")) (ert-info ("half-width Katakana / Hiragana") (evil-test-buffer "カタカナひらが[な]" ("b") "カタカナ[ひ]らがな")) (ert-info ("half-width Katakana / Katakana") (evil-test-buffer "カタカナカタカ[ナ]" ("b") "カタカナ[カ]タカナ")) (ert-info ("half-width Katakana / full-width alphabet") (evil-test-buffer "カタカナAB[C]" ("b") "[カ]タカナABC")) (ert-info ("half-width Katakana / full-width numeric") (evil-test-buffer "カタカナ12[3]" ("b") "[カ]タカナ123")) (ert-info ("half-width Katakana / Hangul") (evil-test-buffer "カタカナ한[글]" ("b") "カタカナ[한]글")) (ert-info ("full-width alphabet / Latin") (evil-test-buffer "ABCabc[d]" ("b") "[A]BCabcd")) (ert-info ("full-width alphabet / numeric") (evil-test-buffer "ABC123[4]" ("b") "[A]BC1234")) (ert-info ("full-width alphabet / Kanji") (evil-test-buffer "ABC漢[字]" ("b") "ABC[漢]字")) (ert-info ("full-width alphabet / Hiragana") (evil-test-buffer "ABCひらが[な]" ("b") "ABC[ひ]らがな")) (ert-info ("full-width alphabet / Katakana") (evil-test-buffer "ABCカタカ[ナ]" ("b") "ABC[カ]タカナ")) (ert-info ("full-width alphabet / half-width Katakana") (evil-test-buffer "ABCカタカ[ナ]" ("b") "[A]BCカタカナ")) (ert-info ("full-width alphabet / full-width numeric") (evil-test-buffer "ABC12[3]" ("b") "[A]BC123")) (ert-info ("full-width alphabet / Hangul") (evil-test-buffer "ABC한[글]" ("b") "ABC[한]글")) (ert-info ("full-width numeric / Latin") (evil-test-buffer "123abc[d]" ("b") "[1]23abcd")) (ert-info ("full-width numeric / numeric") (evil-test-buffer "123123[4]" ("b") "[1]231234")) (ert-info ("full-width numeric / Kanji") (evil-test-buffer "123漢[字]" ("b") "123[漢]字")) (ert-info ("full-width numeric / Hiragana") (evil-test-buffer "123ひらが[な]" ("b") "123[ひ]らがな")) (ert-info ("full-width numeric / Katakana") (evil-test-buffer "123カタカ[ナ]" ("b") "123[カ]タカナ")) (ert-info ("full-width numeric / half-width Katakana") (evil-test-buffer "123カタカ[ナ]" ("b") "[1]23カタカナ")) (ert-info ("full-width numeric / full-width alphabet") (evil-test-buffer "123AB[C]" ("b") "[1]23ABC")) (ert-info ("full-width numeric / Hangul") (evil-test-buffer "123한[글]" ("b") "123[한]글")) (ert-info ("Hangul / Latin") (evil-test-buffer "한글abc[d]" ("b") "한글[a]bcd")) (ert-info ("Hangul / numeric") (evil-test-buffer "한글123[4]" ("b") "한글[1]234")) (ert-info ("Hangul / Kanji") (evil-test-buffer "한글漢[字]" ("b") "한글[漢]字")) (ert-info ("Hangul / Hiragana") (evil-test-buffer "한글ひらが[な]" ("b") "한글[ひ]らがな")) (ert-info ("Hangul / Katakana") (evil-test-buffer "한글カタカ[ナ]" ("b") "한글[カ]タカナ")) (ert-info ("Hangul / half-width Katakana") (evil-test-buffer "한글カタカ[ナ]" ("b") "한글[カ]タカナ")) (ert-info ("Hangul / full-width alphabet") (evil-test-buffer "한글AB[C]" ("b") "한글[A]BC")) (ert-info ("Hangul / full-width numeric") (evil-test-buffer "한글12[3]" ("b") "한글[1]23"))) (ert-deftest evil-test-backword-word-end-cjk () "Test `evil-backward-word-end' on CJK words" :tags '(evil motion cjk) (ert-info ("Latin / numeric") (evil-test-buffer "abcd123[4]" ("ge") "[a]bcd1234")) (ert-info ("Latin / Kanji") (evil-test-buffer "abcd漢[字]" ("ge") "abc[d]漢字")) (ert-info ("Latin / Hiragana") (evil-test-buffer "abcdひらが[な]" ("ge") "abc[d]ひらがな")) (ert-info ("Latin / Katakana") (evil-test-buffer "abcdカタカ[ナ]" ("ge") "abc[d]カタカナ")) (ert-info ("Latin / half-width Katakana") (evil-test-buffer "abcdカタカ[ナ]" ("ge") "[a]bcdカタカナ")) (ert-info ("Latin / full-width alphabet") (evil-test-buffer "abcdAB[C]" ("ge") "[a]bcdABC")) (ert-info ("Latin / full-width numeric") (evil-test-buffer "abcd12[3]" ("ge") "[a]bcd123")) (ert-info ("Latin / Hangul") (evil-test-buffer "abcd한[글]" ("ge") "abc[d]한글")) (ert-info ("numeric / Latin") (evil-test-buffer "1234abc[d]" ("ge") "[1]234abcd")) (ert-info ("numeric / Kanji") (evil-test-buffer "1234漢[字]" ("ge") "123[4]漢字")) (ert-info ("numeric / Hiragana") (evil-test-buffer "1234ひらが[な]" ("ge") "123[4]ひらがな")) (ert-info ("numeric / Katakana") (evil-test-buffer "1234カタカ[ナ]" ("ge") "123[4]カタカナ")) (ert-info ("numeric / half-width Katakana") (evil-test-buffer "1234カタカ[ナ]" ("ge") "[1]234カタカナ")) (ert-info ("numeric / full-width alphabet") (evil-test-buffer "1234AB[C]" ("ge") "[1]234ABC")) (ert-info ("numeric / full-width numeric") (evil-test-buffer "123412[3]" ("ge") "[1]234123")) (ert-info ("numeric / Hangul") (evil-test-buffer "1234한[글]" ("ge") "123[4]한글")) (ert-info ("Kanji / Latin") (evil-test-buffer "漢字abc[d]" ("ge") "漢[字]abcd")) (ert-info ("Kanji / numeric") (evil-test-buffer "漢字123[4]" ("ge") "漢[字]1234")) (ert-info ("Kanji / Hiragana") (evil-test-buffer "漢字ひらが[な]" ("ge") "漢[字]ひらがな")) (ert-info ("Kanji / Katakana") (evil-test-buffer "漢字カタカ[ナ]" ("ge") "漢[字]カタカナ")) (ert-info ("Kanji / half-width Katakana") (evil-test-buffer "漢字カタカ[ナ]" ("ge") "漢[字]カタカナ")) (ert-info ("Kanji / full-width alphabet") (evil-test-buffer "漢字AB[C]" ("ge") "漢[字]ABC")) (ert-info ("Kanji / full-width numeric") (evil-test-buffer "漢字12[3]" ("ge") "漢[字]123")) (ert-info ("Kanji / Hangul") (evil-test-buffer "漢字한[글]" ("ge") "漢[字]한글")) (ert-info ("Hiragana / Latin") (evil-test-buffer "ひらがなabc[d]" ("ge") "ひらが[な]abcd")) (ert-info ("Hiragana / numeric") (evil-test-buffer "ひらがな123[4]" ("ge") "ひらが[な]1234")) (ert-info ("Hiragana / Kanji") (evil-test-buffer "ひらがな漢[字]" ("ge") "ひらが[な]漢字")) (ert-info ("Hiragana / Katakana") (evil-test-buffer "ひらがなカタカ[ナ]" ("ge") "ひらが[な]カタカナ")) (ert-info ("Hiragana / half-width Katakana") (evil-test-buffer "ひらがなカタカ[ナ]" ("ge") "ひらが[な]カタカナ")) (ert-info ("Hiragana / full-width alphabet") (evil-test-buffer "ひらがなAB[C]" ("ge") "ひらが[な]ABC")) (ert-info ("Hiragana / full-width numeric") (evil-test-buffer "ひらがな12[3]" ("ge") "ひらが[な]123")) (ert-info ("Hiragana / Hangul") (evil-test-buffer "ひらがな한[글]" ("ge") "ひらが[な]한글")) (ert-info ("Katakana / Latin") (evil-test-buffer "カタカナabc[d]" ("ge") "カタカ[ナ]abcd")) (ert-info ("Katakana / numeric") (evil-test-buffer "カタカナ123[4]" ("ge") "カタカ[ナ]1234")) (ert-info ("Katakana / Kanji") (evil-test-buffer "カタカナ漢[字]" ("ge") "カタカ[ナ]漢字")) (ert-info ("Katakana / Hiragana") (evil-test-buffer "カタカナひらが[な]" ("ge") "カタカ[ナ]ひらがな")) (ert-info ("Katakana / half-width Katakana") (evil-test-buffer "カタカナカタカ[ナ]" ("ge") "カタカ[ナ]カタカナ")) (ert-info ("Katakana / full-width alphabet") (evil-test-buffer "カタカナAB[C]" ("ge") "カタカ[ナ]ABC")) (ert-info ("Katakana / full-width numeric") (evil-test-buffer "カタカナ12[3]" ("ge") "カタカ[ナ]123")) (ert-info ("Katakana / Hangul") (evil-test-buffer "カタカナ한[글]" ("ge") "カタカ[ナ]한글")) (ert-info ("half-width Katakana / Latin") (evil-test-buffer "カタカナabc[d]" ("ge") "[カ]タカナabcd")) (ert-info ("half-width Katakana / numeric") (evil-test-buffer "カタカナ123[4]" ("ge") "[カ]タカナ1234")) (ert-info ("half-width Katakana / Kanji") (evil-test-buffer "カタカナ漢[字]" ("ge") "カタカ[ナ]漢字")) (ert-info ("half-width Katakana / Hiragana") (evil-test-buffer "カタカナひらが[な]" ("ge") "カタカ[ナ]ひらがな")) (ert-info ("half-width Katakana / Katakana") (evil-test-buffer "カタカナカタカ[ナ]" ("ge") "カタカ[ナ]カタカナ")) (ert-info ("half-width Katakana / full-width alphabet") (evil-test-buffer "カタカナAB[C]" ("ge") "[カ]タカナABC")) (ert-info ("half-width Katakana / full-width numeric") (evil-test-buffer "カタカナ12[3]" ("ge") "[カ]タカナ123")) (ert-info ("half-width Katakana / Hangul") (evil-test-buffer "カタカナ한[글]" ("ge") "カタカ[ナ]한글")) (ert-info ("full-width alphabet / Latin") (evil-test-buffer "ABCabc[d]" ("ge") "[A]BCabcd")) (ert-info ("full-width alphabet / numeric") (evil-test-buffer "ABC123[4]" ("ge") "[A]BC1234")) (ert-info ("full-width alphabet / Kanji") (evil-test-buffer "ABC漢[字]" ("ge") "AB[C]漢字")) (ert-info ("full-width alphabet / Hiragana") (evil-test-buffer "ABCひらが[な]" ("ge") "AB[C]ひらがな")) (ert-info ("full-width alphabet / Katakana") (evil-test-buffer "ABCカタカ[ナ]" ("ge") "AB[C]カタカナ")) (ert-info ("full-width alphabet / half-width Katakana") (evil-test-buffer "ABCカタカ[ナ]" ("ge") "[A]BCカタカナ")) (ert-info ("full-width alphabet / full-width numeric") (evil-test-buffer "ABC12[3]" ("ge") "[A]BC123")) (ert-info ("full-width alphabet / Hangul") (evil-test-buffer "ABC한[글]" ("ge") "AB[C]한글")) (ert-info ("full-width numeric / Latin") (evil-test-buffer "123abc[d]" ("ge") "[1]23abcd")) (ert-info ("full-width numeric / numeric") (evil-test-buffer "123123[4]" ("ge") "[1]231234")) (ert-info ("full-width numeric / Kanji") (evil-test-buffer "123漢[字]" ("ge") "12[3]漢字")) (ert-info ("full-width numeric / Hiragana") (evil-test-buffer "123ひらが[な]" ("ge") "12[3]ひらがな")) (ert-info ("full-width numeric / Katakana") (evil-test-buffer "123カタカ[ナ]" ("ge") "12[3]カタカナ")) (ert-info ("full-width numeric / half-width Katakana") (evil-test-buffer "123カタカ[ナ]" ("ge") "[1]23カタカナ")) (ert-info ("full-width numeric / full-width alphabet") (evil-test-buffer "123AB[C]" ("ge") "[1]23ABC")) (ert-info ("full-width numeric / Hangul") (evil-test-buffer "123한[글]" ("ge") "12[3]한글")) (ert-info ("Hangul / Latin") (evil-test-buffer "한글abc[d]" ("ge") "한[글]abcd")) (ert-info ("Hangul / numeric") (evil-test-buffer "한글123[4]" ("ge") "한[글]1234")) (ert-info ("Hangul / Kanji") (evil-test-buffer "한글漢[字]" ("ge") "한[글]漢字")) (ert-info ("Hangul / Hiragana") (evil-test-buffer "한글ひらが[な]" ("ge") "한[글]ひらがな")) (ert-info ("Hangul / Katakana") (evil-test-buffer "한글カタカ[ナ]" ("ge") "한[글]カタカナ")) (ert-info ("Hangul / half-width Katakana") (evil-test-buffer "한글カタカ[ナ]" ("ge") "한[글]カタカナ")) (ert-info ("Hangul / full-width alphabet") (evil-test-buffer "한글AB[C]" ("ge") "한[글]ABC")) (ert-info ("Hangul / full-width numeric") (evil-test-buffer "한글12[3]" ("ge") "한[글]123"))) (ert-deftest evil-test-forward-paragraph () "Test `evil-forward-paragraph'" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer "[A]bove some line Below some empty line" ("}") "Above some line \[] Below some empty line")) (ert-info ("With count") (evil-test-buffer "[A]bove some line Below some empty line" ("2}") "Above some line Below some empty lin[e]")) (ert-info ("End of buffer") (evil-test-buffer "[B]elow some empty line" ("100}") "Below some empty lin[e]" (should-error (execute-kbd-macro "}")) (should-error (execute-kbd-macro "42}")))) (ert-info ("End of buffer with newline") (evil-test-buffer "[B]elow some empty line\n\n" ("100}") "Below some empty line\n\n[]" (should-error (execute-kbd-macro "}")) (should-error (execute-kbd-macro "42}"))))) (ert-deftest evil-test-backward-paragraph () "Test `evil-backward-paragraph'" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer "Above some line Below some empty lin[e]" ("{") "Above some line \[] Below some empty line")) (ert-info ("With count") (evil-test-buffer "Above some line Below some empty lin[e]" ("2{") "[A]bove some line Below some empty line")) (ert-info ("Beginning of buffer") (evil-test-buffer "Above some line Below some empty lin[e]" ("100{") "[A]bove some line Below some empty line" (should-error (execute-kbd-macro "{")) (should-error (execute-kbd-macro "42{")))) (ert-info ("Beginning of buffer with newlines") (evil-test-buffer "\n\nAbove some line Below some empty lin[e]" ("100{") "[]\n\nAbove some line Below some empty line" (should-error (execute-kbd-macro "{")) (should-error (execute-kbd-macro "42{"))))) (ert-deftest evil-test-forward-sentence () "Test `evil-forward-sentence'" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer "[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. If you want to create a file, ;; visit that file with C-x C-f. Below some empty line." (")") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. [I]f you want to create a file, ;; visit that file with C-x C-f. Below some empty line." (")") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. If you want to create a file, ;; visit that file with C-x C-f. \[] Below some empty line." (")") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. If you want to create a file, ;; visit that file with C-x C-f. \[B]elow some empty line.")) (ert-info ("With count") (evil-test-buffer "[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. If you want to create a file, ;; visit that file with C-x C-f. Below some empty line." ("2)") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. If you want to create a file, ;; visit that file with C-x C-f. \[] Below some empty line." ("2)") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. If you want to create a file, ;; visit that file with C-x C-f. Below some empty line[.]")) (ert-info ("End of buffer") (evil-test-buffer "[B]elow some empty line." ("100)") "Below some empty line[.]" (should-error (execute-kbd-macro ")")) (should-error (execute-kbd-macro "42)")))) (ert-info ("End of buffer with newline") (evil-test-buffer "[B]elow some empty line.\n\n" (")") "Below some empty line.\n[\n]" (")") "Below some empty line.\n\n[]" (should-error (execute-kbd-macro ")")) (should-error (execute-kbd-macro "42)"))))) (ert-deftest evil-test-backward-sentence () "Test `evil-backward-sentence'" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. If you want to create a file, ;; visit that file with C-x C-f. Below some empty line[.]" ("(") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. If you want to create a file, ;; visit that file with C-x C-f. \[B]elow some empty line." ("(") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. If you want to create a file, ;; visit that file with C-x C-f. \[] Below some empty line." ("(") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. [I]f you want to create a file, ;; visit that file with C-x C-f. Below some empty line." ("(") "[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. If you want to create a file, ;; visit that file with C-x C-f. Below some empty line.")) (ert-info ("With count") (evil-test-buffer ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. If you want to create a file, ;; visit that file with C-x C-f. Below some empty line[.]" ("2(") ";; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. If you want to create a file, ;; visit that file with C-x C-f. \[] Below some empty line." ("2(") "[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. If you want to create a file, ;; visit that file with C-x C-f. Below some empty line.")) (ert-info ("Beginning of buffer") (evil-test-buffer ";; This buffer is for notes you don't want to save[.]" ("100(") "[;]; This buffer is for notes you don't want to save." (should-error (execute-kbd-macro "(")) (should-error (execute-kbd-macro "42(")))) (ert-info ("Beginning of buffer with newlines") (evil-test-buffer "\n\n;; This buffer is for notes you don't want to save[.]" ("100(") "[]\n\n;; This buffer is for notes you don't want to save." (should-error (execute-kbd-macro "(")) (should-error (execute-kbd-macro "42("))))) (ert-deftest evil-test-find-char () "Test `evil-find-char'" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer "[;]; This buffer is for notes." ("fT") ";; [T]his buffer is for notes.")) (ert-info ("With count") (evil-test-buffer "[;]; This buffer is for notes." ("2fe") ";; This buffer is for not[e]s.")) (ert-info ("Repeat") (evil-test-buffer "[;]; This buffer is for notes." ("fe;") ";; This buffer is for not[e]s.")) (ert-info ("Repeat backward") (evil-test-buffer "[;]; This buffer is for notes." ("2fe,") ";; This buff[e]r is for notes.")) (ert-info ("No match") (evil-test-buffer "[;]; This buffer is for notes." (should-error (execute-kbd-macro "fL")))) (ert-info ("End of line") (let ((evil-cross-lines t)) (evil-test-buffer "[;]; This buffer is for notes, ;; and for Lisp evaluation." ("fL") ";; This buffer is for notes, ;; and for [L]isp evaluation.")))) (ert-deftest evil-test-find-char-backward () "Test `evil-find-char-backward'" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer ";; This buffer is for notes[.]" ("FT") ";; [T]his buffer is for notes.")) (ert-info ("With count") (evil-test-buffer ";; This buffer is for notes[.]" ("2Fe") ";; This buff[e]r is for notes.")) (ert-info ("Repeat") (evil-test-buffer ";; This buffer is for notes[.]" ("Fe;") ";; This buff[e]r is for notes.")) (ert-info ("Repeat backward") (evil-test-buffer ";; This buffer is for notes[.]" ("2Fe,") ";; This buffer is for not[e]s.")) (ert-info ("No match") (evil-test-buffer ";; This buffer is for notes[.]" (should-error (execute-kbd-macro "FL")))) (ert-info ("End of line") (let ((evil-cross-lines t)) (evil-test-buffer ";; This buffer is for notes, ;; and for Lisp evaluation[.]" ("FT") ";; [T]his buffer is for notes, ;; and for Lisp evaluation.")))) (ert-deftest evil-test-find-char-to () "Test `evil-find-char-to'" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer "[;]; This buffer is for notes." ("tT") ";;[ ]This buffer is for notes.")) (ert-info ("With count") (evil-test-buffer "[;]; This buffer is for notes." ("2te") ";; This buffer is for no[t]es.")) (ert-info ("Repeat") (evil-test-buffer "[;]; This buffer is for notes." ("tel;") ";; This buffer is for no[t]es.")) (ert-info ("Repeat backward") (evil-test-buffer "[;]; This buffer is for notes." ("2te,") ";; This buffe[r] is for notes.")) (ert-info ("Repeat should skip adjacent character") (let ((evil-repeat-find-to-skip-next t)) (evil-test-buffer "[a]aaxaaaxaaaxaaa" ("tx;") "aaaxaa[a]xaaaxaaa" (";") "aaaxaaaxaa[a]xaaa" (",") "aaaxaaax[a]aaxaaa" (",") "aaax[a]aaxaaaxaaa"))) (ert-info ("Repeat should NOT skip adjacent character") (let ((evil-repeat-find-to-skip-next nil)) (evil-test-buffer "[a]aaxaaaxaaaxaaa" ("tx;") "aa[a]xaaaxaaaxaaa"))) (ert-info ("No match") (evil-test-buffer "[;]; This buffer is for notes." (should-error (execute-kbd-macro "tL")))) (ert-info ("End of line") (let ((evil-cross-lines t)) (evil-test-buffer "[;]; This buffer is for notes, ;; and for Lisp evaluation." ("tL") ";; This buffer is for notes, ;; and for[ ]Lisp evaluation.")))) (ert-deftest evil-test-find-char-to-backward () "Test `evil-find-char-to-backward'" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer ";; This buffer is for notes[.]" ("TT") ";; T[h]is buffer is for notes.")) (ert-info ("With count") (evil-test-buffer ";; This buffer is for notes[.]" ("2Te") ";; This buffe[r] is for notes.")) (ert-info ("Repeat") (evil-test-buffer ";; This buffer is for notes[.]" ("Teh;") ";; This buffe[r] is for notes.")) (ert-info ("Repeat backward") (evil-test-buffer ";; This buffer is for notes[.]" ("2Te,") ";; This buffer is for no[t]es.")) (ert-info ("Repeat should skip adjacent character") (let ((evil-repeat-find-to-skip-next t)) (evil-test-buffer "aaaxaaaxaaaxaa[a]" ("Tx;") "aaaxaaax[a]aaxaaa" (";") "aaax[a]aaxaaaxaaa" (",") "aaaxaa[a]xaaaxaaa" (",") "aaaxaaaxaa[a]xaaa"))) (ert-info ("Repeat should NOT skip adjacent character") (let ((evil-repeat-find-to-skip-next nil)) (evil-test-buffer "aaaxaaaxaaaxaa[a]" ("Tx;") "aaaxaaaxaaax[a]aa"))) (ert-info ("No match") (evil-test-buffer ";; This buffer is for notes[.]" (should-error (execute-kbd-macro "TL")))) (ert-info ("End of line") (let ((evil-cross-lines t)) (evil-test-buffer ";; This buffer is for notes, ;; and for Lisp evaluation[.]" ("TT") ";; T[h]is buffer is for notes, ;; and for Lisp evaluation.")))) (ert-deftest evil-test-jump-item () "Test `evil-jump-item'" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer "int main[(]int argc, char** argv)" ("%") "int main(int argc, char** argv[)]" ("%") "int main[(]int argc, char** argv)")) (ert-info ("Before parenthesis") (evil-test-buffer "[i]nt main(int argc, char** argv)" ("%") "int main(int argc, char** argv[)]" ("5h") "int main(int argc, char**[ ]argv)" ("%") "int main[(]int argc, char** argv)")) (ert-info ("Over several lines") (evil-test-buffer "int main(int argc, char** argv) \[{] printf(\"Hello world\\n\"); return EXIT_SUCCESS; }" ("%") "int main(int argc, char** argv) { printf(\"Hello world\\n\"); return EXIT_SUCCESS; \[}]")) (ert-info ("On line without parenthesis") (evil-test-buffer "[#]include " (should-error (execute-kbd-macro "%")))) (ert-info ("Before unmatched opening parenthesies") (evil-test-buffer "x[x]xx ( yyyyy () zzzz" (should-error (execute-kbd-macro "%")) "x[x]xx ( yyyyy () zzzz")) (ert-info ("Before unmatched closing parenthesies") (evil-test-buffer "x[x]xx ) yyyyy () zzzz" (should-error (execute-kbd-macro "%")) "x[x]xx ) yyyyy () zzzz")) (ert-info ("At the end of the line") (evil-test-buffer "[p]ublic void foo(String bar) {\n blabla;\n}\n" ("v$%") "public void foo(String bar) {\n blabla;\n[}]\n"))) (ert-deftest evil-test-unmatched-paren () "Test `evil-previous-open-paren' and `evil-next-close-paren'" :tags '(evil motion) (ert-info ("Simple") (evil-test-buffer "foo ( { ( [b]ar ) baz } )" ("[(") "foo ( { [(] bar ) baz } )" ("])") "foo ( { ( bar [)] baz } )" ("[(") "foo ( { [(] bar ) baz } )" ("[(") "foo [(] { ( bar ) baz } )" ("f)])") "foo ( { ( bar ) baz } [)]")) (ert-info ("With count") (evil-test-buffer "foo ( { ( [b]ar ) baz } )" ("2[(") "foo [(] { ( bar ) baz } )") (evil-test-buffer "foo ( { ( [b]ar ) baz } )" ("2])") "foo ( { ( bar ) baz } [)]"))) (ert-deftest evil-test-flyspell-motions () "Test flyspell motions" :tags '(evil motion) (skip-unless (executable-find "aspell")) (ert-info ("Simple") (evil-test-buffer "[I] cannt tpye for lyfe" (flyspell-mode) (flyspell-buffer) ("]s") "I [c]annt tpye for lyfe" ("]s") "I cannt [t]pye for lyfe" ("]s") "I cannt tpye for [l]yfe" ("]s") "I [c]annt tpye for lyfe" ("[s") "I cannt tpye for [l]yfe" ("[s") "I cannt [t]pye for lyfe")) (ert-info ("With count") (evil-test-buffer "[I] cannt tpye for lyfe" (flyspell-mode) (flyspell-buffer) ("2]s") "I cannt [t]pye for lyfe" ("2]s") "I [c]annt tpye for lyfe" ("2[s") "I cannt [t]pye for lyfe" ("2[s") "I cannt tpye for [l]yfe")) (ert-info ("With evil-search-wrap disabled") (let (evil-search-wrap) (evil-test-buffer "[I] cannt tpye for lyfe" (flyspell-mode) (flyspell-buffer) ("]s") "I [c]annt tpye for lyfe" ("]s") "I cannt [t]pye for lyfe" ("]s") "I cannt tpye for [l]yfe" ("]s") "I cannt tpye for [l]yfe"))) (ert-info ("One mistake") (evil-test-buffer "[I]'m almst there..." (flyspell-mode) (flyspell-buffer) ("]s") "I'm [a]lmst there..." ("]s") "I'm [a]lmst there...")) (ert-info ("No mistakes") (evil-test-buffer "[I]'ve learned to type!" (flyspell-mode) (flyspell-buffer) ("]s") "[I]'ve learned to type!" ("[s") "[I]'ve learned to type!"))) ;;; Text objects (ert-deftest evil-test-text-object () "Test `evil-define-text-object'" :tags '(evil text-object) (let ((object (evil-define-text-object nil (count &optional beg end type) (let ((sel (and beg end (evil-range beg end)))) (when (and sel (> count 0)) (forward-char 1)) (let ((range (if (< count 0) (list (- (point) 3) (point)) (list (point) (+ (point) 3))))) (if sel (evil-range-union range sel) range)))))) (ert-info ("Select three characters after point") (evil-test-buffer :state operator ";; [T]his buffer is for notes." (should (equal (funcall object 1) '(4 7 inclusive))))) (ert-info ("Select three characters before point") (evil-test-buffer :state operator ";; [T]his buffer is for notes." (should (equal (funcall object -1) '(1 4 inclusive))))) (ert-info ("Select three characters after selection") (evil-test-buffer ";; buffer is for notes." (call-interactively object) ";; ffer is for notes.")) (ert-info ("Select three characters before selection") (evil-test-buffer ";; <[T]his> buffer is for notes." (call-interactively object) "<[;]; This> buffer is for notes.")) (ert-info ("Delete three characters after point") (evil-test-buffer "[;]; This buffer is for notes." (define-key evil-operator-state-local-map "io" object) ("dio") "[T]his buffer is for notes.")))) (ert-deftest evil-test-word-objects () "Test `evil-inner-word' and `evil-a-word'" :tags '(evil text-object) (ert-info ("Select a word") (evil-test-buffer ";; [T]his buffer is for notes." ("viw") ";; buffer is for notes.") (evil-test-buffer ";; [T]his buffer is for notes." ("vaw") ";; buffer is for notes.") (evil-test-buffer ";; Thi[s] buffer is for notes." ("viw") ";; buffer is for notes.") (evil-test-buffer ";; Thi[s] buffer is for notes." ("vaw") ";; buffer is for notes.")) (ert-info ("Select two words") (ert-info ("Include whitespace on this side") (evil-test-buffer ";;< Thi[s]> buffer is for notes." ("aw") ";;< This buffe[r]> is for notes.") (evil-test-buffer ";; This <[b]uffer >is for notes." ("aw") ";; <[T]his buffer >is for notes.")) (ert-info ("Include whitespace on the other side") (evil-test-buffer ";; buffer is for notes." ("aw") ";; is for notes.") (evil-test-buffer ";; This<[ ]buffer> is for notes." ("aw") ";;<[ ]This buffer> is for notes."))) (ert-info ("select first visual word") (evil-test-buffer "([a])" ("viw") "(<[a]>)"))) (ert-deftest evil-test-word-objects-cjk () "Test `evil-inner-word' and `evil-a-word' on CJK words" :tags '(evil text-object cjk) (ert-info ("Select a word") (evil-test-buffer "[a]bcd1234" ("viw") "") (evil-test-buffer "[a]bcd1234" ("vaw") "") (evil-test-buffer "[a]bcd漢字" ("viw") "漢字") (evil-test-buffer "[a]bcd漢字" ("vaw") "漢字") (evil-test-buffer "[a]bcdひらがな" ("viw") "ひらがな") (evil-test-buffer "[a]bcdひらがな" ("vaw") "ひらがな") (evil-test-buffer "[a]bcdカタカナ" ("viw") "カタカナ") (evil-test-buffer "[a]bcdカタカナ" ("vaw") "カタカナ") (evil-test-buffer "[a]bcdカタカナ" ("viw") "") (evil-test-buffer "[a]bcdカタカナ" ("vaw") "") (evil-test-buffer "[a]bcdABC" ("viw") "") (evil-test-buffer "[a]bcdABC" ("vaw") "") (evil-test-buffer "[a]bcd123" ("viw") "") (evil-test-buffer "[a]bcd123" ("vaw") "") (evil-test-buffer "[a]bcd한글" ("viw") "한글") (evil-test-buffer "[a]bcd한글" ("vaw") "한글") (evil-test-buffer "[1]234abcd" ("viw") "<1234abc[d]>") (evil-test-buffer "[1]234abcd" ("vaw") "<1234abc[d]>") (evil-test-buffer "[1]234漢字" ("viw") "<123[4]>漢字") (evil-test-buffer "[1]234漢字" ("vaw") "<123[4]>漢字") (evil-test-buffer "[1]234ひらがな" ("viw") "<123[4]>ひらがな") (evil-test-buffer "[1]234ひらがな" ("vaw") "<123[4]>ひらがな") (evil-test-buffer "[1]234カタカナ" ("viw") "<123[4]>カタカナ") (evil-test-buffer "[1]234カタカナ" ("vaw") "<123[4]>カタカナ") (evil-test-buffer "[1]234カタカナ" ("viw") "<1234カタカ[ナ]>") (evil-test-buffer "[1]234カタカナ" ("vaw") "<1234カタカ[ナ]>") (evil-test-buffer "[1]234ABC" ("viw") "<1234AB[C]>") (evil-test-buffer "[1]234ABC" ("vaw") "<1234AB[C]>") (evil-test-buffer "[1]234123" ("viw") "<123412[3]>") (evil-test-buffer "[1]234123" ("vaw") "<123412[3]>") (evil-test-buffer "[1]234한글" ("viw") "<123[4]>한글") (evil-test-buffer "[1]234한글" ("vaw") "<123[4]>한글") (evil-test-buffer "[漢]字abcd" ("viw") "<漢[字]>abcd") (evil-test-buffer "[漢]字abcd" ("vaw") "<漢[字]>abcd") (evil-test-buffer "[漢]字1234" ("viw") "<漢[字]>1234") (evil-test-buffer "[漢]字1234" ("vaw") "<漢[字]>1234") (evil-test-buffer "[漢]字ひらがな" ("viw") "<漢[字]>ひらがな") (evil-test-buffer "[漢]字ひらがな" ("vaw") "<漢[字]>ひらがな") (evil-test-buffer "[漢]字カタカナ" ("viw") "<漢[字]>カタカナ") (evil-test-buffer "[漢]字カタカナ" ("vaw") "<漢[字]>カタカナ") (evil-test-buffer "[漢]字カタカナ" ("viw") "<漢[字]>カタカナ") (evil-test-buffer "[漢]字カタカナ" ("vaw") "<漢[字]>カタカナ") (evil-test-buffer "[漢]字ABC" ("viw") "<漢[字]>ABC") (evil-test-buffer "[漢]字ABC" ("vaw") "<漢[字]>ABC") (evil-test-buffer "[漢]字123" ("viw") "<漢[字]>123") (evil-test-buffer "[漢]字123" ("vaw") "<漢[字]>123") (evil-test-buffer "[漢]字한글" ("viw") "<漢[字]>한글") (evil-test-buffer "[漢]字한글" ("vaw") "<漢[字]>한글") (evil-test-buffer "[ひ]らがなabcd" ("viw") "<ひらが[な]>abcd") (evil-test-buffer "[ひ]らがなabcd" ("vaw") "<ひらが[な]>abcd") (evil-test-buffer "[ひ]らがな1234" ("viw") "<ひらが[な]>1234") (evil-test-buffer "[ひ]らがな1234" ("vaw") "<ひらが[な]>1234") (evil-test-buffer "[ひ]らがな漢字" ("viw") "<ひらが[な]>漢字") (evil-test-buffer "[ひ]らがな漢字" ("vaw") "<ひらが[な]>漢字") (evil-test-buffer "[ひ]らがなカタカナ" ("viw") "<ひらが[な]>カタカナ") (evil-test-buffer "[ひ]らがなカタカナ" ("vaw") "<ひらが[な]>カタカナ") (evil-test-buffer "[ひ]らがなカタカナ" ("viw") "<ひらが[な]>カタカナ") (evil-test-buffer "[ひ]らがなカタカナ" ("vaw") "<ひらが[な]>カタカナ") (evil-test-buffer "[ひ]らがなABC" ("viw") "<ひらが[な]>ABC") (evil-test-buffer "[ひ]らがなABC" ("vaw") "<ひらが[な]>ABC") (evil-test-buffer "[ひ]らがな123" ("viw") "<ひらが[な]>123") (evil-test-buffer "[ひ]らがな123" ("vaw") "<ひらが[な]>123") (evil-test-buffer "[ひ]らがな한글" ("viw") "<ひらが[な]>한글") (evil-test-buffer "[ひ]らがな한글" ("vaw") "<ひらが[な]>한글") (evil-test-buffer "[カ]タカナabcd" ("viw") "<カタカ[ナ]>abcd") (evil-test-buffer "[カ]タカナabcd" ("vaw") "<カタカ[ナ]>abcd") (evil-test-buffer "[カ]タカナ1234" ("viw") "<カタカ[ナ]>1234") (evil-test-buffer "[カ]タカナ1234" ("vaw") "<カタカ[ナ]>1234") (evil-test-buffer "[カ]タカナ漢字" ("viw") "<カタカ[ナ]>漢字") (evil-test-buffer "[カ]タカナ漢字" ("vaw") "<カタカ[ナ]>漢字") (evil-test-buffer "[カ]タカナひらがな" ("viw") "<カタカ[ナ]>ひらがな") (evil-test-buffer "[カ]タカナひらがな" ("vaw") "<カタカ[ナ]>ひらがな") (evil-test-buffer "[カ]タカナカタカナ" ("viw") "<カタカ[ナ]>カタカナ") (evil-test-buffer "[カ]タカナカタカナ" ("vaw") "<カタカ[ナ]>カタカナ") (evil-test-buffer "[カ]タカナABC" ("viw") "<カタカ[ナ]>ABC") (evil-test-buffer "[カ]タカナABC" ("vaw") "<カタカ[ナ]>ABC") (evil-test-buffer "[カ]タカナ123" ("viw") "<カタカ[ナ]>123") (evil-test-buffer "[カ]タカナ123" ("vaw") "<カタカ[ナ]>123") (evil-test-buffer "[カ]タカナ한글" ("viw") "<カタカ[ナ]>한글") (evil-test-buffer "[カ]タカナ한글" ("vaw") "<カタカ[ナ]>한글") (evil-test-buffer "[カ]タカナabcd" ("viw") "<カタカナabc[d]>") (evil-test-buffer "[カ]タカナabcd" ("vaw") "<カタカナabc[d]>") (evil-test-buffer "[カ]タカナ1234" ("viw") "<カタカナ123[4]>") (evil-test-buffer "[カ]タカナ1234" ("vaw") "<カタカナ123[4]>") (evil-test-buffer "[カ]タカナ漢字" ("viw") "<カタカ[ナ]>漢字") (evil-test-buffer "[カ]タカナ漢字" ("vaw") "<カタカ[ナ]>漢字") (evil-test-buffer "[カ]タカナひらがな" ("viw") "<カタカ[ナ]>ひらがな") (evil-test-buffer "[カ]タカナひらがな" ("vaw") "<カタカ[ナ]>ひらがな") (evil-test-buffer "[カ]タカナカタカナ" ("viw") "<カタカ[ナ]>カタカナ") (evil-test-buffer "[カ]タカナカタカナ" ("vaw") "<カタカ[ナ]>カタカナ") (evil-test-buffer "[カ]タカナABC" ("viw") "<カタカナAB[C]>") (evil-test-buffer "[カ]タカナABC" ("vaw") "<カタカナAB[C]>") (evil-test-buffer "[カ]タカナ123" ("viw") "<カタカナ12[3]>") (evil-test-buffer "[カ]タカナ123" ("vaw") "<カタカナ12[3]>") (evil-test-buffer "[カ]タカナ한글" ("viw") "<カタカ[ナ]>한글") (evil-test-buffer "[カ]タカナ한글" ("vaw") "<カタカ[ナ]>한글") (evil-test-buffer "[A]BCabcd" ("viw") "<ABCabc[d]>") (evil-test-buffer "[A]BCabcd" ("vaw") "<ABCabc[d]>") (evil-test-buffer "[A]BC1234" ("viw") "<ABC123[4]>") (evil-test-buffer "[A]BC1234" ("vaw") "<ABC123[4]>") (evil-test-buffer "[A]BC漢字" ("viw") "<AB[C]>漢字") (evil-test-buffer "[A]BC漢字" ("vaw") "<AB[C]>漢字") (evil-test-buffer "[A]BCひらがな" ("viw") "<AB[C]>ひらがな") (evil-test-buffer "[A]BCひらがな" ("vaw") "<AB[C]>ひらがな") (evil-test-buffer "[A]BCカタカナ" ("viw") "<AB[C]>カタカナ") (evil-test-buffer "[A]BCカタカナ" ("vaw") "<AB[C]>カタカナ") (evil-test-buffer "[A]BCカタカナ" ("viw") "<ABCカタカ[ナ]>") (evil-test-buffer "[A]BCカタカナ" ("vaw") "<ABCカタカ[ナ]>") (evil-test-buffer "[A]BC123" ("viw") "<ABC12[3]>") (evil-test-buffer "[A]BC123" ("vaw") "<ABC12[3]>") (evil-test-buffer "[A]BC한글" ("viw") "<AB[C]>한글") (evil-test-buffer "[A]BC한글" ("vaw") "<AB[C]>한글") (evil-test-buffer "[1]23abcd" ("viw") "<123abc[d]>") (evil-test-buffer "[1]23abcd" ("vaw") "<123abc[d]>") (evil-test-buffer "[1]231234" ("viw") "<123123[4]>") (evil-test-buffer "[1]231234" ("vaw") "<123123[4]>") (evil-test-buffer "[1]23漢字" ("viw") "<12[3]>漢字") (evil-test-buffer "[1]23漢字" ("vaw") "<12[3]>漢字") (evil-test-buffer "[1]23ひらがな" ("viw") "<12[3]>ひらがな") (evil-test-buffer "[1]23ひらがな" ("vaw") "<12[3]>ひらがな") (evil-test-buffer "[1]23カタカナ" ("viw") "<12[3]>カタカナ") (evil-test-buffer "[1]23カタカナ" ("vaw") "<12[3]>カタカナ") (evil-test-buffer "[1]23カタカナ" ("viw") "<123カタカ[ナ]>") (evil-test-buffer "[1]23カタカナ" ("vaw") "<123カタカ[ナ]>") (evil-test-buffer "[1]23ABC" ("viw") "<123AB[C]>") (evil-test-buffer "[1]23ABC" ("vaw") "<123AB[C]>") (evil-test-buffer "[1]23한글" ("viw") "<12[3]>한글") (evil-test-buffer "[1]23한글" ("vaw") "<12[3]>한글") (evil-test-buffer "[한]글abcd" ("viw") "<한[글]>abcd") (evil-test-buffer "[한]글abcd" ("vaw") "<한[글]>abcd") (evil-test-buffer "[한]글1234" ("viw") "<한[글]>1234") (evil-test-buffer "[한]글1234" ("vaw") "<한[글]>1234") (evil-test-buffer "[한]글漢字" ("viw") "<한[글]>漢字") (evil-test-buffer "[한]글漢字" ("vaw") "<한[글]>漢字") (evil-test-buffer "[한]글ひらがな" ("viw") "<한[글]>ひらがな") (evil-test-buffer "[한]글ひらがな" ("vaw") "<한[글]>ひらがな") (evil-test-buffer "[한]글カタカナ" ("viw") "<한[글]>カタカナ") (evil-test-buffer "[한]글カタカナ" ("vaw") "<한[글]>カタカナ") (evil-test-buffer "[한]글カタカナ" ("viw") "<한[글]>カタカナ") (evil-test-buffer "[한]글カタカナ" ("vaw") "<한[글]>カタカナ") (evil-test-buffer "[한]글ABC" ("viw") "<한[글]>ABC") (evil-test-buffer "[한]글ABC" ("vaw") "<한[글]>ABC") (evil-test-buffer "[한]글123" ("viw") "<한[글]>123") (evil-test-buffer "[한]글123" ("vaw") "<한[글]>123"))) (ert-deftest evil-test-paragraph-objects () "Test `evil-inner-paragraph' and `evil-a-paragraph'" :tags '(evil text-object) (ert-info ("Select a paragraph with point at beginning") (evil-test-buffer "[;]; This buffer is for notes, ;; and for Lisp evaluation. ;; This buffer is for notes, ;; and for Lisp evaluation." ("vap") "<;; This buffer is for notes, ;; and for Lisp evaluation. \[]\n>\ ;; This buffer is for notes, ;; and for Lisp evaluation.")) (ert-info ("Select a paragraph with point at last line") (evil-test-buffer ";; This buffer is for notes, \[;]; and for Lisp evaluation. ;; This buffer is for notes, ;; and for Lisp evaluation." ("vap") "<;; This buffer is for notes, ;; and for Lisp evaluation. \[]\n>\ ;; This buffer is for notes, ;; and for Lisp evaluation.")) (ert-info ("Select a paragraph with point after paragraph") (evil-test-buffer ";; This buffer is for notes, ;; and for Lisp evaluation. \[] ;; This buffer is for notes, ;; and for Lisp evaluation." ("vap") ";; This buffer is for notes, ;; and for Lisp evaluation. < ;; This buffer is for notes, ;; and for Lisp evaluation[.]>")) (ert-info ("Select inner paragraph") (evil-test-buffer "[;]; This buffer is for notes, ;; and for Lisp evaluation. ;; This buffer is for notes, ;; and for Lisp evaluation." ("vip") "<;; This buffer is for notes, ;; and for Lisp evaluation.[] > ;; This buffer is for notes, ;; and for Lisp evaluation.") (evil-test-buffer ";; This buffer is for notes, \[;]; and for Lisp evaluation. ;; This buffer is for notes, ;; and for Lisp evaluation." ("vip") "<;; This buffer is for notes, ;; and for Lisp evaluation.[] > ;; This buffer is for notes, ;; and for Lisp evaluation.") (evil-test-buffer ";; This buffer is for notes, ;; and for Lisp evaluation. \[] ;; This buffer is for notes, ;; and for Lisp evaluation." ("vip") ";; This buffer is for notes, ;; and for Lisp evaluation. < ;; This buffer is for notes, ;; and for Lisp evaluation[.]>"))) (ert-deftest evil-test-quote-objects () "Test `evil-inner-single-quote' and `evil-a-single-quote'" :tags '(evil text-object) (ert-info ("Select text inside of '...'") (evil-test-buffer "This is 'a [t]est' for quote objects." ("vi'") "This is '' for quote objects.") (evil-test-buffer "This is \"a '[t]est'\" for quote objects." ("vi'") "This is \"a ''\" for quote objects.")) (ert-info ("Select text including enclosing quotes") (evil-test-buffer "This is 'a [t]est' for quote objects." ("v2i'") "This is <'a test[']> for quote objects.")) (ert-info ("Select text including enclosing quotes and following space") (evil-test-buffer "This is 'a [t]est' for quote objects." ("va'") "This is <'a test'[ ]>for quote objects.")) (ert-info ("Select text including enclosing quotes and previous space") (evil-test-buffer "This is 'a [t]est'. For quote objects." ("va'") "This is< 'a test[']>. For quote objects.")) (ert-info ("Select text on opening quote") (evil-test-buffer "This is [\"]a test\". For \"quote\" objects." (emacs-lisp-mode) ("va\"") "This is< \"a test[\"]>. For \"quote\" objects.")) (ert-info ("Select text on closing quote") (evil-test-buffer "This is \"a test[\"]. For \"quote\" objects." (emacs-lisp-mode) ("va\"") "This is< \"a test[\"]>. For \"quote\" objects.")) (ert-info ("Delete text from outside") (evil-test-buffer "Th[i]s is \"a test\". For \"quote\" objects." (emacs-lisp-mode) ("da\"") "This is[.] For \"quote\" objects.")) (ert-info ("Operator on empty quotes") (evil-test-buffer "This is [a]n \"\" empty quote" (emacs-lisp-mode) ("ci\"XXX" [escape]) "This is an \"XX[X]\" empty quote"))) (ert-deftest evil-test-paren-objects () "Test `evil-inner-paren', etc." :tags '(evil text-object) (ert-info ("Select inner text") (evil-test-buffer "[(]aaa)" (emacs-lisp-mode) ; syntax ("vi(") "()") (evil-test-buffer "(aaa[)]" (emacs-lisp-mode) ("vi(") "()") (ert-info ("Next to outer delimiter") (evil-test-buffer "([(]aaa))" (emacs-lisp-mode) ("vi(") "(())") (evil-test-buffer "((aaa[)])" (emacs-lisp-mode) ("vi(") "(())"))) (ert-info ("Select double inner parentheses") (evil-test-buffer "([(]word))" ("dib") "(())") (evil-test-buffer "[(](word))" ("dib") "()") (evil-test-buffer "((word[)])" ("dib") "(())") (evil-test-buffer "((word)[)]" ("dib") "()")) (ert-info ("Select double outer parentheses") (evil-test-buffer "a([(]word))b" ("dab") "a()b") (evil-test-buffer "a[(](word))b" ("dab") "ab") (evil-test-buffer "a((word[)])b" ("dab") "a()b") (evil-test-buffer "a((word)[)]b" ("dab") "ab")) (ert-info ("Select parentheses inside strings") (evil-test-buffer "(aaa \"b(b[b]b)\" aa)" (emacs-lisp-mode) ("va(") "(aaa \"b<(bbb[)]>\" aa)")) (ert-info ("Break out of empty strings") (evil-test-buffer "(aaa \"bb[b]b\" aa)" (emacs-lisp-mode) ("va(") "<(aaa \"bbbb\" aa[)]>")) (ert-info ("Select inner parentheses around strings") (evil-test-buffer "((\"t[e]st\"))\n" (emacs-lisp-mode) ("vib") "((<\"test[\"]>))\n" ("ib") "(<(\"test\"[)]>)\n") (evil-test-buffer "( ( \"t[e]st\" ) )\n" (emacs-lisp-mode) ("vib") "( (< \"test\"[ ]>) )\n" ("ib") "(< ( \"test\" )[ ]>)\n") (evil-test-buffer "((\"t[e]st\"))\n" (emacs-lisp-mode) ("vhhib") "((<[\"]test\">))\n" ("ib") "(<[(]\"test\")>)\n") (evil-test-buffer "( ( \"t[e]st\" ) )\n" (emacs-lisp-mode) ("vhhib") "( (<[ ]\"test\" >) )\n" ("ib") "(<[ ]( \"test\" ) >)\n")) (ert-info ("Select outer parentheses around strings") (evil-test-buffer "((\"t[e]st\"))\n" (emacs-lisp-mode) ("vab") "(<(\"test\"[)]>)\n" ("ab") "<((\"test\")[)]>\n") (evil-test-buffer "( ( \"t[e]st\" ) )\n" (emacs-lisp-mode) ("vab") "( <( \"test\" [)]> )\n" ("ab") "<( ( \"test\" ) [)]>\n") (evil-test-buffer "((\"t[e]st\"))\n" (emacs-lisp-mode) ("vhhab") "(<[(]\"test\")>)\n" ("ab") "<[(](\"test\"))>\n") (evil-test-buffer "( ( \"t[e]st\" ) )\n" (emacs-lisp-mode) ("vhhab") "( <[(] \"test\" )> )\n" ("ab") "<[(] ( \"test\" ) )>\n") (evil-test-buffer "(([\"]\"))\n" ("dab") "([)]\n")) (ert-info ("Select inner paren on different lines") (evil-test-buffer "for (auto i : vector) { if (cond) { do_[s]omething(); } }" ("vi}") "for (auto i : vector) { if (cond) { < do_something();[\n]> }\n}" ("i}") "for (auto i : vector) { < if (cond) { do_something(); }[\n]>}")) (ert-info ("Enlarge to smallest complete surrounding") (evil-test-buffer "for (auto i : vector) { if (comething(); } }" ("i}") "for (auto i : vector) { < if (cond) { do_something(); }[\n]>}")) (ert-info ("yank on blocks is turned linewise") (evil-test-buffer "{\n [f]oo();\n}\n" ("yiBp") "{\n foo();\n [f]oo();\n}\n")) (ert-info ("exclusive like if ending at bol") (evil-test-buffer "(defun foo ()\n[ ] (insert \"bar\")\n )\n" ("cibx" [escape]) "([x]\n )\n")) (ert-info ("Operator on empty parentheses") (evil-test-buffer "a([(]))b" ("cibx" [escape]) "a(([x]))b") (evil-test-buffer "a(([)])b" ("cibx" [escape]) "a(([x]))b"))) (ert-deftest evil-test-forces-linewise-text-objects () "Test `evil-text-object-change-visual-type' option." :tags '(evil text-object) (let ((evil-text-object-change-visual-type t)) (ert-info ("Change visual type") (evil-test-buffer " function(opts) { this.var1 = something(); [t]his.var2 = something_else(); return something_nasty(); } " ("Vi}") " function(opts) { < this.var1 = something(); this.var2 = something_else(); return something_nasty();[ ]> } " (should (eq (evil-visual-type) 'inclusive))))) (let ((evil-text-object-change-visual-type nil)) (ert-info ("Change visual type keeping linewise") (evil-test-buffer " function(opts) { this.var1 = something(); [t]his.var2 = something_else(); return something_nasty(); } " ("Vi}") " function(opts) { < this.var1 = something(); this.var2 = something_else(); return something_nasty();\n> } " (should (eq (evil-visual-type) 'line))))) (let ((evil-text-object-change-visual-type nil)) (ert-info ("Linewise outer block") (evil-test-buffer " function(opts) { this.var1 = something(); [t]his.var2 = something_else(); return something_nasty(); } " ("Va}") "< function(opts) { this.var1 = something(); this.var2 = something_else(); return something_nasty(); } >" (should (eq (evil-visual-type) 'line))))) (ert-info ("Forced motion type should change text object type") (evil-test-buffer "for (int i=0; i<10; i++) { if ([c]ond) { do_something(); } }" ("dVi}") "for (int i=0; i<10; i++) { \[}]"))) (ert-deftest evil-test-tag-objects () "Test `evil-inner-tag', etc." :tags '(evil text-object) (ert-info ("Handle nested tags") (evil-test-buffer :visual-start "{" :visual-end "}" "

f[o]o bar

" ("vit") "

{fo[o]} bar

")) (ert-info ("Break out of tags") (evil-test-buffer :visual-start "{" :visual-end "}" "bbbb" ("vit") "{bbb[b]}") (evil-test-buffer :visual-start "{" :visual-end "}" "bbbb" ("vat") "{bbbb]}")) (ert-info ("Handle quoted strings tags") (evil-test-buffer :visual-start "{" :visual-end "}" "
\[ ]

UPDATE

test hello Creative Commons

" ("vit") "
{\n \n

UPDATE

test hello Creative Commons

[\n]}
" ))) ;;; Visual state (defun evil-test-visual-select (selection &optional mark point) "Verify that TYPE is selected correctly" (let ((type (evil-visual-type selection))) (evil-visual-make-selection mark point type) (ert-info ("Activate region unless SELECTION is `block'") (cond ((eq selection 'block) (should (mark t)) (should-not (region-active-p)) (should-not transient-mark-mode)) (t (should (mark)) (should (region-active-p))))) (ert-info ("Refresh Visual markers") (should (= (evil-range-beginning (evil-expand (point) (mark) type)) evil-visual-beginning)) (should (= (evil-range-end (evil-expand (point) (mark) type)) evil-visual-end)) (should (eq (evil-visual-type) type)) (should (eq evil-visual-direction (if (< (point) (mark)) -1 1)))))) (ert-deftest evil-test-visual-refresh () "Test `evil-visual-refresh'" :tags '(evil visual) (evil-test-buffer ";; [T]his buffer is for notes." (evil-visual-refresh nil nil 'inclusive) (should (= evil-visual-beginning 4)) (should (= evil-visual-end 5))) (evil-test-buffer ";; [T]his buffer is for notes." (let ((evil-visual-region-expanded t)) (evil-visual-refresh nil nil 'inclusive) (should (= evil-visual-beginning 4)) (should (= evil-visual-end 4))))) (ert-deftest evil-test-visual-exchange () "Test `exchange-point-and-mark' in Visual character selection" :tags '(evil visual) (evil-test-buffer ";; <[T]his> buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("o") (should (region-active-p)) ";; buffer is for notes you don't want to save, ;; and for Lisp evaluation.")) (ert-deftest evil-test-visual-char () "Test Visual character selection" :tags '(evil visual) (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." (evil-test-visual-select 'char) ";; <[T]>his buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("e") ";; buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("o") ";; <[T]his> buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("d") ";; [ ]buffer is for notes you don't want to save, ;; and for Lisp evaluation." ("vV") "<;; [ ]buffer is for notes you don't want to save,\n>\ ;; and for Lisp evaluation.") (ert-info ("Test `evil-want-visual-char-semi-exclusive") (let ((evil-want-visual-char-semi-exclusive t)) (evil-test-buffer "[;]; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. ;; And a third line." ("v") "<[;]>; This buffer is for notes you don't want to save, ;; and for Lisp evaluation. ;; And a third line." ("$") "<;; This buffer is for notes you don't want to save,>[ ];; and for Lisp evaluation. ;; And a third line." ("^jj") "<;; This buffer is for notes you don't want to save, ;; and for Lisp evaluation.\n>[;]; And a third line.")))) (ert-deftest evil-test-visual-line () "Test Visual line selection" :tags '(evil visual) (evil-test-buffer ";; [T]his buffer is for notes you don't want to save, ;; and for Lisp evaluation." (evil-test-visual-select 'line) "<;; [T]his buffer is for notes you don't want to save,\n>\ ;; and for Lisp evaluation." ("e") "<;; Thi[s] buffer is for notes you don't want to save,\n>\ ;; and for Lisp evaluation." ("o") "<;; [T]his buffer is for notes you don't want to save,\n>\ ;; and for Lisp evaluation." ("d") "[;]; and for Lisp evaluation.")) (ert-deftest evil-test-visual-block () "Test Visual block selection" :tags '(evil visual) (evil-test-buffer "[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." (evil-test-visual-select 'block) "<[;]>; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer." ("jjll") "<;; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;;[ ]>then enter the text in that file's own buffer." ("O") ";; [;]; then enter the text in that file's own buffer." ("o") ";;[ ];; then enter the text in that file's own buffer." ("O") "<[;]; This buffer is for notes you don't want to save. ;; If you want to create a file, visit that file with C-x C-f, ;; >then enter the text in that file's own buffer." ("d") "This buffer is for notes you don't want to save. If you want to create a file, visit that file with C-x C-f, then enter the text in that file's own buffer.")) (ert-deftest evil-test-visual-restore () "Test restoring a previous selection" :tags '(evil visual) (ert-info ("Start a characterwise selection \ if no previous selection") (evil-test-buffer ";; [T]his buffer is for notes." ("gv") ";; <[T]>his buffer is for notes.")) (ert-info ("Restore characterwise selection") (evil-test-buffer ";; <[T]his> buffer is for notes." ([escape] "gv") ";; <[T]his> buffer is for notes.")) (ert-info ("Restore linewise selection") (evil-test-buffer :visual line "<;; [T]his buffer is for notes.>" ([escape] "gv") "<;; [T]his buffer is for notes.>")) (ert-info ("Restore blockwise selection") (evil-test-buffer :visual block "<;; This buffer is for notes, ;;[ ]>and for Lisp evaluation." ([escape] "gv") "<;; This buffer is for notes, ;;[ ]>and for Lisp evaluation."))) ;;; Replace state (ert-deftest evil-test-replacement () "Test replacing consecutive characters" :tags '(evil replace) (ert-info ("Replace and restore consecutive characters") (evil-test-buffer ";; [T]his buffer is for notes" ("Rfoo") ";; foo[s] buffer is for notes" ([backspace backspace backspace]) ";; [T]his buffer is for notes")) (ert-info ("Replace and restore consecutive characters beyond eol") (evil-test-buffer ";; [T]his buffer is for notes" ("wwwwRxxxxxxx") ";; This buffer is for xxxxxxx[]" ([backspace backspace backspace backspace backspace backspace backspace]) ";; This buffer is for [n]otes")) (ert-info ("Replace from line below and restore") (define-key evil-replace-state-map (kbd "C-e") 'evil-copy-from-below) (evil-test-buffer ";; [f]oo bar\n;; qux quux" ("R\C-e\C-e\C-e") ";; qux[ ]bar\n;; qux quux" ([backspace backspace backspace]) ";; [f]oo bar\n;; qux quux") (define-key evil-replace-state-map (kbd "C-e") nil)) (ert-info ("Replace from line above and restore") (define-key evil-replace-state-map (kbd "C-y") 'evil-copy-from-above) (evil-test-buffer ";; foo bar\n;; [q]ux quux" ("R\C-y\C-y\C-y") ";; foo bar\n;; foo[ ]quux" ([backspace backspace backspace]) ";; foo bar\n;; [q]ux quux") (define-key evil-replace-state-map (kbd "C-y") nil))) ;;; Ex (ert-deftest evil-test-ex-parse () "Test `evil-ex-parse'" :tags '(evil ex) (should (equal (evil-ex-parse "5,2cmd arg") '(evil-ex-call-command (evil-ex-range (evil-ex-line (string-to-number "5") nil) (evil-ex-line (string-to-number "2") nil)) "cmd" "arg"))) (should (equal (evil-ex-parse "5,2cmd !arg") '(evil-ex-call-command (evil-ex-range (evil-ex-line (string-to-number "5") nil) (evil-ex-line (string-to-number "2") nil)) "cmd" "!arg"))) (should (equal (evil-ex-parse "5,2 arg") '(evil-ex-call-command (evil-ex-range (evil-ex-line (string-to-number "5") nil) (evil-ex-line (string-to-number "2") nil)) "arg" nil))) (should (equal (evil-ex-parse "+1,+2t-1") '(evil-ex-call-command (evil-ex-range (evil-ex-line nil (+ (evil-ex-signed-number (intern "+") (string-to-number "1")))) (evil-ex-line nil (+ (evil-ex-signed-number (intern "+") (string-to-number "2"))))) "t" "-1")))) (ert-deftest evil-test-ex-parse-ranges () "Test parsing of ranges" :tags '(evil ex) (should (equal (evil-ex-parse "%" nil 'range) '(evil-ex-full-range))) (should (equal (evil-ex-parse "5,27" nil 'range) '(evil-ex-range (evil-ex-line (string-to-number "5") nil) (evil-ex-line (string-to-number "27") nil)))) (should (equal (evil-ex-parse "5,$" nil 'range) '(evil-ex-range (evil-ex-line (string-to-number "5") nil) (evil-ex-line (evil-ex-last-line) nil)))) (should (equal (evil-ex-parse "5,'x" nil 'range) '(evil-ex-range (evil-ex-line (string-to-number "5") nil) (evil-ex-line (evil-ex-marker "x") nil)))) (should (equal (evil-ex-parse "`x,`y" nil 'range) '(evil-ex-char-marker-range "x" "y"))) (should (equal (evil-ex-parse "5,+" nil 'range) '(evil-ex-range (evil-ex-line (string-to-number "5") nil) (evil-ex-line nil (+ (evil-ex-signed-number (intern "+") nil)))))) (should (equal (evil-ex-parse "5,-" nil 'range) '(evil-ex-range (evil-ex-line (string-to-number "5") nil) (evil-ex-line nil (+ (evil-ex-signed-number (intern "-") nil)))))) (should (equal (evil-ex-parse "5,4+2-7-3+10-" nil 'range) '(evil-ex-range (evil-ex-line (string-to-number "5") nil) (evil-ex-line (string-to-number "4") (+ (evil-ex-signed-number (intern "+") (string-to-number "2")) (evil-ex-signed-number (intern "-") (string-to-number "7")) (evil-ex-signed-number (intern "-") (string-to-number "3")) (evil-ex-signed-number (intern "+") (string-to-number "10")) (evil-ex-signed-number (intern "-") nil)))))) (should (equal (evil-ex-parse ".-2,4+2-7-3+10-" nil 'range) '(evil-ex-range (evil-ex-line (evil-ex-current-line) (+ (evil-ex-signed-number (intern "-") (string-to-number "2")))) (evil-ex-line (string-to-number "4") (+ (evil-ex-signed-number (intern "+") (string-to-number "2")) (evil-ex-signed-number (intern "-") (string-to-number "7")) (evil-ex-signed-number (intern "-") (string-to-number "3")) (evil-ex-signed-number (intern "+") (string-to-number "10")) (evil-ex-signed-number (intern "-") nil)))))) (should (equal (evil-ex-parse "'a-2,$-10" nil 'range) '(evil-ex-range (evil-ex-line (evil-ex-marker "a") (+ (evil-ex-signed-number (intern "-") (string-to-number "2")))) (evil-ex-line (evil-ex-last-line) (+ (evil-ex-signed-number (intern "-") (string-to-number "10"))))))) (should (equal (evil-ex-parse ".+42" nil 'range) '(evil-ex-range (evil-ex-line (evil-ex-current-line) (+ (evil-ex-signed-number (intern "+") (string-to-number "42")))) nil)))) (ert-deftest evil-test-ex-parse-emacs-commands () "Test parsing of Emacs commands" :tags '(evil ex) (should (equal (evil-ex-parse "ido-mode") '(evil-ex-call-command nil "ido-mode" nil))) (should (equal (evil-ex-parse "yas/reload-all") '(evil-ex-call-command nil "yas/reload-all" nil))) (should (equal (evil-ex-parse "mu4e") '(evil-ex-call-command nil "mu4e" nil))) (should (equal (evil-ex-parse "make-frame") '(evil-ex-call-command nil "make-frame" nil)))) (ert-deftest evil-text-ex-search-offset () "Test for addresses like /base//pattern/" :tags '(evil ex) (ert-info ("without base") (evil-test-buffer "[l]ine 1\naaa\nbbb\naaa\nccc\nddd" (":/aaa/d") "line 1\nbbb\naaa\nccc\nddd")) (ert-info ("with base") (evil-test-buffer "[l]ine 1\naaa\nbbb\naaa\nccc\nddd" (":/bbb//aaa/d") "line 1\naaa\nbbb\nccc\nddd")) (ert-info ("range without base") (evil-test-buffer "[l]ine 1\naaa\nbbb\naaa\nccc\nddd\nccc\neee\n" (":/aaa/;/ccc/d") "line 1\nddd\nccc\neee\n")) (ert-info ("range with base") (evil-test-buffer "[l]ine 1\naaa\nbbb\naaa\nccc\nddd\nccc\neee\n" (":/bbb//aaa/;/ddd//ccc/d") "line 1\naaa\nbbb\neee\n"))) (ert-deftest evil-test-ex-goto-line () "Test if :number moves point to a certain line" :tags '(evil ex) (ert-info ("Move to line") (evil-test-buffer :visual line "1\n 2\n [ ]3\n 4\n 5\n" (":4" [return]) "1\n 2\n 3\n [4]\n 5\n" (":2" [return]) "1\n [2]\n 3\n 4\n 5\n"))) (ert-deftest evil-test-ex-repeat () "Test :@: command." :tags '(evil ex) (evil-without-display (ert-info ("Repeat in current line") (evil-test-buffer "[a]bcdef\nabcdef\nabcdef" (":s/[be]/X/g" [return]) "[a]XcdXf\nabcdef\nabcdef" ("jj:@:" [return]) "aXcdXf\nabcdef\n[a]XcdXf")) (ert-info ("Repeat in specified line") (evil-test-buffer "[a]bcdef\nabcdef\nabcdef" (":s/[be]/X/g" [return]) "[a]XcdXf\nabcdef\nabcdef" (":3@:" [return]) "aXcdXf\nabcdef\n[a]XcdXf")) (ert-info ("Double repeat, first without then with specified line") (evil-test-buffer "[a]bcdef\nabcdef\nabcdef" (":s/[be]/X/" [return]) "[a]Xcdef\nabcdef\nabcdef" ("jj:@:" [return] ":1@:" [return]) "[a]XcdXf\nabcdef\naXcdef")))) (ert-deftest evil-test-ex-repeat2 () "Test @: command." :tags '(evil ex) (evil-without-display (ert-info ("Repeat in current line") (evil-test-buffer "[a]bcdef\nabcdef\nabcdef" (":s/[be]/X" [return]) "[a]Xcdef\nabcdef\nabcdef" ("jj@:") "aXcdef\nabcdef\n[a]Xcdef")) (ert-info ("Repeat with count in current line") (evil-test-buffer "[a]bcdef\nabcdef\nabcdef" (":s/[be]/X" [return]) "[a]Xcdef\nabcdef\nabcdef" ("jj2@:") "aXcdef\nabcdef\n[a]XcdXf")) (ert-info ("Do not record dot repeat") (evil-test-buffer "" ("OAAAAAA" [escape] "^") "[A]AAAAA\n" (":s/A/X" [return]) "[X]AAAAA\n" ("@:") "[X]XAAAA\n" (".") "AAAAAA\nXXAAAA\n")))) (ert-deftest evil-test-ex-visual-char-range () "Test visual character ranges in ex state." :tags '(evil ex visual) (evil-without-display (ert-info ("No character range, inclusive") (let ((evil-visual-char 'inclusive) evil-ex-visual-char-range) (evil-test-buffer "li[n]e 1\nline 2\nline 3\nline 4\n" ("vjll:d" [return]) "line 3\nline 4\n"))) (ert-info ("No character range, exclusive") (let ((evil-visual-char 'inclusive) evil-ex-visual-char-range) (evil-test-buffer "li[n]e 1\nline 2\nline 3\nline 4\n" ("vjll:d" [return]) "line 3\nline 4\n"))) (ert-info ("Character range, inclusive") (let ((evil-visual-char 'inclusive) (evil-ex-visual-char-range t)) (evil-test-buffer "li[n]e 1\nline 2\nline 3\nline 4\n" ("vjll:d" [return]) "li2\nline 3\nline 4\n"))) (ert-info ("Character range, exclusive") (let ((evil-visual-char 'exclusive) (evil-ex-visual-char-range t)) (evil-test-buffer "li[n]e 1\nline 2\nline 3\nline 4\n" ("vjll:d" [return]) "li 2\nline 3\nline 4\n"))))) (ert-deftest evil-test-ex-substitute-replacement () "Test `evil-ex-substitute' with special replacements." :tags '(evil ex search) (ert-info ("Substitute upper first on first match in line") (evil-test-buffer "[x]xx foo bar foo bar foo bar" (":s/\\(foo\\|bar\\)/\\u\\1" [return]) "[x]xx Foo bar foo bar foo bar")) (ert-info ("Substitute upper first on first match in line with confirm") (evil-test-buffer "[x]xx foo bar foo bar foo bar" (":s/\\(foo\\|bar\\)/\\u\\1/c" [return] "y") "[x]xx Foo bar foo bar foo bar")) (ert-info ("Substitute upper first on whole line") (evil-test-buffer "[x]xx foo bar foo bar foo bar" (":s/\\(foo\\|bar\\)/\\u\\1/g" [return]) "[x]xx Foo Bar Foo Bar Foo Bar")) (ert-info ("Substitute upper first on whole line") (evil-test-buffer "[x]xx foo bar foo bar foo bar" (":s/\\(foo\\|bar\\)/\\u\\1/gc" [return] "yynyyn") "[x]xx Foo Bar foo Bar Foo bar")) (ert-info ("Substitute upper/lower on first match in line") (evil-test-buffer "[x]xx foo BAR foo BAR foo BAR" (":s/\\(f[[:alpha:]]*\\>\\)\\s-*\\(b[[:alpha:]]*\\>\\)/\\L\\2_\\e\\U\\1" [return]) "[x]xx bar_FOO foo BAR foo BAR")) (ert-info ("Substitute upper/lower on first match in line with confirm") (evil-test-buffer "[x]xx foo BAR foo BAR foo BAR" (":s/\\(f[[:alpha:]]*\\>\\)\\s-*\\(b[[:alpha:]]*\\>\\)/\\L\\2_\\e\\U\\1/c" [return] "y") "[x]xx bar_FOO foo BAR foo BAR")) (ert-info ("Substitute upper/lower on whole line") (evil-test-buffer "[x]xx foo BAR foo BAR foo BAR" (":s/\\(f[[:alpha:]]*\\>\\)\\s-*\\(b[[:alpha:]]*\\>\\)/\\L\\2_\\e\\U\\1/g" [return]) "[x]xx bar_FOO bar_FOO bar_FOO")) (ert-info ("Substitute upper/lower on whole line") (evil-test-buffer "[x]xx foo BAR foo BAR foo BAR" (":s/\\(f[[:alpha:]]*\\>\\)\\s-*\\(b[[:alpha:]]*\\>\\)/\\L\\2_\\e\\U\\1/gc" [return] "yny") "[x]xx bar_FOO foo BAR bar_FOO")) (ert-info ("Substitute with escaped characters in replacement") (evil-test-buffer "[a]bcXdefXghiXjkl\n" (":s/X/\\|\\/\\|/g" [return]) "[a]bc|/|def|/|ghi|/|jkl\n")) (ert-info ("Substitute with register") (evil-test-buffer "[a]bc\niiiXiiiXiiiXiii\n" ("\"ayiwj:s/X/\\=@a/g" [return]) "abc\n[i]iiabciiiabciiiabciii\n")) (ert-info ("Substitute newlines") (evil-test-buffer "[a]bc\ndef\nghi\n" (":%s/\n/z/" [return]) "[a]bczdefzghiz")) (ert-info ("Substitute newlines with g flag") (evil-test-buffer "[a]bc\ndef\nghi\n" (":%s/\n/z/g" [return]) "[a]bczdefzghiz")) (ert-info ("Substitute newlines without newline in regexp") (evil-test-buffer "[A]BC\nDEF\nGHI\n" (":%s/[^]]*/z/" [return]) "Z")) (ert-info ("Substitute n flag does not replace") (evil-test-buffer "[a]bc\naef\nahi\n" (":%s/a//n" [return]) "[a]bc\naef\nahi\n")) (ert-info ("Substitute n flag does not replace with g flag") (evil-test-buffer "[a]bc\naef\nahi\n" (":%s/a//gn" [return]) "[a]bc\naef\nahi\n")) (ert-info ("Substitute $ does not loop infinitely") (evil-test-buffer "[a]bc\ndef\nghi" (":%s/$/ END/g" [return]) "abc END\ndef END\n[g]hi END")) (ert-info ("Substitute the zero-length beginning of line character") (evil-test-buffer "[a]bc\ndef\nghi" (":s/^/ #/" [return]) " [#]abc\ndef\nghi")) (ert-info ("Substitute the zero-length beginning of line character with g flag") (evil-test-buffer "[a]bc\ndef\nghi" (":s/^/ #/g" [return]) " [#]abc\ndef\nghi")) (ert-info ("Use Substitute to delete individual characters") (evil-test-buffer "[x]xyxxz" (":%s/x//g" [return]) "[y]z"))) (ert-deftest evil-test-ex-repeat-substitute-replacement () "Test `evil-ex-substitute' with repeating of previous substitutions." :tags '(evil ex search) (ert-info ("Repeat previous pattern") (evil-select-search-module 'evil-search-module 'evil-search) (evil-test-buffer "[x]xx foo bar foo bar foo bar" (":s/foo/AAA" [return]) "[x]xx AAA bar foo bar foo bar" (":s//BBB" [return]) "[x]xx AAA bar BBB bar foo bar" ("/bar" [return] ":s//CCC" [return]) "[x]xx AAA CCC BBB bar foo bar" (":s/ar/XX" [return]) "[x]xx AAA CCC BBB bXX foo bar" (":s//YY" [return]) "[x]xx AAA CCC BBB bXX foo bYY")) (ert-info ("Repeat previous replacement") (evil-test-buffer "[x]xx foo bar foo bar foo bar" (":s/foo/AAA" [return]) "[x]xx AAA bar foo bar foo bar" (":s/bar/~" [return]) "[x]xx AAA AAA foo bar foo bar")) (ert-info ("Repeat with previous flags") (evil-test-buffer "[x]xx foo bar foo bar foo bar" (":s/foo/AAA/g" [return]) "[x]xx AAA bar AAA bar AAA bar" (":s/bar/BBB/&" [return]) "[x]xx AAA BBB AAA BBB AAA BBB")) (ert-info ("Repeat previous substitute without flags") (evil-select-search-module 'evil-search-module 'evil-search) (evil-test-buffer "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" (":s/foo/AAA/g" [return]) "[x]xx AAA bar AAA bar AAA bar\nxxx foo bar foo bar foo bar" ("j:s" [return]) "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar foo bar foo bar" ("/bar" [return] ":s" [return]) "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar AAA bar foo bar") (evil-test-buffer "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" (":s/foo/AAA/g" [return]) "[x]xx AAA bar AAA bar AAA bar\nxxx foo bar foo bar foo bar" ("j&") "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar foo bar foo bar") (evil-test-buffer "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" (":s/foo/AAA/g" [return]) "[x]xx AAA bar AAA bar AAA bar\nxxx foo bar foo bar foo bar" ("j:&" [return]) "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar foo bar foo bar")) (ert-info ("Repeat previous substitute with the same flags") (evil-test-buffer "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" (":s/foo/AAA/g" [return]) "[x]xx AAA bar AAA bar AAA bar\nxxx foo bar foo bar foo bar" ("j:s//~/&" [return]) "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar AAA bar AAA bar") (evil-test-buffer "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" (":s/foo/AAA/g" [return]) "[x]xx AAA bar AAA bar AAA bar\nxxx foo bar foo bar foo bar" ("j:&&" [return]) "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar AAA bar AAA bar")) (ert-info ("Repeat previous substitute with new flags") (evil-test-buffer "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" (":s/foo/AAA" [return]) "[x]xx AAA bar foo bar foo bar\nxxx foo bar foo bar foo bar" ("j:s g" [return]) "xxx AAA bar foo bar foo bar\n[x]xx AAA bar AAA bar AAA bar") (evil-test-buffer "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" (":s/foo/AAA" [return]) "[x]xx AAA bar foo bar foo bar\nxxx foo bar foo bar foo bar" ("j:& g" [return]) "xxx AAA bar foo bar foo bar\n[x]xx AAA bar AAA bar AAA bar")) (ert-info ("Repeat with previous search pattern") (evil-select-search-module 'evil-search-module 'evil-search) (evil-test-buffer "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" (":s/foo/AAA" [return]) "[x]xx AAA bar foo bar foo bar\nxxx foo bar foo bar foo bar" ("/bar" [return]) "xxx AAA [b]ar foo bar foo bar\nxxx foo bar foo bar foo bar" (":2s rg" [return]) "xxx AAA bar foo bar foo bar\n[x]xx foo AAA foo AAA foo AAA") (evil-test-buffer "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" (":s/foo/AAA" [return]) "[x]xx AAA bar foo bar foo bar\nxxx foo bar foo bar foo bar" ("/bar" [return]) "xxx AAA [b]ar foo bar foo bar\nxxx foo bar foo bar foo bar" (":2~ g" [return]) "xxx AAA bar foo bar foo bar\n[x]xx foo AAA foo AAA foo AAA")) (ert-info ("Repeat previous substitute globally") (evil-test-buffer "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" (":s/foo/AAA/g" [return]) "[x]xx AAA bar AAA bar AAA bar\nxxx foo bar foo bar foo bar" ("g&") "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar AAA bar AAA bar"))) (ert-deftest evil-test-ex-regex-without-case () "Test `evil-ex-regex-without-case'" :tags '(evil ex search) (should (equal (evil-ex-regex-without-case "cdeCDE") "cdeCDE")) (should (equal (evil-ex-regex-without-case "\\ccde\\CCDE") "cdeCDE")) (should (equal (evil-ex-regex-without-case "\\\\ccde\\\\CCDE") "\\\\ccde\\\\CCDE")) (should (equal (evil-ex-regex-without-case "\\\\\\ccde\\\\\\CCDE") "\\\\cde\\\\CDE"))) (ert-deftest evil-test-ex-regex-case () "Test `evil-ex-regex-case'" :tags '(evil ex search) (should (equal (evil-ex-regex-case "cde" 'smart) 'insensitive)) (should (equal (evil-ex-regex-case "cDe" 'smart) 'sensitive)) (should (equal (evil-ex-regex-case "cde" 'sensitive) 'sensitive)) (should (equal (evil-ex-regex-case "cde" 'insensitive) 'insensitive)) (should (equal (evil-ex-regex-case "\\ccde" 'smart) 'insensitive)) (should (equal (evil-ex-regex-case "\\cCde" 'smart) 'insensitive)) (should (equal (evil-ex-regex-case "\\Ccde" 'smart) 'sensitive)) (should (equal (evil-ex-regex-case "\\CCde" 'smart) 'sensitive)) (should (equal (evil-ex-regex-case "\\ccd\\Ce" 'smart) 'insensitive)) (should (equal (evil-ex-regex-case "\\cCd\\Ce" 'smart) 'insensitive)) (should (equal (evil-ex-regex-case "\\Ccd\\ce" 'smart) 'sensitive)) (should (equal (evil-ex-regex-case "\\CCd\\ce" 'smart) 'sensitive))) (ert-deftest evil-test-ex-search () "Test evil internal search." :tags '(evil ex search) (evil-without-display (evil-select-search-module 'evil-search-module 'evil-search) (ert-info ("Test smart case insensitive") (evil-test-buffer "[s]tart you YOU You you YOU You" ("/you" [return]) "start [y]ou YOU You you YOU You" ("n") "start you [Y]OU You you YOU You" ("n") "start you YOU [Y]ou you YOU You" ("n") "start you YOU You [y]ou YOU You")) (ert-info ("Test smart case sensitive") (evil-test-buffer "[s]tart you YOU You you YOU You" ("/You" [return]) "start you YOU [Y]ou you YOU You" ("n") "start you YOU You you YOU [Y]ou")) (ert-info ("Test insensitive") (evil-test-buffer "[s]tart you YOU You you YOU You" ("/\\cyou" [return]) "start [y]ou YOU You you YOU You" ("n") "start you [Y]OU You you YOU You" ("n") "start you YOU [Y]ou you YOU You" ("n") "start you YOU You [y]ou YOU You")) (ert-info ("Test sensitive") (evil-test-buffer "[s]tart you YOU You you YOU You" ("/\\Cyou" [return]) "start [y]ou YOU You you YOU You" ("n") "start you YOU You [y]ou YOU You")) (ert-info ("Test failing search does not move point") (evil-test-buffer "foo [f]oo foo\nbar bar2 bar\nbaz baz baz\n" (error search-failed "/foofoo" [return]) "foo [f]oo foo\nbar bar2 bar\nbaz baz baz\n" ("/bar2" [return]) "foo foo foo\nbar [b]ar2 bar\nbaz baz baz\n" ("dw") "foo foo foo\nbar [b]ar\nbaz baz baz\n" (error search-failed "n") "foo foo foo\nbar [b]ar\nbaz baz baz\n" (error search-failed "N") "foo foo foo\nbar [b]ar\nbaz baz baz\n")) (ert-info ("Test search for newline") (evil-test-buffer "[s]tart\nline 2\nline 3\n\n" ("/\\n" [return]) "star[t]\nline 2\nline 3\n\n" ("n") "start\nline [2]\nline 3\n\n" ("n") "start\nline 2\nline [3]\n\n" ("n") "start\nline 2\nline 3\n[]\n")))) (ert-deftest evil-test-ex-search-offset () "Test search offsets." :tags '(evil ex search) (evil-without-display (evil-select-search-module 'evil-search-module 'evil-search) (ert-info ("Test line offsets") (evil-test-buffer "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" ("/bar/2") "foo foo\nbar bar\nbaz baz\n[A]nother line\nAnd yet another line" ("?bar?-") "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" ("/r bar/") "foo foo\nba[r] bar\nbaz baz\nAnother line\nAnd yet another line")) (ert-info ("Test end offsets") (evil-test-buffer "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" ("/bar/e") "foo foo\nba[r] bar\nbaz baz\nAnother line\nAnd yet another line" ("/baz/e+2") "foo foo\nbar bar\nbaz [b]az\nAnother line\nAnd yet another line" ("/line/e-1") "foo foo\nbar bar\nbaz baz\nAnother li[n]e\nAnd yet another line")) (ert-info ("Test begin offsets") (evil-test-buffer "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" ("/bar/b") "foo foo\n[b]ar bar\nbaz baz\nAnother line\nAnd yet another line" ("/baz/b+2") "foo foo\nbar bar\nba[z] baz\nAnother line\nAnd yet another line" ("/line/b-") "foo foo\nbar bar\nbaz baz\nAnother[ ]line\nAnd yet another line")) (ert-info ("Test search-next with offset") (evil-test-buffer "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" ("/ ba/+1" [return]) "foo foo\nbar bar\n[b]az baz\nAnother line\nAnd yet another line" ("n") "foo foo\nbar bar\nbaz baz\n[A]nother line\nAnd yet another line")) (ert-info ("Test search next after /$") (evil-test-buffer "[l]ine 1\nline 2\n\n\line 4\n" ("/$" [return]) "line [1]\nline 2\n\n\line 4\n" ("n") "line 1\nline [2]\n\n\line 4\n" ("n") "line 1\nline 2\n[\n]\line 4\n" ("n") "line 1\nline 2\n\n\line [4]\n")))) (ert-deftest evil-test-ex-search-pattern-offset () "Test pattern offsets." :tags '(evil ex search) (evil-without-display (evil-select-search-module 'evil-search-module 'evil-search) (ert-info ("Test simple pattern offsets") (evil-test-buffer "[f]oo foo\nbar bar\nfoo foo\nbaz baz\nAnother line\nAnd yet another line" ("/bar/;/foo" [return]) "foo foo\nbar bar\n[f]oo foo\nbaz baz\nAnother line\nAnd yet another line")) (ert-info ("Test simple pattern offsets in backward direction") (evil-test-buffer "[f]oo foo\nbar bar\nfoo foo\nbaz baz\nAnother line\nAnd yet another line" ("/bar/;?foo" [return]) "foo [f]oo\nbar bar\nfoo foo\nbaz baz\nAnother line\nAnd yet another line")) (ert-info ("Ensure second pattern is used for search repeat") (evil-test-buffer "[f]oo foo\nbar bar\nfoo foo\nbaz baz\nAnother line\nAnd yet another line" ("/bar/;?foo" [return] "n") "foo foo\nbar bar\n[f]oo foo\nbaz baz\nAnother line\nAnd yet another line")))) (ert-deftest evil-test-ex-search-repeat () "Test repeat of search." :tags '(evil ex search) (evil-without-display (evil-select-search-module 'evil-search-module 'evil-search) (ert-info ("Test repeat of simple pattern") (evil-test-buffer "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" ("/bar" [return] "/" [return]) "foo foo\nbar [b]ar\nbaz baz\nAnother line\nAnd yet another line")) (ert-info ("Test repeat of simple pattern with new offset") (evil-test-buffer "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" ("/bar" [return] "//e" [return]) "foo foo\nbar ba[r]\nbaz baz\nAnother line\nAnd yet another line")) (ert-info ("Test repeat of pattern with offset") (evil-test-buffer "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" ("/bar/e" [return] "/" [return]) "foo foo\nbar ba[r]\nbaz baz\nAnother line\nAnd yet another line")) (ert-info ("Test repeat of pattern with offset without offset") (evil-test-buffer "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" ("/bar/e" [return] "//" [return]) "foo foo\nbar [b]ar\nbaz baz\nAnother line\nAnd yet another line")) (ert-info ("Test repeat of pattern with offset with new offset") (evil-test-buffer "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" ("/bar/e" [return] "//b+1" [return]) "foo foo\nbar b[a]r\nbaz baz\nAnother line\nAnd yet another line")))) (ert-deftest evil-test-ex-search-word () "Test search for word under point." :tags '(evil ex search) (evil-without-display (evil-select-search-module 'evil-search-module 'evil-search) (setq evil-ex-search-history nil) (evil-test-buffer "so[m]e text with a strange word and here some other stuff maybe we need one line more with some text\n" (setq evil-symbol-word-search nil) ("*") "some text with a strange word and here [s]ome other stuff maybe we need one line more with some text\n" ("n") "some text with a strange word and here some other stuff maybe we need one line more with [s]ome text\n" (ert-info ("Search history") (should (equal evil-ex-search-history '("\\")))) ("*") "[s]ome text with a strange word and here some other stuff maybe we need one line more with some text\n" (ert-info ("Search history with double pattern") (should (equal evil-ex-search-history '("\\"))))) (ert-info ("Test unbounded search") (evil-select-search-module 'evil-search-module 'evil-search) (setq evil-ex-search-history nil) (evil-test-buffer "[s]ymbol\n(defun my-symbolfunc ())\n(defvar my-symbolvar)\nanother symbol\n" ("*") (setq evil-symbol-word-search nil) "symbol\n(defun my-symbolfunc ())\n(defvar my-symbolvar)\nanother [s]ymbol\n" ("ggg*") "symbol\n(defun my-[s]ymbolfunc ())\n(defvar my-symbolvar)\nanother symbol\n" (should (equal evil-ex-search-history '("symbol" "\\"))) ("n") "symbol\n(defun my-symbolfunc ())\n(defvar my-[s]ymbolvar)\nanother symbol\n")) (ert-info ("Test symbol search") (evil-select-search-module 'evil-search-module 'evil-search) (evil-test-buffer "(defun my-s[y]mbol-func ())\n(defvar my-symbol-var)\n(my-symbol-func)\n(setq my-symbol-func2 (my-symbol-func))\n" (setq evil-symbol-word-search t) ("*") "(defun my-symbol-func ())\n(defvar my-symbol-var)\n([m]y-symbol-func)\n(setq my-symbol-func2 (my-symbol-func))\n" ("n") "(defun my-symbol-func ())\n(defvar my-symbol-var)\n(my-symbol-func)\n(setq my-symbol-func2 ([m]y-symbol-func))\n")))) (ert-deftest evil-test-isearch-word () "Test isearch for word under point." :tags '(evil isearch) (evil-without-display (evil-select-search-module 'evil-search-module 'isearch) (evil-test-buffer "so[m]e text with a strange word and here some other stuff maybe we need one line more with some text\n" (setq evil-symbol-word-search nil) ("*") "some text with a strange word and here [s]ome other stuff maybe we need one line more with some text\n" ("n") "some text with a strange word and here some other stuff maybe we need one line more with [s]ome text\n" ("*") "[s]ome text with a strange word and here some other stuff maybe we need one line more with some text\n") (ert-info ("Test unbounded search") (evil-select-search-module 'evil-search-module 'isearch) (evil-test-buffer "[s]ymbol\n(defun my-symbolfunc ())\n(defvar my-symbolvar)\nanother symbol\n" (setq evil-symbol-word-search nil) ("*") "symbol\n(defun my-symbolfunc ())\n(defvar my-symbolvar)\nanother [s]ymbol\n" ("ggg*") "symbol\n(defun my-[s]ymbolfunc ())\n(defvar my-symbolvar)\nanother symbol\n" ("n") "symbol\n(defun my-symbolfunc ())\n(defvar my-[s]ymbolvar)\nanother symbol\n")) (ert-info ("Test symbol search") (evil-select-search-module 'evil-search-module 'isearch) (evil-test-buffer "(defun my-s[y]mbol-func ())\n(defvar my-symbol-var)\n(my-symbol-func)\n(setq my-symbol-func2 (my-symbol-func))\n" (setq evil-symbol-word-search t) ("*") "(defun my-symbol-func ())\n(defvar my-symbol-var)\n([m]y-symbol-func)\n(setq my-symbol-func2 (my-symbol-func))\n" ("n") "(defun my-symbol-func ())\n(defvar my-symbol-var)\n(my-symbol-func)\n(setq my-symbol-func2 ([m]y-symbol-func))\n")))) (ert-deftest evil-test-read () "Test of `evil-read'" :tags '(evil ex) (evil-without-display (ert-info ("Test insertion of file with trailing newline") (evil-with-temp-file name "temp file 1\ntemp file 2\n" (ert-info ("At first line") (evil-test-buffer "[l]ine 1\nline 2" ((vconcat ":read " name [return])) "line 1\n[t]emp file 1\ntemp file 2\nline 2")) (ert-info ("At last line") (evil-test-buffer "line 1\n[l]ine 2" ((vconcat ":read " name [return])) "line 1\nline 2\n[t]emp file 1\ntemp file 2\n")) (ert-info ("After specified line number") (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4\line 5" ((vconcat ":3read " name [return])) "line 1\nline 2\nline 3\n[t]emp file 1\ntemp file 2\nline 4\line 5")) (ert-info ("After specified line 0") (evil-test-buffer "line 1\nline [2]\nline 3\nline 4\line 5" ((vconcat ":0read " name [return])) "[t]emp file 1\ntemp file 2\nline 1\nline 2\nline 3\nline 4\line 5")))) (ert-info ("Test insertion of file without trailing newline") (evil-with-temp-file name "temp file 1\ntemp file 2" (evil-test-buffer "[l]ine 1\nline 2" ((vconcat ":read " name [return])) "line 1\n[t]emp file 1\ntemp file 2\nline 2"))) (ert-info ("Test insertion of shell command") (ert-info ("with space") (evil-test-buffer "[l]line 1\nline 2" (":read !echo cmd line 1" [return]) "line 1\n[c]md line 1\nline 2")) (ert-info ("without space") (evil-test-buffer "[l]line 1\nline 2" (":read!echo cmd line 1" [return]) "line 1\n[c]md line 1\nline 2"))) (ert-info ("Test insertion of shell command without trailing newline") (ert-info ("with space") (evil-test-buffer "[l]line 1\nline 2" (":read !echo -n cmd line 1" [return]) "line 1\n[c]md line 1\nline 2")) (ert-info ("without space") (evil-test-buffer "[l]line 1\nline 2" (":read!echo -n cmd line 1" [return]) "line 1\n[c]md line 1\nline 2"))))) (ert-deftest evil-test-shell-command () "Test `evil-shell-command'." (ert-info ("ex shell command") (evil-test-buffer "[l]ine 5\nline 4\nline 3\nline 2\nline 1\n" (":2,3!sort" [return]) "line 5\n[l]ine 3\nline 4\nline 2\nline 1\n")) (ert-info ("shell command operator with count") (evil-test-buffer "line 5\n[l]ine 4\nline 3\nline 2\nline 1\n" ("2!!sort" [return]) "line 5\n[l]ine 3\nline 4\nline 2\nline 1\n")) (ert-info ("shell command operator with motion") (evil-test-buffer "line 5\n[l]ine 4\nline 3\nline 2\nline 1\n" ("!jsort" [return]) "line 5\n[l]ine 3\nline 4\nline 2\nline 1\n")) (ert-info ("shell command operator with backward motion") (evil-test-buffer "line 5\nline 4\n[l]ine 3\nline 2\nline 1\n" ("!ksort" [return]) "line 5\n[l]ine 3\nline 4\nline 2\nline 1\n")) (ert-info ("shell command operator with visual selection") (evil-test-buffer "line 5\n[l]ine 4\nline 3\nline 2\nline 1\n" ("vj!sort" [return]) "line 5\n[l]ine 3\nline 4\nline 2\nline 1\n"))) (ert-deftest evil-test-global () "Test `evil-ex-global'." :tags '(evil ex global) (ert-info ("global delete") (evil-test-buffer "[n]o 1\nno 2\nno 3\nyes 4\nno 5\nno 6\nno 7\n" (":g/yes/d" [return]) "no 1\nno 2\nno 3\n[n]o 5\nno 6\nno 7\n")) (ert-info ("global substitute") (evil-test-buffer "[n]o 1\nno 2\nno 3\nyes 4\nno 5\nno 6\nno 7\n" (":g/no/s/[3-6]/x" [return]) "no 1\nno 2\nno x\nyes 4\nno x\nno x\n[n]o 7\n" ("u") "no 1\nno 2\nno [3]\nyes 4\nno 5\nno 6\nno 7\n")) (ert-info ("global substitute with trailing slash") (evil-test-buffer "[n]o 1\nno 2\nno 3\nyes 4\nno 5\nno 6\nno 7\n" (":g/no/s/[3-6]/x/" [return]) "no 1\nno 2\nno x\nyes 4\nno x\nno x\n[n]o 7\n" ("u") "no 1\nno 2\nno [3]\nyes 4\nno 5\nno 6\nno 7\n")) (evil-select-search-module 'evil-search-module 'evil-search) (ert-info ("global use last match if none given, with evil-search") (evil-test-buffer "[n]o 1\nno 2\nno 3\nyes 4\nno 5\nno 6\nno 7\n" ("/yes" [return]) "no 1\nno 2\nno 3\nyes 4\nno 5\nno 6\nno 7\n" (":g//d" [return]) "no 1\nno 2\nno 3\n[n]o 5\nno 6\nno 7\n" (":v//d" [return]) "")) (evil-select-search-module 'evil-search-module 'isearch) (ert-info ("global use last match if none given, with isearch") (evil-test-buffer "[n]o 1\nno 2\nno 3\nisearch 4\nno 5\nno 6\nno 7\n" ("/isearch" [return]) "no 1\nno 2\nno 3\nisearch 4\nno 5\nno 6\nno 7\n" (":g//d" [return]) "no 1\nno 2\nno 3\n[n]o 5\nno 6\nno 7\n" (":v//d" [return]) "")) (ert-info (":global should take into account evil-ex-search-case") (evil-with-both-search-modules (let ((evil-ex-search-case 'sensitive)) (evil-test-buffer "this\nThis\n" (":g/this/d" [return]) "This\n")) (let ((evil-ex-search-case 'insensitive)) (evil-test-buffer "this\nThis\n" (":g/this/d" [return]) "")) (let ((evil-ex-search-case 'smart)) (evil-test-buffer "this\nThis\n" (":g/this/d" [return]) "") (evil-test-buffer "this\nThis\n" (":g/This/d" [return]) "this\n"))))) (ert-deftest evil-test-normal () "Test `evil-ex-normal'." :tags '(evil ex) (let (evil-want-fine-undo) (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4\nline 5\n" (":normal lxIABC" [escape] "AXYZ" [return]) "ABClne 1XY[Z]\nline 2\nline 3\nline 4\nline 5\n" (":3,4normal lxIABC" [escape] "AXYZ" [return]) "ABClne 1XYZ\nline 2\nABClne 3XYZ\nABClne 4XY[Z]\nline 5\n" ("u") "ABClne 1XYZ\nline 2\nl[i]ne 3\nline 4\nline 5\n"))) (ert-deftest evil-test-copy () :tags '(evil ex) "Test `evil-copy'." (ert-info ("Copy to last line") (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5\n" (":2,3copy$") "line1\nline2\nline3\nline4\nline5\nline2\n[l]ine3\n")) (ert-info ("Copy to last incomplete line") (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5" (":2,3copy$") "line1\nline2\nline3\nline4\nline5\nline2\n[l]ine3\n")) (ert-info ("Copy incomplete line to last incomplete line") (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5" (":4,5copy$") "line1\nline2\nline3\nline4\nline5\nline4\n[l]ine5\n")) (ert-info ("Copy to first line") (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5\n" (":2,3copy0") "line2\n[l]ine3\nline1\nline2\nline3\nline4\nline5\n")) (ert-info ("Copy to intermediate line") (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5\n" (":2,4copy2") "line1\nline2\nline2\nline3\n[l]ine4\nline3\nline4\nline5\n")) (ert-info ("Copy to current line") (evil-test-buffer "line1\nline2\nline3\nli[n]e4\nline5\n" (":2,4copy.") "line1\nline2\nline3\nline4\nline2\nline3\n[l]ine4\nline5\n"))) (ert-deftest evil-test-move () :tags '(evil ex) "Test `evil-move'." (ert-info ("Move to last line") (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5\n" (":2,3move$") "line1\nline4\nline5\nline2\n[l]ine3\n")) (ert-info ("Move to last incomplete line") (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5" (":2,3move$") "line1\nline4\nline5\nline2\n[l]ine3\n")) (ert-info ("Move incomplete line to last incomplete line") (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5" (":4,5move$") "line1\nline2\nline3\nline4\n[l]ine5\n")) (ert-info ("Move to first line") (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5\n" (":2,3move0") "line2\n[l]ine3\nline1\nline4\nline5\n")) (ert-info ("Move to intermediate line") (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5\n" (":2,4move2") "line1\nline2\nline3\n[l]ine4\nline5\n")) (ert-info ("Move to other line") (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5\n" (":2,3move4") "line1\nline4\nline2\n[l]ine3\nline5\n")) (ert-info ("Move to current line") (evil-test-buffer "line1\nline2\nline3\nli[n]e4\nline5\n" (":2,4move.") "line1\nline2\nline3\n[l]ine4\nline5\n"))) (ert-deftest evil-test-write () :tags '(evil ex) "Test `evil-write'." (ert-info ("Write open file") (evil-with-temp-file filename "line1\nline2\nline3\n" (evil-test-buffer ((vconcat ":e " filename [return])) "[l]ine1\nline2\nline3\n" ("Galine4\nline5\n" [escape]) "line1\nline2\nline3\nline4\nline5\n" (":w") (file filename "line1\nline2\nline3\nline4\nline5\n")))) (ert-info ("Write current buffer to new file") (let ((filename (make-temp-file "evil-test-write"))) (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5\n" (delete-file filename) ((vconcat ":w " filename [return])) (file filename "line1\nline2\nline3\nline4\nline5\n") (delete-file filename)))) (ert-info ("Write part of a buffer") (let ((filename (make-temp-file "evil-test-write"))) (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5\n" (delete-file filename) ((vconcat ":2,3w " filename [return])) (file filename "line2\nline3\n") (delete-file filename)))) (ert-info ("Appending a file") (let ((filename (make-temp-file "evil-test-write"))) (evil-test-buffer "[l]ine1\nline2\nline3\nline4\nline5\n" (delete-file filename) ((vconcat ":4w " filename [return])) (file filename "line4\n") ((vconcat ":1,2w >>" filename [return])) (file filename "line4\nline1\nline2\n") ((vconcat ":w >> " filename [return])) (file filename "line4\nline1\nline2\nline1\nline2\nline3\nline4\nline5\n") (delete-file filename))))) (ert-deftest evil-test-ex-sort () :tags '(evil ex) "Text ex command :sort `evil-ex-sort`." (ert-info ("Plain sort") (evil-test-buffer "[z]zyy\ntest\ntEst\ntesT\nTEST\ntest\n" (":sort") "[T]EST\ntEst\ntesT\ntest\ntest\nzzyy\n")) (ert-info ("Reverse sort") (evil-test-buffer "[z]zyy\ntest\ntEst\ntesT\nTEST\ntest\n" (":sort!") "[z]zyy\ntest\ntest\ntesT\ntEst\nTEST\n")) (ert-info ("case insensitive") (evil-test-buffer "[z]zyy\ntest\ntEst\ntesT\nTEST\ntest\n" (":sort i") "[t]est\ntEst\ntesT\nTEST\ntest\nzzyy\n")) (ert-info ("unique") (evil-test-buffer "[z]zyy\ntest\ntEst\ntesT\nTEST\ntest\n" (":sort u") "[T]EST\ntEst\ntesT\ntest\nzzyy\n")) (ert-info ("case insensitive and unique") (evil-test-buffer "[z]zyy\ntest\ntEst\ntesT\nTEST\ntest\n" (":sort iu") "[t]est\nzzyy\n"))) ;;; Command line window (ert-deftest evil-test-command-window-ex () "Test command line window for ex commands" (let (evil-ex-history) (evil-test-buffer "[f]oo foo foo" (":s/foo/bar" [return]) "[b]ar foo foo" (":s/foo/baz" [return]) "[b]ar baz foo" ("q:") "s/foo/bar\ns/foo/baz\n[]\n" ("kk:s/bar/quz" [return]) "[s]/foo/quz\ns/foo/baz\n" ("fzrx") "s/foo/qu[x]\ns/foo/baz\n" ([return]) "[b]ar baz qux" (should (equal (car evil-ex-history) "s/foo/qux"))))) (ert-deftest evil-test-command-window-recursive () "Test that recursive command windows shouldn't be allowed" (let ((evil-command-window-height 0)) (evil-test-buffer "[f]oo foo foo" (":s/foo/bar" [return]) ("q:") (should-error (execute-kbd-macro "q:"))))) (ert-deftest evil-test-command-window-noop () "Test that executing a blank command does nothing" (evil-test-buffer "[f]oo foo foo" ("q:") "[]\n" ([return]) "[f]oo foo foo")) (ert-deftest evil-test-command-window-multiple () "Test that multiple command line windows can't be visible at the same time" (let ((evil-command-window-height 0)) (evil-test-buffer "[f]oo foo foo" ("q:") (let ((num-windows (length (window-list)))) (select-window (previous-window)) (execute-kbd-macro "q:") (should (= (length (window-list)) num-windows)))))) (defmacro evil-with-both-search-modules (&rest body) `(mapc (lambda (search-module) (setq evil-search-forward-history nil evil-search-backward-history nil evil-ex-search-history nil) (evil-select-search-module 'evil-search-module search-module) ,@body) '(isearch evil-search))) (ert-deftest evil-test-command-window-search-history () "Test command window with forward and backward search history" (let ((evil-search-module 'isearch)) (evil-test-buffer "[f]oo bar baz qux one two three four" ("/qux" [return]) "foo bar baz [q]ux one two three four" ("/three" [return]) "foo bar baz qux one two [t]hree four" ("?bar" [return]) "foo [b]ar baz qux one two three four" ("/four" [return]) "foo bar baz qux one two three [f]our" ("?baz" [return]) "foo bar [b]az qux one two three four" ("q/") "qux\nthree\nfour\n[]\n" ("k" [return]) "foo bar baz qux one two three [f]our" ("0N") "foo bar baz qux one two three [f]our" ("q?") "bar\nbaz\n[]\n" ("k$rr" [return]) "foo [b]ar baz qux one two three four" (should-error (progn (execute-kbd-macro "q/iNOT THERE") (execute-kbd-macro [return]))) "foo [b]ar baz qux one two three four"))) (ert-deftest evil-test-command-window-search-word () "Test command window history when searching for word under cursor" (let ((evil-search-module 'isearch)) (evil-test-buffer "[f]oo bar foo bar foo" ("**") "foo bar foo bar [f]oo" ("B#") "foo [b]ar foo bar foo" ("q/k" [return]) "foo bar [f]oo bar foo" ("q?k" [return]) "foo [b]ar foo bar foo"))) ;;; Utilities (ert-deftest evil-test-parser () "Test `evil-parser'" (let ((grammar '((number "[0-9]+" #'string-to-number) (plus "\\+" #'intern) (minus "-" #'intern) (operator plus minus) (sign ((\? operator) #'$1)) (signed-number (sign number)) (inc (number #'(lambda (n) (1+ n)))) (expr (number operator number) ("2" #'"1+1")) (epsilon nil)))) (ert-info ("Nothing") (should (equal (evil-parser "1+2" nil grammar t) nil)) (should (equal (evil-parser "1+2" nil grammar) '(nil . "1+2"))) (should (equal (evil-parser "1+2" 'epsilon grammar t) nil)) (should (equal (evil-parser "1+2" 'epsilon grammar) '(nil . "1+2")))) (ert-info ("Strings") (should (equal (evil-parser "1" 'number grammar t) '((string-to-number "1")))) (should (equal (evil-parser "11" 'number grammar) '((string-to-number "11") . "")))) (ert-info ("Sequences") (should (equal (evil-parser "1" '(number) grammar t) '((list (string-to-number "1"))))) (should (equal (evil-parser "1+2" '(number operator number) grammar t) '((list (string-to-number "1") (intern "+") (string-to-number "2")))))) (ert-info ("Symbols") (should (equal (evil-parser "+" 'plus grammar t) '((intern "+")))) (should (equal (evil-parser "+" 'operator grammar t) '((intern "+")))) (should (equal (evil-parser "1" 'number grammar t) '((string-to-number "1"))))) (ert-info ("Whitespace") (should (equal (evil-parser " 1" 'number grammar t) '((string-to-number "1"))))) (ert-info ("One or more") (should (equal (evil-parser "1 2 3" '(+ number) grammar t) '((list (string-to-number "1") (string-to-number "2") (string-to-number "3"))))) (should (equal (evil-parser "1 2 3" '(* number) grammar t) '((list (string-to-number "1") (string-to-number "2") (string-to-number "3"))))) (should (equal (evil-parser "1 2 3" '(\? number) grammar) '((string-to-number "1") . " 2 3"))) (should (equal (evil-parser "1 2 3" '(\? number number) grammar) '((list (string-to-number "1") (string-to-number "2")) . " 3"))) (should (equal (evil-parser "1 2 3" '(number (\? number)) grammar) '((list (string-to-number "1") (string-to-number "2")) . " 3"))) (should (equal (evil-parser "1 2 3" '(number (\? number number)) grammar) '((list (string-to-number "1") (list (string-to-number "2") (string-to-number "3"))) . ""))) (should (equal (evil-parser "1 a 3" '(number (\? number)) grammar) '((list (string-to-number "1") nil) . " a 3"))) (should (equal (evil-parser "1" 'signed-number grammar t t) '((signed-number (sign "") (number "1")) . "")))) (ert-info ("Lookahead") (should (equal (evil-parser "foobar" '("foo" (& "bar")) grammar) '((list "foo") . "bar"))) (should (equal (evil-parser "foobar" '("foo" (! "bar")) grammar) nil)) (should (equal (evil-parser "foobar" '("foo" (& "baz")) grammar) nil)) (should (equal (evil-parser "foobar" '("foo" (! "baz")) grammar) '((list "foo") . "bar")))) (ert-info ("Semantic actions") (should (equal (evil-parser "1" 'inc grammar t) '((funcall (lambda (n) (1+ n)) (string-to-number "1"))))) (should (equal (evil-parser "1+1" 'expr grammar t) '((list (string-to-number "1") (intern "+") (string-to-number "1"))))) (should (equal (evil-parser "2" 'expr grammar t) '((list (string-to-number "1") (intern "+") (string-to-number "1")))))))) (ert-deftest evil-test-delimited-arguments () "Test `evil-delimited-arguments'" :tags '(evil util) (ert-info ("Any number of arguments") (should (equal (evil-delimited-arguments "/a/b/c/") '("a" "b" "c"))) (should (equal (evil-delimited-arguments "/a/b/c") '("a" "b" "c"))) (should (equal (evil-delimited-arguments "/a/b//") '("a" "b" ""))) (should (equal (evil-delimited-arguments "/a///") '("a" "" ""))) (should (equal (evil-delimited-arguments "/a/ ") '("a" " "))) (should (equal (evil-delimited-arguments "/a/") '("a"))) (should (equal (evil-delimited-arguments "//b//") '("" "b" ""))) (should (equal (evil-delimited-arguments "/a//c") '("a" "" "c"))) (should (equal (evil-delimited-arguments "////") '("" "" ""))) (should (equal (evil-delimited-arguments "/") nil)) (should (equal (evil-delimited-arguments " ") nil)) (should (equal (evil-delimited-arguments "") nil))) (ert-info ("Two arguments") (should (equal (evil-delimited-arguments "/a/b/c" 2) '("a" "b/c"))) (should (equal (evil-delimited-arguments "/a/b/" 2) '("a" "b"))) (should (equal (evil-delimited-arguments "/a/b" 2) '("a" "b"))) (should (equal (evil-delimited-arguments "/a//" 2) '("a" ""))) (should (equal (evil-delimited-arguments "/a/ " 2) '("a" " "))) (should (equal (evil-delimited-arguments "/a/" 2) '("a" nil))) (should (equal (evil-delimited-arguments "/a" 2) '("a" nil))) (should (equal (evil-delimited-arguments " " 2) '(nil nil))) (should (equal (evil-delimited-arguments "" 2) '(nil nil)))) (ert-info ("One argument") (should (equal (evil-delimited-arguments "/a/b/c" 1) '("a/b/c"))) (should (equal (evil-delimited-arguments "/a/ " 1) '("a"))) (should (equal (evil-delimited-arguments "/a/" 1) '("a"))) (should (equal (evil-delimited-arguments "/a" 1) '("a"))) (should (equal (evil-delimited-arguments "/" 1) '(nil))) (should (equal (evil-delimited-arguments " " 1) '(nil))) (should (equal (evil-delimited-arguments "" 1) '(nil)))) (ert-info ("Zero arguments") (should (equal (evil-delimited-arguments "/a" 0) nil)) (should (equal (evil-delimited-arguments "/" 0) nil)) (should (equal (evil-delimited-arguments " " 0) nil)) (should (equal (evil-delimited-arguments "" 0) nil)))) (ert-deftest evil-test-concat-charsets () "Test `evil-concat-charsets'" :tags '(evil util) (ert-info ("Bracket") (should (equal (evil-concat-charsets "abc" "]def") "]abcdef"))) (ert-info ("Complement") (should (equal (evil-concat-charsets "^abc" "def") "^abcdef")) (should (equal (evil-concat-charsets "^abc" "^def") "^abcdef"))) (ert-info ("Hyphen") (should (equal (evil-concat-charsets "abc" "-def") "-abcdef")) (should (equal (evil-concat-charsets "^abc" "-def") "^-abcdef"))) (ert-info ("Newline") (should (equal (evil-concat-charsets "^ \t\r\n" "[:word:]_") "^ \t\r\n[:word:]_")))) (ert-deftest evil-test-properties () "Test `evil-get-property' and `evil-put-property'" :tags '(evil util) (let (alist) (ert-info ("Set properties") (evil-put-property 'alist 'wibble :foo t) (should (equal alist '((wibble . (:foo t))))) (evil-put-property 'alist 'wibble :bar nil) (should (equal alist '((wibble . (:foo t :bar nil))))) (evil-put-property 'alist 'wobble :foo nil :bar nil :baz t) (should (equal alist '((wobble . (:foo nil :bar nil :baz t)) (wibble . (:foo t :bar nil)))))) (ert-info ("Get properties") (should (evil-get-property alist 'wibble :foo)) (should-not (evil-get-property alist 'wibble :bar)) (should-not (evil-get-property alist 'wobble :foo)) (should-not (evil-get-property alist 'wibble :baz)) (should (equal (evil-get-property alist t :foo) '((wibble . t) (wobble . nil)))) (should (equal (evil-get-property alist t :bar) '((wibble . nil) (wobble . nil)))) (should (equal (evil-get-property alist t :baz) '((wobble . t))))))) (ert-deftest evil-test-filter-list () "Test `evil-filter-list'" :tags '(evil util) (ert-info ("Return filtered list") (should (equal (evil-filter-list #'null '(nil)) nil)) (should (equal (evil-filter-list #'null '(nil 1)) '(1))) (should (equal (evil-filter-list #'null '(nil 1 2 nil)) '(1 2))) (should (equal (evil-filter-list #'null '(nil nil 1)) '(1))) (should (equal (evil-filter-list #'null '(nil 1 nil 2 nil 3)) '(1 2 3)))) (ert-info ("Remove matches by side-effect when possible") (let (list) (setq list '(1 nil)) (evil-filter-list #'null list) (should (equal list '(1))) (setq list '(1 nil nil)) (evil-filter-list #'null list) (should (equal list '(1))) (setq list '(1 nil nil 2)) (evil-filter-list #'null list) (should (equal list '(1 2))) (setq list '(1 nil 2 nil 3)) (evil-filter-list #'null list) (should (equal list '(1 2 3)))))) (ert-deftest evil-test-concat-lists () "Test `evil-concat-lists' and `evil-concat-alists'" :tags '(evil util) (ert-info ("Remove duplicates across lists") (should (equal (evil-concat-lists nil '(a b) '(b c)) '(a b c)))) (ert-info ("Remove duplicates inside lists") (should (equal (evil-concat-lists '(a a b) nil '(b c) nil) '(a b c)))) (ert-info ("Remove duplicate associations") (should (equal (evil-concat-alists '((a . b)) '((a . c))) '((a . c)))) (should-not (equal (evil-concat-lists '((a . b)) '((a . c))) '((a . b)))))) (ert-deftest evil-test-sort () "Test `evil-sort' and `evil-swap'" :tags '(evil util) (let (a b c d) (ert-info ("Two elements") (setq a 2 b 1) (evil-sort a b) (should (= a 1)) (should (= b 2)) (evil-swap a b) (should (= a 2)) (should (= b 1))) (ert-info ("Three elements") (setq a 3 b 1 c 2) (evil-sort a b c) (should (= a 1)) (should (= b 2)) (should (= c 3))) (ert-info ("Four elements") (setq a 4 b 3 c 2 d 1) (evil-sort a b c d) (should (= a 1)) (should (= b 2)) (should (= c 3)) (should (= d 4))))) (ert-deftest evil-test-read-key () "Test `evil-read-key'" :tags '(evil util) (let ((unread-command-events '(?A))) (ert-info ("Prevent downcasing in `this-command-keys'") (should (eq (evil-read-key) ?A)) (should (equal (this-command-keys) "A"))))) (ert-deftest evil-test-extract-count () "Test `evil-extract-count'" :tags '(evil util) (evil-test-buffer (ert-info ("Exact without count") (should (equal (evil-extract-count "x") (list nil 'evil-delete-char "x" nil))) (should (equal (evil-extract-count "g0") (list nil 'evil-beginning-of-visual-line "g0" nil)))) (ert-info ("Exact with count") (should (equal (evil-extract-count "420x") (list 420 'evil-delete-char "x" nil))) (should (equal (evil-extract-count (vconcat "420" [M-right])) (list 420 (key-binding [M-right]) (vconcat [M-right]) nil))) (should (equal (evil-extract-count "2301g0") (list 2301 'evil-beginning-of-visual-line "g0" nil)))) (ert-info ("Extra elements without count") (should (equal (evil-extract-count "xAB") (list nil 'evil-delete-char "x" "AB"))) (should (equal (evil-extract-count "g0CD") (list nil 'evil-beginning-of-visual-line "g0" "CD")))) (ert-info ("Extra elements with count") (should (equal (evil-extract-count "420xAB") (list 420 'evil-delete-char "x" "AB"))) (should (equal (evil-extract-count "2301g0CD") (list 2301 'evil-beginning-of-visual-line "g0" "CD")))) (ert-info ("Exact \"0\" count") (should (equal (evil-extract-count "0") (list nil 'evil-digit-argument-or-evil-beginning-of-line "0" nil)))) (ert-info ("Extra elements and \"0\"") (should (equal (evil-extract-count "0XY") (list nil 'evil-digit-argument-or-evil-beginning-of-line "0" "XY")))) (ert-info ("Count only") (should-error (evil-extract-count "1230"))) (ert-info ("Unknown command") (should-error (evil-extract-count "°")) (should-error (evil-extract-count "12°"))))) (ert-deftest evil-transform-vim-style-regexp () "Test `evil-transform-vim-style-regexp'" (dolist (repl '((?s . "[[:space:]]") (?S . "[^[:space:]]") (?d . "[[:digit:]]") (?D . "[^[:digit:]]") (?x . "[[:xdigit:]]") (?X . "[^[:xdigit:]]") (?o . "[0-7]") (?O . "[^0-7]") (?a . "[[:alpha:]]") (?A . "[^[:alpha:]]") (?l . "[a-z]") (?L . "[^a-z]") (?u . "[A-Z]") (?U . "[^A-Z]") (?y . "\\s") (?Y . "\\S") (?w . "\\w") (?W . "\\W"))) (ert-info ((format "Test transform from '\\%c' to '%s'" (car repl) (cdr repl))) (should (equal (evil-transform-vim-style-regexp (concat "xxx\\" (char-to-string (car repl)) "\\" (char-to-string (car repl)) "\\\\" (char-to-string (car repl)) "\\\\\\" (char-to-string (car repl)) "yyy")) (concat "xxx" (cdr repl) (cdr repl) "\\\\" (char-to-string (car repl)) "\\\\" (cdr repl) "yyy")))))) ;;; Advice (ert-deftest evil-test-eval-last-sexp () "Test advised `evil-last-sexp'" :tags '(evil advice) (ert-info ("Normal state") (evil-test-buffer "(+ 1 (+ 2 3[)])" ("1" (kbd "C-x C-e")) "(+ 1 (+ 2 35[)])")) (ert-info ("Insert state") (evil-test-buffer "(+ 1 (+ 2 3[)])" ("i" (kbd "C-u") (kbd "C-x C-e") [escape]) "(+ 1 (+ 2 3[3]))")) (ert-info ("Emacs state") (evil-test-buffer "(+ 1 (+ 2 3[)])" ((kbd "C-z") (kbd "C-u") (kbd "C-x C-e")) "(+ 1 (+ 2 33[)])"))) ;;; ESC (ert-deftest evil-test-esc-count () "Test if prefix-argument is transfered for key sequences with meta-key" :tags '(evil esc) (unless noninteractive (ert-info ("Test M-") (evil-test-buffer "[A]BC DEF GHI JKL MNO" ("3" (kbd "ESC ")) "ABC DEF GHI[ ]JKL MNO")) (ert-info ("Test shell-command") (evil-test-buffer "[A]BC DEF GHI JKL MNO" ("1" (kbd "ESC !") "echo TEST" [return]) "[T]EST\nABC DEF GHI JKL MNO")))) (when (or evil-tests-profiler evil-tests-run) (evil-tests-initialize)) (ert-deftest evil-test-black-hole-register () :tags '(evil) (ert-info ("Test \"_ on delete word") (evil-test-buffer "[E]vil evil is awesome." ("dw\"_dwP") "Evil[ ]is awesome.")) (ert-info ("Test \"_ on delete line") (evil-test-buffer "[T]his line is a keeper!\nThis line is not." ("dd\"_ddP") "[T]his line is a keeper!")) (ert-info ("Test \"_ on delete region") (evil-test-buffer "!\nThis line is not." ("d\gg\"_dGP") "This region is a keepe[r]"))) (ert-deftest evil-test-pasteable-macros () "Test if we can yank and paste macros containing " :tags '(evil) (ert-info ("Execute yanked macro") (evil-test-buffer "[i]foo\e" ("\"qd$@q\"qp" "fooifoo\e"))) (ert-info ("Paste recorded marco") (evil-test-buffer "" (evil-set-register ?q (vconcat "ifoo" [escape])) ("@q\"qp") "fooifoo\e"))) (ert-deftest evil-test-forward-symbol () :tags '(evil) (ert-info ("Test symbol deletion") (evil-test-buffer "(test [t]his (hello there) with dao)" ("dao") "(test [(]hello there) with dao)")) (ert-info ("Test symbol motion") (evil-test-buffer "(test[ ](hello there) with dao)" (should (eq 0 (forward-evil-symbol 1))) "(test ([h]ello there) with dao)" (should (eq 0 (forward-evil-symbol 1))) "(test (hello[ ]there) with dao)")) (ert-info ("Test dio on whitespace") (evil-test-buffer "(test[ ]dio with whitespace)" ("dio") "(test[d]io with whitespace)")) (ert-info ("Test dao/dio with empty lines") (evil-test-buffer "there are two lines in this file\n[\n]and some whitespace between them" ("dao") "there are two lines in this file\n[a]nd some whitespace between them") (evil-test-buffer "here are another two lines\n[\n]with a blank line between them" ("dio") "here are another two lines\n[w]ith a blank line between them")) (ert-info ("Test dao/dio with empty lines and punctuation") (evil-test-buffer "These two lines \n[\n]!have punctuation on them" ("dao") "These two lines \n[!]have punctuation on them"))) (ert-deftest evil-test-jump () :tags '(evil jumps) (let ((evil--jumps-buffer-targets "\\*\\(new\\|scratch\\|test\\)\\*")) (ert-info ("Test jumping backward and forward in a single buffer") (evil-test-buffer "[z] z z z z z z z z z" ("/z" [return]) "z [z] z z z z z z z z" ("nnnn") "z z z z z [z] z z z z" ("\C-o") "z z z z [z] z z z z z" ("\C-o") "z z z [z] z z z z z z" ("\C-i\C-i") "z z z z z [z] z z z z")) (ert-info ("Test jumping backward and forward with counts") (evil-test-buffer "[z] z z z z z z z z z" ("/z" [return] "nnnn") "z z z z z [z] z z z z" ("3\C-o") "z z [z] z z z z z z z" ("2\C-i") "z z z z [z] z z z z z" )) (ert-info ("Jump list branches off when new jump is set") (evil-test-buffer "[z] z z z z z z z" ("/z" [return] "nnnn4\C-o") ;; adds a bunch of jumps after the 2nd z "z [z] z z z z z z" ("/z" [return]) ;; sets a new jump, list should be reset "z z [z] z z z z z" ("\C-o") "z [z] z z z z z z" ("3\C-i") ;; even after jumping forward 3 times it can't get past the 3rd z "z z [z] z z z z z")))) (ert-deftest evil-test-jump-buffers () :tags '(evil jums) (skip-unless nil) (ert-info ("Test jumping backward and forward across buffers") (evil-test-buffer "[z] z z z z z z z z z" (":new" [return] "inew buffer" [escape]) "new buffe[r]" ("\C-o") "[z] z z z z z z z z z" ("\C-i") "new buffe[r]"))) (ert-deftest evil-test-abbrev-expand () :tags '(evil abbrev) (ert-info ("Test abbrev expansion on insert state exit") (define-abbrev-table 'global-abbrev-table '(("undef" "undefined"))) ;; add global abbrev (evil-test-buffer "foo unde[f] bar" ("a" [escape]) "foo undefine[d] bar") ;; 'undef' should be expanded (evil-test-buffer "fo[o] undef bar" ("a" [escape]) "fo[o] undef bar") ;; 'foo' shouldn't be expanded, it's not an abbrev (kill-all-abbrevs) ;; remove abbrevs (evil-test-buffer "foo unde[f] bar" ("a" [escape]) "foo unde[f] bar") ;; 'undef' is not an abbrev, shouldn't be expanded (setq abbrevs-changed nil))) (ert-deftest evil-test-text-object-macro () :tags '(evil abbrev) (ert-info ("Test pipe character and other delimiters as object delimiters") ;; This is the macro that broke after pull #747. (defmacro evil-test-define-and-bind-text-object (name key start-regex end-regex) (let ((inner-name (make-symbol (concat "evil-inner-" name))) (outer-name (make-symbol (concat "evil-a-" name)))) `(progn (evil-define-text-object ,inner-name (count &optional beg end type) (evil-select-paren ,start-regex ,end-regex beg end type count nil)) (evil-define-text-object ,outer-name (count &optional beg end type) (evil-select-paren ,start-regex ,end-regex beg end type count t)) (define-key evil-inner-text-objects-map ,key #',inner-name) (define-key evil-outer-text-objects-map ,key #',outer-name)))) (evil-test-define-and-bind-text-object "pipe" "|" "|" "|") (evil-test-define-and-bind-text-object "rackety" "#" "#|" "|#") (evil-test-buffer "#|this i[s] a test #|with rackety|# multiline and nestable comments|#" ("vi#") "#||#") (evil-test-buffer "| foo | aoe[u] | bar |" ("vi|") "| foo |< aoeu >| bar |" ("a|") "| foo <| aoeu |> bar |" ("a|") "<| foo | aoeu | bar |>") (evil-test-buffer "| foo | aoe[u] | bar |" ("ci|testing" [escape]) "| foo |testing| bar |"))) (ert-deftest evil-test-undo-kbd-macro () "Test if evil can undo the changes made by a keyboard macro when an error stops the execution of the macro" :tags '(evil undo kbd-macro) (ert-info ("When kbd-macro goes to the end of buffer") (evil-test-buffer "[l]ine 1\nline 2\nline 3\nline 4" (evil-set-register ?q "jdd") ("jdd") (should-error (execute-kbd-macro "2@q")) ("uu") "line 1\n[l]ine 2\nline 3\nline 4")) (ert-info ("When kbd-macro goes to the end of line") (evil-test-buffer "[f]ofof" (evil-set-register ?q "lx") ("lx") (should-error (execute-kbd-macro "2@q")) ("uu") "f[o]fof")) (ert-info ("When kbd-macro goes to the beginning of buffer") (evil-test-buffer "line 1\nline 2\n[l]ine 3" (evil-set-register ?q "kx") ("kx") (should-error (execute-kbd-macro "2@q")) ("uu") "line 1\n[l]ine 2\nline 3"))) (ert-deftest evil-test-visual-update-x-selection () "Test `evil-visual-update-x-selection'." :tags '(evil) (ert-info ("Buffer argument isn't a live buffer") ; create buffer in normal mode, so we don't try to actually copy anything to ; the X selection. (let ((buf (evil-test-buffer-from-string "foobar"))) (kill-buffer buf) ; should not raise an "Selecting deleted buffer" error (evil-visual-update-x-selection buf)))) ;;; Core (ert-deftest evil-test-initial-state () "Test `evil-initial-state'" :tags '(evil core) (define-derived-mode test-1-mode prog-mode "Test1") (define-derived-mode test-2-mode test-1-mode "Test2") (evil-set-initial-state 'test-1-mode 'insert) (ert-info ("Check default state") (should (eq (evil-initial-state 'prog-mode 'normal) 'normal))) (ert-info ("Basic functionality 1") (should (eq (evil-initial-state 'test-1-mode) 'insert))) (ert-info ("Basic functionality 2") (evil-test-buffer "abc\ndef\n" (test-1-mode) (should (eq evil-state 'insert)))) (ert-info ("Inherit initial state from a parent") (evil-test-buffer "abc\ndef\n" (test-2-mode) (should (eq evil-state 'insert)))) (evil-set-initial-state 'test-1-mode nil) (ert-info ("Check for inheritance loops") (evil-test-buffer "abc\ndef\n" (unwind-protect (let ((major-mode 'test-2-mode)) (put 'test-1-mode 'derived-mode-parent 'test-2-mode) ;; avoid triggering all of the hooks here, some of which might get ;; caught in loops depending on the environment. settings major-mode ;; is sufficient for `evil-initial-state-for-buffer' to work. (should-error (evil-initial-state-for-buffer))) (put 'test-1-mode 'derived-mode-parent 'prog-mode)))) (defalias 'test-1-alias-mode 'test-1-mode) (define-derived-mode test-3-mode test-1-alias-mode "Test3") (evil-set-initial-state 'test-1-mode 'insert) (ert-info ("Check inheritance from major mode aliases") "abc\ndef\n" (test-3-mode) (should (eq evil-state 'insert)))) (provide 'evil-tests) ;;; evil-tests.el ends here evil-1.12.17/evil-types.el000066400000000000000000000367531360703323200152620ustar00rootroot00000000000000;;; evil-types.el --- Type system ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . ;;; Commentary: ;; A type defines a transformation on a pair of buffer positions. ;; Types are used by Visual state (character/line/block selection) ;; and Operator-Pending state (character/line/block motions). ;; ;; The basic transformation is "expansion". For example, the `line' ;; type "expands" a pair of positions to whole lines by moving the ;; first position to the beginning of the line and the last position ;; to the end of the line. That expanded selection is what the rest ;; of Emacs sees and acts on. ;; ;; An optional transformation is "contraction", which is the opposite ;; of expansion. If the transformation is one-to-one, expansion ;; followed by contraction always returns the original range. ;; (The `line' type is not one-to-one, as it may expand multiple ;; positions to the same lines.) ;; ;; Another optional transformation is "normalization", which takes ;; two unexpanded positions and adjusts them before expansion. ;; This is useful for cleaning up "invalid" positions. ;; ;; Types are defined at the end of this file using the macro ;; `evil-define-type'. (require 'evil-common) (require 'evil-macros) ;;; Code: ;;; Type definitions (evil-define-type exclusive "Return the positions unchanged, with some exceptions. If the end position is at the beginning of a line, then: * If the beginning position is at or before the first non-blank character on the line, return `line' (expanded). * Otherwise, move the end position to the end of the previous line and return `inclusive' (expanded)." :normalize (lambda (beg end) (cond ((progn (goto-char end) (and (/= beg end) (bolp))) (setq end (max beg (1- end))) (cond ((progn (goto-char beg) (looking-back "^[ \f\t\v]*" (line-beginning-position))) (evil-expand beg end 'line)) (t (unless evil-cross-lines (setq end (max beg (1- end)))) (evil-expand beg end 'inclusive)))) (t (evil-range beg end)))) :string (lambda (beg end) (let ((width (- end beg))) (format "%s character%s" width (if (= width 1) "" "s"))))) (evil-define-type inclusive "Include the character under point. If the end position is at the beginning of a line or the end of a line and `evil-want-visual-char-semi-exclusive', then: * If in visual state return `exclusive' (expanded)." :expand (lambda (beg end) (if (and evil-want-visual-char-semi-exclusive (evil-visual-state-p) (< beg end) (save-excursion (goto-char end) (or (bolp) (eolp)))) (evil-range beg end 'exclusive) (evil-range beg (1+ end)))) :contract (lambda (beg end) (evil-range beg (max beg (1- end)))) :normalize (lambda (beg end) (goto-char end) (when (eq (char-after) ?\n) (setq end (max beg (1- end)))) (evil-range beg end)) :string (lambda (beg end) (let ((width (- end beg))) (format "%s character%s" width (if (= width 1) "" "s"))))) (evil-define-type line "Include whole lines." :one-to-one nil :expand (lambda (beg end) (evil-range (progn (goto-char beg) (min (line-beginning-position) (progn ;; move to beginning of line as displayed (evil-move-beginning-of-line) (line-beginning-position)))) (progn (goto-char end) (max (line-beginning-position 2) (progn ;; move to end of line as displayed (evil-move-end-of-line) (line-beginning-position 2)))))) :contract (lambda (beg end) (evil-range beg (max beg (1- end)))) :string (lambda (beg end) (let ((height (count-lines beg end))) (format "%s line%s" height (if (= height 1) "" "s"))))) (evil-define-type screen-line "Include whole lines, being aware of `visual-line-mode' when `evil-respect-visual-line-mode' is non-nil." :one-to-one nil :expand (lambda (beg end) (if (or (not evil-respect-visual-line-mode) (not visual-line-mode)) (evil-line-expand beg end) (evil-range (progn (goto-char beg) (save-excursion (beginning-of-visual-line))) (progn (goto-char end) (save-excursion ;; `beginning-of-visual-line' reverts to the beginning of the ;; last visual line if the end of the last line is the end of ;; the buffer. This would prevent selecting the last screen ;; line. (if (= (line-beginning-position 2) (point-max)) (point-max) (beginning-of-visual-line 2))))))) :contract (lambda (beg end) (evil-range beg (max beg (1- end)))) :string (lambda (beg end) (let ((height (count-screen-lines beg end))) (format "%s screen line%s" height (if (= height 1) "" "s"))))) (evil-define-type block "Like `inclusive', but for rectangles: the last column is included." :expand (lambda (beg end &rest properties) (let ((beg-col (evil-column beg)) (end-col (evil-column end)) (corner (plist-get properties :corner))) ;; Since blocks are implemented as a pair of buffer ;; positions, expansion is restricted to what the buffer ;; allows. In the case of a one-column block, there are ;; two ways to expand it (either move the upper corner ;; beyond the lower corner, or the lower beyond the ;; upper), so try out both possibilities when ;; encountering the end of the line. (cond ((= beg-col end-col) (goto-char end) (cond ((eolp) (goto-char beg) (if (eolp) (evil-range beg end) (evil-range (1+ beg) end))) ((memq corner '(lower-right upper-right right)) (evil-range (1+ beg) end)) (t (evil-range beg (1+ end))))) ((< beg-col end-col) (goto-char end) (if (eolp) (evil-range beg end) (evil-range beg (1+ end)))) (t (goto-char beg) (if (eolp) (evil-range beg end) (evil-range (1+ beg) end)))))) :contract (lambda (beg end) (let ((beg-col (evil-column beg)) (end-col (evil-column end))) (if (> beg-col end-col) (evil-range (1- beg) end) (evil-range beg (max beg (1- end)))))) :string (lambda (beg end) (let ((height (count-lines beg (progn (goto-char end) (if (and (bolp) (not (eobp))) (1+ end) end)))) (width (abs (- (evil-column beg) (evil-column end))))) (format "%s row%s and %s column%s" height (if (= height 1) "" "s") width (if (= width 1) "" "s")))) :rotate (lambda (beg end &rest properties) "Rotate block according to :corner property. :corner can be one of `upper-left',``upper-right', `lower-left' and `lower-right'." (let ((left (evil-column beg)) (right (evil-column end)) (corner (or (plist-get properties :corner) 'upper-left))) (evil-sort left right) (goto-char beg) (if (memq corner '(upper-right lower-left)) (move-to-column right) (move-to-column left)) (setq beg (point)) (goto-char end) (if (memq corner '(upper-right lower-left)) (move-to-column left) (move-to-column right)) (setq end (point)) (setq properties (plist-put properties :corner corner)) (apply #'evil-range beg end properties)))) (evil-define-type rectangle "Like `exclusive', but for rectangles: the last column is excluded." :expand (lambda (beg end) ;; select at least one column (if (= (evil-column beg) (evil-column end)) (evil-expand beg end 'block) (evil-range beg end 'block)))) ;;; Standard interactive codes (evil-define-interactive-code "*" "Signal error if the buffer is read-only." (when buffer-read-only (signal 'buffer-read-only nil))) (evil-define-interactive-code "b" (prompt) "Name of existing buffer." (list (read-buffer prompt (current-buffer) t))) (evil-define-interactive-code "c" "Read character." (list (read-char))) (evil-define-interactive-code "p" "Prefix argument converted to number." (list (prefix-numeric-value current-prefix-arg))) (evil-define-interactive-code "P" "Prefix argument in raw form." (list current-prefix-arg)) ;;; Custom interactive codes (evil-define-interactive-code "" "Count." (list (when current-prefix-arg (prefix-numeric-value current-prefix-arg)))) (evil-define-interactive-code "" "Count, but only in visual state. This should be used by an operator taking a count. In normal state the count should not be handled by the operator but by the motion that defines the operator's range. In visual state the range is specified by the visual region and the count is not used at all. Thus in the case the operator may use the count directly." (list (when (and (evil-visual-state-p) current-prefix-arg) (prefix-numeric-value current-prefix-arg)))) (evil-define-interactive-code "" "Character read through `evil-read-key'." (list (if (evil-operator-state-p) (evil-without-restriction (evil-read-key)) (evil-read-key)))) (evil-define-interactive-code "" "Untyped motion range (BEG END)." (evil-operator-range)) (evil-define-interactive-code "" "Typed motion range (BEG END TYPE)." (evil-operator-range t)) (evil-define-interactive-code "" "Typed motion range of visual range(BEG END TYPE). If visual state is inactive then those values are nil." (if (evil-visual-state-p) (let ((range (evil-visual-range))) (list (car range) (cadr range) (evil-type range))) (list nil nil nil))) (evil-define-interactive-code "" "Current register." (list evil-this-register)) (evil-define-interactive-code "" "Current yank-handler." (list (evil-yank-handler))) (evil-define-interactive-code "" "Ex argument." :ex-arg t (list (when (evil-ex-p) evil-ex-argument))) (evil-define-interactive-code "" "Ex file argument." :ex-arg file (list (when (evil-ex-p) (evil-ex-file-arg)))) (evil-define-interactive-code "" "Ex buffer argument." :ex-arg buffer (list (when (evil-ex-p) evil-ex-argument))) (evil-define-interactive-code "" "Ex shell command argument." :ex-arg shell (list (when (evil-ex-p) evil-ex-argument))) (evil-define-interactive-code "" "Ex file or shell command argument." :ex-arg file-or-shell (list (when (evil-ex-p) evil-ex-argument))) (evil-define-interactive-code "" "Ex symbolic argument." :ex-arg sym (list (when (and (evil-ex-p) evil-ex-argument) (intern evil-ex-argument)))) (evil-define-interactive-code "" "Ex line number." (list (and (evil-ex-p) (let ((expr (evil-ex-parse evil-ex-argument))) (if (eq (car expr) 'evil-goto-line) (save-excursion (goto-char evil-ex-point) (eval (cadr expr))) (user-error "Invalid address")))))) (evil-define-interactive-code "" "Ex bang argument." :ex-bang t (list (when (evil-ex-p) evil-ex-bang))) (evil-define-interactive-code "" "Ex delimited argument." (when (evil-ex-p) (evil-delimited-arguments evil-ex-argument))) (evil-define-interactive-code "" "Ex global argument." (when (evil-ex-p) (evil-ex-parse-global evil-ex-argument))) (evil-define-interactive-code "" "Ex substitution argument." :ex-arg substitution (when (evil-ex-p) (evil-ex-get-substitute-info evil-ex-argument t))) (evil-define-interactive-code "" "Ex register and count argument, both optional. Can be used for commands such as :delete [REGISTER] [COUNT] where the command can be called with either zero, one or two arguments. When the argument is one, if it's numeric it's treated as a COUNT, otherwise - REGISTER" (when (evil-ex-p) (evil-ex-get-optional-register-and-count evil-ex-argument))) (defun evil-ex-get-optional-register-and-count (string) "Parse STRING as an ex arg with both optional REGISTER and COUNT. Returns a list (REGISTER COUNT)." (let* ((split-args (split-string (or string ""))) (arg-count (length split-args)) (arg0 (car split-args)) (arg1 (cadr split-args)) (number-regex "^-?[1-9][0-9]*$") (register nil) (count nil)) (cond ;; :command REGISTER or :command COUNT ((= arg-count 1) (if (string-match-p number-regex arg0) (setq count arg0) (setq register arg0))) ;; :command REGISTER COUNT ((eq arg-count 2) (setq register arg0 count arg1)) ;; more than 2 args aren't allowed ((> arg-count 2) (user-error "Invalid use"))) ;; if register is given, check it's valid (when register (unless (= (length register) 1) (user-error "Invalid register")) (setq register (string-to-char register))) ;; if count is given, check it's valid (when count (unless (string-match-p number-regex count) (user-error "Invalid count")) (setq count (string-to-number count)) (unless (> count 0) (user-error "Invalid count"))) (list register count))) (provide 'evil-types) ;;; evil-types.el ends here evil-1.12.17/evil-vars.el000066400000000000000000001725431360703323200150670ustar00rootroot00000000000000;;; evil-vars.el --- Settings and variables ;; Author: Vegard Øye ;; Maintainer: Vegard Øye ;; Version: 1.12.17 ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . ;;; Code: (declare-function evil-add-command-properties "evil-common" (command &rest properties)) (declare-function evil-update-insert-state-bindings "evil-maps" (&optional _option-name remove force)) ;;; Hooks (defvar evil-after-load-hook nil "Functions to be run when loading of Evil is finished. This hook can be used the execute some initialization routines when Evil is completely loaded.") (defcustom evil-goto-definition-functions '(evil-goto-definition-imenu evil-goto-definition-semantic evil-goto-definition-xref evil-goto-definition-search) "List of functions run until success by `evil-goto-definition'." :type 'hook :group 'evil) ;;; Initialization (defvar evil-pending-custom-initialize nil "A list of pending initializations for custom variables. Each element is a triple (FUNC VAR VALUE). When Evil is completely loaded then the functions (funcall FUNC VAR VALUE) is called for each element. FUNC should be a function suitable for the :initialize property of `defcustom'.") (defun evil-custom-initialize-pending-reset (var value) "Add a pending customization with `custom-initialize-reset'." (push (list 'custom-initialize-reset var value) evil-pending-custom-initialize)) (defun evil-run-pending-custom-initialize () "Executes the pending initializations. See `evil-pending-custom-initialize'." (dolist (init evil-pending-custom-initialize) (apply (car init) (cdr init))) (remove-hook 'evil-after-load-hook 'evil-run-pending-custom-initialize)) (add-hook 'evil-after-load-hook 'evil-run-pending-custom-initialize) ;;; Setters (defun evil-set-toggle-key (key) "Set `evil-toggle-key' to KEY. KEY must be readable by `read-kbd-macro'." (let ((old-key (read-kbd-macro (if (boundp 'evil-toggle-key) evil-toggle-key "C-z"))) (key (read-kbd-macro key))) (with-no-warnings (dolist (pair '((evil-motion-state-map evil-emacs-state) (evil-insert-state-map evil-emacs-state) (evil-emacs-state-map evil-exit-emacs-state))) (when (boundp (car pair)) (let ((map (symbol-value (car pair))) (fun (cadr pair))) (when (keymapp map) (define-key map key fun) (define-key map old-key nil)))))))) (defun evil-set-custom-state-maps (var pending-var key make newlist) "Changes the list of special keymaps. VAR is the variable containing the list of keymaps. PENDING-VAR is the variable containing the list of the currently pending keymaps. KEY the special symbol to be stored in the keymaps. MAKE the creation function of the special keymaps. NEWLIST the list of new special keymaps." (set-default pending-var newlist) (when (default-boundp var) (dolist (map (default-value var)) (when (and (boundp (car map)) (keymapp (default-value (car map)))) (define-key (default-value (car map)) (vector key) nil)))) (set-default var newlist) (evil-update-pending-maps)) (defun evil-update-pending-maps (&optional file) "Tries to set pending special keymaps. This function should be called from an `after-load-functions' hook." (let ((maps '((evil-make-overriding-map . evil-pending-overriding-maps) (evil-make-intercept-map . evil-pending-intercept-maps)))) (while maps (let* ((map (pop maps)) (make (car map)) (pending-var (cdr map)) (pending (symbol-value pending-var)) newlist) (while pending (let* ((map (pop pending)) (kmap (and (boundp (car map)) (keymapp (symbol-value (car map))) (symbol-value (car map)))) (state (cdr map))) (if kmap (funcall make kmap state) (push map newlist)))) (set-default pending-var newlist))))) (defun evil-set-visual-newline-commands (var value) "Set the value of `evil-visual-newline-commands'. Setting this variable changes the properties of the appropriate commands." (with-no-warnings (when (default-boundp var) (dolist (cmd (default-value var)) (evil-set-command-property cmd :exclude-newline nil))) (set-default var value) (dolist (cmd (default-value var)) (evil-set-command-property cmd :exclude-newline t)))) (defun evil-set-custom-motions (var values) "Sets the list of motion commands." (with-no-warnings (when (default-boundp var) (dolist (motion (default-value var)) (evil-add-command-properties motion :keep-visual nil :repeat nil))) (set-default var values) (mapc #'evil-declare-motion (default-value var)))) ;;; Customization group (defgroup evil nil "Extensible vi layer." :group 'emulations :prefix 'evil-) (defcustom evil-auto-indent t "Whether to auto-indent when opening lines." :type 'boolean :group 'evil) (make-variable-buffer-local 'evil-auto-indent) (defcustom evil-shift-width 4 "The offset used by \\\\[evil-shift-right] \ and \\[evil-shift-left]." :type 'integer :group 'evil) (make-variable-buffer-local 'evil-shift-width) (defcustom evil-shift-round t "Whether \\\\[evil-shift-right] \ and \\[evil-shift-left] round to the nearest multiple \ of `evil-shift-width'." :type 'boolean :group 'evil) (make-variable-buffer-local 'evil-shift-round) (defcustom evil-indent-convert-tabs t "If non-nil `evil-indent' converts between leading tabs and spaces. Whether tabs are converted to spaces or vice versa depends on the value of `indent-tabs-mode'." :type 'boolean :group 'evil) (defcustom evil-default-cursor t "The default cursor. May be a cursor type as per `cursor-type', a color string as passed to `set-cursor-color', a zero-argument function for changing the cursor, or a list of the above." :type '(set symbol (cons symbol symbol) string function) :group 'evil) (defvar evil-force-cursor nil "Overwrite the current states default cursor.") (defcustom evil-repeat-move-cursor t "Whether \"\\\\[evil-repeat]\" \ moves the cursor." :type 'boolean :group 'evil) (defcustom evil-cross-lines nil "Whether motions may cross newlines." :type 'boolean :group 'evil) (defcustom evil-backspace-join-lines t "Whether backward delete in insert state may join lines." :type 'boolean :group 'evil) (defcustom evil-move-cursor-back t "Whether the cursor is moved backwards when exiting Insert state." :type 'boolean :group 'evil) (defcustom evil-move-beyond-eol nil "Whether the cursor is allowed to move past the last character of \ a line." :type 'boolean :group 'evil) (defcustom evil-respect-visual-line-mode nil "Whether movement commands respect `visual-line-mode'. This variable must be set before Evil is loaded." :type 'boolean :group 'evil) (defcustom evil-repeat-find-to-skip-next t "Whether a repeat of t or T should skip an adjacent character." :type 'boolean :group 'evil) (defcustom evil-kbd-macro-suppress-motion-error nil "Whether left/right motions signal errors during keyboard-macro definition. If this variable is set to non-nil, then the function `evil-forward-char' and `evil-backward-char' do not signal `end-of-line' or `beginning-of-line' errors when a keyboard macro is being defined and/or it is being executed. This may be desired because such an error would cause the macro definition/execution being terminated." :type '(radio (const :tag "No" :value nil) (const :tag "Record" :value record) (const :tag "Replay" :value replay) (const :tag "Both" :value t)) :group 'evil) (defcustom evil-track-eol t "If non-nil line moves after a call to `evil-end-of-line' stay at eol. This is analogous to `track-eol' but deals with the end-of-line interpretation of evil." :type 'boolean :group 'evil) (defcustom evil-mode-line-format 'before "The position of the mode line tag. Either a symbol or a cons-cell. If it is a symbol it should be one of 'before, 'after or 'nil. 'before means the tag is placed before the mode-list, 'after means it is placed after the mode-list, and 'nil means no mode line tag. If it is a cons cell it should have the form (WHERE . WHICH) where WHERE is either 'before or 'after and WHICH is a symbol in `mode-line-format'. The tag is then placed right before or after that symbol." :type '(radio :value 'before (const before) (const after) (cons :tag "Next to symbol" (choice :value after (const before) (const after)) symbol)) :group 'evil) (defcustom evil-mouse-word 'evil-word "The thing-at-point symbol for double click selection. The double-click starts visual state in a special word selection mode. This symbol is used to determine the words to be selected. Possible values are 'evil-word or 'evil-WORD." :type 'symbol :group 'evil) (defcustom evil-bigword "^ \t\r\n" "The characters to be considered as a big word. This should be a regexp set without the enclosing []." :type 'string :group 'evil) (make-variable-buffer-local 'evil-bigword) (defcustom evil-want-fine-undo nil "Whether actions like \"cw\" are undone in several steps. There are three possible choices. \"No\" means all changes made during insert state including a possible delete after a change operation are collected in a single undo step. If \"Yes\" is selected, undo steps are determined according to Emacs heuristics and no attempt is made to further aggregate changes. As of 1.2.14, the option \"fine\" is ignored and means the same thing as \"No\". It used to be the case that fine would only try to merge the first two changes in an insert operation. For example, merging the delete and first insert operation after \"cw\", but this option was removed because it did not work consistently." :type '(radio (const :tag "No" :value nil) (const :tag "Fine (obsolete)" :value fine) (const :tag "Yes" :value t)) :group 'evil) (defcustom evil-regexp-search t "Whether to use regular expressions for searching." :type 'boolean :group 'evil) (defcustom evil-search-wrap t "Whether search wraps around." :type 'boolean :group 'evil) (defcustom evil-flash-delay 2 "Time in seconds to flash search matches." :type 'number :group 'evil) (defcustom evil-fold-level 0 "Default fold level." :type 'integer :group 'evil) (defcustom evil-auto-balance-windows t "If non-nil creating/deleting a window causes a rebalance." :type 'boolean :group 'evil) (defcustom evil-split-window-below nil "If non-nil split windows are created below." :type 'boolean :group 'evil) (defcustom evil-vsplit-window-right nil "If non-nil vsplit windows are created to the right." :type 'boolean :group 'evil) (defcustom evil-esc-delay 0.01 "Time in seconds to wait for another key after ESC." :type 'number :group 'evil) (defvar evil-esc-mode nil "Non-nil if `evil-esc-mode' is enabled.") (defvar evil-esc-map nil "Original ESC prefix map in `input-decode-map'. Used by `evil-esc-mode'.") (defvar evil-inhibit-esc nil "If non-nil, the \\e event will never be translated to 'escape.") (defcustom evil-intercept-esc 'always "Whether Evil should intercept the ESC key. In terminal, a plain ESC key and a meta-key-sequence both generate the same event. In order to distinguish both Evil modifies `input-decode-map'. This is necessary in terminal but not in X mode. However, the terminal ESC is equivalent to C-[, so if you want to use C-[ instead of ESC in X, then Evil must intercept the ESC event in X, too. This variable determines when Evil should intercept the event." :type '(radio (const :tag "Never" :value nil) (const :tag "In terminal only" :value t) (const :tag "Always" :value always)) :group 'evil) (defcustom evil-show-paren-range 0 "The minimal distance between point and a parenthesis which causes the parenthesis to be highlighted." :type 'integer :group 'evil) (defcustom evil-ex-hl-update-delay 0.02 "Time in seconds of idle before updating search highlighting. Setting this to a period shorter than that of keyboard's repeat rate allows highlights to update while scrolling." :type 'number :group 'evil) (defcustom evil-highlight-closing-paren-at-point-states '(not emacs insert replace) "The states in which the closing parenthesis at point should be highlighted. All states listed here highlight the closing parenthesis at point (which is Vim default behavior), all others highlight the parenthesis before point (which is Emacs default behavior). If this list contains the symbol 'not then its meaning is inverted, i.e., all states listed here highlight the closing parenthesis before point." :type '(repeat symbol) :group 'evil) (defcustom evil-kill-on-visual-paste t "Whether `evil-visual-paste' adds the replaced text to the kill ring, making it the default for the next paste. The default, t, replicates the default vim behavior." :type 'boolean :group 'evil) (defcustom evil-want-C-i-jump t "Whether \"C-i\" jumps forward like in Vim." :type 'boolean :group 'evil :set #'(lambda (sym value) (set-default sym value) (when (boundp 'evil-motion-state-map) (cond ((and (not value) (eq (lookup-key evil-motion-state-map (kbd "C-i")) 'evil-jump-forward)) (define-key evil-motion-state-map (kbd "C-i") nil)) ((and value (not (lookup-key evil-motion-state-map (kbd "C-i")))) (define-key evil-motion-state-map (kbd "C-i") 'evil-jump-forward)))))) (defcustom evil-want-C-u-scroll nil "Whether \"C-u\" scrolls like in Vim." :type 'boolean :group 'evil :set #'(lambda (sym value) (set-default sym value) (when (boundp 'evil-motion-state-map) (cond ((and (not value) (eq (lookup-key evil-motion-state-map (kbd "C-u")) 'evil-scroll-up)) (define-key evil-motion-state-map (kbd "C-u") nil)) ((and value (not (lookup-key evil-motion-state-map (kbd "C-u")))) (define-key evil-motion-state-map (kbd "C-u") 'evil-scroll-up)))))) (defcustom evil-want-C-d-scroll t "Whether \"C-d\" scrolls like in Vim." :type 'boolean :group 'evil :set #'(lambda (sym value) (set-default sym value) (when (boundp 'evil-motion-state-map) (cond ((and (not value) (eq (lookup-key evil-motion-state-map (kbd "C-d")) 'evil-scroll-down)) (define-key evil-motion-state-map (kbd "C-d") nil)) ((and value (not (lookup-key evil-motion-state-map (kbd "C-d")))) (define-key evil-motion-state-map (kbd "C-d") 'evil-scroll-down)))))) (defcustom evil-want-C-w-delete t "Whether \"C-w\" deletes a word in Insert state." :type 'boolean :group 'evil :set #'(lambda (sym value) (set-default sym value) (when (boundp 'evil-insert-state-map) (cond ((and (not value) (eq (lookup-key evil-insert-state-map (kbd "C-w")) 'evil-delete-backward-word)) (define-key evil-insert-state-map (kbd "C-w") 'evil-window-map)) ((and value (eq (lookup-key evil-insert-state-map (kbd "C-w")) 'evil-window-map)) (define-key evil-insert-state-map (kbd "C-w") 'evil-delete-backward-word)))))) (defcustom evil-want-C-w-in-emacs-state nil "Whether \"C-w\" prefixes windows commands in Emacs state." :type 'boolean :group 'evil :set #'(lambda (sym value) (set-default sym value) (when (boundp 'evil-emacs-state-map) (cond ((and (not value) (eq (lookup-key evil-emacs-state-map (kbd "C-w")) 'evil-window-map)) (define-key evil-emacs-state-map (kbd "C-w") nil)) ((and value (not (lookup-key evil-emacs-state-map (kbd "C-w")))) (define-key evil-emacs-state-map (kbd "C-w") 'evil-window-map)))))) (defcustom evil-want-change-word-to-end t "Whether \"cw\" behaves like \"ce\"." :type 'boolean :group 'evil) (defcustom evil-want-Y-yank-to-eol nil "Whether \"Y\" yanks to the end of the line. The default behavior is to yank the whole line." :group 'evil :type 'boolean :initialize #'evil-custom-initialize-pending-reset :set #'(lambda (sym value) (evil-add-command-properties 'evil-yank-line :motion (if value 'evil-end-of-line-or-visual-line 'evil-line-or-visual-line)))) (defcustom evil-disable-insert-state-bindings nil "Whether insert state bindings should be used. Excludes bindings for escape, delete and `evil-toggle-key'." :group 'evil :type 'boolean :initialize #'evil-custom-initialize-pending-reset :set #'evil-update-insert-state-bindings) (defcustom evil-echo-state t "Whether to signal the current state in the echo area." :type 'boolean :group 'evil) (defcustom evil-complete-all-buffers t "Whether completion looks for matches in all buffers." :type 'boolean :group 'evil) (defcustom evil-complete-next-func #'(lambda (arg) (require 'dabbrev) (let ((dabbrev-search-these-buffers-only (unless evil-complete-all-buffers (list (current-buffer)))) dabbrev-case-distinction) (condition-case nil (if (eq last-command this-command) (dabbrev-expand nil) (dabbrev-expand (- (abs (or arg 1))))) (error (dabbrev-expand nil))))) "Completion function used by \ \\\\[evil-complete-next]." :type 'function :group 'evil) (defcustom evil-complete-previous-func #'(lambda (arg) (require 'dabbrev) (let ((dabbrev-search-these-buffers-only (unless evil-complete-all-buffers (list (current-buffer)))) dabbrev-case-distinction) (dabbrev-expand arg))) "Completion function used by \ \\\\[evil-complete-previous]." :type 'function :group 'evil) (defcustom evil-complete-next-minibuffer-func 'minibuffer-complete "Minibuffer completion function used by \ \\\\[evil-complete-next]." :type 'function :group 'evil) (defcustom evil-complete-previous-minibuffer-func 'minibuffer-complete "Minibuffer completion function used by \ \\\\[evil-complete-previous]." :type 'function :group 'evil) (defcustom evil-complete-next-line-func #'(lambda (arg) (let ((hippie-expand-try-functions-list '(try-expand-line try-expand-line-all-buffers))) (hippie-expand arg))) "Minibuffer completion function used by \ \\\\[evil-complete-next-line]." :type 'function :group 'evil) (defcustom evil-complete-previous-line-func evil-complete-next-line-func "Minibuffer completion function used by \ \\\\[evil-complete-previous-line]." :type 'function :group 'evil) (defcustom evil-lookup-func #'woman "Lookup function used by \ \"\\\\[evil-lookup]\"." :type 'function :group 'evil) (defcustom evil-toggle-key "C-z" "The key used to change to and from Emacs state. Must be readable by `read-kbd-macro'. For example: \"C-z\"." :type 'string :group 'evil :set #'(lambda (sym value) (evil-set-toggle-key value) (set-default sym value))) (defcustom evil-default-state 'normal "The default Evil state. This is the state a mode comes up in when it is not listed in `evil-emacs-state-modes', `evil-insert-state-modes' or `evil-motion-state-modes'. The value may be one of `normal', `insert', `visual', `replace', `operator', `motion' and `emacs'." :type 'symbol :group 'evil) (defcustom evil-buffer-regexps '(("^ \\*load\\*" . nil)) "Regular expression determining the initial state for a buffer. Entries have the form (REGEXP . STATE), where REGEXP is a regular expression matching the buffer's name and STATE is one of `normal', `insert', `visual', `replace', `operator', `motion', `emacs' and nil. If STATE is nil, Evil is disabled in the buffer." :type '(alist :key-type string :value-type symbol) :group 'evil) (defcustom evil-emacs-state-modes '(5x5-mode archive-mode bbdb-mode biblio-selection-mode blackbox-mode bookmark-bmenu-mode bookmark-edit-annotation-mode browse-kill-ring-mode bubbles-mode bzr-annotate-mode calc-mode cfw:calendar-mode completion-list-mode Custom-mode custom-theme-choose-mode debugger-mode delicious-search-mode desktop-menu-blist-mode desktop-menu-mode doc-view-mode dun-mode dvc-bookmarks-mode dvc-diff-mode dvc-info-buffer-mode dvc-log-buffer-mode dvc-revlist-mode dvc-revlog-mode dvc-status-mode dvc-tips-mode ediff-mode ediff-meta-mode efs-mode Electric-buffer-menu-mode emms-browser-mode emms-mark-mode emms-metaplaylist-mode emms-playlist-mode ess-help-mode etags-select-mode fj-mode gc-issues-mode gdb-breakpoints-mode gdb-disassembly-mode gdb-frames-mode gdb-locals-mode gdb-memory-mode gdb-registers-mode gdb-threads-mode gist-list-mode git-commit-mode git-rebase-mode gnus-article-mode gnus-browse-mode gnus-group-mode gnus-server-mode gnus-summary-mode gomoku-mode google-maps-static-mode ibuffer-mode jde-javadoc-checker-report-mode magit-cherry-mode magit-diff-mode magit-log-mode magit-log-select-mode magit-popup-mode magit-popup-sequence-mode magit-process-mode magit-reflog-mode magit-refs-mode magit-revision-mode magit-stash-mode magit-stashes-mode magit-status-mode ;; Obsolete as of Magit v2.1.0 magit-mode magit-branch-manager-mode magit-commit-mode magit-key-mode magit-rebase-mode magit-wazzup-mode ;; end obsolete mh-folder-mode monky-mode mpuz-mode mu4e-main-mode mu4e-headers-mode mu4e-view-mode notmuch-hello-mode notmuch-search-mode notmuch-show-mode notmuch-tree-mode occur-mode org-agenda-mode package-menu-mode pdf-outline-buffer-mode pdf-view-mode proced-mode rcirc-mode rebase-mode recentf-dialog-mode reftex-select-bib-mode reftex-select-label-mode reftex-toc-mode sldb-mode slime-inspector-mode slime-thread-control-mode slime-xref-mode snake-mode solitaire-mode sr-buttons-mode sr-mode sr-tree-mode sr-virtual-mode tar-mode tetris-mode tla-annotate-mode tla-archive-list-mode tla-bconfig-mode tla-bookmarks-mode tla-branch-list-mode tla-browse-mode tla-category-list-mode tla-changelog-mode tla-follow-symlinks-mode tla-inventory-file-mode tla-inventory-mode tla-lint-mode tla-logs-mode tla-revision-list-mode tla-revlog-mode tla-tree-lint-mode tla-version-list-mode twittering-mode urlview-mode vc-annotate-mode vc-dir-mode vc-git-log-view-mode vc-hg-log-view-mode vc-svn-log-view-mode vm-mode vm-summary-mode w3m-mode wab-compilation-mode xgit-annotate-mode xgit-changelog-mode xgit-diff-mode xgit-revlog-mode xhg-annotate-mode xhg-log-mode xhg-mode xhg-mq-mode xhg-mq-sub-mode xhg-status-extra-mode) "Modes that should come up in Emacs state." :type '(repeat symbol) :group 'evil) (defcustom evil-insert-state-modes '(comint-mode erc-mode eshell-mode geiser-repl-mode gud-mode inferior-apl-mode inferior-caml-mode inferior-emacs-lisp-mode inferior-j-mode inferior-python-mode inferior-scheme-mode inferior-sml-mode internal-ange-ftp-mode prolog-inferior-mode reb-mode shell-mode slime-repl-mode term-mode wdired-mode) "Modes that should come up in Insert state." :type '(repeat symbol) :group 'evil) (defcustom evil-motion-state-modes '(apropos-mode Buffer-menu-mode calendar-mode color-theme-mode command-history-mode compilation-mode dictionary-mode ert-results-mode help-mode Info-mode Man-mode speedbar-mode undo-tree-visualizer-mode woman-mode) "Modes that should come up in Motion state." :type '(repeat symbol) :group 'evil) (defvar evil-pending-overriding-maps nil "An alist of pending overriding maps.") (defvar evil-pending-intercept-maps nil "An alist of pending intercept maps.") (defcustom evil-overriding-maps '((Buffer-menu-mode-map . nil) (color-theme-mode-map . nil) (comint-mode-map . nil) (compilation-mode-map . nil) (grep-mode-map . nil) (dictionary-mode-map . nil) (ert-results-mode-map . motion) (Info-mode-map . motion) (speedbar-key-map . nil) (speedbar-file-key-map . nil) (speedbar-buffers-key-map . nil)) "Keymaps that should override Evil maps. Entries have the form (MAP-VAR . STATE), where MAP-VAR is a keymap variable and STATE is the state whose bindings should be overridden. If STATE is nil, all states are overridden." :type '(alist :key-type symbol :value-type symbol) :group 'evil :set #'(lambda (var values) (evil-set-custom-state-maps 'evil-overriding-maps 'evil-pending-overriding-maps 'override-state 'evil-make-overriding-map values)) :initialize 'evil-custom-initialize-pending-reset) (add-hook 'after-load-functions #'evil-update-pending-maps) (defcustom evil-intercept-maps '((edebug-mode-map . nil)) "Keymaps that should intercept Evil maps. Entries have the form (MAP-VAR . STATE), where MAP-VAR is a keymap variable and STATE is the state whose bindings should be intercepted. If STATE is nil, all states are intercepted." :type '(alist :key-type symbol :value-type symbol) :group 'evil :set #'(lambda (var values) (evil-set-custom-state-maps 'evil-intercept-maps 'evil-pending-intercept-maps 'intercept-state 'evil-make-intercept-map values)) :initialize 'evil-custom-initialize-pending-reset) (defcustom evil-motions '(back-to-indentation backward-char backward-list backward-paragraph backward-sentence backward-sexp backward-up-list backward-word beginning-of-buffer beginning-of-defun beginning-of-line beginning-of-visual-line c-beginning-of-defun c-end-of-defun diff-file-next diff-file-prev diff-hunk-next diff-hunk-prev down-list end-of-buffer end-of-defun end-of-line end-of-visual-line exchange-point-and-mark forward-char forward-list forward-paragraph forward-sentence forward-sexp forward-word goto-last-change ibuffer-backward-line ibuffer-forward-line isearch-abort isearch-cancel isearch-complete isearch-del-char isearch-delete-char isearch-edit-string isearch-exit isearch-highlight-regexp isearch-occur isearch-other-control-char isearch-other-meta-char isearch-printing-char isearch-query-replace isearch-query-replace-regexp isearch-quote-char isearch-repeat-backward isearch-repeat-forward isearch-ring-advance isearch-ring-retreat isearch-toggle-case-fold isearch-toggle-input-method isearch-toggle-regexp isearch-toggle-specified-input-method isearch-toggle-word isearch-yank-char isearch-yank-kill isearch-yank-line isearch-yank-word-or-char keyboard-quit left-char left-word mouse-drag-region mouse-save-then-kill mouse-set-point mouse-set-region mwheel-scroll move-beginning-of-line move-end-of-line next-error next-line paredit-backward paredit-backward-down paredit-backward-up paredit-forward paredit-forward-down paredit-forward-up pop-global-mark pop-tag-mark pop-to-mark-command previous-error previous-line right-char right-word scroll-down scroll-down-command scroll-up scroll-up-command sgml-skip-tag-backward sgml-skip-tag-forward up-list) "Non-Evil commands to initialize to motions." :type '(repeat symbol) :group 'evil :set 'evil-set-custom-motions :initialize 'evil-custom-initialize-pending-reset) (defcustom evil-visual-newline-commands '(LaTeX-section TeX-font) "Commands excluding the trailing newline of a Visual Line selection. These commands work better without this newline." :type '(repeat symbol) :group 'evil :set 'evil-set-visual-newline-commands :initialize 'evil-custom-initialize-pending-reset) (defcustom evil-want-visual-char-semi-exclusive nil "Visual character selection to beginning/end of line is exclusive. If non nil then an inclusive visual character selection which ends at the beginning or end of a line is turned into an exclusive selection. Thus if the selected (inclusive) range ends at the beginning of a line it is changed to not include the first character of that line, and if the selected range ends at the end of a line it is changed to not include the newline character of that line." :type 'boolean :group 'evil) (defcustom evil-text-object-change-visual-type t "Text objects change the current visual state type. If non-nil then a text-object changes the type of the visual state to its default selection type (e.g. a word object always changes to charwise visual state). Otherwise the current visual state type is preserved." :type 'boolean :group 'evil) (defgroup evil-cjk nil "CJK support" :prefix "evil-cjk-" :group 'evil) (defcustom evil-cjk-emacs-word-boundary nil "Determine word boundary exactly the same way as Emacs does." :type 'boolean :group 'evil-cjk) (defcustom evil-cjk-word-separating-categories '(;; Kanji (?C . ?H) (?C . ?K) (?C . ?k) (?C . ?A) (?C . ?G) ;; Hiragana (?H . ?C) (?H . ?K) (?H . ?k) (?H . ?A) (?H . ?G) ;; Katakana (?K . ?C) (?K . ?H) (?K . ?k) (?K . ?A) (?K . ?G) ;; half-width Katakana (?k . ?C) (?k . ?H) (?k . ?K) ; (?k . ?A) (?k . ?G) ;; full-width alphanumeric (?A . ?C) (?A . ?H) (?A . ?K) ; (?A . ?k) (?A . ?G) ;; full-width Greek (?G . ?C) (?G . ?H) (?G . ?K) ; (?G . ?k) (?G . ?A) ) "List of pair (cons) of categories to determine word boundary used in `evil-cjk-word-boundary-p'. See the documentation of `word-separating-categories'. Use `describe-categories' to see the list of categories." :type '(alist :key-type (choice character (const nil)) :value-type (choice character (const nil))) :group 'evil-cjk) (defcustom evil-cjk-word-combining-categories '(;; default value in word-combining-categories (nil . ?^) (?^ . nil) ;; Roman (?r . ?k) (?r . ?A) (?r . ?G) ;; half-width Katakana (?k . ?r) (?k . ?A) (?k . ?G) ;; full-width alphanumeric (?A . ?r) (?A . ?k) (?A . ?G) ;; full-width Greek (?G . ?r) (?G . ?k) (?G . ?A) ) "List of pair (cons) of categories to determine word boundary used in `evil-cjk-word-boundary-p'. See the documentation of `word-combining-categories'. Use `describe-categories' to see the list of categories." :type '(alist :key-type (choice character (const nil)) :value-type (choice character (const nil))) :group 'evil-cjk) (defcustom evil-ex-complete-emacs-commands 'in-turn "TAB-completion for Emacs commands in ex command line. This variable determines when Emacs commands are considered for completion, always, never, or only if no Evil ex command is available for completion." :group 'evil :type '(radio (const :tag "Only if no ex-command." :value in-turn) (const :tag "Never" :value nil) (const :tag "Always" :value t))) (defface evil-ex-commands '(( nil :underline t :slant italic)) "Face for the Evil command in completion in ex mode." :group 'evil) (defface evil-ex-info '(( ((supports :slant)) :slant italic :foreground "red")) "Face for the info message in ex mode." :group 'evil) (defcustom evil-ex-visual-char-range nil "Type of default ex range in visual char state. If non-nil the default range when starting an ex command from character visual state is `<,`> otherwise it is '<,'>. In the first case the ex command will be passed a region covering only the visual selection. In the second case the passed region will be extended to contain full lines." :group 'evil :type 'boolean) ;; Searching (defcustom evil-symbol-word-search nil "If nil then * and # search for words otherwise for symbols." :group 'evil :type 'boolean) (make-variable-buffer-local 'evil-symbol-word-search) (defcustom evil-magic t "Meaning which characters in a pattern are magic. The meaning of those values is the same as in Vim. Note that it only has influence if the Evil search module is chosen in `evil-search-module'." :group 'evil :type '(radio (const :tag "Very magic." :value very-magic) (const :tag "Magic" :value t) (const :tag "Nomagic" :value nil) (const :tag "Very nomagic" :value very-nomagic))) (defcustom evil-ex-search-vim-style-regexp nil "If non-nil Vim-style backslash codes are supported in search patterns. See `evil-transform-vim-style-regexp' for the supported backslash codes. Note that this only affects the search command if `evil-search-module' is set to 'evil-search. The isearch module always uses plain Emacs regular expressions." :type 'boolean :group 'evil) (defcustom evil-ex-interactive-search-highlight 'all-windows "Determine in which windows the interactive highlighting should be shown." :type '(radio (const :tag "All windows." all-windows) (const :tag "Selected window." selected-window) (const :tag "Disable highlighting." nil)) :group 'evil) (defcustom evil-ex-search-persistent-highlight t "If non-nil matches remain highlighted when the search ends." :type 'boolean :group 'evil) (defcustom evil-ex-search-case 'smart "The case behaviour of the search command. Smart case means that the pattern is case sensitive if and only if it contains an upper case letter, otherwise it is case insensitive." :type '(radio (const :tag "Case sensitive." sensitive) (const :tag "Case insensitive." insensitive) (const :tag "Smart case." smart)) :group 'evil) (defcustom evil-ex-substitute-case nil "The case behaviour of the search command. Smart case means that the pattern is case sensitive if and only if it contains an upper case letter, otherwise it is case insensitive. If nil then the setting of `evil-ex-search-case' is used." :type '(radio (const :tag "Same as interactive search." nil) (const :tag "Case sensitive." sensitive) (const :tag "Case insensitive." insensitive) (const :tag "Smart case." smart)) :group 'evil) (defcustom evil-ex-search-interactive t "If t search is interactive." :type 'boolean :group 'evil) (defcustom evil-ex-search-highlight-all t "If t and interactive search is enabled, all matches are highlighted." :type 'boolean :group 'evil) (defcustom evil-ex-substitute-highlight-all t "If t all matches for the substitute pattern are highlighted." :type 'boolean :group 'evil) (defcustom evil-ex-substitute-interactive-replace t "If t and substitute patterns are highlighted, the replacement is shown interactively." :type 'boolean :group 'evil) (defcustom evil-ex-substitute-global nil "If non-nil substitute patterns are global by default. Usually (if this variable is nil) a substitution works only on the first match of a pattern in a line unless the 'g' flag is given, in which case the substitution happens on all matches in a line. If this option is non-nil, this behaviour is reversed: the substitution works on all matches unless the 'g' pattern is specified, then is works only on the first match." :type 'boolean :group 'evil) (defface evil-ex-search '((t :inherit isearch)) "Face for interactive search." :group 'evil) (defface evil-ex-lazy-highlight '((t :inherit lazy-highlight)) "Face for highlighting all matches in interactive search." :group 'evil) (defface evil-ex-substitute-matches '((t :inherit lazy-highlight)) "Face for interactive substitute matches." :group 'evil) (defface evil-ex-substitute-replacement '((((supports :underline)) :underline t :foreground "red")) "Face for interactive replacement text." :group 'evil) (defcustom evil-command-window-height 8 "Height (in lines) of the command line window. Set to 0 to use the default height for `split-window'." :type 'integer :group 'evil) (defcustom evil-display-shell-error-in-message nil "Show error output of a shell command in the error buffer. If this variable is non-nil the error output of a shell command goes to the messages buffer instead of being mixed with the regular output. This happens only if the exit status of the command is non-zero." :type 'boolean :group 'evil) (defcustom evil-want-abbrev-expand-on-insert-exit t "If non-nil abbrevs will be expanded when leaving Insert state like in Vim. This variable is read only on load." :type 'boolean :group 'evil) ;;; Variables (defmacro evil-define-local-var (symbol &optional initvalue docstring) "Define SYMBOL as permanent buffer local variable, and return SYMBOL. The parameters are the same as for `defvar', but the variable SYMBOL is made permanent buffer local." (declare (indent defun) (doc-string 3) (debug (symbolp &optional form stringp))) `(progn (defvar ,symbol ,initvalue ,docstring) (make-variable-buffer-local ',symbol) (put ',symbol 'permanent-local t))) (evil-define-local-var evil-scroll-count 0 "Holds last used prefix for `evil-scroll-up' and `evil-scroll-down'. Determines how many lines should be scrolled. Default value is 0 - scroll half the screen.") (evil-define-local-var evil-state nil "The current Evil state. To change the state, use `evil-change-state' or call the state function (e.g., `evil-normal-state').") ;; these may be used inside `evil-define-state' (evil-define-local-var evil-next-state nil "The Evil state being switched to.") (evil-define-local-var evil-previous-state-alist nil "For Each evil state the Evil state being switched from.") (evil-define-local-var evil-previous-state nil "The Evil state being switched from.") (defvar evil-execute-in-emacs-state-buffer nil "The buffer of the latest `evil-execute-in-emacs-state'. When this command is being executed the current buffer is stored in this variable. This is necessary in case the Emacs-command to be called changes the current buffer.") (evil-define-local-var evil-mode-line-tag nil "Mode-Line indicator for the current state.") (put 'evil-mode-line-tag 'risky-local-variable t) (defvar evil-global-keymaps-alist nil "Association list of keymap variables. Entries have the form (MODE . KEYMAP), where KEYMAP is the variable containing the keymap for MODE.") (defvar evil-local-keymaps-alist nil "Association list of keymap variables that must be reinitialized in each buffer. Entries have the form \(MODE . KEYMAP), where KEYMAP is the variable containing the keymap for MODE.") (defvar evil-minor-mode-keymaps-alist nil "Association list of Evil states to minor-mode keymap alists. Entries have the form (STATE . MODE-MAP-ALIST), where MODE-MAP-ALIST is an alist taking the form of `minor-mode-map-alist'.") (defvar evil-state-properties nil "Specifications made by `evil-define-state'. Entries have the form (STATE . PLIST), where PLIST is a property list specifying various aspects of the state. To access a property, use `evil-state-property'.") (evil-define-local-var evil-mode-map-alist nil "Association list of keymaps to use for Evil modes. Elements have the form (MODE . KEYMAP), with the first keymaps having higher priority.") (defvar evil-command-properties nil "Specifications made by `evil-define-command'.") (defvar evil-change-commands '(evil-change) "Commands that wrap or replace `evil-change'. This list exists to apply an inconsistency with vim's change command to commands that wrap or redefine it. See emacs-evil/evil#916.") (defvar evil-transient-vars '(cua-mode transient-mark-mode select-active-regions) "List of variables pertaining to Transient Mark mode.") (defvar evil-transient-vals nil "Association list of old values for Transient Mark mode variables. Entries have the form (VARIABLE VALUE LOCAL), where LOCAL is whether the variable was previously buffer-local.") (evil-define-local-var evil-no-display nil "If non-nil, various Evil displays are inhibited. Use the macro `evil-without-display' to set this variable.") (defvar evil-type-properties nil "Specifications made by `evil-define-type'. Entries have the form (TYPE . PLIST), where PLIST is a property list specifying functions for handling the type: expanding it, describing it, etc.") (defvar evil-interactive-alist nil "Association list of Evil-specific interactive codes.") (evil-define-local-var evil-motion-marker nil "Marker for storing the starting position of a motion.") (evil-define-local-var evil-this-type nil "Current motion type.") (evil-define-local-var evil-this-type-modified nil "Non-nil iff current motion type has been modified by the user. If the type has been modified, this variable contains the new type.") (evil-define-local-var evil-this-register nil "Current register.") (defvar evil-this-macro nil "Current macro register.") (evil-define-local-var evil-this-operator nil "Current operator.") (evil-define-local-var evil-this-motion nil "Current motion.") (evil-define-local-var evil-this-motion-count nil "Current motion count.") (defvar evil-last-register nil "The last executed register.") (defvar evil-inhibit-operator nil "Inhibit current operator. If an operator calls a motion and the motion sets this variable to t, the operator code is not executed.") (defvar evil-inhibit-operator-value nil "This variable is used to transfer the value of `evil-inhibit-operator' from one local scope to another.") ;; used by `evil-define-operator' (defvar evil-operator-range-beginning nil "Beginning of `evil-operator-range'.") (defvar evil-operator-range-end nil "End of `evil-operator-range'.") (defvar evil-operator-range-type nil "Type of `evil-operator-range'.") (defvar evil-operator-range-motion nil "Motion of `evil-operator-range'.") (defvar evil-restriction-stack nil "List of previous restrictions. Using `evil-with-restriction' stores the previous values of `point-min' and `point-max' as a pair in this list.") (evil-define-local-var evil-markers-alist '((?\( . evil-backward-sentence) (?\) . evil-forward-sentence) (?{ . evil-backward-paragraph) (?} . evil-forward-paragraph) (?' . evil-jump-backward-swap) (?` . evil-jump-backward-swap) (?< . evil-visual-beginning) (?> . evil-visual-goto-end) (?. . (lambda () (let (last-command) (goto-last-change nil))))) "Association list for markers. Entries have the form (CHAR . DATA), where CHAR is the marker's name and DATA is either a marker object as returned by `make-marker', a variable, a movement function, or a cons cell (STRING NUMBER), where STRING is a file path and NUMBER is a buffer position. The global value of this variable holds markers available from every buffer, while the buffer-local value holds markers available only in the current buffer.") (defconst evil-suppress-map (make-keymap) "Full keymap disabling default bindings to `self-insert-command'.") (suppress-keymap evil-suppress-map t) (defvar evil-read-key-map (make-sparse-keymap) "Keymap active during `evil-read-key'. This keymap can be used to bind some commands during the execution of `evil-read-key' which is usually used to read a character argument for some commands, e.g. `evil-replace'.") ;; TODO: customize size of ring (defvar evil-repeat-ring (make-ring 10) "A ring of repeat-informations to repeat the last command.") (defvar evil-repeat-types '((t . evil-repeat-keystrokes) (change . evil-repeat-changes) (motion . evil-repeat-motion) (insert-at-point . evil-repeat-insert-at-point) (ignore . nil)) "An alist of defined repeat-types.") (defvar evil-recording-repeat nil "Whether we are recording a repeat.") (defvar evil-recording-current-command nil "Whether we are recording the current command for repeat.") (defvar evil-repeat-changes nil "Accumulated buffer changes for changed-based commands.") (defvar evil-repeat-info nil "Information accumulated during current repeat.") (defvar evil-repeat-buffer nil "The buffer in which the repeat started. If the buffer is changed, the repeat is cancelled.") (defvar evil-repeat-pos nil "The position of point at the beginning of an change-tracking editing command.") (defvar evil-repeat-keys nil "The keys that invoked the current command.") (defvar evil-last-repeat nil "Information about the latest repeat command. This is a list of three elements (POINT COUNT UNDO-POINTER), where POINT is the position of point before the latest repeat, COUNT the count-argument of the latest repeat command and UNDO-POINTER the head of the undo-list before the last command has been repeated.") (defvar evil-repeat-count nil "The explicit count when repeating a command.") (defvar evil-maybe-remove-spaces nil "Flag to determine if newly inserted spaces should be removed. See the function `evil-maybe-remove-spaces'.") (evil-define-local-var evil-insert-count nil "The explicit count passed to an command starting Insert state.") (evil-define-local-var evil-insert-vcount nil "The information about the number of following lines the insertion should be repeated. This is list (LINE COLUMN COUNT) where LINE is the line-number where the original insertion started and COLUMN is either a number or function determining the column where the repeated insertions should take place. COUNT is number of repeats (including the original insertion).") (defvar evil-insert-skip-empty-lines nil "Non-nil of the current insertion should not take place on lines at which the insertion point is behind the end of the line.") (evil-define-local-var evil-insert-lines nil "Non-nil if the current insertion command is a line-insertion command o or O.") (evil-define-local-var evil-insert-repeat-info nil "Repeat information accumulated during an insertion.") (evil-define-local-var evil-replace-alist nil "Association list of characters overwritten in Replace state. The format is (POS . CHAR).") (evil-define-local-var evil-echo-area-message nil "Previous value of `current-message'.") (defvar evil-write-echo-area nil "If set to t inside `evil-save-echo-area', then the echo area is not restored.") (defvar evil-last-find nil "A pair (FUNCTION . CHAR) describing the lastest character search command.") (defvar evil-last-paste nil "Information about the latest paste. This should be a list (CMD COUNT POINT BEG END FIRSTVISUAL) where CMD is the last paste-command (`evil-paste-before', `evil-paste-after' or `evil-visual-paste'), COUNT is the repeat count of the paste, POINT is the position of point before the paste, BEG end END are the region of the inserted text. FIRSTVISUAL is t if and only if the previous command was the first visual paste (i.e. before any paste-pop).") (evil-define-local-var evil-last-undo-entry nil "Information about the latest undo entry in the buffer. This should be a pair (OBJ . CONS) where OBJ is the entry as an object, and CONS is a copy of the entry.") (evil-define-local-var evil-current-insertion nil "Information about the latest insertion in insert state. This should be a pair (BEG . END) that describes the buffer-region of the newly inserted text.") (defvar evil-last-insertion nil "The last piece of inserted text.") (defvar evil-last-small-deletion nil "The last piece of deleted text. The text should be less than a line.") (defvar evil-was-yanked-without-register t "Whether text being saved to the numbered-register ring was not deleted and not yanked to a specific register.") (defvar evil-paste-count nil "The count argument of the current paste command.") (defvar evil-temporary-undo nil "When undo is disabled in current buffer. Certain commands depending on undo use this variable instead of `buffer-undo-list'.") (evil-define-local-var evil-undo-list-pointer nil "Everything up to this mark is united in the undo-list.") (defvar evil-in-single-undo nil "Set to non-nil if the current undo steps are connected.") (defvar evil-flash-timer nil "Timer for flashing search results.") (defvar evil-search-prompt nil "String to use for search prompt.") (defvar evil-search-forward-history nil "History of forward searches.") (defvar evil-search-backward-history nil "History of backward searches.") (defvar evil-inner-text-objects-map (make-sparse-keymap) "Keymap for inner text objects.") (defvar evil-outer-text-objects-map (make-sparse-keymap) "Keymap for outer text objects.") (defvar evil-window-map (make-sparse-keymap) "Keymap for window-related commands.") (evil-define-local-var evil-input-method nil "Input method used in Insert state and Emacs state.") ;;; Visual state (evil-define-local-var evil-visual-beginning nil "The beginning of the Visual selection, a marker.") (evil-define-local-var evil-visual-end nil "The end of the Visual selection, a marker.") (evil-define-local-var evil-visual-point nil "The position of point in Visual state, a marker.") (evil-define-local-var evil-visual-mark nil "The position of mark in Visual state, a marker.") (evil-define-local-var evil-visual-previous-mark nil "The position of mark before Visual state, a marker.") (evil-define-local-var evil-visual-selection nil "The kind of Visual selection. This is a selection as defined by `evil-define-visual-selection'.") ;; we could infer the direction by comparing `evil-visual-mark' ;; and `evil-visual-point', but destructive operations may ;; displace the markers (evil-define-local-var evil-visual-direction 0 "Whether point follows mark in Visual state. Negative if point precedes mark, otherwise positive. See also the function `evil-visual-direction'.") (evil-define-local-var evil-visual-properties nil "Property list of miscellaneous Visual properties.") (evil-define-local-var evil-visual-region-expanded nil "Whether the region matches the Visual selection. That is, whether the positions of point and mark have been expanded to coincide with the selection's boundaries. This makes the selection available to functions acting on Emacs' region.") (evil-define-local-var evil-visual-overlay nil "Overlay for highlighting the Visual selection. Not used for blockwise selections, in which case see `evil-visual-block-overlays'.") (evil-define-local-var evil-visual-block-overlays nil "Overlays for Visual Block selection, one for each line. They are reused to minimize flicker.") (defvar evil-visual-alist nil "Association list of Visual selection functions. Elements have the form (NAME . FUNCTION).") (evil-define-local-var evil-visual-x-select-timer nil "Timer for updating the X selection in visual state.") (defvar evil-visual-x-select-timeout 0.1 "Time in seconds for the update of the X selection.") (declare-function origami-open-all-nodes "ext:origami.el") (declare-function origami-close-all-nodes "ext:origami.el") (declare-function origami-toggle-node "ext:origami.el") (declare-function origami-open-node "ext:origami.el") (declare-function origami-open-node-recursively "ext:origami.el") (declare-function origami-close-node "ext:origami.el") (defvar evil-fold-list `(((vdiff-mode) :open-all vdiff-open-all-folds :close-all vdiff-close-all-folds :toggle ,(lambda () (call-interactively 'vdiff-toggle-fold)) :open ,(lambda () (call-interactively 'vdiff-open-fold)) :open-rec ,(lambda () (call-interactively 'vdiff-open-fold)) :close ,(lambda () (call-interactively 'vdiff-close-fold))) ((vdiff-3way-mode) :open-all vdiff-open-all-folds :close-all vdiff-close-all-folds :toggle ,(lambda () (call-interactively 'vdiff-toggle-fold)) :open ,(lambda () (call-interactively 'vdiff-open-fold)) :open-rec ,(lambda () (call-interactively 'vdiff-open-fold)) :close ,(lambda () (call-interactively 'vdiff-close-fold))) ((hs-minor-mode) :open-all hs-show-all :close-all hs-hide-all :toggle hs-toggle-hiding :open hs-show-block :open-rec nil :close hs-hide-block) ((hide-ifdef-mode) :open-all show-ifdefs :close-all hide-ifdefs :toggle nil :open show-ifdef-block :open-rec nil :close hide-ifdef-block) ((outline-mode outline-minor-mode org-mode markdown-mode) :open-all show-all :close-all ,(lambda () (with-no-warnings (hide-sublevels 1))) :toggle outline-toggle-children :open ,(lambda () (with-no-warnings (show-entry) (show-children))) :open-rec show-subtree :close hide-subtree) ((origami-mode) :open-all ,(lambda () (origami-open-all-nodes (current-buffer))) :close-all ,(lambda () (origami-close-all-nodes (current-buffer))) :toggle ,(lambda () (origami-toggle-node (current-buffer) (point))) :open ,(lambda () (origami-open-node (current-buffer) (point))) :open-rec ,(lambda () (origami-open-node-recursively (current-buffer) (point))) :close ,(lambda () (origami-close-node (current-buffer) (point))))) "Actions to be performed for various folding operations. The value should be a list of fold handlers, were a fold handler has the format: ((MODES) PROPERTIES) MODES acts as a predicate, containing the symbols of all major or minor modes for which the handler should match. For example: '((outline-minor-mode org-mode) ...) would match for either outline-minor-mode or org-mode, even though the former is a minor mode and the latter is a major. PROPERTIES specifies possible folding actions and the functions to be applied in the event of a match on one (or more) of the MODES; the supported properties are: - `:open-all' Open all folds. - `:close-all' Close all folds. - `:toggle' Toggle the display of the fold at point. - `:open' Open the fold at point. - `:open-rec' Open the fold at point recursively. - `:close' Close the fold at point. Each value must be a function. A value of `nil' will cause the action to be ignored for that respective handler. For example: `((org-mode) :close-all nil :open ,(lambda () (show-entry) (show-children)) :close hide-subtree) would ignore `:close-all' actions and invoke the provided functions on `:open' or `:close'.") ;;; Ex (defvar evil-ex-map (make-sparse-keymap) "Keymap for Ex. Key sequences bound in this map are immediately executed.") (defvar evil-ex-completion-map (make-sparse-keymap) "Completion keymap for Ex.") (defvar evil-ex-initial-input nil "Additional initial content of the ex command line. This content of this variable is appended to the ex command line if ex is started interactively.") (defvar evil-ex-shell-argument-initialized nil "This variable is set to t if shell command completion has been initialized. See `evil-ex-init-shell-argument-completion'.") (defvar evil-ex-commands nil "Association list of command bindings and functions.") (defvar evil-ex-history nil "History of Ex commands.") (defvar evil-ex-current-buffer nil "The buffer from which Ex was started.") (defvar evil-ex-expression nil "The evaluation tree.") (defvar evil-ex-tree nil "The syntax tree.") (defvar evil-ex-command nil "The current Ex command.") (defvar evil-ex-previous-command nil "The previously executed Ex command.") (defvar evil-ex-cmd nil "The current Ex command string.") (defvar evil-ex-point nil "The position of `point' when the ex command has been called.") (defvar evil-ex-range nil "The current range of the Ex command.") (defvar evil-ex-bang nil "The \"!\" argument of the current Ex command.") (defvar evil-ex-argument nil "The current argument of the Ex command.") (defvar evil-ex-argument-handler nil "The argument handler for the current Ex command.") (defvar evil-ex-argument-types nil "Association list of argument handlers.") (defvar evil-previous-shell-command nil "The last shell command.") ;; Searching (defvar evil-ex-search-history nil "The history for the search command.") (defvar evil-ex-search-direction nil "The direction of the current search, either 'forward or 'backward.") (defvar evil-ex-search-count nil "The count if the current search.") (defvar evil-ex-search-start-point nil "The point where the search started.") (defvar evil-ex-search-overlay nil "The overlay for the current search result.") (defvar evil-ex-search-pattern nil "The last search pattern.") (defvar evil-ex-search-offset nil "The last search offset.") (defvar evil-ex-search-match-beg nil "The beginning position of the last match.") (defvar evil-ex-search-match-end nil "The end position of the last match.") (defvar evil-ex-substitute-pattern nil "The last substitute pattern.") (defvar evil-ex-substitute-replacement nil "The last substitute replacement.") (defvar evil-ex-substitute-flags nil "The last substitute flags.") (defvar evil-ex-substitute-current-replacement nil "The actual replacement.") (defvar evil-ex-last-was-search nil "Non-nil if the previous was a search. Otherwise the previous command is assumed as substitute.") ;;; Command line window (defvar evil-command-window-current-buffer nil "The buffer from which the command line window was called.") (evil-define-local-var evil-command-window-execute-fn nil "The command to execute when exiting the command line window.") (evil-define-local-var evil-command-window-cmd-key nil "The key for the command that opened the command line window (:, /, or ?).") ;; The lazy-highlighting framework. (evil-define-local-var evil-ex-active-highlights-alist nil "An alist of currently active highlights.") (evil-define-local-var evil-ex-hl-update-timer nil "Time used for updating highlights.") (defvar evil-ex-search-keymap (make-sparse-keymap) "Keymap used in ex-search-mode.") (define-key evil-ex-search-keymap [escape] 'abort-recursive-edit) (set-keymap-parent evil-ex-search-keymap minibuffer-local-map) (defconst evil-version (eval-when-compile (with-temp-buffer (let ((dir (file-name-directory (or load-file-name byte-compile-current-file)))) ;; git repository (if (and (file-exists-p (concat dir "/.git")) (ignore-errors (zerop (call-process "git" nil '(t nil) nil "rev-parse" "--short" "HEAD")))) (progn (goto-char (point-min)) (concat "evil-git-" (buffer-substring (point-min) (line-end-position)))) ;; no repo, use plain version "1.12.17")))) "The current version of Evil") (defcustom evil-want-integration t "Whether to load evil-integration.el. This variable must be set before Evil is loaded." :type 'boolean :group 'evil) (defcustom evil-want-keybinding t "Whether to load evil-keybindings.el. This loads a set of keybindings for evil in other modes as well as setting the initial evil state in those modes. This variable must be set before evil is loaded." :type 'boolean :group 'evil) (defcustom evil-want-minibuffer nil "Whether to enable Evil in minibuffer(s)." :type 'boolean :group 'evil :set #'(lambda (sym value) (set-default sym value) (if value (add-hook 'minibuffer-setup-hook 'evil-initialize) (remove-hook 'minibuffer-setup-hook 'evil-initialize)))) (defun evil-version () (interactive) (message "Evil version %s" evil-version)) (provide 'evil-vars) ;;; evil-vars.el ends here evil-1.12.17/evil.el000066400000000000000000000130251360703323200141030ustar00rootroot00000000000000;;; evil.el --- extensible vi layer ;; The following list of authors was kept up to date until the beginning of ;; 2017, when evil moved under new maintainers. For authors since then, please ;; consult the git logs. ;; Alessandro Piras ;; Alexander Baier ;; Antono Vasiljev ;; Bailey Ling ;; Barry O'Reilly ;; Christoph Lange ;; Daniel Reiter ;; Eivind Fonn ;; Emanuel Evans ;; Eric Siegel ;; Eugene Yaremenko ;; Frank Fischer ;; Frank Terbeck ;; Gordon Gustafson ;; Herbert Jones ;; Jonas Bernoulli ;; Jonathan Claggett ;; José A. Romero L. ;; Justin Burkett ;; Lars Andersen ;; Lintaro Ina ;; Lukasz Wrzosek ;; Marian Schubert ;; Matthew Malcomson <> ;; Michael Markert ;; Mike Gerwitz ;; Nikolai Weibull ;; phaebz ;; ralesi ;; Rodrigo Setti ;; Sanel Zukan ;; Sarah Brofeldt ;; Simon Hafner ;; Stefan Wehr ;; Sune Simonsen ;; Thomas Hisch ;; Tim Harper ;; Tom Willemse ;; Trevor Murphy ;; Ulrich Müller ;; Vasilij Schneidermann ;; Vegard Øye ;; Winfred Lu ;; Wolfgang Jenkner ;; Xiao Hanyu ;; York Zhao ;; Maintainers: The emacs-evil team. ;; To get in touch, please use the bug tracker or the ;; mailing list (see below). ;; Created: 2011-03-01 ;; Version: 1.12.17 ;; Keywords: emulation, vim ;; URL: https://github.com/emacs-evil/evil ;; Repository: https://github.com/emacs-evil/evil.git ;; EmacsWiki: http://www.emacswiki.org/emacs/Evil ;; Bug tracker: https://github.com/emacs-evil/evil/issues ;; If you have bug reports, suggestions or patches, please ;; create an issue at the bug tracker (open for everyone). ;; Other discussions (tips, extensions) go to the mailing list. ;; Mailing list: ;; Subscribe: http://tinyurl.com/implementations-list ;; Newsgroup: nntp://news.gmane.org/gmane.emacs.vim-emulation ;; Archives: http://dir.gmane.org/gmane.emacs.vim-emulation ;; You don't have to subscribe to post; we usually reply ;; within a few days and CC our replies back to you. ;; ;; This file is NOT part of GNU Emacs. ;;; License: ;; This file is part of Evil. ;; ;; Evil is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Evil is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Evil. If not, see . ;;; Commentary: ;; Evil is an extensible vi layer for Emacs. It emulates the main ;; features of Vim, and provides facilities for writing custom ;; extensions. ;; ;; Evil lives in a Git repository. To obtain Evil, do ;; ;; git clone git://github.com/emacs-evil/evil.git ;; ;; Move Evil to ~/.emacs.d/evil (or somewhere else in the `load-path'). ;; Then add the following lines to ~/.emacs: ;; ;; (add-to-list 'load-path "~/.emacs.d/evil") ;; (require 'evil) ;; (evil-mode 1) ;; ;; Evil requires undo-tree.el for linear undo and undo branches: ;; ;; http://www.emacswiki.org/emacs/UndoTree ;; ;; Otherwise, Evil uses regular Emacs undo. ;; ;; Evil requires `goto-last-change' and `goto-last-change-reverse' ;; function for the corresponding motions g; g, as well as the ;; last-change-register `.'. One package providing these functions is ;; goto-chg.el: ;; ;; http://www.emacswiki.org/emacs/GotoChg ;; ;; Without this package the corresponding motions will raise an error. ;;; Code: (require 'evil-vars) (require 'evil-common) (require 'evil-core) (require 'evil-states) (require 'evil-repeat) (require 'evil-macros) (require 'evil-search) (require 'evil-ex) (require 'evil-digraphs) (require 'evil-types) (require 'evil-commands) (require 'evil-jumps) (require 'evil-maps) (when evil-want-integration (require 'evil-integration)) (when evil-want-keybinding (require 'evil-keybindings)) (run-hooks 'evil-after-load-hook) (provide 'evil) ;;; evil.el ends here evil-1.12.17/lib/000077500000000000000000000000001360703323200133675ustar00rootroot00000000000000evil-1.12.17/lib/.nosearch000066400000000000000000000000001360703323200151600ustar00rootroot00000000000000evil-1.12.17/lib/README000066400000000000000000000004111360703323200142430ustar00rootroot00000000000000This folder contains external libraries that are freely distributable under the GNU GPL license. They may not be up to date. Emacs does not add subdirectories to the `load-path' by default. Therefore this directory is not covered by the installation instructions. evil-1.12.17/lib/goto-chg.el000066400000000000000000000375311360703323200154310ustar00rootroot00000000000000;;; goto-chg.el --- goto last change ;;-------------------------------------------------------------------- ;; ;; Copyright (C) 2002-2008,2013 David Andersson ;; ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 2 of ;; the License, or (at your option) any later version. ;; ;; This program is distributed in the hope that it will be ;; useful, but WITHOUT ANY WARRANTY; without even the implied ;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. See the GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public ;; License along with this program; if not, write to the Free ;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, ;; MA 02111-1307 USA ;; ;;------------------------------------------------------------------- ;; ;; Author: David Andersson ;; Maintainer: Vasilij Schneidermann ;; Created: 16 May 2002 ;; Version: 1.7 ;; Keywords: convenience, matching ;; ;;; Commentary: ;; ;; Goto Last Change ;; ;; Goto the point of the most recent edit in the buffer. ;; When repeated, goto the second most recent edit, etc. ;; Negative argument, C-u -, for reverse direction. ;; Works by looking into buffer-undo-list to find points of edit. ;; ;; You would probably like to bind this command to a key. ;; For example in your ~/.emacs: ;; ;; (require 'goto-chg) ;; ;; (global-set-key [(control ?.)] 'goto-last-change) ;; (global-set-key [(control ?,)] 'goto-last-change-reverse) ;; ;; Works with emacs-19.29, 19.31, 20.3, 20.7, 21.1, 21.4, 22.1 and 23.1 ;; Works with XEmacs-20.4 and 21.4 (but see todo about `last-command' below) ;; ;;-------------------------------------------------------------------- ;; History ;; ;; Ver 1.7 2017-09-17 Vasilij Schneidermann ;; Make it work with undo-tree-mode (see ;; ) ;; Ver 1.6 2013-12-12 David Andersson ;; Add keywords; Cleanup comments ;; Ver 1.5 2013-12-11 David Andersson ;; Autoload and document `goto-last-change-reverse' ;; Ver 1.4 2008-09-20 David Andersson ;; Improved property change description; Update comments. ;; Ver 1.3 2007-03-14 David Andersson ;; Added `goto-last-change-reverse' ;; Ver 1.2 2003-04-06 David Andersson ;; Don't let repeating error depthen glc-probe-depth. ;; Ver 1.1 2003-04-06 David Andersson ;; Zero arg describe changes. Negative arg go back. ;; Autoload. Remove message using nil in stead of an empty string. ;; Ver 1.0 2002-05-18 David Andersson ;; Initial version ;; ;;-------------------------------------------------------------------- ;; ;;todo: Rename "goto-chg.el" -> "gotochange.el" or "goto-chgs" ? ;;todo: Rename function goto-last-change -> goto-last-edit ? ;;todo: Rename adjective "-last-" -> "-latest-" or "-most-recent-" ? ;;todo: There are some, maybe useful, funcs for region undo ;; in simple.el in emacs 20. Take a look. ;;todo: Add functionality to visit changed point in text order, not only in ;; chronological order. (Naa, highlight-changes-mode does that). ;;todo: Inverse indication that a change has been saved or not ;;todo: Highlight the range of text involved in the last change? ;;todo: See session-jump-to-last-change in session.el? ;;todo: Unhide invisible text (e.g. outline mode) like isearch do. ;;todo: XEmacs sets last-command to `t' after an error, so you cannot reverse ;; after "No furter change info". Should we bother? ;;todo: Try distinguish "No further change info" (end of truncated undo list) ;; and "No further changes" (end of a complete undo list). ;; ;;-------------------------------------------------------------------- ;;; Code: (defvar glc-default-span 8 "*goto-last-change don't visit the same point twice. glc-default-span tells how far around a visited point not to visit again.") (defvar glc-current-span 8 "Internal for goto-last-change.\nA copy of glc-default-span or the ARG passed to goto-last-change.") (defvar glc-probe-depth 0 "Internal for goto-last-change.\nIt is non-zero between successive goto-last-change.") ;;todo: Find begin and end of line, then use it somewhere (defun glc-center-ellipsis (str maxlen &optional ellipsis) "Truncate STRING in the middle to length MAXLEN. If STRING is max MAXLEN just return the string. Optional third argument is the replacement, which defaults to \"...\"." (if (<= (length str) maxlen) str ;; else (let* ((lipsis (or ellipsis "...")) (i (/ (- maxlen (length lipsis)) 2))) (concat (substring str 0 i) lipsis (substring str (- i)))))) (defun glc-adjust-pos2 (pos p1 p2 adj) ;; Helper function to glc-adjust-pos ;; p1, p2: interval where an edit occured ;; adj: amount of text added (positive) or removed (negativ) by the edit ;; Return pos if well before p1, or pos+adj if well after p2, or nil if too close (cond ((<= pos (- p1 glc-current-span)) pos) ((> pos (+ p2 glc-current-span)) (+ pos adj)) ((zerop glc-current-span) p1) (t nil))) (defun glc-adjust-pos (pos e) "Given POS, a buffer position before the edit E, compute and return the \"same\" buffer position after E happened. Exception: return nil if POS is closer than `glc-current-span' to the edit E. \nInsertion edits before POS returns a larger value. Deletion edits before POS returns a smaller value. \nThe edit E is an entry from the `buffer-undo-list'. See for details." (cond ((atom e) ; nil==cmd boundary, or, num==changed pos pos) ((numberp (car e)) ; (beg . end)==insertion (glc-adjust-pos2 pos (car e) (car e) (- (cdr e) (car e)))) ((stringp (car e)) ; (string . pos)==deletion (glc-adjust-pos2 pos (abs (cdr e)) (+ (abs (cdr e)) (length (car e))) (- (length (car e))))) ((null (car e)) ; (nil prop val beg . end)==prop change (glc-adjust-pos2 pos (nth 3 e) (nthcdr 4 e) 0)) (t ; (marker . dist)==marker moved pos))) ;; If recursive in stead of iterative (while), it tends to fill the call stack. ;; (Isn't it tail optimized?) (defun glc-adjust-list (r) "R is list of edit entries in chronological order. Pick the point of the first edit entry and update that point with the second, third, etc, edit entries. Return the final updated point, or nil if the point was closer than `glc-current-span' to some edit in R. \nR is basically a reversed slice from the buffer-undo-list." (if r ;; Get pos (let ((pos (glc-get-pos (car r)))) (setq r (cdr r)) ;; Walk back in reverse list (while (and r pos) (setq pos (glc-adjust-pos pos (car r)) r (cdr r))) pos) ;; else nil)) (defun glc-get-pos (e) "If E represents an edit, return a position value in E, the position where the edit took place. Return nil if E represents no real change. \nE is an entry in the buffer-undo-list." (cond ((numberp e) e) ; num==changed position ((atom e) nil) ; nil==command boundary ((numberp (car e)) (cdr e)) ; (beg . end)==insertion ((stringp (car e)) (abs (cdr e))) ; (string . pos)==deletion ((null (car e)) (nthcdr 4 e)) ; (nil ...)==text property change ((atom (car e)) nil) ; (t ...)==file modification time (t nil))) ; (marker ...)==marker moved (defun glc-get-descript (e &optional n) "If E represents an edit, return a short string describing E. Return nil if E represents no real change. \nE is an entry in the buffer-undo-list." (let ((nn (or (format "T-%d: " n) ""))) (cond ((numberp e) "New position") ; num==changed position ((atom e) nil) ; nil==command boundary ((numberp (car e)) ; (beg . end)==insertion (if (and n (< n 2)) (format "%sInserted %d chars \"%s\"" nn (- (cdr e) (car e)) (glc-center-ellipsis (buffer-substring (car e) (cdr e)) 60)) ;; else ;; An older insert. The inserted text cannot easily be computed. ;; Just show the char count. (format "%sInserted %d chars" nn (- (cdr e) (car e))))) ((stringp (car e)) ; (string . pos)==deletion (format "%sDeleted \"%s\"" nn (glc-center-ellipsis (car e) 60))) ((null (car e)) ; (nil ...)==text property change (format "%sProperty change" nn)) ((atom (car e)) nil) ; (t ...)==file modification time (t nil)))) ; (marker ...)==marker moved (defun glc-is-positionable (e) "Return non-nil if E is an insertion, deletion or text property change. \nE is an entry in the buffer-undo-list." (and (not (numberp e)) (glc-get-pos e))) (defun glc-is-filetime (e) "Return t if E indicates a buffer became \"modified\", that is, it was previously saved or unchanged. Nil otherwise." (and (listp e) (eq (car e) t))) ;;;###autoload (defun goto-last-change (arg) "Go to the point where the last edit was made in the current buffer. Repeat the command to go to the second last edit, etc. \nTo go back to more recent edit, the reverse of this command, use \\[goto-last-change-reverse] or precede this command with \\[universal-argument] - (minus). \nIt does not go to the same point twice even if there has been many edits there. I call the minimal distance between distinguishable edits \"span\". Set variable `glc-default-span' to control how close is \"the same point\". Default span is 8. The span can be changed temporarily with \\[universal-argument] right before \\[goto-last-change]: \\[universal-argument] set current span to that number, \\[universal-argument] (no number) multiplies span by 4, starting with default. The so set span remains until it is changed again with \\[universal-argument], or the consecutive repetition of this command is ended by any other command. \nWhen span is zero (i.e. \\[universal-argument] 0) subsequent \\[goto-last-change] visits each and every point of edit and a message shows what change was made there. In this case it may go to the same point twice. \nThis command uses undo information. If undo is disabled, so is this command. At times, when undo information becomes too large, the oldest information is discarded. See variable `undo-limit'." (interactive "P") (cond ((not (eq this-command last-command)) ;; Start a glc sequence ;; Don't go to current point if last command was an obvious edit ;; (yank or self-insert, but not kill-region). Makes it easier to ;; jump back and forth when copying seleced lines. (setq glc-probe-depth (if (memq last-command '(yank self-insert-command)) 1 0) glc-direction 1 glc-current-span glc-default-span) (if (< (prefix-numeric-value arg) 0) (error "Negative arg: Cannot reverse as the first operation")))) (cond ((null buffer-undo-list) (error "Buffer has not been changed")) ((eq buffer-undo-list t) (error "No change info (undo is disabled)"))) (cond ((numberp arg) ; Numeric arg sets span (setq glc-current-span (abs arg))) ((consp arg) ; C-u's multiply previous span by 4 (setq glc-current-span (* (abs (car arg)) glc-default-span)) (message "Current span is %d chars" glc-current-span))) ;todo: keep message with "waiting" and "is saved" (cond ((< (prefix-numeric-value arg) 0) (setq glc-direction -1)) (t (setq glc-direction 1))) (let (rev ; Reversed (and filtered) undo list pos ; The pos we look for, nil until found (n 0) ; Steps in undo list (length of 'rev') (l buffer-undo-list) (passed-save-entry (not (buffer-modified-p))) (new-probe-depth glc-probe-depth) (undo-tree-p (bound-and-true-p undo-tree-mode)) glc-seen-canary) ;; Walk back and forth in the buffer-undo-list, each time one step deeper, ;; until we can walk back the whole list with a 'pos' that is not coming ;; too close to another edit. (while (null pos) (setq new-probe-depth (+ new-probe-depth glc-direction)) (if (< glc-direction 0) (setq rev () n 0 l buffer-undo-list passed-save-entry (not (buffer-modified-p)))) (if (< new-probe-depth 1) (error "No later change info")) (if (> n 150) (message "working...")) ;; Walk forward in buffer-undo-list, glc-probe-depth steps. ;; Build reverse list along the way (if (not undo-tree-p) (while (< n new-probe-depth) (cond ((null l) ;(setq this-command t) ; Disrupt repeat sequence (error "No further change info")) ((glc-is-positionable (car l)) (setq n (1+ n) rev (cons (car l) rev))) ((or passed-save-entry (glc-is-filetime (car l))) (setq passed-save-entry t))) (setq l (cdr l))) (when (not glc-seen-canary) (while (and (not (null l)) (not glc-seen-canary) (< n new-probe-depth)) (cond ((eq 'undo-tree-canary (car l)) ; used by buffer-undo-tree (message "Canary found...") (setq l (undo-tree-current buffer-undo-tree) glc-seen-canary t)) ((glc-is-positionable (car l)) (setq n (1+ n) rev (cons (car l) rev))) ((or passed-save-entry (glc-is-filetime (car l))) (setq passed-save-entry t))) (when (not glc-seen-canary) (setq l (cdr l))))) (when glc-seen-canary (while (< n new-probe-depth) (cond ((null l) ;(setq this-command t) ; Disrupt repeat sequence (error "No further change info")) ((glc-is-positionable (car (undo-tree-node-undo l))) (setq n (1+ n) rev (cons (car (undo-tree-node-undo l)) rev))) ((or passed-save-entry (glc-is-filetime (car (undo-tree-node-undo l)))) (setq passed-save-entry t))) (setq l (undo-tree-node-previous l)))) (when (null l) (error "No further change info"))) ;; Walk back in reverse list, from older to newer edits. ;; Adjusting pos along the way. (setq pos (glc-adjust-list rev))) ;; Found a place not previously visited, in 'pos'. ;; (An error have been issued if nothing (more) found.) (if (> n 150) (message nil)) ; remove message "working..." (if (and (= glc-current-span 0) (glc-get-descript (car rev) n)) (message "%s" (glc-get-descript (car rev) n)) ;; else (if passed-save-entry (message "(This change is saved)"))) (setq glc-probe-depth new-probe-depth) (goto-char pos))) ;;;###autoload (defun goto-last-change-reverse (arg) "Go back to more recent changes after \\[goto-last-change] have been used. See `goto-last-change' for use of prefix argument." (interactive "P") ;; Negate arg, all kinds (cond ((eq arg nil) (setq arg '-)) ((eq arg '-) (setq arg nil)) ((listp arg) (setq arg (list (- (car arg))))) (t (setq arg (- arg)))) ;; Make 'goto-last-change-reverse' look like 'goto-last-change' (cond ((eq last-command this-command) (setq last-command 'goto-last-change))) (setq this-command 'goto-last-change) ;; Call 'goto-last-change' to do the job (goto-last-change arg)) (provide 'goto-chg) ;;; goto-chg.el ends here evil-1.12.17/lib/undo-tree.el000066400000000000000000005204161360703323200156230ustar00rootroot00000000000000;;; undo-tree.el --- Treat undo history as a tree -*- lexical-binding: t; -*- ;; Copyright (C) 2009-2013 Free Software Foundation, Inc ;; Author: Toby Cubitt ;; Version: 0.6.5 ;; Keywords: convenience, files, undo, redo, history, tree ;; URL: http://www.dr-qubit.org/emacs.php ;; Repository: http://www.dr-qubit.org/git/undo-tree.git ;; This file is part of Emacs. ;; ;; This file is free software: you can redistribute it and/or modify it under ;; the terms of the GNU General Public License as published by the Free ;; Software Foundation, either version 3 of the License, or (at your option) ;; any later version. ;; ;; This program is distributed in the hope that it will be useful, but WITHOUT ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ;; more details. ;; ;; You should have received a copy of the GNU General Public License along ;; with GNU Emacs. If not, see . ;;; Commentary: ;; ;; Emacs has a powerful undo system. Unlike the standard undo/redo system in ;; most software, it allows you to recover *any* past state of a buffer ;; (whereas the standard undo/redo system can lose past states as soon as you ;; redo). However, this power comes at a price: many people find Emacs' undo ;; system confusing and difficult to use, spawning a number of packages that ;; replace it with the less powerful but more intuitive undo/redo system. ;; ;; Both the loss of data with standard undo/redo, and the confusion of Emacs' ;; undo, stem from trying to treat undo history as a linear sequence of ;; changes. It's not. The `undo-tree-mode' provided by this package replaces ;; Emacs' undo system with a system that treats undo history as what it is: a ;; branching tree of changes. This simple idea allows the more intuitive ;; behaviour of the standard undo/redo system to be combined with the power of ;; never losing any history. An added side bonus is that undo history can in ;; some cases be stored more efficiently, allowing more changes to accumulate ;; before Emacs starts discarding history. ;; ;; The only downside to this more advanced yet simpler undo system is that it ;; was inspired by Vim. But, after all, most successful religions steal the ;; best ideas from their competitors! ;; ;; ;; Installation ;; ============ ;; ;; This package has only been tested with Emacs versions 24 and CVS. It should ;; work in Emacs versions 22 and 23 too, but will not work without ;; modifications in earlier versions of Emacs. ;; ;; To install `undo-tree-mode', make sure this file is saved in a directory in ;; your `load-path', and add the line: ;; ;; (require 'undo-tree) ;; ;; to your .emacs file. Byte-compiling undo-tree.el is recommended (e.g. using ;; "M-x byte-compile-file" from within emacs). ;; ;; If you want to replace the standard Emacs' undo system with the ;; `undo-tree-mode' system in all buffers, you can enable it globally by ;; adding: ;; ;; (global-undo-tree-mode) ;; ;; to your .emacs file. ;; ;; ;; Quick-Start ;; =========== ;; ;; If you're the kind of person who likes to jump in the car and drive, ;; without bothering to first figure out whether the button on the left dips ;; the headlights or operates the ejector seat (after all, you'll soon figure ;; it out when you push it), then here's the minimum you need to know: ;; ;; `undo-tree-mode' and `global-undo-tree-mode' ;; Enable undo-tree mode (either in the current buffer or globally). ;; ;; C-_ C-/ (`undo-tree-undo') ;; Undo changes. ;; ;; M-_ C-? (`undo-tree-redo') ;; Redo changes. ;; ;; `undo-tree-switch-branch' ;; Switch undo-tree branch. ;; (What does this mean? Better press the button and see!) ;; ;; C-x u (`undo-tree-visualize') ;; Visualize the undo tree. ;; (Better try pressing this button too!) ;; ;; C-x r u (`undo-tree-save-state-to-register') ;; Save current buffer state to register. ;; ;; C-x r U (`undo-tree-restore-state-from-register') ;; Restore buffer state from register. ;; ;; ;; ;; In the undo-tree visualizer: ;; ;; p C-p (`undo-tree-visualize-undo') ;; Undo changes. ;; ;; n C-n (`undo-tree-visualize-redo') ;; Redo changes. ;; ;; b C-b (`undo-tree-visualize-switch-branch-left') ;; Switch to previous undo-tree branch. ;; ;; f C-f (`undo-tree-visualize-switch-branch-right') ;; Switch to next undo-tree branch. ;; ;; C- M-{ (`undo-tree-visualize-undo-to-x') ;; Undo changes up to last branch point. ;; ;; C- M-} (`undo-tree-visualize-redo-to-x') ;; Redo changes down to next branch point. ;; ;; n C-n (`undo-tree-visualize-redo') ;; Redo changes. ;; ;; (`undo-tree-visualizer-mouse-set') ;; Set state to node at mouse click. ;; ;; t (`undo-tree-visualizer-toggle-timestamps') ;; Toggle display of time-stamps. ;; ;; d (`undo-tree-visualizer-toggle-diff') ;; Toggle diff display. ;; ;; s (`undo-tree-visualizer-selection-mode') ;; Toggle keyboard selection mode. ;; ;; q (`undo-tree-visualizer-quit') ;; Quit undo-tree-visualizer. ;; ;; C-q (`undo-tree-visualizer-abort') ;; Abort undo-tree-visualizer. ;; ;; , < ;; Scroll left. ;; ;; . > ;; Scroll right. ;; ;; M-v ;; Scroll up. ;; ;; C-v ;; Scroll down. ;; ;; ;; ;; In visualizer selection mode: ;; ;; p C-p (`undo-tree-visualizer-select-previous') ;; Select previous node. ;; ;; n C-n (`undo-tree-visualizer-select-next') ;; Select next node. ;; ;; b C-b (`undo-tree-visualizer-select-left') ;; Select left sibling node. ;; ;; f C-f (`undo-tree-visualizer-select-right') ;; Select right sibling node. ;; ;; M-v ;; Select node 10 above. ;; ;; C-v ;; Select node 10 below. ;; ;; (`undo-tree-visualizer-set') ;; Set state to selected node and exit selection mode. ;; ;; s (`undo-tree-visualizer-mode') ;; Exit selection mode. ;; ;; t (`undo-tree-visualizer-toggle-timestamps') ;; Toggle display of time-stamps. ;; ;; d (`undo-tree-visualizer-toggle-diff') ;; Toggle diff display. ;; ;; q (`undo-tree-visualizer-quit') ;; Quit undo-tree-visualizer. ;; ;; C-q (`undo-tree-visualizer-abort') ;; Abort undo-tree-visualizer. ;; ;; , < ;; Scroll left. ;; ;; . > ;; Scroll right. ;; ;; ;; ;; Persistent undo history: ;; ;; Note: Requires Emacs version 24.3 or higher. ;; ;; `undo-tree-auto-save-history' (variable) ;; automatically save and restore undo-tree history along with buffer ;; (disabled by default) ;; ;; `undo-tree-save-history' (command) ;; manually save undo history to file ;; ;; `undo-tree-load-history' (command) ;; manually load undo history from file ;; ;; ;; ;; Compressing undo history: ;; ;; Undo history files cannot grow beyond the maximum undo tree size, which ;; is limited by `undo-limit', `undo-strong-limit' and ;; `undo-outer-limit'. Nevertheless, undo history files can grow quite ;; large. If you want to automatically compress undo history, add the ;; following advice to your .emacs file (replacing ".gz" with the filename ;; extension of your favourite compression algorithm): ;; ;; (defadvice undo-tree-make-history-save-file-name ;; (after undo-tree activate) ;; (setq ad-return-value (concat ad-return-value ".gz"))) ;; ;; ;; ;; ;; Undo Systems ;; ============ ;; ;; To understand the different undo systems, it's easiest to consider an ;; example. Imagine you make a few edits in a buffer. As you edit, you ;; accumulate a history of changes, which we might visualize as a string of ;; past buffer states, growing downwards: ;; ;; o (initial buffer state) ;; | ;; | ;; o (first edit) ;; | ;; | ;; o (second edit) ;; | ;; | ;; x (current buffer state) ;; ;; ;; Now imagine that you undo the last two changes. We can visualize this as ;; rewinding the current state back two steps: ;; ;; o (initial buffer state) ;; | ;; | ;; x (current buffer state) ;; | ;; | ;; o ;; | ;; | ;; o ;; ;; ;; However, this isn't a good representation of what Emacs' undo system ;; does. Instead, it treats the undos as *new* changes to the buffer, and adds ;; them to the history: ;; ;; o (initial buffer state) ;; | ;; | ;; o (first edit) ;; | ;; | ;; o (second edit) ;; | ;; | ;; x (buffer state before undo) ;; | ;; | ;; o (first undo) ;; | ;; | ;; x (second undo) ;; ;; ;; Actually, since the buffer returns to a previous state after an undo, ;; perhaps a better way to visualize it is to imagine the string of changes ;; turning back on itself: ;; ;; (initial buffer state) o ;; | ;; | ;; (first edit) o x (second undo) ;; | | ;; | | ;; (second edit) o o (first undo) ;; | / ;; |/ ;; o (buffer state before undo) ;; ;; Treating undos as new changes might seem a strange thing to do. But the ;; advantage becomes clear as soon as we imagine what happens when you edit ;; the buffer again. Since you've undone a couple of changes, new edits will ;; branch off from the buffer state that you've rewound to. Conceptually, it ;; looks like this: ;; ;; o (initial buffer state) ;; | ;; | ;; o ;; |\ ;; | \ ;; o x (new edit) ;; | ;; | ;; o ;; ;; The standard undo/redo system only lets you go backwards and forwards ;; linearly. So as soon as you make that new edit, it discards the old ;; branch. Emacs' undo just keeps adding changes to the end of the string. So ;; the undo history in the two systems now looks like this: ;; ;; Undo/Redo: Emacs' undo ;; ;; o o ;; | | ;; | | ;; o o o ;; .\ | |\ ;; . \ | | \ ;; . x (new edit) o o | ;; (discarded . | / | ;; branch) . |/ | ;; . o | ;; | ;; | ;; x (new edit) ;; ;; Now, what if you change your mind about those undos, and decide you did ;; like those other changes you'd made after all? With the standard undo/redo ;; system, you're lost. There's no way to recover them, because that branch ;; was discarded when you made the new edit. ;; ;; However, in Emacs' undo system, those old buffer states are still there in ;; the undo history. You just have to rewind back through the new edit, and ;; back through the changes made by the undos, until you reach them. Of ;; course, since Emacs treats undos (even undos of undos!) as new changes, ;; you're really weaving backwards and forwards through the history, all the ;; time adding new changes to the end of the string as you go: ;; ;; o ;; | ;; | ;; o o o (undo new edit) ;; | |\ |\ ;; | | \ | \ ;; o o | | o (undo the undo) ;; | / | | | ;; |/ | | | ;; (trying to get o | | x (undo the undo) ;; to this state) | / ;; |/ ;; o ;; ;; So far, this is still reasonably intuitive to use. It doesn't behave so ;; differently to standard undo/redo, except that by going back far enough you ;; can access changes that would be lost in standard undo/redo. ;; ;; However, imagine that after undoing as just described, you decide you ;; actually want to rewind right back to the initial state. If you're lucky, ;; and haven't invoked any command since the last undo, you can just keep on ;; undoing until you get back to the start: ;; ;; (trying to get o x (got there!) ;; to this state) | | ;; | | ;; o o o o (keep undoing) ;; | |\ |\ | ;; | | \ | \ | ;; o o | | o o (keep undoing) ;; | / | | | / ;; |/ | | |/ ;; (already undid o | | o (got this far) ;; to this state) | / ;; |/ ;; o ;; ;; But if you're unlucky, and you happen to have moved the point (say) after ;; getting to the state labelled "got this far", then you've "broken the undo ;; chain". Hold on to something solid, because things are about to get ;; hairy. If you try to undo now, Emacs thinks you're trying to undo the ;; undos! So to get back to the initial state you now have to rewind through ;; *all* the changes, including the undos you just did: ;; ;; (trying to get o x (finally got there!) ;; to this state) | | ;; | | ;; o o o o o o ;; | |\ |\ |\ |\ | ;; | | \ | \ | \ | \ | ;; o o | | o o o | o o ;; | / | | | / | | | / ;; |/ | | |/ | | |/ ;; (already undid o | | o<. | | o ;; to this state) | / : | / ;; |/ : |/ ;; o : o ;; : ;; (got this far, but ;; broke the undo chain) ;; ;; Confused? ;; ;; In practice you can just hold down the undo key until you reach the buffer ;; state that you want. But whatever you do, don't move around in the buffer ;; to *check* that you've got back to where you want! Because you'll break the ;; undo chain, and then you'll have to traverse the entire string of undos ;; again, just to get back to the point at which you broke the ;; chain. Undo-in-region and commands such as `undo-only' help to make using ;; Emacs' undo a little easier, but nonetheless it remains confusing for many ;; people. ;; ;; ;; So what does `undo-tree-mode' do? Remember the diagram we drew to represent ;; the history we've been discussing (make a few edits, undo a couple of them, ;; and edit again)? The diagram that conceptually represented our undo ;; history, before we started discussing specific undo systems? It looked like ;; this: ;; ;; o (initial buffer state) ;; | ;; | ;; o ;; |\ ;; | \ ;; o x (current state) ;; | ;; | ;; o ;; ;; Well, that's *exactly* what the undo history looks like to ;; `undo-tree-mode'. It doesn't discard the old branch (as standard undo/redo ;; does), nor does it treat undos as new changes to be added to the end of a ;; linear string of buffer states (as Emacs' undo does). It just keeps track ;; of the tree of branching changes that make up the entire undo history. ;; ;; If you undo from this point, you'll rewind back up the tree to the previous ;; state: ;; ;; o ;; | ;; | ;; x (undo) ;; |\ ;; | \ ;; o o ;; | ;; | ;; o ;; ;; If you were to undo again, you'd rewind back to the initial state. If on ;; the other hand you redo the change, you'll end up back at the bottom of the ;; most recent branch: ;; ;; o (undo takes you here) ;; | ;; | ;; o (start here) ;; |\ ;; | \ ;; o x (redo takes you here) ;; | ;; | ;; o ;; ;; So far, this is just like the standard undo/redo system. But what if you ;; want to return to a buffer state located on a previous branch of the ;; history? Since `undo-tree-mode' keeps the entire history, you simply need ;; to tell it to switch to a different branch, and then redo the changes you ;; want: ;; ;; o ;; | ;; | ;; o (start here, but switch ;; |\ to the other branch) ;; | \ ;; (redo) o o ;; | ;; | ;; (redo) x ;; ;; Now you're on the other branch, if you undo and redo changes you'll stay on ;; that branch, moving up and down through the buffer states located on that ;; branch. Until you decide to switch branches again, of course. ;; ;; Real undo trees might have multiple branches and sub-branches: ;; ;; o ;; ____|______ ;; / \ ;; o o ;; ____|__ __| ;; / | \ / \ ;; o o o o x ;; | | ;; / \ / \ ;; o o o o ;; ;; Trying to imagine what Emacs' undo would do as you move about such a tree ;; will likely frazzle your brain circuits! But in `undo-tree-mode', you're ;; just moving around this undo history tree. Most of the time, you'll ;; probably only need to stay on the most recent branch, in which case it ;; behaves like standard undo/redo, and is just as simple to understand. But ;; if you ever need to recover a buffer state on a different branch, the ;; possibility of switching between branches and accessing the full undo ;; history is still there. ;; ;; ;; ;; The Undo-Tree Visualizer ;; ======================== ;; ;; Actually, it gets better. You don't have to imagine all these tree ;; diagrams, because `undo-tree-mode' includes an undo-tree visualizer which ;; draws them for you! In fact, it draws even better diagrams: it highlights ;; the node representing the current buffer state, it highlights the current ;; branch, and you can toggle the display of time-stamps (by hitting "t") and ;; a diff of the undo changes (by hitting "d"). (There's one other tiny ;; difference: the visualizer puts the most recent branch on the left rather ;; than the right.) ;; ;; Bring up the undo tree visualizer whenever you want by hitting "C-x u". ;; ;; In the visualizer, the usual keys for moving up and down a buffer instead ;; move up and down the undo history tree (e.g. the up and down arrow keys, or ;; "C-n" and "C-p"). The state of the "parent" buffer (the buffer whose undo ;; history you are visualizing) is updated as you move around the undo tree in ;; the visualizer. If you reach a branch point in the visualizer, the usual ;; keys for moving forward and backward in a buffer instead switch branch ;; (e.g. the left and right arrow keys, or "C-f" and "C-b"). ;; ;; Clicking with the mouse on any node in the visualizer will take you ;; directly to that node, resetting the state of the parent buffer to the ;; state represented by that node. ;; ;; You can also select nodes directly using the keyboard, by hitting "s" to ;; toggle selection mode. The usual motion keys now allow you to move around ;; the tree without changing the parent buffer. Hitting will reset the ;; state of the parent buffer to the state represented by the currently ;; selected node. ;; ;; It can be useful to see how long ago the parent buffer was in the state ;; represented by a particular node in the visualizer. Hitting "t" in the ;; visualizer toggles the display of time-stamps for all the nodes. (Note ;; that, because of the way `undo-tree-mode' works, these time-stamps may be ;; somewhat later than the true times, especially if it's been a long time ;; since you last undid any changes.) ;; ;; To get some idea of what changes are represented by a given node in the ;; tree, it can be useful to see a diff of the changes. Hit "d" in the ;; visualizer to toggle a diff display. This normally displays a diff between ;; the current state and the previous one, i.e. it shows you the changes that ;; will be applied if you undo (move up the tree). However, the diff display ;; really comes into its own in the visualizer's selection mode (see above), ;; where it instead shows a diff between the current state and the currently ;; selected state, i.e. it shows you the changes that will be applied if you ;; reset to the selected state. ;; ;; (Note that the diff is generated by the Emacs `diff' command, and is ;; displayed using `diff-mode'. See the corresponding customization groups if ;; you want to customize the diff display.) ;; ;; Finally, hitting "q" will quit the visualizer, leaving the parent buffer in ;; whatever state you ended at. Hitting "C-q" will abort the visualizer, ;; returning the parent buffer to whatever state it was originally in when the ;; visualizer was . ;; ;; ;; ;; Undo-in-Region ;; ============== ;; ;; Emacs allows a very useful and powerful method of undoing only selected ;; changes: when a region is active, only changes that affect the text within ;; that region will be undone. With the standard Emacs undo system, changes ;; produced by undoing-in-region naturally get added onto the end of the ;; linear undo history: ;; ;; o ;; | ;; | x (second undo-in-region) ;; o | ;; | | ;; | o (first undo-in-region) ;; o | ;; | / ;; |/ ;; o ;; ;; You can of course redo these undos-in-region as usual, by undoing the ;; undos: ;; ;; o ;; | ;; | o_ ;; o | \ ;; | | | ;; | o o (undo the undo-in-region) ;; o | | ;; | / | ;; |/ | ;; o x (undo the undo-in-region) ;; ;; ;; In `undo-tree-mode', undo-in-region works similarly: when there's an active ;; region, undoing only undoes changes that affect that region. However, the ;; way these undos-in-region are recorded in the undo history is quite ;; different. In `undo-tree-mode', undo-in-region creates a new branch in the ;; undo history. The new branch consists of an undo step that undoes some of ;; the changes that affect the current region, and another step that undoes ;; the remaining changes needed to rejoin the previous undo history. ;; ;; Previous undo history Undo-in-region ;; ;; o o ;; | | ;; | | ;; o o ;; | |\ ;; | | \ ;; o o x (undo-in-region) ;; | | | ;; | | | ;; x o o ;; ;; As long as you don't change the active region after undoing-in-region, ;; continuing to undo-in-region extends the new branch, pulling more changes ;; that affect the current region into an undo step immediately above your ;; current location in the undo tree, and pushing the point at which the new ;; branch is attached further up the tree: ;; ;; First undo-in-region Second undo-in-region ;; ;; o o ;; | |\ ;; | | \ ;; o o x (undo-in-region) ;; |\ | | ;; | \ | | ;; o x o o ;; | | | | ;; | | | | ;; o o o o ;; ;; Redoing takes you back down the undo tree, as usual (as long as you haven't ;; changed the active region after undoing-in-region, it doesn't matter if it ;; is still active): ;; ;; o ;; |\ ;; | \ ;; o o ;; | | ;; | | ;; o o (redo) ;; | | ;; | | ;; o x (redo) ;; ;; ;; What about redo-in-region? Obviously, this only makes sense if you have ;; already undone some changes, so that there are some changes to redo! ;; Redoing-in-region splits off a new branch of the undo history below your ;; current location in the undo tree. This time, the new branch consists of a ;; redo step that redoes some of the redo changes that affect the current ;; region, followed by all the remaining redo changes. ;; ;; Previous undo history Redo-in-region ;; ;; o o ;; | | ;; | | ;; x o ;; | |\ ;; | | \ ;; o o x (redo-in-region) ;; | | | ;; | | | ;; o o o ;; ;; As long as you don't change the active region after redoing-in-region, ;; continuing to redo-in-region extends the new branch, pulling more redo ;; changes into a redo step immediately below your current location in the ;; undo tree. ;; ;; First redo-in-region Second redo-in-region ;; ;; o o ;; | | ;; | | ;; o o ;; |\ |\ ;; | \ | \ ;; o x (redo-in-region) o o ;; | | | | ;; | | | | ;; o o o x (redo-in-region) ;; | ;; | ;; o ;; ;; Note that undo-in-region and redo-in-region only ever add new changes to ;; the undo tree, they *never* modify existing undo history. So you can always ;; return to previous buffer states by switching to a previous branch of the ;; tree. ;;; Code: (eval-when-compile (require 'cl)) (require 'diff) ;;; ===================================================================== ;;; Compatibility hacks for older Emacsen ;; `characterp' isn't defined in Emacs versions < 23 (unless (fboundp 'characterp) (defalias 'characterp 'char-valid-p)) ;; `region-active-p' isn't defined in Emacs versions < 23 (unless (fboundp 'region-active-p) (defun region-active-p () (and transient-mark-mode mark-active))) ;; `registerv' defstruct isn't defined in Emacs versions < 24 (unless (fboundp 'registerv-make) (defmacro registerv-make (data &rest _dummy) data)) (unless (fboundp 'registerv-data) (defmacro registerv-data (data) data)) ;; `diff-no-select' and `diff-file-local-copy' aren't defined in Emacs ;; versions < 24 (copied and adapted from Emacs 24) (unless (fboundp 'diff-no-select) (defun diff-no-select (old new &optional switches no-async buf) ;; Noninteractive helper for creating and reverting diff buffers (unless (bufferp new) (setq new (expand-file-name new))) (unless (bufferp old) (setq old (expand-file-name old))) (or switches (setq switches diff-switches)) ; If not specified, use default. (unless (listp switches) (setq switches (list switches))) (or buf (setq buf (get-buffer-create "*Diff*"))) (let* ((old-alt (diff-file-local-copy old)) (new-alt (diff-file-local-copy new)) (command (mapconcat 'identity `(,diff-command ;; Use explicitly specified switches ,@switches ,@(mapcar #'shell-quote-argument (nconc (when (or old-alt new-alt) (list "-L" (if (stringp old) old (prin1-to-string old)) "-L" (if (stringp new) new (prin1-to-string new)))) (list (or old-alt old) (or new-alt new))))) " ")) (thisdir default-directory)) (with-current-buffer buf (setq buffer-read-only t) (buffer-disable-undo (current-buffer)) (let ((inhibit-read-only t)) (erase-buffer)) (buffer-enable-undo (current-buffer)) (diff-mode) (set (make-local-variable 'revert-buffer-function) (lambda (_ignore-auto _noconfirm) (diff-no-select old new switches no-async (current-buffer)))) (setq default-directory thisdir) (let ((inhibit-read-only t)) (insert command "\n")) (if (and (not no-async) (fboundp 'start-process)) (let ((proc (start-process "Diff" buf shell-file-name shell-command-switch command))) (set-process-filter proc 'diff-process-filter) (set-process-sentinel proc (lambda (proc _msg) (with-current-buffer (process-buffer proc) (diff-sentinel (process-exit-status proc)) (if old-alt (delete-file old-alt)) (if new-alt (delete-file new-alt)))))) ;; Async processes aren't available. (let ((inhibit-read-only t)) (diff-sentinel (call-process shell-file-name nil buf nil shell-command-switch command)) (if old-alt (delete-file old-alt)) (if new-alt (delete-file new-alt))))) buf))) (unless (fboundp 'diff-file-local-copy) (defun diff-file-local-copy (file-or-buf) (if (bufferp file-or-buf) (with-current-buffer file-or-buf (let ((tempfile (make-temp-file "buffer-content-"))) (write-region nil nil tempfile nil 'nomessage) tempfile)) (file-local-copy file-or-buf)))) ;; `user-error' isn't defined in Emacs < 24.3 (unless (fboundp 'user-error) (defalias 'user-error 'error) ;; prevent debugger being called on user errors (add-to-list 'debug-ignored-errors "^No further undo information") (add-to-list 'debug-ignored-errors "^No further redo information") (add-to-list 'debug-ignored-errors "^No further redo information for region")) ;;; ===================================================================== ;;; Global variables and customization options (defvar buffer-undo-tree nil "Tree of undo entries in current buffer.") (put 'buffer-undo-tree 'permanent-local t) (make-variable-buffer-local 'buffer-undo-tree) (defgroup undo-tree nil "Tree undo/redo." :group 'undo) (defcustom undo-tree-mode-lighter " Undo-Tree" "Lighter displayed in mode line when `undo-tree-mode' is enabled." :group 'undo-tree :type 'string) (defcustom undo-tree-incompatible-major-modes '(term-mode) "List of major-modes in which `undo-tree-mode' should not be enabled. \(See `turn-on-undo-tree-mode'.\)" :group 'undo-tree :type '(repeat symbol)) (defcustom undo-tree-enable-undo-in-region t "When non-nil, enable undo-in-region. When undo-in-region is enabled, undoing or redoing when the region is active (in `transient-mark-mode') or with a prefix argument (not in `transient-mark-mode') only undoes changes within the current region." :group 'undo-tree :type 'boolean) (defcustom undo-tree-auto-save-history nil "When non-nil, `undo-tree-mode' will save undo history to file when a buffer is saved to file. It will automatically load undo history when a buffer is loaded from file, if an undo save file exists. By default, undo-tree history is saved to a file called \"..~undo-tree~\" in the same directory as the file itself. To save under a different directory, customize `undo-tree-history-directory-alist' (see the documentation for that variable for details). WARNING! `undo-tree-auto-save-history' will not work properly in Emacs versions prior to 24.3, so it cannot be enabled via the customization interface in versions earlier than that one. To ignore this warning and enable it regardless, set `undo-tree-auto-save-history' to a non-nil value outside of customize." :group 'undo-tree :type (if (version-list-< (version-to-list emacs-version) '(24 3)) '(choice (const :tag "" nil)) 'boolean)) (defcustom undo-tree-history-directory-alist nil "Alist of filename patterns and undo history directory names. Each element looks like (REGEXP . DIRECTORY). Undo history for files with names matching REGEXP will be saved in DIRECTORY. DIRECTORY may be relative or absolute. If it is absolute, so that all matching files are backed up into the same directory, the file names in this directory will be the full name of the file backed up with all directory separators changed to `!' to prevent clashes. This will not work correctly if your filesystem truncates the resulting name. For the common case of all backups going into one directory, the alist should contain a single element pairing \".\" with the appropriate directory name. If this variable is nil, or it fails to match a filename, the backup is made in the original file's directory. On MS-DOS filesystems without long names this variable is always ignored." :group 'undo-tree :type '(repeat (cons (regexp :tag "Regexp matching filename") (directory :tag "Undo history directory name")))) (defcustom undo-tree-visualizer-relative-timestamps t "When non-nil, display times relative to current time when displaying time stamps in visualizer. Otherwise, display absolute times." :group 'undo-tree :type 'boolean) (defcustom undo-tree-visualizer-timestamps nil "When non-nil, display time-stamps by default in undo-tree visualizer. \\You can always toggle time-stamps on and off \ using \\[undo-tree-visualizer-toggle-timestamps], regardless of the setting of this variable." :group 'undo-tree :type 'boolean) (defcustom undo-tree-visualizer-diff nil "When non-nil, display diff by default in undo-tree visualizer. \\You can always toggle the diff display \ using \\[undo-tree-visualizer-toggle-diff], regardless of the setting of this variable." :group 'undo-tree :type 'boolean) (defcustom undo-tree-visualizer-lazy-drawing 100 "When non-nil, use lazy undo-tree drawing in visualizer. Setting this to a number causes the visualizer to switch to lazy drawing when the number of nodes in the tree is larger than this value. Lazy drawing means that only the visible portion of the tree will be drawn initially, and the tree will be extended later as needed. For the most part, the only visible effect of this is to significantly speed up displaying the visualizer for very large trees. There is one potential negative effect of lazy drawing. Other branches of the tree will only be drawn once the node from which they branch off becomes visible. So it can happen that certain portions of the tree that would be shown with lazy drawing disabled, will not be drawn immediately when it is enabled. However, this effect is quite rare in practice." :group 'undo-tree :type '(choice (const :tag "never" nil) (const :tag "always" t) (integer :tag "> size"))) (defface undo-tree-visualizer-default-face '((((class color)) :foreground "gray")) "Face used to draw undo-tree in visualizer." :group 'undo-tree) (defface undo-tree-visualizer-current-face '((((class color)) :foreground "red")) "Face used to highlight current undo-tree node in visualizer." :group 'undo-tree) (defface undo-tree-visualizer-active-branch-face '((((class color) (background dark)) (:foreground "white" :weight bold)) (((class color) (background light)) (:foreground "black" :weight bold))) "Face used to highlight active undo-tree branch in visualizer." :group 'undo-tree) (defface undo-tree-visualizer-register-face '((((class color)) :foreground "yellow")) "Face used to highlight undo-tree nodes saved to a register in visualizer." :group 'undo-tree) (defface undo-tree-visualizer-unmodified-face '((((class color)) :foreground "cyan")) "Face used to highlight nodes corresponding to unmodified buffers in visualizer." :group 'undo-tree) (defvar undo-tree-visualizer-parent-buffer nil "Parent buffer in visualizer.") (put 'undo-tree-visualizer-parent-buffer 'permanent-local t) (make-variable-buffer-local 'undo-tree-visualizer-parent-buffer) ;; stores modification time of parent buffer's file, if any (defvar undo-tree-visualizer-parent-mtime nil) (put 'undo-tree-visualizer-parent-mtime 'permanent-local t) (make-variable-buffer-local 'undo-tree-visualizer-parent-mtime) ;; stores current horizontal spacing needed for drawing undo-tree (defvar undo-tree-visualizer-spacing nil) (put 'undo-tree-visualizer-spacing 'permanent-local t) (make-variable-buffer-local 'undo-tree-visualizer-spacing) ;; calculate horizontal spacing required for drawing tree with current ;; settings (defsubst undo-tree-visualizer-calculate-spacing () (if undo-tree-visualizer-timestamps (if undo-tree-visualizer-relative-timestamps 9 13) 3)) ;; holds node that was current when visualizer was invoked (defvar undo-tree-visualizer-initial-node nil) (put 'undo-tree-visualizer-initial-node 'permanent-local t) (make-variable-buffer-local 'undo-tree-visualizer-initial-node) ;; holds currently selected node in visualizer selection mode (defvar undo-tree-visualizer-selected-node nil) (put 'undo-tree-visualizer-selected-node 'permanent-local t) (make-variable-buffer-local 'undo-tree-visualizer-selected) ;; used to store nodes at edge of currently drawn portion of tree (defvar undo-tree-visualizer-needs-extending-down nil) (put 'undo-tree-visualizer-needs-extending-down 'permanent-local t) (make-variable-buffer-local 'undo-tree-visualizer-needs-extending-down) (defvar undo-tree-visualizer-needs-extending-up nil) (put 'undo-tree-visualizer-needs-extending-up 'permanent-local t) (make-variable-buffer-local 'undo-tree-visualizer-needs-extending-up) ;; dynamically bound to t when undoing from visualizer, to inhibit ;; `undo-tree-kill-visualizer' hook function in parent buffer (defvar undo-tree-inhibit-kill-visualizer nil) ;; can be let-bound to a face name, used in drawing functions (defvar undo-tree-insert-face nil) ;; visualizer buffer names (defconst undo-tree-visualizer-buffer-name " *undo-tree*") (defconst undo-tree-diff-buffer-name "*undo-tree Diff*") ;; install history-auto-save hooks (add-hook 'write-file-functions 'undo-tree-save-history-hook) (add-hook 'find-file-hook 'undo-tree-load-history-hook) ;;; ================================================================= ;;; Default keymaps (defvar undo-tree-map nil "Keymap used in undo-tree-mode.") (unless undo-tree-map (let ((map (make-sparse-keymap))) ;; remap `undo' and `undo-only' to `undo-tree-undo' (define-key map [remap undo] 'undo-tree-undo) (define-key map [remap undo-only] 'undo-tree-undo) ;; bind standard undo bindings (since these match redo counterparts) (define-key map (kbd "C-/") 'undo-tree-undo) (define-key map "\C-_" 'undo-tree-undo) ;; redo doesn't exist normally, so define our own keybindings (define-key map (kbd "C-?") 'undo-tree-redo) (define-key map (kbd "M-_") 'undo-tree-redo) ;; just in case something has defined `redo'... (define-key map [remap redo] 'undo-tree-redo) ;; we use "C-x u" for the undo-tree visualizer (define-key map (kbd "\C-x u") 'undo-tree-visualize) ;; bind register commands (define-key map (kbd "C-x r u") 'undo-tree-save-state-to-register) (define-key map (kbd "C-x r U") 'undo-tree-restore-state-from-register) ;; set keymap (setq undo-tree-map map))) (defvar undo-tree-visualizer-mode-map nil "Keymap used in undo-tree visualizer.") (unless undo-tree-visualizer-mode-map (let ((map (make-sparse-keymap))) ;; vertical motion keys undo/redo (define-key map [remap previous-line] 'undo-tree-visualize-undo) (define-key map [remap next-line] 'undo-tree-visualize-redo) (define-key map [up] 'undo-tree-visualize-undo) (define-key map "p" 'undo-tree-visualize-undo) (define-key map "\C-p" 'undo-tree-visualize-undo) (define-key map [down] 'undo-tree-visualize-redo) (define-key map "n" 'undo-tree-visualize-redo) (define-key map "\C-n" 'undo-tree-visualize-redo) ;; horizontal motion keys switch branch (define-key map [remap forward-char] 'undo-tree-visualize-switch-branch-right) (define-key map [remap backward-char] 'undo-tree-visualize-switch-branch-left) (define-key map [right] 'undo-tree-visualize-switch-branch-right) (define-key map "f" 'undo-tree-visualize-switch-branch-right) (define-key map "\C-f" 'undo-tree-visualize-switch-branch-right) (define-key map [left] 'undo-tree-visualize-switch-branch-left) (define-key map "b" 'undo-tree-visualize-switch-branch-left) (define-key map "\C-b" 'undo-tree-visualize-switch-branch-left) ;; paragraph motion keys undo/redo to significant points in tree (define-key map [remap backward-paragraph] 'undo-tree-visualize-undo-to-x) (define-key map [remap forward-paragraph] 'undo-tree-visualize-redo-to-x) (define-key map "\M-{" 'undo-tree-visualize-undo-to-x) (define-key map "\M-}" 'undo-tree-visualize-redo-to-x) (define-key map [C-up] 'undo-tree-visualize-undo-to-x) (define-key map [C-down] 'undo-tree-visualize-redo-to-x) ;; mouse sets buffer state to node at click (define-key map [mouse-1] 'undo-tree-visualizer-mouse-set) ;; toggle timestamps (define-key map "t" 'undo-tree-visualizer-toggle-timestamps) ;; toggle diff (define-key map "d" 'undo-tree-visualizer-toggle-diff) ;; toggle selection mode (define-key map "s" 'undo-tree-visualizer-selection-mode) ;; horizontal scrolling may be needed if the tree is very wide (define-key map "," 'undo-tree-visualizer-scroll-left) (define-key map "." 'undo-tree-visualizer-scroll-right) (define-key map "<" 'undo-tree-visualizer-scroll-left) (define-key map ">" 'undo-tree-visualizer-scroll-right) ;; vertical scrolling may be needed if the tree is very tall (define-key map [next] 'undo-tree-visualizer-scroll-up) (define-key map [prior] 'undo-tree-visualizer-scroll-down) ;; quit/abort visualizer (define-key map "q" 'undo-tree-visualizer-quit) (define-key map "\C-q" 'undo-tree-visualizer-abort) ;; set keymap (setq undo-tree-visualizer-mode-map map))) (defvar undo-tree-visualizer-selection-mode-map nil "Keymap used in undo-tree visualizer selection mode.") (unless undo-tree-visualizer-selection-mode-map (let ((map (make-sparse-keymap))) ;; vertical motion keys move up and down tree (define-key map [remap previous-line] 'undo-tree-visualizer-select-previous) (define-key map [remap next-line] 'undo-tree-visualizer-select-next) (define-key map [up] 'undo-tree-visualizer-select-previous) (define-key map "p" 'undo-tree-visualizer-select-previous) (define-key map "\C-p" 'undo-tree-visualizer-select-previous) (define-key map [down] 'undo-tree-visualizer-select-next) (define-key map "n" 'undo-tree-visualizer-select-next) (define-key map "\C-n" 'undo-tree-visualizer-select-next) ;; vertical scroll keys move up and down quickly (define-key map [next] (lambda () (interactive) (undo-tree-visualizer-select-next 10))) (define-key map [prior] (lambda () (interactive) (undo-tree-visualizer-select-previous 10))) ;; horizontal motion keys move to left and right siblings (define-key map [remap forward-char] 'undo-tree-visualizer-select-right) (define-key map [remap backward-char] 'undo-tree-visualizer-select-left) (define-key map [right] 'undo-tree-visualizer-select-right) (define-key map "f" 'undo-tree-visualizer-select-right) (define-key map "\C-f" 'undo-tree-visualizer-select-right) (define-key map [left] 'undo-tree-visualizer-select-left) (define-key map "b" 'undo-tree-visualizer-select-left) (define-key map "\C-b" 'undo-tree-visualizer-select-left) ;; horizontal scroll keys move left or right quickly (define-key map "," (lambda () (interactive) (undo-tree-visualizer-select-left 10))) (define-key map "." (lambda () (interactive) (undo-tree-visualizer-select-right 10))) (define-key map "<" (lambda () (interactive) (undo-tree-visualizer-select-left 10))) (define-key map ">" (lambda () (interactive) (undo-tree-visualizer-select-right 10))) ;; sets buffer state to node at point (define-key map "\r" 'undo-tree-visualizer-set) ;; mouse selects node at click (define-key map [mouse-1] 'undo-tree-visualizer-mouse-select) ;; toggle diff (define-key map "d" 'undo-tree-visualizer-selection-toggle-diff) ;; set keymap (setq undo-tree-visualizer-selection-mode-map map))) (defvar undo-tree-old-undo-menu-item nil) (defun undo-tree-update-menu-bar () "Update `undo-tree-mode' Edit menu items." (if undo-tree-mode (progn ;; save old undo menu item, and install undo/redo menu items (setq undo-tree-old-undo-menu-item (cdr (assq 'undo (lookup-key global-map [menu-bar edit])))) (define-key (lookup-key global-map [menu-bar edit]) [undo] '(menu-item "Undo" undo-tree-undo :enable (and undo-tree-mode (not buffer-read-only) (not (eq t buffer-undo-list)) (undo-tree-node-previous (undo-tree-current buffer-undo-tree))) :help "Undo last operation")) (define-key-after (lookup-key global-map [menu-bar edit]) [redo] '(menu-item "Redo" undo-tree-redo :enable (and undo-tree-mode (not buffer-read-only) (not (eq t buffer-undo-list)) (undo-tree-node-next (undo-tree-current buffer-undo-tree))) :help "Redo last operation") 'undo)) ;; uninstall undo/redo menu items (define-key (lookup-key global-map [menu-bar edit]) [undo] undo-tree-old-undo-menu-item) (define-key (lookup-key global-map [menu-bar edit]) [redo] nil))) (add-hook 'menu-bar-update-hook 'undo-tree-update-menu-bar) ;;; ===================================================================== ;;; Undo-tree data structure (defstruct (undo-tree :named (:constructor nil) (:constructor make-undo-tree (&aux (root (undo-tree-make-node nil nil)) (current root) (size 0) (count 0) (object-pool (make-hash-table :test 'eq :weakness 'value)))) ;;(:copier nil) ) root current size count object-pool) (defstruct (undo-tree-node (:type vector) ; create unnamed struct (:constructor nil) (:constructor undo-tree-make-node (previous undo &optional redo &aux (timestamp (current-time)) (branch 0))) (:constructor undo-tree-make-node-backwards (next-node undo &optional redo &aux (next (list next-node)) (timestamp (current-time)) (branch 0))) (:copier nil)) previous next undo redo timestamp branch meta-data) (defmacro undo-tree-node-p (n) (let ((len (length (undo-tree-make-node nil nil)))) `(and (vectorp ,n) (= (length ,n) ,len)))) (defstruct (undo-tree-region-data (:type vector) ; create unnamed struct (:constructor nil) (:constructor undo-tree-make-region-data (&optional undo-beginning undo-end redo-beginning redo-end)) (:constructor undo-tree-make-undo-region-data (undo-beginning undo-end)) (:constructor undo-tree-make-redo-region-data (redo-beginning redo-end)) (:copier nil)) undo-beginning undo-end redo-beginning redo-end) (defmacro undo-tree-region-data-p (r) (let ((len (length (undo-tree-make-region-data)))) `(and (vectorp ,r) (= (length ,r) ,len)))) (defmacro undo-tree-node-clear-region-data (node) `(setf (undo-tree-node-meta-data ,node) (delq nil (delq :region (plist-put (undo-tree-node-meta-data ,node) :region nil))))) (defmacro undo-tree-node-undo-beginning (node) `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region))) (when (undo-tree-region-data-p r) (undo-tree-region-data-undo-beginning r)))) (defmacro undo-tree-node-undo-end (node) `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region))) (when (undo-tree-region-data-p r) (undo-tree-region-data-undo-end r)))) (defmacro undo-tree-node-redo-beginning (node) `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region))) (when (undo-tree-region-data-p r) (undo-tree-region-data-redo-beginning r)))) (defmacro undo-tree-node-redo-end (node) `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region))) (when (undo-tree-region-data-p r) (undo-tree-region-data-redo-end r)))) (defsetf undo-tree-node-undo-beginning (node) (val) `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region))) (unless (undo-tree-region-data-p r) (setf (undo-tree-node-meta-data ,node) (plist-put (undo-tree-node-meta-data ,node) :region (setq r (undo-tree-make-region-data))))) (setf (undo-tree-region-data-undo-beginning r) ,val))) (defsetf undo-tree-node-undo-end (node) (val) `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region))) (unless (undo-tree-region-data-p r) (setf (undo-tree-node-meta-data ,node) (plist-put (undo-tree-node-meta-data ,node) :region (setq r (undo-tree-make-region-data))))) (setf (undo-tree-region-data-undo-end r) ,val))) (defsetf undo-tree-node-redo-beginning (node) (val) `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region))) (unless (undo-tree-region-data-p r) (setf (undo-tree-node-meta-data ,node) (plist-put (undo-tree-node-meta-data ,node) :region (setq r (undo-tree-make-region-data))))) (setf (undo-tree-region-data-redo-beginning r) ,val))) (defsetf undo-tree-node-redo-end (node) (val) `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region))) (unless (undo-tree-region-data-p r) (setf (undo-tree-node-meta-data ,node) (plist-put (undo-tree-node-meta-data ,node) :region (setq r (undo-tree-make-region-data))))) (setf (undo-tree-region-data-redo-end r) ,val))) (defstruct (undo-tree-visualizer-data (:type vector) ; create unnamed struct (:constructor nil) (:constructor undo-tree-make-visualizer-data (&optional lwidth cwidth rwidth marker)) (:copier nil)) lwidth cwidth rwidth marker) (defmacro undo-tree-visualizer-data-p (v) (let ((len (length (undo-tree-make-visualizer-data)))) `(and (vectorp ,v) (= (length ,v) ,len)))) (defun undo-tree-node-clear-visualizer-data (node) (let ((plist (undo-tree-node-meta-data node))) (if (eq (car plist) :visualizer) (setf (undo-tree-node-meta-data node) (nthcdr 2 plist)) (while (and plist (not (eq (cadr plist) :visualizer))) (setq plist (cdr plist))) (if plist (setcdr plist (nthcdr 3 plist)))))) (defmacro undo-tree-node-lwidth (node) `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer))) (when (undo-tree-visualizer-data-p v) (undo-tree-visualizer-data-lwidth v)))) (defmacro undo-tree-node-cwidth (node) `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer))) (when (undo-tree-visualizer-data-p v) (undo-tree-visualizer-data-cwidth v)))) (defmacro undo-tree-node-rwidth (node) `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer))) (when (undo-tree-visualizer-data-p v) (undo-tree-visualizer-data-rwidth v)))) (defmacro undo-tree-node-marker (node) `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer))) (when (undo-tree-visualizer-data-p v) (undo-tree-visualizer-data-marker v)))) (defsetf undo-tree-node-lwidth (node) (val) `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer))) (unless (undo-tree-visualizer-data-p v) (setf (undo-tree-node-meta-data ,node) (plist-put (undo-tree-node-meta-data ,node) :visualizer (setq v (undo-tree-make-visualizer-data))))) (setf (undo-tree-visualizer-data-lwidth v) ,val))) (defsetf undo-tree-node-cwidth (node) (val) `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer))) (unless (undo-tree-visualizer-data-p v) (setf (undo-tree-node-meta-data ,node) (plist-put (undo-tree-node-meta-data ,node) :visualizer (setq v (undo-tree-make-visualizer-data))))) (setf (undo-tree-visualizer-data-cwidth v) ,val))) (defsetf undo-tree-node-rwidth (node) (val) `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer))) (unless (undo-tree-visualizer-data-p v) (setf (undo-tree-node-meta-data ,node) (plist-put (undo-tree-node-meta-data ,node) :visualizer (setq v (undo-tree-make-visualizer-data))))) (setf (undo-tree-visualizer-data-rwidth v) ,val))) (defsetf undo-tree-node-marker (node) (val) `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer))) (unless (undo-tree-visualizer-data-p v) (setf (undo-tree-node-meta-data ,node) (plist-put (undo-tree-node-meta-data ,node) :visualizer (setq v (undo-tree-make-visualizer-data))))) (setf (undo-tree-visualizer-data-marker v) ,val))) (defstruct (undo-tree-register-data (:type vector) (:constructor nil) (:constructor undo-tree-make-register-data (buffer node))) buffer node) (defun undo-tree-register-data-p (data) (and (vectorp data) (= (length data) 2) (undo-tree-node-p (undo-tree-register-data-node data)))) (defun undo-tree-register-data-print-func (data) (princ (format "an undo-tree state for buffer %s" (undo-tree-register-data-buffer data)))) (defmacro undo-tree-node-register (node) `(plist-get (undo-tree-node-meta-data ,node) :register)) (defsetf undo-tree-node-register (node) (val) `(setf (undo-tree-node-meta-data ,node) (plist-put (undo-tree-node-meta-data ,node) :register ,val))) ;;; ===================================================================== ;;; Basic undo-tree data structure functions (defun undo-tree-grow (undo) "Add an UNDO node to current branch of `buffer-undo-tree'." (let* ((current (undo-tree-current buffer-undo-tree)) (new (undo-tree-make-node current undo))) (push new (undo-tree-node-next current)) (setf (undo-tree-current buffer-undo-tree) new))) (defun undo-tree-grow-backwards (node undo &optional redo) "Add new node *above* undo-tree NODE, and return new node. Note that this will overwrite NODE's \"previous\" link, so should only be used on a detached NODE, never on nodes that are already part of `buffer-undo-tree'." (let ((new (undo-tree-make-node-backwards node undo redo))) (setf (undo-tree-node-previous node) new) new)) (defun undo-tree-splice-node (node splice) "Splice NODE into undo tree, below node SPLICE. Note that this will overwrite NODE's \"next\" and \"previous\" links, so should only be used on a detached NODE, never on nodes that are already part of `buffer-undo-tree'." (setf (undo-tree-node-next node) (undo-tree-node-next splice) (undo-tree-node-branch node) (undo-tree-node-branch splice) (undo-tree-node-previous node) splice (undo-tree-node-next splice) (list node) (undo-tree-node-branch splice) 0) (dolist (n (undo-tree-node-next node)) (setf (undo-tree-node-previous n) node))) (defun undo-tree-snip-node (node) "Snip NODE out of undo tree." (let* ((parent (undo-tree-node-previous node)) position p) ;; if NODE is only child, replace parent's next links with NODE's (if (= (length (undo-tree-node-next parent)) 0) (setf (undo-tree-node-next parent) (undo-tree-node-next node) (undo-tree-node-branch parent) (undo-tree-node-branch node)) ;; otherwise... (setq position (undo-tree-position node (undo-tree-node-next parent))) (cond ;; if active branch used do go via NODE, set parent's branch to active ;; branch of NODE ((= (undo-tree-node-branch parent) position) (setf (undo-tree-node-branch parent) (+ position (undo-tree-node-branch node)))) ;; if active branch didn't go via NODE, update parent's branch to point ;; to same node as before ((> (undo-tree-node-branch parent) position) (incf (undo-tree-node-branch parent) (1- (length (undo-tree-node-next node)))))) ;; replace NODE in parent's next list with NODE's entire next list (if (= position 0) (setf (undo-tree-node-next parent) (nconc (undo-tree-node-next node) (cdr (undo-tree-node-next parent)))) (setq p (nthcdr (1- position) (undo-tree-node-next parent))) (setcdr p (nconc (undo-tree-node-next node) (cddr p))))) ;; update previous links of NODE's children (dolist (n (undo-tree-node-next node)) (setf (undo-tree-node-previous n) parent)))) (defun undo-tree-mapc (--undo-tree-mapc-function-- node) ;; Apply FUNCTION to NODE and to each node below it. (let ((stack (list node)) n) (while stack (setq n (pop stack)) (funcall --undo-tree-mapc-function-- n) (setq stack (append (undo-tree-node-next n) stack))))) (defmacro undo-tree-num-branches () "Return number of branches at current undo tree node." '(length (undo-tree-node-next (undo-tree-current buffer-undo-tree)))) (defun undo-tree-position (node list) "Find the first occurrence of NODE in LIST. Return the index of the matching item, or nil of not found. Comparison is done with `eq'." (let ((i 0)) (catch 'found (while (progn (when (eq node (car list)) (throw 'found i)) (incf i) (setq list (cdr list)))) nil))) (defvar *undo-tree-id-counter* 0) (make-variable-buffer-local '*undo-tree-id-counter*) (defmacro undo-tree-generate-id () ;; Generate a new, unique id (uninterned symbol). ;; The name is made by appending a number to "undo-tree-id". ;; (Copied from CL package `gensym'.) `(let ((num (prog1 *undo-tree-id-counter* (incf *undo-tree-id-counter*)))) (make-symbol (format "undo-tree-id%d" num)))) (defun undo-tree-decircle (undo-tree) ;; Nullify PREVIOUS links of UNDO-TREE nodes, to make UNDO-TREE data ;; structure non-circular. (undo-tree-mapc (lambda (node) (dolist (n (undo-tree-node-next node)) (setf (undo-tree-node-previous n) nil))) (undo-tree-root undo-tree))) (defun undo-tree-recircle (undo-tree) ;; Recreate PREVIOUS links of UNDO-TREE nodes, to restore circular UNDO-TREE ;; data structure. (undo-tree-mapc (lambda (node) (dolist (n (undo-tree-node-next node)) (setf (undo-tree-node-previous n) node))) (undo-tree-root undo-tree))) ;;; ===================================================================== ;;; Undo list and undo changeset utility functions (defmacro undo-list-marker-elt-p (elt) `(markerp (car-safe ,elt))) (defmacro undo-list-GCd-marker-elt-p (elt) ;; Return t if ELT is a marker element whose marker has been moved to the ;; object-pool, so may potentially have been garbage-collected. ;; Note: Valid marker undo elements should be uniquely identified as cons ;; cells with a symbol in the car (replacing the marker), and a number in ;; the cdr. However, to guard against future changes to undo element ;; formats, we perform an additional redundant check on the symbol name. `(and (car-safe ,elt) (symbolp (car ,elt)) (let ((str (symbol-name (car ,elt)))) (and (> (length str) 12) (string= (substring str 0 12) "undo-tree-id"))) (numberp (cdr-safe ,elt)))) (defun undo-tree-move-GC-elts-to-pool (elt) ;; Move elements that can be garbage-collected into `buffer-undo-tree' ;; object pool, substituting a unique id that can be used to retrieve them ;; later. (Only markers require this treatment currently.) (when (undo-list-marker-elt-p elt) (let ((id (undo-tree-generate-id))) (puthash id (car elt) (undo-tree-object-pool buffer-undo-tree)) (setcar elt id)))) (defun undo-tree-restore-GC-elts-from-pool (elt) ;; Replace object id's in ELT with corresponding objects from ;; `buffer-undo-tree' object pool and return modified ELT, or return nil if ;; any object in ELT has been garbage-collected. (if (undo-list-GCd-marker-elt-p elt) (when (setcar elt (gethash (car elt) (undo-tree-object-pool buffer-undo-tree))) elt) elt)) (defun undo-list-clean-GCd-elts (undo-list) ;; Remove object id's from UNDO-LIST that refer to elements that have been ;; garbage-collected. UNDO-LIST is modified by side-effect. (while (undo-list-GCd-marker-elt-p (car undo-list)) (unless (gethash (caar undo-list) (undo-tree-object-pool buffer-undo-tree)) (setq undo-list (cdr undo-list)))) (let ((p undo-list)) (while (cdr p) (when (and (undo-list-GCd-marker-elt-p (cadr p)) (null (gethash (car (cadr p)) (undo-tree-object-pool buffer-undo-tree)))) (setcdr p (cddr p))) (setq p (cdr p)))) undo-list) (defun undo-list-pop-changeset (&optional discard-pos) ;; Pop changeset from `buffer-undo-list'. If DISCARD-POS is non-nil, discard ;; any position entries from changeset. ;; discard undo boundaries and (if DISCARD-POS is non-nil) position entries ;; at head of undo list (while (or (null (car buffer-undo-list)) (and discard-pos (integerp (car buffer-undo-list)))) (setq buffer-undo-list (cdr buffer-undo-list))) ;; pop elements up to next undo boundary, discarding position entries if ;; DISCARD-POS is non-nil (if (eq (car buffer-undo-list) 'undo-tree-canary) (push nil buffer-undo-list) (let* ((changeset (list (pop buffer-undo-list))) (p changeset)) (while (progn (undo-tree-move-GC-elts-to-pool (car p)) (while (and discard-pos (integerp (car buffer-undo-list))) (setq buffer-undo-list (cdr buffer-undo-list))) (and (car buffer-undo-list) (not (eq (car buffer-undo-list) 'undo-tree-canary)))) (setcdr p (list (pop buffer-undo-list))) (setq p (cdr p))) changeset))) (defun undo-tree-copy-list (undo-list) ;; Return a deep copy of first changeset in `undo-list'. Object id's are ;; replaced by corresponding objects from `buffer-undo-tree' object-pool. (when undo-list (let (copy p) ;; if first element contains an object id, replace it with object from ;; pool, discarding element entirely if it's been GC'd (while (null copy) (setq copy (undo-tree-restore-GC-elts-from-pool (pop undo-list)))) (setq copy (list copy) p copy) ;; copy remaining elements, replacing object id's with objects from ;; pool, or discarding them entirely if they've been GC'd (while undo-list (when (setcdr p (undo-tree-restore-GC-elts-from-pool (undo-copy-list-1 (pop undo-list)))) (setcdr p (list (cdr p))) (setq p (cdr p)))) copy))) (defun undo-list-transfer-to-tree () ;; Transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'. ;; `undo-list-transfer-to-tree' should never be called when undo is disabled ;; (i.e. `buffer-undo-tree' is t) (assert (not (eq buffer-undo-tree t))) ;; if `buffer-undo-tree' is empty, create initial undo-tree (when (null buffer-undo-tree) (setq buffer-undo-tree (make-undo-tree))) ;; make sure there's a canary at end of `buffer-undo-list' (when (null buffer-undo-list) (setq buffer-undo-list '(nil undo-tree-canary))) (unless (or (eq (cadr buffer-undo-list) 'undo-tree-canary) (eq (car buffer-undo-list) 'undo-tree-canary)) ;; create new node from first changeset in `buffer-undo-list', save old ;; `buffer-undo-tree' current node, and make new node the current node (let* ((node (undo-tree-make-node nil (undo-list-pop-changeset))) (splice (undo-tree-current buffer-undo-tree)) (size (undo-list-byte-size (undo-tree-node-undo node))) (count 1)) (setf (undo-tree-current buffer-undo-tree) node) ;; grow tree fragment backwards using `buffer-undo-list' changesets (while (and buffer-undo-list (not (eq (cadr buffer-undo-list) 'undo-tree-canary))) (setq node (undo-tree-grow-backwards node (undo-list-pop-changeset))) (incf size (undo-list-byte-size (undo-tree-node-undo node))) (incf count)) ;; if no undo history has been discarded from `buffer-undo-list' since ;; last transfer, splice new tree fragment onto end of old ;; `buffer-undo-tree' current node (if (or (eq (cadr buffer-undo-list) 'undo-tree-canary) (eq (car buffer-undo-list) 'undo-tree-canary)) (progn (setf (undo-tree-node-previous node) splice) (push node (undo-tree-node-next splice)) (setf (undo-tree-node-branch splice) 0) (incf (undo-tree-size buffer-undo-tree) size) (incf (undo-tree-count buffer-undo-tree) count)) ;; if undo history has been discarded, replace entire ;; `buffer-undo-tree' with new tree fragment (setq node (undo-tree-grow-backwards node nil)) (setf (undo-tree-root buffer-undo-tree) node) (setq buffer-undo-list '(nil undo-tree-canary)) (setf (undo-tree-size buffer-undo-tree) size) (setf (undo-tree-count buffer-undo-tree) count) (setq buffer-undo-list '(nil undo-tree-canary)))) ;; discard undo history if necessary (undo-tree-discard-history))) (defun undo-list-byte-size (undo-list) ;; Return size (in bytes) of UNDO-LIST (let ((size 0) (p undo-list)) (while p (incf size 8) ; cons cells use up 8 bytes (when (and (consp (car p)) (stringp (caar p))) (incf size (string-bytes (caar p)))) (setq p (cdr p))) size)) (defun undo-list-rebuild-from-tree () "Rebuild `buffer-undo-list' from information in `buffer-undo-tree'." (unless (eq buffer-undo-list t) (undo-list-transfer-to-tree) (setq buffer-undo-list nil) (when buffer-undo-tree (let ((stack (list (list (undo-tree-root buffer-undo-tree))))) (push (sort (mapcar 'identity (undo-tree-node-next (caar stack))) (lambda (a b) (time-less-p (undo-tree-node-timestamp a) (undo-tree-node-timestamp b)))) stack) ;; Traverse tree in depth-and-oldest-first order, but add undo records ;; on the way down, and redo records on the way up. (while (or (car stack) (not (eq (car (nth 1 stack)) (undo-tree-current buffer-undo-tree)))) (if (car stack) (progn (setq buffer-undo-list (append (undo-tree-node-undo (caar stack)) buffer-undo-list)) (undo-boundary) (push (sort (mapcar 'identity (undo-tree-node-next (caar stack))) (lambda (a b) (time-less-p (undo-tree-node-timestamp a) (undo-tree-node-timestamp b)))) stack)) (pop stack) (setq buffer-undo-list (append (undo-tree-node-redo (caar stack)) buffer-undo-list)) (undo-boundary) (pop (car stack)))))))) ;;; ===================================================================== ;;; History discarding utility functions (defun undo-tree-oldest-leaf (node) ;; Return oldest leaf node below NODE. (while (undo-tree-node-next node) (setq node (car (sort (mapcar 'identity (undo-tree-node-next node)) (lambda (a b) (time-less-p (undo-tree-node-timestamp a) (undo-tree-node-timestamp b))))))) node) (defun undo-tree-discard-node (node) ;; Discard NODE from `buffer-undo-tree', and return next in line for ;; discarding. ;; don't discard current node (unless (eq node (undo-tree-current buffer-undo-tree)) ;; discarding root node... (if (eq node (undo-tree-root buffer-undo-tree)) (cond ;; should always discard branches before root ((> (length (undo-tree-node-next node)) 1) (error "Trying to discard undo-tree root which still\ has multiple branches")) ;; don't discard root if current node is only child ((eq (car (undo-tree-node-next node)) (undo-tree-current buffer-undo-tree)) nil) ;; discard root (t ;; clear any register referring to root (let ((r (undo-tree-node-register node))) (when (and r (eq (get-register r) node)) (set-register r nil))) ;; make child of root into new root (setq node (setf (undo-tree-root buffer-undo-tree) (car (undo-tree-node-next node)))) ;; update undo-tree size (decf (undo-tree-size buffer-undo-tree) (+ (undo-list-byte-size (undo-tree-node-undo node)) (undo-list-byte-size (undo-tree-node-redo node)))) (decf (undo-tree-count buffer-undo-tree)) ;; discard new root's undo data and PREVIOUS link (setf (undo-tree-node-undo node) nil (undo-tree-node-redo node) nil (undo-tree-node-previous node) nil) ;; if new root has branches, or new root is current node, next node ;; to discard is oldest leaf, otherwise it's new root (if (or (> (length (undo-tree-node-next node)) 1) (eq (car (undo-tree-node-next node)) (undo-tree-current buffer-undo-tree))) (undo-tree-oldest-leaf node) node))) ;; discarding leaf node... (let* ((parent (undo-tree-node-previous node)) (current (nth (undo-tree-node-branch parent) (undo-tree-node-next parent)))) ;; clear any register referring to the discarded node (let ((r (undo-tree-node-register node))) (when (and r (eq (get-register r) node)) (set-register r nil))) ;; update undo-tree size (decf (undo-tree-size buffer-undo-tree) (+ (undo-list-byte-size (undo-tree-node-undo node)) (undo-list-byte-size (undo-tree-node-redo node)))) (decf (undo-tree-count buffer-undo-tree)) ;; discard leaf (setf (undo-tree-node-next parent) (delq node (undo-tree-node-next parent)) (undo-tree-node-branch parent) (undo-tree-position current (undo-tree-node-next parent))) ;; if parent has branches, or parent is current node, next node to ;; discard is oldest leaf, otherwise it's the parent itself (if (or (eq parent (undo-tree-current buffer-undo-tree)) (and (undo-tree-node-next parent) (or (not (eq parent (undo-tree-root buffer-undo-tree))) (> (length (undo-tree-node-next parent)) 1)))) (undo-tree-oldest-leaf parent) parent))))) (defun undo-tree-discard-history () "Discard undo history until we're within memory usage limits set by `undo-limit', `undo-strong-limit' and `undo-outer-limit'." (when (> (undo-tree-size buffer-undo-tree) undo-limit) ;; if there are no branches off root, first node to discard is root; ;; otherwise it's leaf node at botom of oldest branch (let ((node (if (> (length (undo-tree-node-next (undo-tree-root buffer-undo-tree))) 1) (undo-tree-oldest-leaf (undo-tree-root buffer-undo-tree)) (undo-tree-root buffer-undo-tree)))) ;; discard nodes until memory use is within `undo-strong-limit' (while (and node (> (undo-tree-size buffer-undo-tree) undo-strong-limit)) (setq node (undo-tree-discard-node node))) ;; discard nodes until next node to discard would bring memory use ;; within `undo-limit' (while (and node ;; check first if last discard has brought us within ;; `undo-limit', in case we can avoid more expensive ;; `undo-strong-limit' calculation ;; Note: this assumes undo-strong-limit > undo-limit; ;; if not, effectively undo-strong-limit = undo-limit (> (undo-tree-size buffer-undo-tree) undo-limit) (> (- (undo-tree-size buffer-undo-tree) ;; if next node to discard is root, the memory we ;; free-up comes from discarding changesets from its ;; only child... (if (eq node (undo-tree-root buffer-undo-tree)) (+ (undo-list-byte-size (undo-tree-node-undo (car (undo-tree-node-next node)))) (undo-list-byte-size (undo-tree-node-redo (car (undo-tree-node-next node))))) ;; ...otherwise, it comes from discarding changesets ;; from along with the node itself (+ (undo-list-byte-size (undo-tree-node-undo node)) (undo-list-byte-size (undo-tree-node-redo node))) )) undo-limit)) (setq node (undo-tree-discard-node node))) ;; if we're still over the `undo-outer-limit', discard entire history (when (> (undo-tree-size buffer-undo-tree) undo-outer-limit) ;; query first if `undo-ask-before-discard' is set (if undo-ask-before-discard (when (yes-or-no-p (format "Buffer `%s' undo info is %d bytes long; discard it? " (buffer-name) (undo-tree-size buffer-undo-tree))) (setq buffer-undo-tree nil)) ;; otherwise, discard and display warning (display-warning '(undo discard-info) (concat (format "Buffer `%s' undo info was %d bytes long.\n" (buffer-name) (undo-tree-size buffer-undo-tree)) "The undo info was discarded because it exceeded\ `undo-outer-limit'. This is normal if you executed a command that made a huge change to the buffer. In that case, to prevent similar problems in the future, set `undo-outer-limit' to a value that is large enough to cover the maximum size of normal changes you expect a single command to make, but not so large that it might exceed the maximum memory allotted to Emacs. If you did not execute any such command, the situation is probably due to a bug and you should report it. You can disable the popping up of this buffer by adding the entry \(undo discard-info) to the user option `warning-suppress-types', which is defined in the `warnings' library.\n") :warning) (setq buffer-undo-tree nil))) ))) ;;; ===================================================================== ;;; Visualizer utility functions (defun undo-tree-compute-widths (node) "Recursively compute widths for nodes below NODE." (let ((stack (list node)) res) (while stack ;; try to compute widths for node at top of stack (if (undo-tree-node-p (setq res (undo-tree-node-compute-widths (car stack)))) ;; if computation fails, it returns a node whose widths still need ;; computing, which we push onto the stack (push res stack) ;; otherwise, store widths and remove it from stack (setf (undo-tree-node-lwidth (car stack)) (aref res 0) (undo-tree-node-cwidth (car stack)) (aref res 1) (undo-tree-node-rwidth (car stack)) (aref res 2)) (pop stack))))) (defun undo-tree-node-compute-widths (node) ;; Compute NODE's left-, centre-, and right-subtree widths. Returns widths ;; (in a vector) if successful. Otherwise, returns a node whose widths need ;; calculating before NODE's can be calculated. (let ((num-children (length (undo-tree-node-next node))) (lwidth 0) (cwidth 0) (rwidth 0) p) (catch 'need-widths (cond ;; leaf nodes have 0 width ((= 0 num-children) (setf cwidth 1 (undo-tree-node-lwidth node) 0 (undo-tree-node-cwidth node) 1 (undo-tree-node-rwidth node) 0)) ;; odd number of children ((= (mod num-children 2) 1) (setq p (undo-tree-node-next node)) ;; compute left-width (dotimes (i (/ num-children 2)) (if (undo-tree-node-lwidth (car p)) (incf lwidth (+ (undo-tree-node-lwidth (car p)) (undo-tree-node-cwidth (car p)) (undo-tree-node-rwidth (car p)))) ;; if child's widths haven't been computed, return that child (throw 'need-widths (car p))) (setq p (cdr p))) (if (undo-tree-node-lwidth (car p)) (incf lwidth (undo-tree-node-lwidth (car p))) (throw 'need-widths (car p))) ;; centre-width is inherited from middle child (setf cwidth (undo-tree-node-cwidth (car p))) ;; compute right-width (incf rwidth (undo-tree-node-rwidth (car p))) (setq p (cdr p)) (dotimes (i (/ num-children 2)) (if (undo-tree-node-lwidth (car p)) (incf rwidth (+ (undo-tree-node-lwidth (car p)) (undo-tree-node-cwidth (car p)) (undo-tree-node-rwidth (car p)))) (throw 'need-widths (car p))) (setq p (cdr p)))) ;; even number of children (t (setq p (undo-tree-node-next node)) ;; compute left-width (dotimes (i (/ num-children 2)) (if (undo-tree-node-lwidth (car p)) (incf lwidth (+ (undo-tree-node-lwidth (car p)) (undo-tree-node-cwidth (car p)) (undo-tree-node-rwidth (car p)))) (throw 'need-widths (car p))) (setq p (cdr p))) ;; centre-width is 0 when number of children is even (setq cwidth 0) ;; compute right-width (dotimes (i (/ num-children 2)) (if (undo-tree-node-lwidth (car p)) (incf rwidth (+ (undo-tree-node-lwidth (car p)) (undo-tree-node-cwidth (car p)) (undo-tree-node-rwidth (car p)))) (throw 'need-widths (car p))) (setq p (cdr p))))) ;; return left-, centre- and right-widths (vector lwidth cwidth rwidth)))) (defun undo-tree-clear-visualizer-data (tree) ;; Clear visualizer data below NODE. (undo-tree-mapc (lambda (n) (undo-tree-node-clear-visualizer-data n)) (undo-tree-root tree))) (defun undo-tree-node-unmodified-p (node &optional mtime) ;; Return non-nil if NODE corresponds to a buffer state that once upon a ;; time was unmodified. If a file modification time MTIME is specified, ;; return non-nil if the corresponding buffer state really is unmodified. (let (changeset ntime) (setq changeset (or (undo-tree-node-redo node) (and (setq changeset (car (undo-tree-node-next node))) (undo-tree-node-undo changeset))) ntime (catch 'found (dolist (elt changeset) (when (and (consp elt) (eq (car elt) t) (consp (cdr elt)) (throw 'found (cdr elt))))))) (and ntime (or (null mtime) ;; high-precision timestamps (if (listp (cdr ntime)) (equal ntime mtime) ;; old-style timestamps (and (= (car ntime) (car mtime)) (= (cdr ntime) (cadr mtime)))))))) ;;; ===================================================================== ;;; Undo-in-region utility functions ;; `undo-elt-in-region' uses this as a dynamically-scoped variable (defvar undo-adjusted-markers nil) (defun undo-tree-pull-undo-in-region-branch (start end) ;; Pull out entries from undo changesets to create a new undo-in-region ;; branch, which undoes changeset entries lying between START and END first, ;; followed by remaining entries from the changesets, before rejoining the ;; existing undo tree history. Repeated calls will, if appropriate, extend ;; the current undo-in-region branch rather than creating a new one. ;; if we're just reverting the last redo-in-region, we don't need to ;; manipulate the undo tree at all (if (undo-tree-reverting-redo-in-region-p start end) t ; return t to indicate success ;; We build the `region-changeset' and `delta-list' lists forwards, using ;; pointers `r' and `d' to the penultimate element of the list. So that we ;; don't have to treat the first element differently, we prepend a dummy ;; leading nil to the lists, and have the pointers point to that ;; initially. ;; Note: using '(nil) instead of (list nil) in the `let*' results in ;; bizarre errors when the code is byte-compiled, where parts of the ;; lists appear to survive across different calls to this function. ;; An obscure byte-compiler bug, perhaps? (let* ((region-changeset (list nil)) (r region-changeset) (delta-list (list nil)) (d delta-list) (node (undo-tree-current buffer-undo-tree)) (repeated-undo-in-region (undo-tree-repeated-undo-in-region-p start end)) undo-adjusted-markers ; `undo-elt-in-region' expects this fragment splice original-fragment original-splice original-current got-visible-elt undo-list elt) ;; --- initialisation --- (cond ;; if this is a repeated undo in the same region, start pulling changes ;; from NODE at which undo-in-region branch iss attached, and detatch ;; the branch, using it as initial FRAGMENT of branch being constructed (repeated-undo-in-region (setq original-current node fragment (car (undo-tree-node-next node)) splice node) ;; undo up to node at which undo-in-region branch is attached ;; (recognizable as first node with more than one branch) (let ((mark-active nil)) (while (= (length (undo-tree-node-next node)) 1) (undo-tree-undo-1) (setq fragment node node (undo-tree-current buffer-undo-tree)))) (when (eq splice node) (setq splice nil)) ;; detatch undo-in-region branch (setf (undo-tree-node-next node) (delq fragment (undo-tree-node-next node)) (undo-tree-node-previous fragment) nil original-fragment fragment original-splice node)) ;; if this is a new undo-in-region, initial FRAGMENT is a copy of all ;; nodes below the current one in the active branch ((undo-tree-node-next node) (setq fragment (undo-tree-make-node nil nil) splice fragment) (while (setq node (nth (undo-tree-node-branch node) (undo-tree-node-next node))) (push (undo-tree-make-node splice (undo-copy-list (undo-tree-node-undo node)) (undo-copy-list (undo-tree-node-redo node))) (undo-tree-node-next splice)) (setq splice (car (undo-tree-node-next splice)))) (setq fragment (car (undo-tree-node-next fragment)) splice nil node (undo-tree-current buffer-undo-tree)))) ;; --- pull undo-in-region elements into branch --- ;; work backwards up tree, pulling out undo elements within region until ;; we've got one that undoes a visible change (insertion or deletion) (catch 'abort (while (and (not got-visible-elt) node (undo-tree-node-undo node)) ;; we cons a dummy nil element on the front of the changeset so that ;; we can conveniently remove the first (real) element from the ;; changeset if we need to; the leading nil is removed once we're ;; done with this changeset (setq undo-list (cons nil (undo-copy-list (undo-tree-node-undo node))) elt (cadr undo-list)) (if fragment (progn (setq fragment (undo-tree-grow-backwards fragment undo-list)) (unless splice (setq splice fragment))) (setq fragment (undo-tree-make-node nil undo-list)) (setq splice fragment)) (while elt (cond ;; keep elements within region ((undo-elt-in-region elt start end) ;; set flag if kept element is visible (insertion or deletion) (when (and (consp elt) (or (stringp (car elt)) (integerp (car elt)))) (setq got-visible-elt t)) ;; adjust buffer positions in elements previously undone before ;; kept element, as kept element will now be undone first (undo-tree-adjust-elements-to-elt splice elt) ;; move kept element to undo-in-region changeset, adjusting its ;; buffer position as it will now be undone first (setcdr r (list (undo-tree-apply-deltas elt (cdr delta-list)))) (setq r (cdr r)) (setcdr undo-list (cddr undo-list))) ;; discard "was unmodified" elements ;; FIXME: deal properly with these ((and (consp elt) (eq (car elt) t)) (setcdr undo-list (cddr undo-list))) ;; if element crosses region, we can't pull any more elements ((undo-elt-crosses-region elt start end) ;; if we've found a visible element, it must be earlier in ;; current node's changeset; stop pulling elements (null ;; `undo-list' and non-nil `got-visible-elt' cause loop to exit) (if got-visible-elt (setq undo-list nil) ;; if we haven't found a visible element yet, pulling ;; undo-in-region branch has failed (setq region-changeset nil) (throw 'abort t))) ;; if rejecting element, add its delta (if any) to the list (t (let ((delta (undo-delta elt))) (when (/= 0 (cdr delta)) (setcdr d (list delta)) (setq d (cdr d)))) (setq undo-list (cdr undo-list)))) ;; process next element of current changeset (setq elt (cadr undo-list))) ;; if there are remaining elements in changeset, remove dummy nil ;; from front (if (cadr (undo-tree-node-undo fragment)) (pop (undo-tree-node-undo fragment)) ;; otherwise, if we've kept all elements in changeset, discard ;; empty changeset (when (eq splice fragment) (setq splice nil)) (setq fragment (car (undo-tree-node-next fragment)))) ;; process changeset from next node up the tree (setq node (undo-tree-node-previous node)))) ;; pop dummy nil from front of `region-changeset' (setq region-changeset (cdr region-changeset)) ;; --- integrate branch into tree --- ;; if no undo-in-region elements were found, restore undo tree (if (null region-changeset) (when original-current (push original-fragment (undo-tree-node-next original-splice)) (setf (undo-tree-node-branch original-splice) 0 (undo-tree-node-previous original-fragment) original-splice) (let ((mark-active nil)) (while (not (eq (undo-tree-current buffer-undo-tree) original-current)) (undo-tree-redo-1))) nil) ; return nil to indicate failure ;; otherwise... ;; need to undo up to node where new branch will be attached, to ;; ensure redo entries are populated, and then redo back to where we ;; started (let ((mark-active nil) (current (undo-tree-current buffer-undo-tree))) (while (not (eq (undo-tree-current buffer-undo-tree) node)) (undo-tree-undo-1)) (while (not (eq (undo-tree-current buffer-undo-tree) current)) (undo-tree-redo-1))) (cond ;; if there's no remaining fragment, just create undo-in-region node ;; and attach it to parent of last node from which elements were ;; pulled ((null fragment) (setq fragment (undo-tree-make-node node region-changeset)) (push fragment (undo-tree-node-next node)) (setf (undo-tree-node-branch node) 0) ;; set current node to undo-in-region node (setf (undo-tree-current buffer-undo-tree) fragment)) ;; if no splice point has been set, add undo-in-region node to top of ;; fragment and attach it to parent of last node from which elements ;; were pulled ((null splice) (setq fragment (undo-tree-grow-backwards fragment region-changeset)) (push fragment (undo-tree-node-next node)) (setf (undo-tree-node-branch node) 0 (undo-tree-node-previous fragment) node) ;; set current node to undo-in-region node (setf (undo-tree-current buffer-undo-tree) fragment)) ;; if fragment contains nodes, attach fragment to parent of last node ;; from which elements were pulled, and splice in undo-in-region node (t (setf (undo-tree-node-previous fragment) node) (push fragment (undo-tree-node-next node)) (setf (undo-tree-node-branch node) 0) ;; if this is a repeated undo-in-region, then we've left the current ;; node at the original splice-point; we need to set the current ;; node to the equivalent node on the undo-in-region branch and redo ;; back to where we started (when repeated-undo-in-region (setf (undo-tree-current buffer-undo-tree) (undo-tree-node-previous original-fragment)) (let ((mark-active nil)) (while (not (eq (undo-tree-current buffer-undo-tree) splice)) (undo-tree-redo-1 nil 'preserve-undo)))) ;; splice new undo-in-region node into fragment (setq node (undo-tree-make-node nil region-changeset)) (undo-tree-splice-node node splice) ;; set current node to undo-in-region node (setf (undo-tree-current buffer-undo-tree) node))) ;; update undo-tree size (setq node (undo-tree-node-previous fragment)) (while (progn (and (setq node (car (undo-tree-node-next node))) (not (eq node original-fragment)) (incf (undo-tree-count buffer-undo-tree)) (incf (undo-tree-size buffer-undo-tree) (+ (undo-list-byte-size (undo-tree-node-undo node)) (undo-list-byte-size (undo-tree-node-redo node))))))) t) ; indicate undo-in-region branch was successfully pulled ))) (defun undo-tree-pull-redo-in-region-branch (start end) ;; Pull out entries from redo changesets to create a new redo-in-region ;; branch, which redoes changeset entries lying between START and END first, ;; followed by remaining entries from the changesets. Repeated calls will, ;; if appropriate, extend the current redo-in-region branch rather than ;; creating a new one. ;; if we're just reverting the last undo-in-region, we don't need to ;; manipulate the undo tree at all (if (undo-tree-reverting-undo-in-region-p start end) t ; return t to indicate success ;; We build the `region-changeset' and `delta-list' lists forwards, using ;; pointers `r' and `d' to the penultimate element of the list. So that we ;; don't have to treat the first element differently, we prepend a dummy ;; leading nil to the lists, and have the pointers point to that ;; initially. ;; Note: using '(nil) instead of (list nil) in the `let*' causes bizarre ;; errors when the code is byte-compiled, where parts of the lists ;; appear to survive across different calls to this function. An ;; obscure byte-compiler bug, perhaps? (let* ((region-changeset (list nil)) (r region-changeset) (delta-list (list nil)) (d delta-list) (node (undo-tree-current buffer-undo-tree)) (repeated-redo-in-region (undo-tree-repeated-redo-in-region-p start end)) undo-adjusted-markers ; `undo-elt-in-region' expects this fragment splice got-visible-elt redo-list elt) ;; --- inisitalisation --- (cond ;; if this is a repeated redo-in-region, detach fragment below current ;; node (repeated-redo-in-region (when (setq fragment (car (undo-tree-node-next node))) (setf (undo-tree-node-previous fragment) nil (undo-tree-node-next node) (delq fragment (undo-tree-node-next node))))) ;; if this is a new redo-in-region, initial fragment is a copy of all ;; nodes below the current one in the active branch ((undo-tree-node-next node) (setq fragment (undo-tree-make-node nil nil) splice fragment) (while (setq node (nth (undo-tree-node-branch node) (undo-tree-node-next node))) (push (undo-tree-make-node splice nil (undo-copy-list (undo-tree-node-redo node))) (undo-tree-node-next splice)) (setq splice (car (undo-tree-node-next splice)))) (setq fragment (car (undo-tree-node-next fragment))))) ;; --- pull redo-in-region elements into branch --- ;; work down fragment, pulling out redo elements within region until ;; we've got one that redoes a visible change (insertion or deletion) (setq node fragment) (catch 'abort (while (and (not got-visible-elt) node (undo-tree-node-redo node)) ;; we cons a dummy nil element on the front of the changeset so that ;; we can conveniently remove the first (real) element from the ;; changeset if we need to; the leading nil is removed once we're ;; done with this changeset (setq redo-list (push nil (undo-tree-node-redo node)) elt (cadr redo-list)) (while elt (cond ;; keep elements within region ((undo-elt-in-region elt start end) ;; set flag if kept element is visible (insertion or deletion) (when (and (consp elt) (or (stringp (car elt)) (integerp (car elt)))) (setq got-visible-elt t)) ;; adjust buffer positions in elements previously redone before ;; kept element, as kept element will now be redone first (undo-tree-adjust-elements-to-elt fragment elt t) ;; move kept element to redo-in-region changeset, adjusting its ;; buffer position as it will now be redone first (setcdr r (list (undo-tree-apply-deltas elt (cdr delta-list) -1))) (setq r (cdr r)) (setcdr redo-list (cddr redo-list))) ;; discard "was unmodified" elements ;; FIXME: deal properly with these ((and (consp elt) (eq (car elt) t)) (setcdr redo-list (cddr redo-list))) ;; if element crosses region, we can't pull any more elements ((undo-elt-crosses-region elt start end) ;; if we've found a visible element, it must be earlier in ;; current node's changeset; stop pulling elements (null ;; `redo-list' and non-nil `got-visible-elt' cause loop to exit) (if got-visible-elt (setq redo-list nil) ;; if we haven't found a visible element yet, pulling ;; redo-in-region branch has failed (setq region-changeset nil) (throw 'abort t))) ;; if rejecting element, add its delta (if any) to the list (t (let ((delta (undo-delta elt))) (when (/= 0 (cdr delta)) (setcdr d (list delta)) (setq d (cdr d)))) (setq redo-list (cdr redo-list)))) ;; process next element of current changeset (setq elt (cadr redo-list))) ;; if there are remaining elements in changeset, remove dummy nil ;; from front (if (cadr (undo-tree-node-redo node)) (pop (undo-tree-node-undo node)) ;; otherwise, if we've kept all elements in changeset, discard ;; empty changeset (if (eq fragment node) (setq fragment (car (undo-tree-node-next fragment))) (undo-tree-snip-node node))) ;; process changeset from next node in fragment (setq node (car (undo-tree-node-next node))))) ;; pop dummy nil from front of `region-changeset' (setq region-changeset (cdr region-changeset)) ;; --- integrate branch into tree --- (setq node (undo-tree-current buffer-undo-tree)) ;; if no redo-in-region elements were found, restore undo tree (if (null (car region-changeset)) (when (and repeated-redo-in-region fragment) (push fragment (undo-tree-node-next node)) (setf (undo-tree-node-branch node) 0 (undo-tree-node-previous fragment) node) nil) ; return nil to indicate failure ;; otherwise, add redo-in-region node to top of fragment, and attach ;; it below current node (setq fragment (if fragment (undo-tree-grow-backwards fragment nil region-changeset) (undo-tree-make-node nil nil region-changeset))) (push fragment (undo-tree-node-next node)) (setf (undo-tree-node-branch node) 0 (undo-tree-node-previous fragment) node) ;; update undo-tree size (unless repeated-redo-in-region (setq node fragment) (while (and (setq node (car (undo-tree-node-next node))) (incf (undo-tree-count buffer-undo-tree)) (incf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-redo node)))))) (incf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-redo fragment))) t) ; indicate redo-in-region branch was successfully pulled ))) (defun undo-tree-adjust-elements-to-elt (node undo-elt &optional below) "Adjust buffer positions of undo elements, starting at NODE's and going up the tree (or down the active branch if BELOW is non-nil) and through the nodes' undo elements until we reach UNDO-ELT. UNDO-ELT must appear somewhere in the undo changeset of either NODE itself or some node above it in the tree." (let ((delta (list (undo-delta undo-elt))) (undo-list (undo-tree-node-undo node))) ;; adjust elements until we reach UNDO-ELT (while (and (car undo-list) (not (eq (car undo-list) undo-elt))) (setcar undo-list (undo-tree-apply-deltas (car undo-list) delta -1)) ;; move to next undo element in list, or to next node if we've run out ;; of elements (unless (car (setq undo-list (cdr undo-list))) (if below (setq node (nth (undo-tree-node-branch node) (undo-tree-node-next node))) (setq node (undo-tree-node-previous node))) (setq undo-list (undo-tree-node-undo node)))))) (defun undo-tree-apply-deltas (undo-elt deltas &optional sgn) ;; Apply DELTAS in order to UNDO-ELT, multiplying deltas by SGN ;; (only useful value for SGN is -1). (let (position offset) (dolist (delta deltas) (setq position (car delta) offset (* (cdr delta) (or sgn 1))) (cond ;; POSITION ((integerp undo-elt) (when (>= undo-elt position) (setq undo-elt (- undo-elt offset)))) ;; nil (or any other atom) ((atom undo-elt)) ;; (TEXT . POSITION) ((stringp (car undo-elt)) (let ((text-pos (abs (cdr undo-elt))) (point-at-end (< (cdr undo-elt) 0))) (if (>= text-pos position) (setcdr undo-elt (* (if point-at-end -1 1) (- text-pos offset)))))) ;; (BEGIN . END) ((integerp (car undo-elt)) (when (>= (car undo-elt) position) (setcar undo-elt (- (car undo-elt) offset)) (setcdr undo-elt (- (cdr undo-elt) offset)))) ;; (nil PROPERTY VALUE BEG . END) ((null (car undo-elt)) (let ((tail (nthcdr 3 undo-elt))) (when (>= (car tail) position) (setcar tail (- (car tail) offset)) (setcdr tail (- (cdr tail) offset))))) )) undo-elt)) (defun undo-tree-repeated-undo-in-region-p (start end) ;; Return non-nil if undo-in-region between START and END is a repeated ;; undo-in-region (let ((node (undo-tree-current buffer-undo-tree))) (and (setq node (nth (undo-tree-node-branch node) (undo-tree-node-next node))) (eq (undo-tree-node-undo-beginning node) start) (eq (undo-tree-node-undo-end node) end)))) (defun undo-tree-repeated-redo-in-region-p (start end) ;; Return non-nil if undo-in-region between START and END is a repeated ;; undo-in-region (let ((node (undo-tree-current buffer-undo-tree))) (and (eq (undo-tree-node-redo-beginning node) start) (eq (undo-tree-node-redo-end node) end)))) ;; Return non-nil if undo-in-region between START and END is simply ;; reverting the last redo-in-region (defalias 'undo-tree-reverting-undo-in-region-p 'undo-tree-repeated-undo-in-region-p) ;; Return non-nil if redo-in-region between START and END is simply ;; reverting the last undo-in-region (defalias 'undo-tree-reverting-redo-in-region-p 'undo-tree-repeated-redo-in-region-p) ;;; ===================================================================== ;;; Undo-tree commands ;;;###autoload (define-minor-mode undo-tree-mode "Toggle undo-tree mode. With no argument, this command toggles the mode. A positive prefix argument turns the mode on. A negative prefix argument turns it off. Undo-tree-mode replaces Emacs' standard undo feature with a more powerful yet easier to use version, that treats the undo history as what it is: a tree. The following keys are available in `undo-tree-mode': \\{undo-tree-map} Within the undo-tree visualizer, the following keys are available: \\{undo-tree-visualizer-mode-map}" nil ; init value undo-tree-mode-lighter ; lighter undo-tree-map ; keymap ;; if disabling `undo-tree-mode', rebuild `buffer-undo-list' from tree so ;; Emacs undo can work (when (not undo-tree-mode) (undo-list-rebuild-from-tree) (setq buffer-undo-tree nil))) (defun turn-on-undo-tree-mode (&optional print-message) "Enable `undo-tree-mode' in the current buffer, when appropriate. Some major modes implement their own undo system, which should not normally be overridden by `undo-tree-mode'. This command does not enable `undo-tree-mode' in such buffers. If you want to force `undo-tree-mode' to be enabled regardless, use (undo-tree-mode 1) instead. The heuristic used to detect major modes in which `undo-tree-mode' should not be used is to check whether either the `undo' command has been remapped, or the default undo keybindings (C-/ and C-_) have been overridden somewhere other than in the global map. In addition, `undo-tree-mode' will not be enabled if the buffer's `major-mode' appears in `undo-tree-incompatible-major-modes'." (interactive "p") (if (or (key-binding [remap undo]) (undo-tree-overridden-undo-bindings-p) (memq major-mode undo-tree-incompatible-major-modes)) (when print-message (message "Buffer does not support undo-tree-mode;\ undo-tree-mode NOT enabled")) (undo-tree-mode 1))) (defun undo-tree-overridden-undo-bindings-p () "Returns t if default undo bindings are overridden, nil otherwise. Checks if either of the default undo key bindings (\"C-/\" or \"C-_\") are overridden in the current buffer by any keymap other than the global one. (So global redefinitions of the default undo key bindings do not count.)" (let ((binding1 (lookup-key (current-global-map) [?\C-/])) (binding2 (lookup-key (current-global-map) [?\C-_]))) (global-set-key [?\C-/] 'undo) (global-set-key [?\C-_] 'undo) (unwind-protect (or (and (key-binding [?\C-/]) (not (eq (key-binding [?\C-/]) 'undo))) (and (key-binding [?\C-_]) (not (eq (key-binding [?\C-_]) 'undo)))) (global-set-key [?\C-/] binding1) (global-set-key [?\C-_] binding2)))) ;;;###autoload (define-globalized-minor-mode global-undo-tree-mode undo-tree-mode turn-on-undo-tree-mode) (defun undo-tree-undo (&optional arg) "Undo changes. Repeat this command to undo more changes. A numeric ARG serves as a repeat count. In Transient Mark mode when the mark is active, only undo changes within the current region. Similarly, when not in Transient Mark mode, just \\[universal-argument] as an argument limits undo to changes within the current region." (interactive "*P") ;; throw error if undo is disabled in buffer (when (eq buffer-undo-list t) (user-error "No undo information in this buffer")) (undo-tree-undo-1 arg) ;; inform user if at branch point (when (> (undo-tree-num-branches) 1) (message "Undo branch point!"))) (defun undo-tree-undo-1 (&optional arg preserve-redo preserve-timestamps) ;; Internal undo function. An active mark in `transient-mark-mode', or ;; non-nil ARG otherwise, enables undo-in-region. Non-nil PRESERVE-REDO ;; causes the existing redo record to be preserved, rather than replacing it ;; with the new one generated by undoing. Non-nil PRESERVE-TIMESTAMPS ;; disables updating of timestamps in visited undo-tree nodes. (This latter ;; should *only* be used when temporarily visiting another undo state and ;; immediately returning to the original state afterwards. Otherwise, it ;; could cause history-discarding errors.) (let ((undo-in-progress t) (undo-in-region (and undo-tree-enable-undo-in-region (or (region-active-p) (and arg (not (numberp arg)))))) pos current) ;; transfer entries accumulated in `buffer-undo-list' to ;; `buffer-undo-tree' (undo-list-transfer-to-tree) (dotimes (i (or (and (numberp arg) (prefix-numeric-value arg)) 1)) ;; check if at top of undo tree (unless (undo-tree-node-previous (undo-tree-current buffer-undo-tree)) (user-error "No further undo information")) ;; if region is active, or a non-numeric prefix argument was supplied, ;; try to pull out a new branch of changes affecting the region (when (and undo-in-region (not (undo-tree-pull-undo-in-region-branch (region-beginning) (region-end)))) (user-error "No further undo information for region")) ;; remove any GC'd elements from node's undo list (setq current (undo-tree-current buffer-undo-tree)) (decf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-undo current))) (setf (undo-tree-node-undo current) (undo-list-clean-GCd-elts (undo-tree-node-undo current))) (incf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-undo current))) ;; undo one record from undo tree (when undo-in-region (setq pos (set-marker (make-marker) (point))) (set-marker-insertion-type pos t)) (primitive-undo 1 (undo-tree-copy-list (undo-tree-node-undo current))) (undo-boundary) ;; if preserving old redo record, discard new redo entries that ;; `primitive-undo' has added to `buffer-undo-list', and remove any GC'd ;; elements from node's redo list (if preserve-redo (progn (undo-list-pop-changeset) (decf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-redo current))) (setf (undo-tree-node-redo current) (undo-list-clean-GCd-elts (undo-tree-node-redo current))) (incf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-redo current)))) ;; otherwise, record redo entries that `primitive-undo' has added to ;; `buffer-undo-list' in current node's redo record, replacing ;; existing entry if one already exists (decf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-redo current))) (setf (undo-tree-node-redo current) (undo-list-pop-changeset 'discard-pos)) (incf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-redo current)))) ;; rewind current node and update timestamp (setf (undo-tree-current buffer-undo-tree) (undo-tree-node-previous (undo-tree-current buffer-undo-tree))) (unless preserve-timestamps (setf (undo-tree-node-timestamp (undo-tree-current buffer-undo-tree)) (current-time))) ;; if undoing-in-region, record current node, region and direction so we ;; can tell if undo-in-region is repeated, and re-activate mark if in ;; `transient-mark-mode'; if not, erase any leftover data (if (not undo-in-region) (undo-tree-node-clear-region-data current) (goto-char pos) ;; note: we deliberately want to store the region information in the ;; node *below* the now current one (setf (undo-tree-node-undo-beginning current) (region-beginning) (undo-tree-node-undo-end current) (region-end)) (set-marker pos nil))) ;; undo deactivates mark unless undoing-in-region (setq deactivate-mark (not undo-in-region)))) (defun undo-tree-redo (&optional arg) "Redo changes. A numeric ARG serves as a repeat count. In Transient Mark mode when the mark is active, only redo changes within the current region. Similarly, when not in Transient Mark mode, just \\[universal-argument] as an argument limits redo to changes within the current region." (interactive "*P") ;; throw error if undo is disabled in buffer (when (eq buffer-undo-list t) (user-error "No undo information in this buffer")) (undo-tree-redo-1 arg) ;; inform user if at branch point (when (> (undo-tree-num-branches) 1) (message "Undo branch point!"))) (defun undo-tree-redo-1 (&optional arg preserve-undo preserve-timestamps) ;; Internal redo function. An active mark in `transient-mark-mode', or ;; non-nil ARG otherwise, enables undo-in-region. Non-nil PRESERVE-UNDO ;; causes the existing redo record to be preserved, rather than replacing it ;; with the new one generated by undoing. Non-nil PRESERVE-TIMESTAMPS ;; disables updating of timestamps in visited undo-tree nodes. (This latter ;; should *only* be used when temporarily visiting another undo state and ;; immediately returning to the original state afterwards. Otherwise, it ;; could cause history-discarding errors.) (let ((undo-in-progress t) (redo-in-region (and undo-tree-enable-undo-in-region (or (region-active-p) (and arg (not (numberp arg)))))) pos current) ;; transfer entries accumulated in `buffer-undo-list' to ;; `buffer-undo-tree' (undo-list-transfer-to-tree) (dotimes (i (or (and (numberp arg) (prefix-numeric-value arg)) 1)) ;; check if at bottom of undo tree (when (null (undo-tree-node-next (undo-tree-current buffer-undo-tree))) (user-error "No further redo information")) ;; if region is active, or a non-numeric prefix argument was supplied, ;; try to pull out a new branch of changes affecting the region (when (and redo-in-region (not (undo-tree-pull-redo-in-region-branch (region-beginning) (region-end)))) (user-error "No further redo information for region")) ;; get next node (but DON'T advance current node in tree yet, in case ;; redoing fails) (setq current (undo-tree-current buffer-undo-tree) current (nth (undo-tree-node-branch current) (undo-tree-node-next current))) ;; remove any GC'd elements from node's redo list (decf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-redo current))) (setf (undo-tree-node-redo current) (undo-list-clean-GCd-elts (undo-tree-node-redo current))) (incf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-redo current))) ;; redo one record from undo tree (when redo-in-region (setq pos (set-marker (make-marker) (point))) (set-marker-insertion-type pos t)) (primitive-undo 1 (undo-tree-copy-list (undo-tree-node-redo current))) (undo-boundary) ;; advance current node in tree (setf (undo-tree-current buffer-undo-tree) current) ;; if preserving old undo record, discard new undo entries that ;; `primitive-undo' has added to `buffer-undo-list', and remove any GC'd ;; elements from node's redo list (if preserve-undo (progn (undo-list-pop-changeset) (decf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-undo current))) (setf (undo-tree-node-undo current) (undo-list-clean-GCd-elts (undo-tree-node-undo current))) (incf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-undo current)))) ;; otherwise, record undo entries that `primitive-undo' has added to ;; `buffer-undo-list' in current node's undo record, replacing ;; existing entry if one already exists (decf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-undo current))) (setf (undo-tree-node-undo current) (undo-list-pop-changeset 'discard-pos)) (incf (undo-tree-size buffer-undo-tree) (undo-list-byte-size (undo-tree-node-undo current)))) ;; update timestamp (unless preserve-timestamps (setf (undo-tree-node-timestamp current) (current-time))) ;; if redoing-in-region, record current node, region and direction so we ;; can tell if redo-in-region is repeated, and re-activate mark if in ;; `transient-mark-mode' (if (not redo-in-region) (undo-tree-node-clear-region-data current) (goto-char pos) (setf (undo-tree-node-redo-beginning current) (region-beginning) (undo-tree-node-redo-end current) (region-end)) (set-marker pos nil))) ;; redo deactivates the mark unless redoing-in-region (setq deactivate-mark (not redo-in-region)))) (defun undo-tree-switch-branch (branch) "Switch to a different BRANCH of the undo tree. This will affect which branch to descend when *redoing* changes using `undo-tree-redo'." (interactive (list (or (and prefix-arg (prefix-numeric-value prefix-arg)) (and (not (eq buffer-undo-list t)) (or (undo-list-transfer-to-tree) t) (let ((b (undo-tree-node-branch (undo-tree-current buffer-undo-tree)))) (cond ;; switch to other branch if only 2 ((= (undo-tree-num-branches) 2) (- 1 b)) ;; prompt if more than 2 ((> (undo-tree-num-branches) 2) (read-number (format "Branch (0-%d, on %d): " (1- (undo-tree-num-branches)) b))) )))))) ;; throw error if undo is disabled in buffer (when (eq buffer-undo-list t) (user-error "No undo information in this buffer")) ;; sanity check branch number (when (<= (undo-tree-num-branches) 1) (user-error "Not at undo branch point")) (when (or (< branch 0) (> branch (1- (undo-tree-num-branches)))) (user-error "Invalid branch number")) ;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree' (undo-list-transfer-to-tree) ;; switch branch (setf (undo-tree-node-branch (undo-tree-current buffer-undo-tree)) branch) (message "Switched to branch %d" branch)) (defun undo-tree-set (node &optional preserve-timestamps) ;; Set buffer to state corresponding to NODE. Returns intersection point ;; between path back from current node and path back from selected NODE. ;; Non-nil PRESERVE-TIMESTAMPS disables updating of timestamps in visited ;; undo-tree nodes. (This should *only* be used when temporarily visiting ;; another undo state and immediately returning to the original state ;; afterwards. Otherwise, it could cause history-discarding errors.) (let ((path (make-hash-table :test 'eq)) (n node)) (puthash (undo-tree-root buffer-undo-tree) t path) ;; build list of nodes leading back from selected node to root, updating ;; branches as we go to point down to selected node (while (progn (puthash n t path) (when (undo-tree-node-previous n) (setf (undo-tree-node-branch (undo-tree-node-previous n)) (undo-tree-position n (undo-tree-node-next (undo-tree-node-previous n)))) (setq n (undo-tree-node-previous n))))) ;; work backwards from current node until we intersect path back from ;; selected node (setq n (undo-tree-current buffer-undo-tree)) (while (not (gethash n path)) (setq n (undo-tree-node-previous n))) ;; ascend tree until intersection node (while (not (eq (undo-tree-current buffer-undo-tree) n)) (undo-tree-undo-1 nil nil preserve-timestamps)) ;; descend tree until selected node (while (not (eq (undo-tree-current buffer-undo-tree) node)) (undo-tree-redo-1 nil nil preserve-timestamps)) n)) ; return intersection node (defun undo-tree-save-state-to-register (register) "Store current undo-tree state to REGISTER. The saved state can be restored using `undo-tree-restore-state-from-register'. Argument is a character, naming the register." (interactive "cUndo-tree state to register: ") ;; throw error if undo is disabled in buffer (when (eq buffer-undo-list t) (user-error "No undo information in this buffer")) ;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree' (undo-list-transfer-to-tree) ;; save current node to REGISTER (set-register register (registerv-make (undo-tree-make-register-data (current-buffer) (undo-tree-current buffer-undo-tree)) :print-func 'undo-tree-register-data-print-func)) ;; record REGISTER in current node, for visualizer (setf (undo-tree-node-register (undo-tree-current buffer-undo-tree)) register)) (defun undo-tree-restore-state-from-register (register) "Restore undo-tree state from REGISTER. The state must be saved using `undo-tree-save-state-to-register'. Argument is a character, naming the register." (interactive "*cRestore undo-tree state from register: ") ;; throw error if undo is disabled in buffer, or if register doesn't contain ;; an undo-tree node (let ((data (registerv-data (get-register register)))) (cond ((eq buffer-undo-list t) (user-error "No undo information in this buffer")) ((not (undo-tree-register-data-p data)) (user-error "Register doesn't contain undo-tree state")) ((not (eq (current-buffer) (undo-tree-register-data-buffer data))) (user-error "Register contains undo-tree state for a different buffer"))) ;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree' (undo-list-transfer-to-tree) ;; restore buffer state corresponding to saved node (undo-tree-set (undo-tree-register-data-node data)))) ;;; ===================================================================== ;;; Persistent storage commands (defun undo-tree-make-history-save-file-name (file) "Create the undo history file name for FILE. Normally this is the file's name with \".\" prepended and \".~undo-tree~\" appended. A match for FILE is sought in `undo-tree-history-directory-alist' \(see the documentation of that variable for details\). If the directory for the backup doesn't exist, it is created." (let* ((backup-directory-alist undo-tree-history-directory-alist) (name (make-backup-file-name-1 file))) (concat (file-name-directory name) "." (file-name-nondirectory name) ".~undo-tree~"))) (defun undo-tree-save-history (&optional filename overwrite) "Store undo-tree history to file. If optional argument FILENAME is omitted, default save file is \"..~undo-tree\" if buffer is visiting a file. Otherwise, prompt for one. If OVERWRITE is non-nil, any existing file will be overwritten without asking for confirmation." (interactive) (when (eq buffer-undo-list t) (user-error "No undo information in this buffer")) (undo-list-transfer-to-tree) (when (and buffer-undo-tree (not (eq buffer-undo-tree t))) (condition-case nil (undo-tree-kill-visualizer) (error (undo-tree-clear-visualizer-data buffer-undo-tree))) (let ((buff (current-buffer)) tree) ;; get filename (unless filename (setq filename (if buffer-file-name (undo-tree-make-history-save-file-name buffer-file-name) (expand-file-name (read-file-name "File to save in: ") nil)))) (when (or (not (file-exists-p filename)) overwrite (yes-or-no-p (format "Overwrite \"%s\"? " filename))) (unwind-protect (progn ;; transform undo-tree into non-circular structure, and make ;; temporary copy (undo-tree-decircle buffer-undo-tree) (setq tree (copy-undo-tree buffer-undo-tree)) ;; discard undo-tree object pool before saving (setf (undo-tree-object-pool tree) nil) ;; print undo-tree to file ;; NOTE: We use `with-temp-buffer' instead of `with-temp-file' ;; to allow `auto-compression-mode' to take effect, in ;; case user has overridden or advised the default ;; `undo-tree-make-history-save-file-name' to add a ;; compressed file extension. (with-auto-compression-mode (with-temp-buffer (prin1 (sha1 buff) (current-buffer)) (terpri (current-buffer)) (let ((print-circle t)) (prin1 tree (current-buffer))) (write-region nil nil filename)))) ;; restore circular undo-tree data structure (undo-tree-recircle buffer-undo-tree)) )))) (defun undo-tree-load-history (&optional filename noerror) "Load undo-tree history from file. If optional argument FILENAME is null, default load file is \"..~undo-tree\" if buffer is visiting a file. Otherwise, prompt for one. If optional argument NOERROR is non-nil, return nil instead of signaling an error if file is not found." (interactive) ;; get filename (unless filename (setq filename (if buffer-file-name (undo-tree-make-history-save-file-name buffer-file-name) (expand-file-name (read-file-name "File to load from: ") nil)))) ;; attempt to read undo-tree from FILENAME (catch 'load-error (unless (file-exists-p filename) (if noerror (throw 'load-error nil) (error "File \"%s\" does not exist; could not load undo-tree history" filename))) (let (buff hash tree) (setq buff (current-buffer)) (with-auto-compression-mode (with-temp-buffer (insert-file-contents filename) (goto-char (point-min)) (condition-case nil (setq hash (read (current-buffer))) (error (kill-buffer nil) (funcall (if noerror 'message 'user-error) "Error reading undo-tree history from \"%s\"" filename) (throw 'load-error nil))) (unless (string= (sha1 buff) hash) (kill-buffer nil) (funcall (if noerror 'message 'user-error) "Buffer has been modified; could not load undo-tree history") (throw 'load-error nil)) (condition-case nil (setq tree (read (current-buffer))) (error (kill-buffer nil) (funcall (if noerror 'message 'error) "Error reading undo-tree history from \"%s\"" filename) (throw 'load-error nil))) (kill-buffer nil))) ;; initialise empty undo-tree object pool (setf (undo-tree-object-pool tree) (make-hash-table :test 'eq :weakness 'value)) ;; restore circular undo-tree data structure (undo-tree-recircle tree) (setq buffer-undo-tree tree)))) ;; Versions of save/load functions for use in hooks (defun undo-tree-save-history-hook () (when (and undo-tree-mode undo-tree-auto-save-history (not (eq buffer-undo-list t))) (undo-tree-save-history nil t) nil)) (defun undo-tree-load-history-hook () (when (and undo-tree-mode undo-tree-auto-save-history (not (eq buffer-undo-list t)) (not revert-buffer-in-progress-p)) (undo-tree-load-history nil t))) ;;; ===================================================================== ;;; Visualizer drawing functions (defun undo-tree-visualize () "Visualize the current buffer's undo tree." (interactive "*") (deactivate-mark) ;; throw error if undo is disabled in buffer (when (eq buffer-undo-list t) (user-error "No undo information in this buffer")) ;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree' (undo-list-transfer-to-tree) ;; add hook to kill visualizer buffer if original buffer is changed (add-hook 'before-change-functions 'undo-tree-kill-visualizer nil t) ;; prepare *undo-tree* buffer, then draw tree in it (let ((undo-tree buffer-undo-tree) (buff (current-buffer)) (display-buffer-mark-dedicated 'soft)) (switch-to-buffer-other-window (get-buffer-create undo-tree-visualizer-buffer-name)) (setq undo-tree-visualizer-parent-buffer buff) (setq undo-tree-visualizer-parent-mtime (and (buffer-file-name buff) (nth 5 (file-attributes (buffer-file-name buff))))) (setq undo-tree-visualizer-initial-node (undo-tree-current undo-tree)) (setq undo-tree-visualizer-spacing (undo-tree-visualizer-calculate-spacing)) (make-local-variable 'undo-tree-visualizer-timestamps) (make-local-variable 'undo-tree-visualizer-diff) (setq buffer-undo-tree undo-tree) (undo-tree-visualizer-mode) ;; FIXME; don't know why `undo-tree-visualizer-mode' clears this (setq buffer-undo-tree undo-tree) (set (make-local-variable 'undo-tree-visualizer-lazy-drawing) (or (eq undo-tree-visualizer-lazy-drawing t) (and (numberp undo-tree-visualizer-lazy-drawing) (>= (undo-tree-count undo-tree) undo-tree-visualizer-lazy-drawing)))) (when undo-tree-visualizer-diff (undo-tree-visualizer-show-diff)) (let ((inhibit-read-only t)) (undo-tree-draw-tree undo-tree)))) (defun undo-tree-kill-visualizer (&rest _dummy) ;; Kill visualizer. Added to `before-change-functions' hook of original ;; buffer when visualizer is invoked. (unless (or undo-tree-inhibit-kill-visualizer (null (get-buffer undo-tree-visualizer-buffer-name))) (with-current-buffer undo-tree-visualizer-buffer-name (undo-tree-visualizer-quit)))) (defun undo-tree-draw-tree (undo-tree) ;; Draw undo-tree in current buffer starting from NODE (or root if nil). (let ((node (if undo-tree-visualizer-lazy-drawing (undo-tree-current undo-tree) (undo-tree-root undo-tree)))) (erase-buffer) (setq undo-tree-visualizer-needs-extending-down nil undo-tree-visualizer-needs-extending-up nil) (undo-tree-clear-visualizer-data undo-tree) (undo-tree-compute-widths node) ;; lazy drawing starts vertically centred and displaced horizontally to ;; the left (window-width/4), since trees will typically grow right (if undo-tree-visualizer-lazy-drawing (progn (undo-tree-move-down (/ (window-height) 2)) (undo-tree-move-forward (max 2 (/ (window-width) 4)))) ; left margin ;; non-lazy drawing starts in centre at top of buffer (undo-tree-move-down 1) ; top margin (undo-tree-move-forward (max (/ (window-width) 2) (+ (undo-tree-node-char-lwidth node) ;; add space for left part of left-most time-stamp (if undo-tree-visualizer-timestamps (/ (- undo-tree-visualizer-spacing 4) 2) 0) 2)))) ; left margin ;; link starting node to its representation in visualizer (setf (undo-tree-node-marker node) (make-marker)) (set-marker-insertion-type (undo-tree-node-marker node) nil) (move-marker (undo-tree-node-marker node) (point)) ;; draw undo-tree (let ((undo-tree-insert-face 'undo-tree-visualizer-default-face) node-list) (if (not undo-tree-visualizer-lazy-drawing) (undo-tree-extend-down node t) (undo-tree-extend-down node) (undo-tree-extend-up node) (setq node-list undo-tree-visualizer-needs-extending-down undo-tree-visualizer-needs-extending-down nil) (while node-list (undo-tree-extend-down (pop node-list))))) ;; highlight active branch (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face)) (undo-tree-highlight-active-branch (or undo-tree-visualizer-needs-extending-up (undo-tree-root undo-tree)))) ;; highlight current node (undo-tree-draw-node (undo-tree-current undo-tree) 'current))) (defun undo-tree-extend-down (node &optional bottom) ;; Extend tree downwards starting from NODE and point. If BOTTOM is t, ;; extend all the way down to the leaves. If BOTTOM is a node, extend down ;; as far as that node. If BOTTOM is an integer, extend down as far as that ;; line. Otherwise, only extend visible portion of tree. NODE is assumed to ;; already have a node marker. Returns non-nil if anything was actually ;; extended. (let ((extended nil) (cur-stack (list node)) next-stack) ;; don't bother extending if BOTTOM specifies an already-drawn node (unless (and (undo-tree-node-p bottom) (undo-tree-node-marker bottom)) ;; draw nodes layer by layer (while (or cur-stack (prog1 (setq cur-stack next-stack) (setq next-stack nil))) (setq node (pop cur-stack)) ;; if node is within range being drawn... (if (or (eq bottom t) (and (undo-tree-node-p bottom) (not (eq (undo-tree-node-previous node) bottom))) (and (integerp bottom) (>= bottom (line-number-at-pos (undo-tree-node-marker node)))) (and (null bottom) (pos-visible-in-window-p (undo-tree-node-marker node) nil t))) ;; ...draw one layer of node's subtree (if not already drawn) (progn (unless (and (undo-tree-node-next node) (undo-tree-node-marker (nth (undo-tree-node-branch node) (undo-tree-node-next node)))) (goto-char (undo-tree-node-marker node)) (undo-tree-draw-subtree node) (setq extended t)) (setq next-stack (append (undo-tree-node-next node) next-stack))) ;; ...otherwise, postpone drawing until later (push node undo-tree-visualizer-needs-extending-down)))) extended)) (defun undo-tree-extend-up (node &optional top) ;; Extend tree upwards starting from NODE. If TOP is t, extend all the way ;; to root. If TOP is a node, extend up as far as that node. If TOP is an ;; integer, extend up as far as that line. Otherwise, only extend visible ;; portion of tree. NODE is assumed to already have a node marker. Returns ;; non-nil if anything was actually extended. (let ((extended nil) parent) ;; don't bother extending if TOP specifies an already-drawn node (unless (and (undo-tree-node-p top) (undo-tree-node-marker top)) (while node (setq parent (undo-tree-node-previous node)) ;; if we haven't reached root... (if parent ;; ...and node is within range being drawn... (if (or (eq top t) (and (undo-tree-node-p top) (not (eq node top))) (and (integerp top) (< top (line-number-at-pos (undo-tree-node-marker node)))) (and (null top) ;; NOTE: we check point in case window-start is outdated (< (min (line-number-at-pos (point)) (line-number-at-pos (window-start))) (line-number-at-pos (undo-tree-node-marker node))))) ;; ...and it hasn't already been drawn (when (not (undo-tree-node-marker parent)) ;; link parent node to its representation in visualizer (undo-tree-compute-widths parent) (undo-tree-move-to-parent node) (setf (undo-tree-node-marker parent) (make-marker)) (set-marker-insertion-type (undo-tree-node-marker parent) nil) (move-marker (undo-tree-node-marker parent) (point)) ;; draw subtree beneath parent (setq undo-tree-visualizer-needs-extending-down (nconc (delq node (undo-tree-draw-subtree parent)) undo-tree-visualizer-needs-extending-down)) (setq extended t)) ;; ...otherwise, postpone drawing for later and exit (setq undo-tree-visualizer-needs-extending-up (when parent node) parent nil)) ;; if we've reached root, stop extending and add top margin (setq undo-tree-visualizer-needs-extending-up nil) (goto-char (undo-tree-node-marker node)) (undo-tree-move-up 1) ; top margin (delete-region (point-min) (line-beginning-position))) ;; next iteration (setq node parent))) extended)) (defun undo-tree-expand-down (from &optional to) ;; Expand tree downwards. FROM is the node to start expanding from. Stop ;; expanding at TO if specified. Otherwise, just expand visible portion of ;; tree and highlight active branch from FROM. (when undo-tree-visualizer-needs-extending-down (let ((inhibit-read-only t) node-list extended) ;; extend down as far as TO node (when to (setq extended (undo-tree-extend-down from to)) (goto-char (undo-tree-node-marker to)) (redisplay t)) ; force redisplay to scroll buffer if necessary ;; extend visible portion of tree downwards (setq node-list undo-tree-visualizer-needs-extending-down undo-tree-visualizer-needs-extending-down nil) (when node-list (dolist (n node-list) (when (undo-tree-extend-down n) (setq extended t))) ;; highlight active branch in newly-extended-down portion, if any (when extended (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face)) (undo-tree-highlight-active-branch from))))))) (defun undo-tree-expand-up (from &optional to) ;; Expand tree upwards. FROM is the node to start expanding from, TO is the ;; node to stop expanding at. If TO node isn't specified, just expand visible ;; portion of tree and highlight active branch down to FROM. (when undo-tree-visualizer-needs-extending-up (let ((inhibit-read-only t) extended node-list) ;; extend up as far as TO node (when to (setq extended (undo-tree-extend-up from to)) (goto-char (undo-tree-node-marker to)) ;; simulate auto-scrolling if close to top of buffer (when (<= (line-number-at-pos (point)) scroll-margin) (undo-tree-move-up (if (= scroll-conservatively 0) (/ (window-height) 2) 3)) (when (undo-tree-extend-up to) (setq extended t)) (goto-char (undo-tree-node-marker to)) (unless (= scroll-conservatively 0) (recenter scroll-margin)))) ;; extend visible portion of tree upwards (and undo-tree-visualizer-needs-extending-up (undo-tree-extend-up undo-tree-visualizer-needs-extending-up) (setq extended t)) ;; extend visible portion of tree downwards (setq node-list undo-tree-visualizer-needs-extending-down undo-tree-visualizer-needs-extending-down nil) (dolist (n node-list) (undo-tree-extend-down n)) ;; highlight active branch in newly-extended-up portion, if any (when extended (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face)) (undo-tree-highlight-active-branch (or undo-tree-visualizer-needs-extending-up (undo-tree-root buffer-undo-tree)) from)))))) (defun undo-tree-highlight-active-branch (node &optional end) ;; Draw highlighted active branch below NODE in current buffer. Stop ;; highlighting at END node if specified. (let ((stack (list node))) ;; draw active branch (while stack (setq node (pop stack)) (unless (or (eq node end) (memq node undo-tree-visualizer-needs-extending-down)) (goto-char (undo-tree-node-marker node)) (setq node (undo-tree-draw-subtree node 'active) stack (nconc stack node)))))) (defun undo-tree-draw-node (node &optional current) ;; Draw symbol representing NODE in visualizer. If CURRENT is non-nil, node ;; is current node. (goto-char (undo-tree-node-marker node)) (when undo-tree-visualizer-timestamps (undo-tree-move-backward (/ undo-tree-visualizer-spacing 2))) (let* ((undo-tree-insert-face (and undo-tree-insert-face (or (and (consp undo-tree-insert-face) undo-tree-insert-face) (list undo-tree-insert-face)))) (register (undo-tree-node-register node)) (unmodified (if undo-tree-visualizer-parent-mtime (undo-tree-node-unmodified-p node undo-tree-visualizer-parent-mtime) (undo-tree-node-unmodified-p node))) node-string) ;; check node's register (if any) still stores appropriate undo-tree state (unless (and register (undo-tree-register-data-p (registerv-data (get-register register))) (eq node (undo-tree-register-data-node (registerv-data (get-register register))))) (setq register nil)) ;; represent node by different symbols, depending on whether it's the ;; current node, is saved in a register, or corresponds to an unmodified ;; buffer (setq node-string (cond (undo-tree-visualizer-timestamps (undo-tree-timestamp-to-string (undo-tree-node-timestamp node) undo-tree-visualizer-relative-timestamps current register)) (register (char-to-string register)) (unmodified "s") (current "x") (t "o")) undo-tree-insert-face (nconc (cond (current '(undo-tree-visualizer-current-face)) (unmodified '(undo-tree-visualizer-unmodified-face)) (register '(undo-tree-visualizer-register-face))) undo-tree-insert-face)) ;; draw node and link it to its representation in visualizer (undo-tree-insert node-string) (undo-tree-move-backward (if undo-tree-visualizer-timestamps (1+ (/ undo-tree-visualizer-spacing 2)) 1)) (move-marker (undo-tree-node-marker node) (point)) (put-text-property (point) (1+ (point)) 'undo-tree-node node))) (defun undo-tree-draw-subtree (node &optional active-branch) ;; Draw subtree rooted at NODE. The subtree will start from point. ;; If ACTIVE-BRANCH is non-nil, just draw active branch below NODE. Returns ;; list of nodes below NODE. (let ((num-children (length (undo-tree-node-next node))) node-list pos trunk-pos n) ;; draw node itself (undo-tree-draw-node node) (cond ;; if we're at a leaf node, we're done ((= num-children 0)) ;; if node has only one child, draw it (not strictly necessary to deal ;; with this case separately, but as it's by far the most common case ;; this makes the code clearer and more efficient) ((= num-children 1) (undo-tree-move-down 1) (undo-tree-insert ?|) (undo-tree-move-backward 1) (undo-tree-move-down 1) (undo-tree-insert ?|) (undo-tree-move-backward 1) (undo-tree-move-down 1) (setq n (car (undo-tree-node-next node))) ;; link next node to its representation in visualizer (unless (markerp (undo-tree-node-marker n)) (setf (undo-tree-node-marker n) (make-marker)) (set-marker-insertion-type (undo-tree-node-marker n) nil)) (move-marker (undo-tree-node-marker n) (point)) ;; add next node to list of nodes to draw next (push n node-list)) ;; if node has multiple children, draw branches (t (undo-tree-move-down 1) (undo-tree-insert ?|) (undo-tree-move-backward 1) (move-marker (setq trunk-pos (make-marker)) (point)) ;; left subtrees (undo-tree-move-backward (- (undo-tree-node-char-lwidth node) (undo-tree-node-char-lwidth (car (undo-tree-node-next node))))) (move-marker (setq pos (make-marker)) (point)) (setq n (cons nil (undo-tree-node-next node))) (dotimes (i (/ num-children 2)) (setq n (cdr n)) (when (or (null active-branch) (eq (car n) (nth (undo-tree-node-branch node) (undo-tree-node-next node)))) (undo-tree-move-forward 2) (undo-tree-insert ?_ (- trunk-pos pos 2)) (goto-char pos) (undo-tree-move-forward 1) (undo-tree-move-down 1) (undo-tree-insert ?/) (undo-tree-move-backward 2) (undo-tree-move-down 1) ;; link node to its representation in visualizer (unless (markerp (undo-tree-node-marker (car n))) (setf (undo-tree-node-marker (car n)) (make-marker)) (set-marker-insertion-type (undo-tree-node-marker (car n)) nil)) (move-marker (undo-tree-node-marker (car n)) (point)) ;; add node to list of nodes to draw next (push (car n) node-list)) (goto-char pos) (undo-tree-move-forward (+ (undo-tree-node-char-rwidth (car n)) (undo-tree-node-char-lwidth (cadr n)) undo-tree-visualizer-spacing 1)) (move-marker pos (point))) ;; middle subtree (only when number of children is odd) (when (= (mod num-children 2) 1) (setq n (cdr n)) (when (or (null active-branch) (eq (car n) (nth (undo-tree-node-branch node) (undo-tree-node-next node)))) (undo-tree-move-down 1) (undo-tree-insert ?|) (undo-tree-move-backward 1) (undo-tree-move-down 1) ;; link node to its representation in visualizer (unless (markerp (undo-tree-node-marker (car n))) (setf (undo-tree-node-marker (car n)) (make-marker)) (set-marker-insertion-type (undo-tree-node-marker (car n)) nil)) (move-marker (undo-tree-node-marker (car n)) (point)) ;; add node to list of nodes to draw next (push (car n) node-list)) (goto-char pos) (undo-tree-move-forward (+ (undo-tree-node-char-rwidth (car n)) (if (cadr n) (undo-tree-node-char-lwidth (cadr n)) 0) undo-tree-visualizer-spacing 1)) (move-marker pos (point))) ;; right subtrees (move-marker trunk-pos (1+ trunk-pos)) (dotimes (i (/ num-children 2)) (setq n (cdr n)) (when (or (null active-branch) (eq (car n) (nth (undo-tree-node-branch node) (undo-tree-node-next node)))) (goto-char trunk-pos) (undo-tree-insert ?_ (- pos trunk-pos 1)) (goto-char pos) (undo-tree-move-backward 1) (undo-tree-move-down 1) (undo-tree-insert ?\\) (undo-tree-move-down 1) ;; link node to its representation in visualizer (unless (markerp (undo-tree-node-marker (car n))) (setf (undo-tree-node-marker (car n)) (make-marker)) (set-marker-insertion-type (undo-tree-node-marker (car n)) nil)) (move-marker (undo-tree-node-marker (car n)) (point)) ;; add node to list of nodes to draw next (push (car n) node-list)) (when (cdr n) (goto-char pos) (undo-tree-move-forward (+ (undo-tree-node-char-rwidth (car n)) (if (cadr n) (undo-tree-node-char-lwidth (cadr n)) 0) undo-tree-visualizer-spacing 1)) (move-marker pos (point)))) )) ;; return list of nodes to draw next (nreverse node-list))) (defun undo-tree-node-char-lwidth (node) ;; Return left-width of NODE measured in characters. (if (= (length (undo-tree-node-next node)) 0) 0 (- (* (+ undo-tree-visualizer-spacing 1) (undo-tree-node-lwidth node)) (if (= (undo-tree-node-cwidth node) 0) (1+ (/ undo-tree-visualizer-spacing 2)) 0)))) (defun undo-tree-node-char-rwidth (node) ;; Return right-width of NODE measured in characters. (if (= (length (undo-tree-node-next node)) 0) 0 (- (* (+ undo-tree-visualizer-spacing 1) (undo-tree-node-rwidth node)) (if (= (undo-tree-node-cwidth node) 0) (1+ (/ undo-tree-visualizer-spacing 2)) 0)))) (defun undo-tree-insert (str &optional arg) ;; Insert character or string STR ARG times, overwriting, and using ;; `undo-tree-insert-face'. (unless arg (setq arg 1)) (when (characterp str) (setq str (make-string arg str)) (setq arg 1)) (dotimes (i arg) (insert str)) (setq arg (* arg (length str))) (undo-tree-move-forward arg) ;; make sure mark isn't active, otherwise `backward-delete-char' might ;; delete region instead of single char if transient-mark-mode is enabled (setq mark-active nil) (backward-delete-char arg) (when undo-tree-insert-face (put-text-property (- (point) arg) (point) 'face undo-tree-insert-face))) (defun undo-tree-move-down (&optional arg) ;; Move down, extending buffer if necessary. (let ((row (line-number-at-pos)) (col (current-column)) line) (unless arg (setq arg 1)) (forward-line arg) (setq line (line-number-at-pos)) ;; if buffer doesn't have enough lines, add some (when (/= line (+ row arg)) (cond ((< arg 0) (insert (make-string (- line row arg) ?\n)) (forward-line (+ arg (- row line)))) (t (insert (make-string (- arg (- line row)) ?\n))))) (undo-tree-move-forward col))) (defun undo-tree-move-up (&optional arg) ;; Move up, extending buffer if necessary. (unless arg (setq arg 1)) (undo-tree-move-down (- arg))) (defun undo-tree-move-forward (&optional arg) ;; Move forward, extending buffer if necessary. (unless arg (setq arg 1)) (let (n) (cond ((>= arg 0) (setq n (- (line-end-position) (point))) (if (> n arg) (forward-char arg) (end-of-line) (insert (make-string (- arg n) ? )))) ((< arg 0) (setq arg (- arg)) (setq n (- (point) (line-beginning-position))) (when (< (- n 2) arg) ; -2 to create left-margin ;; no space left - shift entire buffer contents right! (let ((pos (move-marker (make-marker) (point)))) (set-marker-insertion-type pos t) (goto-char (point-min)) (while (not (eobp)) (insert-before-markers (make-string (- arg -2 n) ? )) (forward-line 1)) (goto-char pos))) (backward-char arg))))) (defun undo-tree-move-backward (&optional arg) ;; Move backward, extending buffer if necessary. (unless arg (setq arg 1)) (undo-tree-move-forward (- arg))) (defun undo-tree-move-to-parent (node) ;; Move to position of parent of NODE, extending buffer if necessary. (let* ((parent (undo-tree-node-previous node)) (n (undo-tree-node-next parent)) (l (length n)) p) (goto-char (undo-tree-node-marker node)) (unless (= l 1) ;; move horizontally (setq p (undo-tree-position node n)) (cond ;; node in centre subtree: no horizontal movement ((and (= (mod l 2) 1) (= p (/ l 2)))) ;; node in left subtree: move right ((< p (/ l 2)) (setq n (nthcdr p n)) (undo-tree-move-forward (+ (undo-tree-node-char-rwidth (car n)) (/ undo-tree-visualizer-spacing 2) 1)) (dotimes (i (- (/ l 2) p 1)) (setq n (cdr n)) (undo-tree-move-forward (+ (undo-tree-node-char-lwidth (car n)) (undo-tree-node-char-rwidth (car n)) undo-tree-visualizer-spacing 1))) (when (= (mod l 2) 1) (setq n (cdr n)) (undo-tree-move-forward (+ (undo-tree-node-char-lwidth (car n)) (/ undo-tree-visualizer-spacing 2) 1)))) (t ;; node in right subtree: move left (setq n (nthcdr (/ l 2) n)) (when (= (mod l 2) 1) (undo-tree-move-backward (+ (undo-tree-node-char-rwidth (car n)) (/ undo-tree-visualizer-spacing 2) 1)) (setq n (cdr n))) (dotimes (i (- p (/ l 2) (mod l 2))) (undo-tree-move-backward (+ (undo-tree-node-char-lwidth (car n)) (undo-tree-node-char-rwidth (car n)) undo-tree-visualizer-spacing 1)) (setq n (cdr n))) (undo-tree-move-backward (+ (undo-tree-node-char-lwidth (car n)) (/ undo-tree-visualizer-spacing 2) 1))))) ;; move vertically (undo-tree-move-up 3))) (defun undo-tree-timestamp-to-string (timestamp &optional relative current register) ;; Convert TIMESTAMP to string (either absolute or RELATVE time), indicating ;; if it's the CURRENT node and/or has an associated REGISTER. (if relative ;; relative time (let ((time (floor (float-time (subtract-time (current-time) timestamp)))) n) (setq time ;; years (if (> (setq n (/ time 315360000)) 0) (if (> n 999) "-ages" (format "-%dy" n)) (setq time (% time 315360000)) ;; days (if (> (setq n (/ time 86400)) 0) (format "-%dd" n) (setq time (% time 86400)) ;; hours (if (> (setq n (/ time 3600)) 0) (format "-%dh" n) (setq time (% time 3600)) ;; mins (if (> (setq n (/ time 60)) 0) (format "-%dm" n) ;; secs (format "-%ds" (% time 60))))))) (setq time (concat (if current "*" " ") time (if register (concat "[" (char-to-string register) "]") " "))) (setq n (length time)) (if (< n 9) (concat (make-string (- 9 n) ? ) time) time)) ;; absolute time (concat (if current " *" " ") (format-time-string "%H:%M:%S" timestamp) (if register (concat "[" (char-to-string register) "]") " ")))) ;;; ===================================================================== ;;; Visualizer commands (define-derived-mode undo-tree-visualizer-mode special-mode "undo-tree-visualizer" "Major mode used in undo-tree visualizer. The undo-tree visualizer can only be invoked from a buffer in which `undo-tree-mode' is enabled. The visualizer displays the undo history tree graphically, and allows you to browse around the undo history, undoing or redoing the corresponding changes in the parent buffer. Within the undo-tree visualizer, the following keys are available: \\{undo-tree-visualizer-mode-map}" :syntax-table nil :abbrev-table nil (setq truncate-lines t) (setq cursor-type nil) (setq undo-tree-visualizer-selected-node nil)) (defun undo-tree-visualize-undo (&optional arg) "Undo changes. A numeric ARG serves as a repeat count." (interactive "p") (let ((old (undo-tree-current buffer-undo-tree)) current) ;; unhighlight old current node (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face) (inhibit-read-only t)) (undo-tree-draw-node old)) ;; undo in parent buffer (switch-to-buffer-other-window undo-tree-visualizer-parent-buffer) (deactivate-mark) (unwind-protect (let ((undo-tree-inhibit-kill-visualizer t)) (undo-tree-undo-1 arg)) (setq current (undo-tree-current buffer-undo-tree)) (switch-to-buffer-other-window undo-tree-visualizer-buffer-name) ;; when using lazy drawing, extend tree upwards as required (when undo-tree-visualizer-lazy-drawing (undo-tree-expand-up old current)) ;; highlight new current node (let ((inhibit-read-only t)) (undo-tree-draw-node current 'current)) ;; update diff display, if any (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff))))) (defun undo-tree-visualize-redo (&optional arg) "Redo changes. A numeric ARG serves as a repeat count." (interactive "p") (let ((old (undo-tree-current buffer-undo-tree)) current) ;; unhighlight old current node (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face) (inhibit-read-only t)) (undo-tree-draw-node (undo-tree-current buffer-undo-tree))) ;; redo in parent buffer (switch-to-buffer-other-window undo-tree-visualizer-parent-buffer) (deactivate-mark) (unwind-protect (let ((undo-tree-inhibit-kill-visualizer t)) (undo-tree-redo-1 arg)) (setq current (undo-tree-current buffer-undo-tree)) (switch-to-buffer-other-window undo-tree-visualizer-buffer-name) ;; when using lazy drawing, extend tree downwards as required (when undo-tree-visualizer-lazy-drawing (undo-tree-expand-down old current)) ;; highlight new current node (let ((inhibit-read-only t)) (undo-tree-draw-node current 'current)) ;; update diff display, if any (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff))))) (defun undo-tree-visualize-switch-branch-right (arg) "Switch to next branch of the undo tree. This will affect which branch to descend when *redoing* changes using `undo-tree-redo' or `undo-tree-visualizer-redo'." (interactive "p") ;; un-highlight old active branch below current node (goto-char (undo-tree-node-marker (undo-tree-current buffer-undo-tree))) (let ((undo-tree-insert-face 'undo-tree-visualizer-default-face) (inhibit-read-only t)) (undo-tree-highlight-active-branch (undo-tree-current buffer-undo-tree))) ;; increment branch (let ((branch (undo-tree-node-branch (undo-tree-current buffer-undo-tree)))) (setf (undo-tree-node-branch (undo-tree-current buffer-undo-tree)) (cond ((>= (+ branch arg) (undo-tree-num-branches)) (1- (undo-tree-num-branches))) ((<= (+ branch arg) 0) 0) (t (+ branch arg)))) (let ((inhibit-read-only t)) ;; highlight new active branch below current node (goto-char (undo-tree-node-marker (undo-tree-current buffer-undo-tree))) (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face)) (undo-tree-highlight-active-branch (undo-tree-current buffer-undo-tree))) ;; re-highlight current node (undo-tree-draw-node (undo-tree-current buffer-undo-tree) 'current)))) (defun undo-tree-visualize-switch-branch-left (arg) "Switch to previous branch of the undo tree. This will affect which branch to descend when *redoing* changes using `undo-tree-redo' or `undo-tree-visualizer-redo'." (interactive "p") (undo-tree-visualize-switch-branch-right (- arg))) (defun undo-tree-visualizer-quit () "Quit the undo-tree visualizer." (interactive) (undo-tree-clear-visualizer-data buffer-undo-tree) ;; remove kill visualizer hook from parent buffer (unwind-protect (with-current-buffer undo-tree-visualizer-parent-buffer (remove-hook 'before-change-functions 'undo-tree-kill-visualizer t)) ;; kill diff buffer, if any (when undo-tree-visualizer-diff (undo-tree-visualizer-hide-diff)) (let ((parent undo-tree-visualizer-parent-buffer) window) ;; kill visualizer buffer (kill-buffer nil) ;; switch back to parent buffer (unwind-protect (if (setq window (get-buffer-window parent)) (select-window window) (switch-to-buffer parent)))))) (defun undo-tree-visualizer-abort () "Quit the undo-tree visualizer and return buffer to original state." (interactive) (let ((node undo-tree-visualizer-initial-node)) (undo-tree-visualizer-quit) (undo-tree-set node))) (defun undo-tree-visualizer-set (&optional pos) "Set buffer to state corresponding to undo tree node at POS, or point if POS is nil." (interactive) (unless pos (setq pos (point))) (let ((node (get-text-property pos 'undo-tree-node))) (when node ;; set parent buffer to state corresponding to node at POS (switch-to-buffer-other-window undo-tree-visualizer-parent-buffer) (let ((undo-tree-inhibit-kill-visualizer t)) (undo-tree-set node)) (switch-to-buffer-other-window undo-tree-visualizer-buffer-name) ;; re-draw undo tree (let ((inhibit-read-only t)) (undo-tree-draw-tree buffer-undo-tree)) (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff))))) (defun undo-tree-visualizer-mouse-set (pos) "Set buffer to state corresponding to undo tree node at mouse event POS." (interactive "@e") (undo-tree-visualizer-set (event-start (nth 1 pos)))) (defun undo-tree-visualize-undo-to-x (&optional x) "Undo to last branch point, register, or saved state. If X is the symbol `branch', undo to last branch point. If X is the symbol `register', undo to last register. If X is the sumbol `saved', undo to last saved state. If X is null, undo to first of these that's encountered. Interactively, a single \\[universal-argument] specifies `branch', a double \\[universal-argument] \\[universal-argument] specifies `saved', and a negative prefix argument specifies `register'." (interactive "P") (when (and (called-interactively-p 'any) x) (setq x (prefix-numeric-value x) x (cond ((< x 0) 'register) ((<= x 4) 'branch) (t 'saved)))) (let ((current (if undo-tree-visualizer-selection-mode undo-tree-visualizer-selected-node (undo-tree-current buffer-undo-tree))) (diff undo-tree-visualizer-diff) r) (undo-tree-visualizer-hide-diff) (while (and (undo-tree-node-previous current) (or (if undo-tree-visualizer-selection-mode (progn (undo-tree-visualizer-select-previous) (setq current undo-tree-visualizer-selected-node)) (undo-tree-visualize-undo) (setq current (undo-tree-current buffer-undo-tree))) t) ;; branch point (not (or (and (or (null x) (eq x 'branch)) (> (undo-tree-num-branches) 1)) ;; register (and (or (null x) (eq x 'register)) (setq r (undo-tree-node-register current)) (undo-tree-register-data-p (setq r (registerv-data (get-register r)))) (eq current (undo-tree-register-data-node r))) ;; saved state (and (or (null x) (eq x 'saved)) (undo-tree-node-unmodified-p current)) )))) ;; update diff display, if any (when diff (undo-tree-visualizer-show-diff (when undo-tree-visualizer-selection-mode undo-tree-visualizer-selected-node))))) (defun undo-tree-visualize-redo-to-x (&optional x) "Redo to last branch point, register, or saved state. If X is the symbol `branch', redo to last branch point. If X is the symbol `register', redo to last register. If X is the sumbol `saved', redo to last saved state. If X is null, redo to first of these that's encountered. Interactively, a single \\[universal-argument] specifies `branch', a double \\[universal-argument] \\[universal-argument] specifies `saved', and a negative prefix argument specifies `register'." (interactive "P") (when (and (called-interactively-p 'any) x) (setq x (prefix-numeric-value x) x (cond ((< x 0) 'register) ((<= x 4) 'branch) (t 'saved)))) (let ((current (if undo-tree-visualizer-selection-mode undo-tree-visualizer-selected-node (undo-tree-current buffer-undo-tree))) (diff undo-tree-visualizer-diff) r) (undo-tree-visualizer-hide-diff) (while (and (undo-tree-node-next current) (or (if undo-tree-visualizer-selection-mode (progn (undo-tree-visualizer-select-next) (setq current undo-tree-visualizer-selected-node)) (undo-tree-visualize-redo) (setq current (undo-tree-current buffer-undo-tree))) t) ;; branch point (not (or (and (or (null x) (eq x 'branch)) (> (undo-tree-num-branches) 1)) ;; register (and (or (null x) (eq x 'register)) (setq r (undo-tree-node-register current)) (undo-tree-register-data-p (setq r (registerv-data (get-register r)))) (eq current (undo-tree-register-data-node r))) ;; saved state (and (or (null x) (eq x 'saved)) (undo-tree-node-unmodified-p current)) )))) ;; update diff display, if any (when diff (undo-tree-visualizer-show-diff (when undo-tree-visualizer-selection-mode undo-tree-visualizer-selected-node))))) (defun undo-tree-visualizer-toggle-timestamps () "Toggle display of time-stamps." (interactive) (setq undo-tree-visualizer-timestamps (not undo-tree-visualizer-timestamps)) (setq undo-tree-visualizer-spacing (undo-tree-visualizer-calculate-spacing)) ;; redraw tree (let ((inhibit-read-only t)) (undo-tree-draw-tree buffer-undo-tree))) (defun undo-tree-visualizer-scroll-left (&optional arg) (interactive "p") (scroll-left (or arg 1) t)) (defun undo-tree-visualizer-scroll-right (&optional arg) (interactive "p") (scroll-right (or arg 1) t)) (defun undo-tree-visualizer-scroll-up (&optional arg) (interactive "P") (if (or (and (numberp arg) (< arg 0)) (eq arg '-)) (undo-tree-visualizer-scroll-down arg) ;; scroll up and expand newly-visible portion of tree (unwind-protect (scroll-up-command arg) (undo-tree-expand-down (nth (undo-tree-node-branch (undo-tree-current buffer-undo-tree)) (undo-tree-node-next (undo-tree-current buffer-undo-tree))))) ;; signal error if at eob (when (and (not undo-tree-visualizer-needs-extending-down) (eobp)) (scroll-up)))) (defun undo-tree-visualizer-scroll-down (&optional arg) (interactive "P") (if (or (and (numberp arg) (< arg 0)) (eq arg '-)) (undo-tree-visualizer-scroll-up arg) ;; ensure there's enough room at top of buffer to scroll (let ((scroll-lines (or arg (- (window-height) next-screen-context-lines))) (window-line (1- (line-number-at-pos (window-start))))) (when (and undo-tree-visualizer-needs-extending-up (< window-line scroll-lines)) (let ((inhibit-read-only t)) (goto-char (point-min)) (undo-tree-move-up (- scroll-lines window-line))))) ;; scroll down and expand newly-visible portion of tree (unwind-protect (scroll-down-command arg) (undo-tree-expand-up (undo-tree-node-previous (undo-tree-current buffer-undo-tree)))) ;; signal error if at bob (when (and (not undo-tree-visualizer-needs-extending-down) (bobp)) (scroll-down)))) ;;; ===================================================================== ;;; Visualizer selection mode (define-minor-mode undo-tree-visualizer-selection-mode "Toggle mode to select nodes in undo-tree visualizer." :lighter "Select" :keymap undo-tree-visualizer-selection-mode-map :group undo-tree (cond ;; enable selection mode (undo-tree-visualizer-selection-mode (setq cursor-type 'box) (setq undo-tree-visualizer-selected-node (undo-tree-current buffer-undo-tree)) ;; erase diff (if any), as initially selected node is identical to current (when undo-tree-visualizer-diff (let ((buff (get-buffer undo-tree-diff-buffer-name)) (inhibit-read-only t)) (when buff (with-current-buffer buff (erase-buffer)))))) (t ;; disable selection mode (setq cursor-type nil) (setq undo-tree-visualizer-selected-node nil) (goto-char (undo-tree-node-marker (undo-tree-current buffer-undo-tree))) (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff))) )) (defun undo-tree-visualizer-select-previous (&optional arg) "Move to previous node." (interactive "p") (let ((node undo-tree-visualizer-selected-node)) (catch 'top (dotimes (i (or arg 1)) (unless (undo-tree-node-previous node) (throw 'top t)) (setq node (undo-tree-node-previous node)))) ;; when using lazy drawing, extend tree upwards as required (when undo-tree-visualizer-lazy-drawing (undo-tree-expand-up undo-tree-visualizer-selected-node node)) ;; update diff display, if any (when (and undo-tree-visualizer-diff (not (eq node undo-tree-visualizer-selected-node))) (undo-tree-visualizer-update-diff node)) ;; move to selected node (goto-char (undo-tree-node-marker node)) (setq undo-tree-visualizer-selected-node node))) (defun undo-tree-visualizer-select-next (&optional arg) "Move to next node." (interactive "p") (let ((node undo-tree-visualizer-selected-node)) (catch 'bottom (dotimes (i (or arg 1)) (unless (nth (undo-tree-node-branch node) (undo-tree-node-next node)) (throw 'bottom t)) (setq node (nth (undo-tree-node-branch node) (undo-tree-node-next node))))) ;; when using lazy drawing, extend tree downwards as required (when undo-tree-visualizer-lazy-drawing (undo-tree-expand-down undo-tree-visualizer-selected-node node)) ;; update diff display, if any (when (and undo-tree-visualizer-diff (not (eq node undo-tree-visualizer-selected-node))) (undo-tree-visualizer-update-diff node)) ;; move to selected node (goto-char (undo-tree-node-marker node)) (setq undo-tree-visualizer-selected-node node))) (defun undo-tree-visualizer-select-right (&optional arg) "Move right to a sibling node." (interactive "p") (let ((node undo-tree-visualizer-selected-node) end) (goto-char (undo-tree-node-marker undo-tree-visualizer-selected-node)) (setq end (line-end-position)) (catch 'end (dotimes (i arg) (while (or (null node) (eq node undo-tree-visualizer-selected-node)) (forward-char) (setq node (get-text-property (point) 'undo-tree-node)) (when (= (point) end) (throw 'end t))))) (goto-char (undo-tree-node-marker (or node undo-tree-visualizer-selected-node))) (when (and undo-tree-visualizer-diff node (not (eq node undo-tree-visualizer-selected-node))) (undo-tree-visualizer-update-diff node)) (when node (setq undo-tree-visualizer-selected-node node)))) (defun undo-tree-visualizer-select-left (&optional arg) "Move left to a sibling node." (interactive "p") (let ((node (get-text-property (point) 'undo-tree-node)) beg) (goto-char (undo-tree-node-marker undo-tree-visualizer-selected-node)) (setq beg (line-beginning-position)) (catch 'beg (dotimes (i arg) (while (or (null node) (eq node undo-tree-visualizer-selected-node)) (backward-char) (setq node (get-text-property (point) 'undo-tree-node)) (when (= (point) beg) (throw 'beg t))))) (goto-char (undo-tree-node-marker (or node undo-tree-visualizer-selected-node))) (when (and undo-tree-visualizer-diff node (not (eq node undo-tree-visualizer-selected-node))) (undo-tree-visualizer-update-diff node)) (when node (setq undo-tree-visualizer-selected-node node)))) (defun undo-tree-visualizer-select (pos) (let ((node (get-text-property pos 'undo-tree-node))) (when node ;; select node at POS (goto-char (undo-tree-node-marker node)) ;; when using lazy drawing, extend tree up and down as required (when undo-tree-visualizer-lazy-drawing (undo-tree-expand-up undo-tree-visualizer-selected-node node) (undo-tree-expand-down undo-tree-visualizer-selected-node node)) ;; update diff display, if any (when (and undo-tree-visualizer-diff (not (eq node undo-tree-visualizer-selected-node))) (undo-tree-visualizer-update-diff node)) ;; update selected node (setq undo-tree-visualizer-selected-node node) ))) (defun undo-tree-visualizer-mouse-select (pos) "Select undo tree node at mouse event POS." (interactive "@e") (undo-tree-visualizer-select (event-start (nth 1 pos)))) ;;; ===================================================================== ;;; Visualizer diff display (defun undo-tree-visualizer-toggle-diff () "Toggle diff display in undo-tree visualizer." (interactive) (if undo-tree-visualizer-diff (undo-tree-visualizer-hide-diff) (undo-tree-visualizer-show-diff))) (defun undo-tree-visualizer-selection-toggle-diff () "Toggle diff display in undo-tree visualizer selection mode." (interactive) (if undo-tree-visualizer-diff (undo-tree-visualizer-hide-diff) (let ((node (get-text-property (point) 'undo-tree-node))) (when node (undo-tree-visualizer-show-diff node))))) (defun undo-tree-visualizer-show-diff (&optional node) ;; show visualizer diff display (setq undo-tree-visualizer-diff t) (let ((buff (with-current-buffer undo-tree-visualizer-parent-buffer (undo-tree-diff node))) (display-buffer-mark-dedicated 'soft) win) (setq win (split-window)) (set-window-buffer win buff) (shrink-window-if-larger-than-buffer win))) (defun undo-tree-visualizer-hide-diff () ;; hide visualizer diff display (setq undo-tree-visualizer-diff nil) (let ((win (get-buffer-window undo-tree-diff-buffer-name))) (when win (with-selected-window win (kill-buffer-and-window))))) (defun undo-tree-diff (&optional node) ;; Create diff between NODE and current state (or previous state and current ;; state, if NODE is null). Returns buffer containing diff. (let (tmpfile buff) ;; generate diff (let ((undo-tree-inhibit-kill-visualizer t) (current (undo-tree-current buffer-undo-tree))) (undo-tree-set (or node (undo-tree-node-previous current) current) 'preserve-timestamps) (setq tmpfile (diff-file-local-copy (current-buffer))) (undo-tree-set current 'preserve-timestamps)) (setq buff (diff-no-select tmpfile (current-buffer) nil 'noasync (get-buffer-create undo-tree-diff-buffer-name))) ;; delete process messages and useless headers from diff buffer (let ((inhibit-read-only t)) (with-current-buffer buff (goto-char (point-min)) (delete-region (point) (1+ (line-end-position 3))) (goto-char (point-max)) (forward-line -2) (delete-region (point) (point-max)) (setq cursor-type nil) (setq buffer-read-only t))) buff)) (defun undo-tree-visualizer-update-diff (&optional node) ;; update visualizer diff display to show diff between current state and ;; NODE (or previous state, if NODE is null) (with-current-buffer undo-tree-visualizer-parent-buffer (undo-tree-diff node)) (let ((win (get-buffer-window undo-tree-diff-buffer-name))) (when win (balance-windows) (shrink-window-if-larger-than-buffer win)))) ;;;; ChangeLog: ;; 2013-12-28 Toby S. Cubitt ;; ;; * undo-tree: Update to version 0.6.5. ;; ;; 2012-12-05 Toby S. Cubitt ;; ;; Update undo-tree to version 0.6.3 ;; ;; * undo-tree.el: Implement lazy tree drawing to significantly speed up ;; visualization of large trees + various more minor improvements. ;; ;; 2012-09-25 Toby S. Cubitt ;; ;; Updated undo-tree package to version 0.5.5. ;; ;; Small bug-fix to avoid hooks triggering an error when trying to save ;; undo history in a buffer where undo is disabled. ;; ;; 2012-09-11 Toby S. Cubitt ;; ;; Updated undo-tree package to version 0.5.4 ;; ;; Bug-fixes and improvements to persistent history storage. ;; ;; 2012-07-18 Toby S. Cubitt ;; ;; Update undo-tree to version 0.5.3 ;; ;; * undo-tree.el: Cope gracefully with undo boundaries being deleted ;; (cf. bug#11774). Allow customization of directory to which undo ;; history is ;; saved. ;; ;; 2012-05-24 Toby S. Cubitt ;; ;; updated undo-tree package to version 0.5.2 ;; ;; * undo-tree.el: add diff view feature in undo-tree visualizer. ;; ;; 2012-05-02 Toby S. Cubitt ;; ;; undo-tree.el: Update package to version 0.4 ;; ;; 2012-04-20 Toby S. Cubitt ;; ;; undo-tree.el: Update package to version 0.3.4 ;; ;; * undo-tree.el (undo-list-pop-changeset): fix pernicious bug causing ;; undo history to be lost. ;; (buffer-undo-tree): set permanent-local property. ;; (undo-tree-enable-undo-in-region): add new customization option ;; allowing undo-in-region to be disabled. ;; ;; 2012-01-26 Toby S. Cubitt ;; ;; undo-tree.el: Fixed copyright attribution and Emacs status. ;; ;; 2012-01-26 Toby S. Cubitt ;; ;; undo-tree.el: Update package to version 0.3.3 ;; ;; 2011-09-17 Stefan Monnier ;; ;; Add undo-tree.el ;; (provide 'undo-tree) ;;; undo-tree.el ends here evil-1.12.17/scripts/000077500000000000000000000000001360703323200143105ustar00rootroot00000000000000evil-1.12.17/scripts/evil-release-stable000077500000000000000000000031421360703323200200630ustar00rootroot00000000000000#!/usr/bin/env ruby # Copyright (c) 2015 Frank Fischer # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # This script releases a new (minor) stable release given that some # new commits on the stable branch since the last tag exist. Dir.chdir File.dirname(__FILE__) def die(msg = "Failed") STDERR.puts msg exit 1 end def run(cmd) system(cmd) or die(cmd) end run 'hg pull' run 'hg update -r stable' tag = `hg tags`.split("\n").select{|line| line =~ /^\d+\.\d+\.\d+/}.map do |line| tag, rev = line.split major, minor, tiny = tag.split(/\./).map(&:to_i) [major, minor, tiny, rev[/\d+/].to_i] end.max tag or die 'No tagged revision found' stable = `hg log -r 'branch(stable) and not file("../.hgtags") and not ..tag("re:\\d+\\.\\d+\\.\\d+")' | wc -l`.to_i != 0 if stable new_tag = "#{tag[0]}.#{tag[1]}.#{tag[2]+1}" run "make -C .. nversion VERSION='#{new_tag}'" run "hg commit -m 'update version to #{new_tag}'" run "hg tag -m 'version #{new_tag}' -r stable #{new_tag}" run "hg push -r stable" end evil-1.12.17/scripts/evilupdate000077500000000000000000000140561360703323200164060ustar00rootroot00000000000000#!/usr/bin/emacs --script ;;; evilupate.el -- Publishing script for Evil ;;; Header: ;; This file is not part of Emacs ;; Author: Frank Fischer ;; Maintainer: Frank Fischer ;; Version: 1.0 ;; Package-Requires: ((emacs "24.3") (s "1.9.0") (f "0.17.2") yaoddmuse) ;; The contents of this file are subject to the GPL License, Version 3.0. ;; Copyright (C) 2015, 2016, Frank Fischer ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; This is a small script to update Evil's version at certain places: ;; ;; - topic of the IRC channel #evil-mode in irc.freenode.net ;; - EmacsWiki page ;; - header of all source files ;; - the ELPA package file ;; ;; The script should be invoked with the new version string ;; ;; evil-update.el 1.2.3 ;; ;;; Code: (package-initialize) (require 'f) (require 'erc) (require 'yaoddmuse) (defconst evilupdate-irc-nick "lyrobot") (defconst evilupdate-irc-channel "#evil-mode") (defconst evilupdate-irc-topic "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") (defconst evilupdate-wiki-page "Evil") (defvar evilupdate-version "1.0.0") (defvar evilupdate-done nil) (defun evilupdate-wait () "Wait until `evilupdate-done' is set to t." (while (not evilupdate-done) (sleep-for 1)) (setq evilupdate-done nil)) (defun evilupdate-done () "Set `evilupdate-done' to t to stop the corresponding `evilupdate-wait'." (setq evilupdate-done t)) (defun evilupdate-update-irc () "Update the topic of the IRC channel." (let ((erc-nick evilupdate-irc-nick) (erc-autojoin-channels-alist nil) (auth-sources nil)) (erc-tls :server "irc.freenode.net" :port "6697" :nick evilupdate-irc-nick) (add-hook 'erc-join-hook (lambda () (let (case-fold-search) (erc-set-topic (replace-regexp-in-string "VERSION" evilupdate-version evilupdate-irc-topic nil t))) (erc-quit-server "") (sleep-for 5) (evilupdate-done))) (erc-join-channel evilupdate-irc-channel) (evilupdate-wait))) (defun evilupdate-wiki-trace (page-buffer-name) "Callback for updating the EmacsWiki page in buffer PAGE-BUFFER-NAME." (with-current-buffer page-buffer-name (goto-char (point-min)) (when (re-search-forward "Current stable version: \\*\\*\\([^*]*\\)\\*\\*") (goto-char (match-beginning 1)) (delete-region (match-beginning 1) (match-end 1)) (insert evilupdate-version) (yaoddmuse-post-buffer (current-buffer) evilupdate-version nil) (evilupdate-done)))) (unless (require 'nadvice nil t) (defadvice yaoddmuse-display-page (around evilupdate activate) (evilupdate-wiki-trace (ad-get-arg 0)))) (defun evilupdate-update-emacswiki () "Update the version information on the EmacsWiki page." (setq yaoddmuse-wikis '(("EmacsWiki" "https://www.emacswiki.org/emacs" utf-8 "uihnscuskc=1;"))) (when (featurep 'nadvice) (advice-add 'yaoddmuse-display-page :after 'evilupdate-wiki-trace)) (yaoddmuse-edit "EmacsWiki" evilupdate-wiki-page t) (evilupdate-wait)) (defun evilupdate-update-regexp (file regexp) "Update version tag in FILE. The version tag is defined by the REGEXP, in particular by the first match group." (find-file file) (goto-char (point-min)) (when (re-search-forward regexp nil t) (goto-char (match-beginning 1)) (delete-region (match-beginning 1) (match-end 1)) (insert evilupdate-version) (save-buffer))) (defun evilupdate-update-files () "Replace version comments in all source files." (dolist (file (f-glob "*.el")) (evilupdate-update-regexp file ";;\\s-*Version:\\s-*\\([^\n]+\\)"))) (defun evilupdate-update-pkg () "Replace version in package file." (evilupdate-update-regexp "evil-pkg.el" "\"evil\"[ \t\n\r]*\"\\([^\"]+\\)\"")) (defun evilupdate-update-var () "Replace version in `evil-version' variable." (evilupdate-update-regexp "evil-vars.el" "t \"\\([^\"]*\\)\"[) \n\r\t]*\"The current version of Evil")) (defun evilupdate-update-news () "Send an posting to the mailing list." (shell-command (concat "thunderbird -compose \"newsgroups=gmane.emacs.vim-emulation,preselectid=id2,subject='[ANN] Evil version " evilupdate-version " released',body='" "Evil version " evilupdate-version " has been released. The stable version can be installed from MELPA stable [1]. The latest development version is available from MELPA [2]. The Evil developers. [1] http://stable.melpa.org [2] http://melpa.org '\""))) (defun evilupdate-update (version nonews) "Update Evil to VERSION. If NONEWS is non-nil do not post a message to the newsgroup." (setq evilupdate-cnt 0) (setq evilupdate-version version) (evilupdate-update-emacswiki) (evilupdate-update-irc) (evilupdate-update-files) (evilupdate-update-pkg) (evilupdate-update-var) (unless nonews (evilupdate-update-news))) (cond ((= (length argv) 2) (unless (equal (car argv) "nonews") (user-error "Usage: evilupdate.el [-n] VERSION")) (evilupdate-update (cadr argv) t)) ((= (length argv) 1) (evilupdate-update (cadr argv))) (t (user-error "Usage: evilupdate.el [-n] VERSION"))) ;;; evilupdate.el ends here