[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master 85bec8d: * externals-list: Convert multishell, pcaed, and
From: |
Stefan Monnier |
Subject: |
[elpa] master 85bec8d: * externals-list: Convert multishell, pcaed, and swiper to :external |
Date: |
Sun, 29 Nov 2020 23:20:54 -0500 (EST) |
branch: master
commit 85bec8db6406bea80d89fcdc1493428f0b85f7dc
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>
* externals-list: Convert multishell, pcaed, and swiper to :external
---
externals-list | 5 +-
packages/multishell/.gitignore | 2 -
packages/multishell/LICENSE | 674 ------------
packages/multishell/README.md | 57 -
packages/multishell/getting-to-a-shell.md | 41 -
packages/multishell/multishell-list.el | 314 ------
packages/multishell/multishell.el | 846 ---------------
packages/paced/.bzrignore | 8 -
packages/paced/.elpaignore | 5 -
packages/paced/COPYING | 674 ------------
packages/paced/Project.ede | 48 -
packages/paced/dir | 19 -
packages/paced/paced-async.el | 111 --
packages/paced/paced-tests.el | 507 ---------
packages/paced/paced.el | 1356 -----------------------
packages/paced/paced.info | 1029 ------------------
packages/paced/paced.org | 783 --------------
packages/paced/test-files/first.txt | 1 -
packages/paced/test-files/fourth.org | 2 -
packages/paced/test-files/second.cpp | 1 -
packages/paced/test-files/third.org | 1 -
packages/paced/test.mk | 27 -
packages/swiper/swiper.el | 1673 -----------------------------
23 files changed, 4 insertions(+), 8180 deletions(-)
diff --git a/externals-list b/externals-list
index df04b9a..808e5bc 100644
--- a/externals-list
+++ b/externals-list
@@ -139,6 +139,7 @@
("mmm-mode" :external "https://github.com/purcell/mmm-mode.git")
("modus-operandi-theme":external
"https://gitlab.com/protesilaos/modus-themes")
("modus-vivendi-theme" :external
"https://gitlab.com/protesilaos/modus-themes")
+ ("multishell" :external
"https://github.com/kenmanheimer/EmacsMultishell")
("muse" :external "https://github.com/alexott/muse") ;FIXME:
Not nearly in-sync
("myers" :external nil)
("nameless" :external "https://github.com/Malabarba/Nameless")
@@ -153,6 +154,7 @@
;;FIXME:("org" :external ??) ;; Need to introduce snapshots!!
("orgalist" :external nil)
("org-edna" :external
"https://savannah.nongnu.org/projects/org-edna-el") ;URL?
+ ("paced" :external
"bzr::bzr://bzr.savannah.nongnu.org/paced-el/trunk")
("pabbrev" :external "https://github.com/phillord/pabbrev.git")
("parsec" :external
"https://github.com/cute-jumper/parsec.el.git")
("peg" :external) ;Was in
"https://github.com/ellerh/peg.el"
@@ -201,10 +203,11 @@
("sql-smie" :external nil)
("ssh-deploy" :external
"https://github.com/cjohansson/emacs-ssh-deploy")
("svg" :core ("lisp/svg.el"))
+ ("swiper" :external "https://github.com/abo-abo/swiper")
("system-packages" :external
"https://gitlab.com/jabranham/system-packages")
("temp-buffer-browse" :external
"https://github.com/leoliu/temp-buffer-browse")
("test-simple" :external "https://github.com/rocky/emacs-test-simple")
- ("timerfunctions" :external nil)
+ ("timerfunctions" :external nil)
("undo-tree" :external "http://www.dr-qubit.org/git/undo-tree.git")
("uni-confusables" :external nil)
("url-http-ntlm" :external nil)
diff --git a/packages/multishell/.gitignore b/packages/multishell/.gitignore
deleted file mode 100644
index 1c17549..0000000
--- a/packages/multishell/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# Compiled
-*.elc
diff --git a/packages/multishell/LICENSE b/packages/multishell/LICENSE
deleted file mode 100644
index ef7e7ef..0000000
--- a/packages/multishell/LICENSE
+++ /dev/null
@@ -1,674 +0,0 @@
-GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- 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.
-
- {one line to give the program's name and a brief idea of what it does.}
- Copyright (C) {year} {name of author}
-
- 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 <http://www.gnu.org/licenses/>.
-
-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:
-
- {project} Copyright (C) {year} {fullname}
- 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
-<http://www.gnu.org/licenses/>.
-
- 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
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/packages/multishell/README.md b/packages/multishell/README.md
deleted file mode 100644
index 4004e51..0000000
--- a/packages/multishell/README.md
+++ /dev/null
@@ -1,57 +0,0 @@
-multishell.el
-=============
-
-Facilitate use of multiple local and remote Emacs shell buffers.
-
-Multishell is available via Emacs package manager, [in
ELPA](https://elpa.gnu.org/packages/multishell.html). Install "multishell" from
the `M-x package-list-packages` listing.
-
-I use the emacs shell a *lot*, including separate shells for separate
-project, and more shells for access to remote systems (which I do a lot, as
-a systems administrator). On top of emacs' powerful shell and tramp
-facilities, use a `multishell` (customization-activated) key binding to:
-
-* Get to the input point from wherever you are in a shell buffer,
- ... or to any of your shell buffers, from anywhere inside emacs.
-
-* Use universal arguments to launch and choose among alternate shell buffers,
- ... and change which is the current default.
-
-* Easily restart disconnected shells, or shells from prior sessions
- ... the latter from Emacs builtin savehist minibuf history persistence
-
-* Append a path to a new shell name to launch a shell in that directory,
- ... and use a path with Emacs tramp syntax to launch a remote shell -
- for example:
-
- * `#root/sudo:root@localhost:/etc` for a buffer named "#root" with a
- root shell starting in /etc.
-
- * `/ssh:example.net:/` for a shell buffer in / on example.net.
- The buffer will be named "*example.net*".
-
- * `#ex/ssh:example.net|sudo:root@example.net:/etc` for a root shell
- starting in /etc on example.net named "*#ex*".
-
- * `interior/ssh:gateway.corp.com|ssh:interior.corp.com:` to go via
- gateway.corp.com to your homedir on interior.corp.com. The buffer
- will be named "*interior*". You could append a sudo hop, and so on.
-
-* Thanks to tramp, file visits from the shell will seamlessly be on the
- host where the shell is running, in the auspices of the target account.
-
-See the `multishell-pop-to-shell` docstring (in
-[multishell.el](multishell.el)) for details, and
-[getting-to-a-shell.md](getting-to-a-shell.md) for the nitty-gritty
-decision tree that determines where the keybinding according to the various
-conditions.
-
-Customize-group `multishell' to select and activate a keybinding and set
-various behaviors. Customize-group `savehist' to preserve buffer
-names/paths across emacs restarts.
-
-Please use
-[the multishell repository](https://github.com/kenmanheimer/EmacsMultishell)
-issue tracker to report problems, suggestions, etc.
-
-See the [multishell.el](multishell.el) file commentary for a change log and
-Todo list.
diff --git a/packages/multishell/getting-to-a-shell.md
b/packages/multishell/getting-to-a-shell.md
deleted file mode 100644
index a2ad649..0000000
--- a/packages/multishell/getting-to-a-shell.md
+++ /dev/null
@@ -1,41 +0,0 @@
-Multishell enables you to get to the input prompt in the shell you want
-with as few keystrokes as possible.
-
-* One keybinding, unmodified, gets you to the your current default shell, if
- not in a shell, or to the input prompt of the current shell, if you're in
- one.
-
-* Use the universal argument to select a specific shell buffer, wherever
- point happens to be residing. Enter an empty line to the prompt to go to
- your current default shell, or use completing read to go to a shell from
- your multishell history, or start a new shell at the path you specify -
- including remote paths, using tramp syntax. (See the
- multishell-pop-to-shell docstring in [multishell.el](multishell.el) for
- details.)
-
-* Use a doubled universal argument to set the shell you choose to be the
- current default. (The prompt will indicate that mode with a "<==".)
-
-Here's the decision tree:
-
-* No universal argument - use:
-
- * From-buffer is shell buffer: use from-buffer current name/path
- - if shell/connection is stopped, restart/reconnect
- - if not at input prompt, go there
- * From-buffer is not shell buffer:
- - Go to multishell-primary-name current name/path, creating or
- restarting and/or reconnecting if that shell is not currently running.
-
-* Universal argument provided - use:
-
- - No name is specified - use current multishell-primary-name path
- * Name is specified - use named buffer (creating if not already present):
- * Path is also specified:
- - shell is running - ignore new path
- - shell will be started or restarted - use new path
- * No path is specified:
- - Name has history: use path from history
- - Name has no history: use path that target buffer already has or
inherits
- - If the universal argument is doubled, set the selected shell as the
- default one, going forwards.
diff --git a/packages/multishell/multishell-list.el
b/packages/multishell/multishell-list.el
deleted file mode 100644
index 5cecae0..0000000
--- a/packages/multishell/multishell-list.el
+++ /dev/null
@@ -1,314 +0,0 @@
-;;; multishell-list.el --- tabulated-list-mode for multishell shell buffers
-*- lexical-binding:t -*-
-
-;; Copyright (C) 2016-2020 Free Software Foundation, Inc. and Ken Manheimer
-
-;; Author: Ken Manheimer <ken.manheimer@gmail.com>
-;; Version: 1.1.8
-;; Created: 2016 -- first public availability
-;; Keywords: processes
-;; URL: https://github.com/kenmanheimer/EmacsMultishell
-
-;; See multishell.el for commentary, change log, etc.
-
-(require 'tabulated-list)
-(require 'multishell)
-(eval-when-compile (require 'cl-lib))
-
-(defgroup multishell-list nil
- "Show a menu of all shell buffers in a buffer."
- :group 'multishell)
-
-(defface multishell-list-name
- '((t (:weight bold)))
- "Face for shell names in the Multishell List."
- :group 'multishell-list)
-
-(defun multishell-list-open-pop (&optional arg)
- "Pop to current entry's shell in separate window.
-
-The shell is started if it's not already going, unless this is
-invoked with optional `universal-argument'. In that case we
-pop to the buffer but don't change its run state."
- (interactive "P")
- (let ((list-buffer (current-buffer))
- (entry (tabulated-list-get-id)))
- (if arg
- (pop-to-buffer
- (multishell-bracket (multishell-name-from-entry entry)))
- (multishell-list-dispatch-selected entry t))
- (with-current-buffer list-buffer
- (revert-buffer)
- (multishell-list-goto-item-by-entry entry))))
-
-(defun multishell-list-open-as-default ()
- "Pop to current entry's shell, and set as the default shell."
- (interactive)
- (let ((list-buffer (current-buffer))
- (entry (tabulated-list-get-id)))
- (message "%s <==" (multishell-name-from-entry entry))
- (multishell-list-dispatch-selected entry t t)
- (with-current-buffer list-buffer
- (revert-buffer)
- (multishell-list-goto-item-by-entry entry))))
-
-(defun multishell-list-open-here (&optional arg)
- "Switch to current entry's shell buffer.
-
-The shell is started if it's not already going, unless this is
-invoked with optional `universal-argument'. In that case we
-switch to the buffer but don't activate (or deactivate) it it."
- (interactive "P")
- (let* ((list-buffer (current-buffer))
- (entry (tabulated-list-get-id)))
- (if arg
- (switch-to-buffer
- (multishell-bracket (multishell-name-from-entry entry)))
- (multishell-list-dispatch-selected entry nil))
- (with-current-buffer list-buffer
- (revert-buffer))))
-
-(defun multishell-list-delete (&optional _arg)
- "Remove current shell entry, and prompt for buffer-removal if present."
- (interactive)
- (let* ((entry (tabulated-list-get-id))
- (name (multishell-name-from-entry entry))
- (name-bracketed (multishell-bracket name))
- (buffer (get-buffer name-bracketed)))
- (when (multishell-delete-history-name name)
- (and buffer
- ;; If the process is live, let shell-mode get confirmation:
- (or (comint-check-proc (current-buffer))
- (y-or-n-p (format "Kill buffer %s? " name-bracketed)))
- (kill-buffer name-bracketed)))
- (tabulated-list-delete-entry)))
-
-(defun multishell-list-edit-entry (&optional arg)
- "Edit the value of current shell entry.
-
-Submitting the change will not launch the entry, unless this is
-invoked with optional `universal-argument'. In the latter case,
-submitting the entry will pop to the shell in a new window,
-starting it if it's not already going."
-
- (interactive "P")
- (let* ((list-buffer (current-buffer))
- (entry (tabulated-list-get-id))
- (name (multishell-name-from-entry entry))
- (revised (multishell-read-unbracketed-entry
- (format "Edit shell spec for %s: " name)
- entry
- 'no-record))
- (revised-name (multishell-name-from-entry revised))
- buffer)
- (when (not (string= revised entry))
- (multishell-replace-entry entry revised)
- (when (and (not (string= name revised-name))
- (setq buffer (get-buffer (multishell-bracket name))))
- (with-current-buffer buffer
- (rename-buffer (multishell-bracket revised-name)))))
- (when arg
- (multishell-list-dispatch-selected revised-name t))
- (with-current-buffer list-buffer
- (revert-buffer)
- (multishell-list-goto-item-by-entry revised))))
-
-(defun multishell-list-clone-entry (&optional arg)
- "Create a new list entry, edited from the current one, ready to launch.
-
-If you provide an optional `universal-argument', the new entry
-will be launched when it's created.
-
-The already existing original entry is left untouched."
- (interactive "P")
- (let* ((prototype (tabulated-list-get-id))
- (name (multishell-name-from-entry prototype))
- (new (multishell-read-unbracketed-entry
- (format "Clone new shell spec from %s: " name)
- prototype
- 'no-record))
- (new-name (multishell-name-from-entry new))
- (new-path (cadr (multishell-split-entry new))))
- (when (not (string= new prototype))
- (multishell-register-name-to-path new-name new-path)
- (revert-buffer)
- (multishell-list-goto-item-by-entry new)
- (when arg
- (multishell-list-dispatch-selected new-name t)))))
-
-(defun multishell-list-mouse-select (event)
- "Select the shell whose line is clicked."
- (interactive "e")
- (select-window (posn-window (event-end event)))
- (let ((entry (tabulated-list-get-id (posn-point (event-end event)))))
- (multishell-list-dispatch-selected entry nil)))
-
-(defun multishell-list-dispatch-selected (entry pop &optional set-primary)
- "Go to multishell ENTRY, popping to window if POP is non-nil.
-
-Optional arg SET-PRIMARY non-nil sets `multishell-primary-name' to entry.
-
-Provide for concluding minibuffer interaction if we're in completing mode."
- (let ((set-primary-as-arg (and set-primary '(16))))
- (if multishell-completing-read
- ;; In multishell completing-read, arrange to conclude minibuffer input:
- (throw 'multishell-minibuffer-exit (list entry pop set-primary-as-arg))
- (multishell-pop-to-shell set-primary-as-arg entry (not pop)))))
-
-(defun multishell-list-placeholder (value default)
- "Return VALUE if non-empty string, else DEFAULT."
- (if (or (not value) (string= value ""))
- default
- value))
-(defconst multishell-list-active-flag "+")
-(defconst multishell-list-inactive-flag ".")
-(defconst multishell-list-absent-flag "x")
-
-(defun multishell-list-entries ()
- "Generate multishell name/path-spec entries list for tabulated-list."
- (let ((recency 0))
- (mapcar #'(lambda (entry)
- (setq recency (1+ recency))
- (let* ((splat (multishell-split-entry entry))
- (name (car splat))
- (buffer (and name
- (get-buffer
- (multishell-bracket name))))
- (status (cond ((not buffer)
- multishell-list-absent-flag)
- ((comint-check-proc buffer)
- multishell-list-active-flag)
- (t multishell-list-inactive-flag)))
- (rest (cadr splat))
- (dir (and rest (or (file-remote-p rest 'localname)
- rest)))
- (hops (and dir
- (file-remote-p rest 'localname)
- (substring
- rest 0 (- (length rest) (length dir))))))
- (when (not name)
- (setq name (multishell-name-from-entry entry)))
- (list entry
- (vector (format "%d" recency)
- status
- (multishell-list--decorate-name name)
- (multishell-list-placeholder hops "-")
- (multishell-list-placeholder dir "~")))))
- (multishell-all-entries))))
-
-(defun multishell-list-goto-item-by-entry (entry)
- "Position at beginning of line of tabulated list item for ENTRY."
- (goto-char (point-min))
- (while (and (not (eobp))
- (not (string= (tabulated-list-get-id) entry)))
- (forward-line 1)))
-
-(define-obsolete-function-alias 'multishell-collate-row-strings-as-numbers
- #'multishell-list--collate-row-strings-as-numbers "multishell 1.1.6")
-(defun multishell-list--collate-row-strings-as-numbers (a b)
- (let ((a (aref (cadr a) 0))
- (b (aref (cadr b) 0)))
- (> (string-to-number a) (string-to-number b))))
-
-(defun multishell-list--decorate-name (name)
- (propertize name
- 'font-lock-face 'multishell-list-name
- 'mouse-face 'highlight))
-
-(defvar multishell-list-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map tabulated-list-mode-map)
- (define-key map (kbd "c") 'multishell-list-clone-entry)
- (define-key map (kbd "d") 'multishell-list-delete)
- (define-key map (kbd "\C-k") 'multishell-list-delete)
- (define-key map (kbd "k") 'multishell-list-delete)
- (define-key map (kbd "e") 'multishell-list-edit-entry)
- (define-key map (kbd "o") 'multishell-list-open-pop)
- (define-key map (kbd " ") 'multishell-list-open-pop)
- (define-key map (kbd "O") 'multishell-list-open-as-default)
- (define-key map (kbd "RET") 'multishell-list-open-here)
- (define-key map [mouse-2] 'multishell-list-mouse-select)
- (define-key map [follow-link] 'mouse-face)
- map))
-(define-derived-mode multishell-list-mode
- tabulated-list-mode "Shells"
- "Major mode for listing current and historically registered shells.
-
-Initial sort is from most to least recently used:
-
-- First active shells, flagged with `+' a plus sign
-- Then, inactive shells, flagged with `.' a period
-- Then historical shells that currently have no buffer, flagged with `x' an ex
-
-\\{multishell-list-mode-map\}"
- (setq tabulated-list-format
- [;; (name width sort '(:right-align nil :pad-right nil))
- ("#" 0 multishell-list--collate-row-strings-as-numbers :pad-right 1)
- ("! " 1 t :pad-right 1)
- ("Name" 15 t)
- ("Hops" 30 t)
- ("Directory" 30 t)]
- tabulated-list-sort-key '("#" . t)
- tabulated-list-entries #'multishell-list-entries)
- (tabulated-list-init-header))
-
-(defun multishell-list-cull-dups (entries)
- "Return list of multishell ENTRIES sans ones with duplicate names.
-
-For duplicates, we prefer the ones that have paths."
- (let ((tally (make-hash-table :test #'equal))
- got name name-order-reversed already)
- (dolist (entry entries)
- (setq name (multishell-name-from-entry entry)
- already (gethash name tally nil))
- (when (not already)
- (push name name-order-reversed))
- (when (or (not already) (< (length already) (length entry)))
- ;; Add new or replace shorter prior entry for name:
- (puthash name entry tally)))
- (dolist (name name-order-reversed)
- (push (gethash name tally) got))
- got))
-
-;;;###autoload
-(defun multishell-list (&optional completing)
- "Edit your current and historic list of shell buffers.
-
-If optional COMPLETING is nil, we present the full
-`multishell-history' list in a popped buffer named `*Shells*'.
-
-In the buffer, hit ? or h for a list of commands.
-
-When optional COMPLETING is non-nil, it must be a list of
-multishell-history completion candidate entries, as provided by
-`completing-read'. Then we present the list as a part of
-minibuffer completion.
-
-You can get to the shells listing by recursively invoking
-\\[multishell-pop-to-shell] at the `multishell-pop-to-shell'
-`universal-argument' prompts."
- (interactive)
- (let ((from-entry (car (multishell-history-entries
- (multishell-unbracket (buffer-name
- (current-buffer))))))
- (buffer (get-buffer-create (if completing
- "*Completions*"
- "*Shells*"))))
- (if completing
- (set-buffer buffer)
- (pop-to-buffer buffer))
- (multishell-list-mode)
- (cl-progv
- ;; Temporarily assign multishell-history only when completing:
- (when completing '(multishell-history))
- (when completing
- (list (multishell-list-cull-dups (mapcar #'substring-no-properties
- completing))))
- (tabulated-list-print))
- (when completing
- )
- (when from-entry
- (multishell-list-goto-item-by-entry from-entry))))
-
-(provide 'multishell-list)
-
-;;; multishell-list.el ends here
diff --git a/packages/multishell/multishell.el
b/packages/multishell/multishell.el
deleted file mode 100644
index 6d93485..0000000
--- a/packages/multishell/multishell.el
+++ /dev/null
@@ -1,846 +0,0 @@
-;;; multishell.el --- Easily use multiple shell buffers, local and remote -*-
lexical-binding:t -*-
-
-;; Copyright (C) 1999-2020 Free Software Foundation, Inc. and Ken Manheimer
-
-;; Author: Ken Manheimer <ken.manheimer@gmail.com>
-;; Version: 1.1.9
-;; Created: 1999 -- first public availability
-;; Keywords: processes
-;; Package-Requires: ((cl-lib "0.5"))
-;; URL: https://github.com/kenmanheimer/EmacsMultishell
-;;
-;;; Commentary:
-;;
-;; Easily use and navigate multiple shell buffers, including remote shells.
-;; Fundamentally, multishell is the function `multishell-pop-to-shell' -
-;; a la `pop-to-buffer' - plus a keybinding. Together, they enable you to:
-;;
-;; * Get to the input point from wherever you are in a shell buffer,
-;; ... or to any of your shell buffers, from anywhere inside emacs.
-;;
-;; * Use universal arguments to launch and choose among alternate shell
buffers,
-;; ... and change which is the current default.
-;;
-;; * Easily restart disconnected shells, or shells from prior sessions
-;; ... the latter from Emacs builtin savehist minibuf history persistence
-;;
-;; * Append a path to a new shell name to launch a shell in that directory,
-;; ... and use a path with Emacs tramp syntax to launch a remote shell -
-;; for example:
-;;
-;; * `#root/sudo:root@localhost:/etc` for a buffer named "*#root*" with a
-;; root shell starting in /etc.
-;;
-;; * `/ssh:example.net:` for a shell buffer in your homedir on example.net.
-;; The buffer will be named "*example.net*".
-;;
-;; * `#ex/ssh:example.net|sudo:root@example.net:/var/log` for a root shell
-;; starting in /var/log on example.net named "*#ex*".
-;;
-;; * 'interior/ssh:gateway.corp.com|ssh:interior.corp.com:' to go via
-;; gateway.corp.com to your homedir on interior.corp.com. The buffer
-;; will be named "*interior*". You could append a sudo hop, and so on.
-;;
-;; * Thanks to tramp, file visits from the shell will seamlessly be in
-;; the auspices of the target account, and relative to the current
-;; directory, on the host where the shell is running.
-;;
-;; * Manage your list of shells, current and past, as a collection.
-;;
-;; See the `multishell-pop-to-shell' docstring for details.
-;;
-;; Customize-group `multishell' to select and activate a keybinding and set
-;; various behaviors. Customize-group `savehist' to preserve buffer
-;; names/paths across emacs restarts.
-;;
-;; Please use
-;; [the multishell repository](https://github.com/kenmanheimer/EmacsMultishell)
-;; issue tracker to report problems, suggestions, etc, and see that
-;; repository for a bit more documentation.
-;;
-;; Change Log:
-;;
-;; * 2020-10-30 1.1.9 Ken Manheimer:
-;; - Require cl-lib when compiling for cl-letf macro.
-;; * 2020-10-28 1.1.8 Ken Manheimer:
-;; - Change back to having multishell-list require multishell,
-;; rather than the other way around, and remove now unnecessary
-;; new autoloads.
-;; - Bump version for ELPA release.
-;; * 2020-10-28 1.1.7 Ken Manheimer:
-;; - Forward compatibility: 'cl-progv' rather than 'progv', resolves
-;; multishell-list error in recent emacs versions.
-;; - Incorporate gnu refinements (thanks!)
-;; * 2016-06-27 1.1.6 Ken Manheimer (unreleased):
-;; - When starting a remote shell, if cd fails to an inital remote
-;; directory, try again without the cd.
-;; * 2016-02-11 1.1.5 Ken Manheimer:
-;; - Rectify multishell list sorting to preserve recentness
-;; - Increment the actual multishell-version setting, neglected for 1.1.4.
-;; * 2016-02-11 1.1.4 Ken Manheimer:
-;; - hookup multishell-list as completion help buffer.
-;; Mouse and keyboard selections from help listing properly exits
-;; minibuffer.
-;; * 2016-02-09 1.1.3 Ken Manheimer:
-;; multishell-list:
-;; - add some handy operations, like cloning new entry from existing
-;; - add optional behaviors to existing operations for returning to
-;; stopped shells without restarting them.
-;; - solidify maintaining focus on current entry
-;; - fix miscellaneous.
-;; * 2016-01-31 1.1.2 Ken Manheimer:
-;; - Settle puzzling instability of multishell-all-entries
-;; - The accumulations was putting items going from more to less active
-;; categories to be put at the end, not beginning.
-;; - Also, using history for prompting changes history - implement
-;; no-record option to avoid this when needed.
-;; - Implement simple edit-in-place multishell-replace-entry and use in
-;; multishell-list-edit-entry.
-;; - Remove now unnecessary multishell-list-revert-buffer-kludge.
-;; - Rectify byte compiler offenses, and other fixes - thanks to Stefan
-;; Monnier for pointing out many of the corrections.
-;; - Avoid directly calling tramp functions unnecessarily.
-;; * 2016-01-30 1.1.1 Ken Manheimer:
-;; - shake out initial multishell-list glitches:
-;; - (Offer to) delete shell buffer, if present, when deleting entry.
-;; - Set recency (numeric rank) as initial sort field
-;; - Recompute list on most operations that affect the order, and try to
-;; preserve stability. (Kludgy solution, needs work.)
-;; - Set version to 1.1.1 - multishell-list addition should have been 1.1.0.
-;; * 2016-01-30 1.0.9 Ken Manheimer:
-;; - Add multishell-list for managing the collection of current and
-;; history-registered shells: edit, delete, and switch/pop to entries.
-;; Easy access by invoking `multishell-pop-to-shell' from in the
-;; `multishell-pop-to-shell' universal arg prompts.
-;; - Duplicate existing shell buffer names in completions, for distinction.
-;; - Add paths to buffers started without one, when multishell history dir
-;; tracking is enabled.
-;; - Major code cleanup:
-;; - Simplify multishell-start-shell-in-buffer, in particular using
-;; shell function, rather than unnecessarily going underneath it.
-;; - Establish multishell-name-from-entry as canonical name resolver.
-;; - Fallback to eval-after-load in emacs versions that lack
-;; with-eval-after-load (eg, emacs 23).
-;; - save-match-data, where match-string is used
-;; - resituate some helpers
-;; * 2016-01-24 1.0.8 Ken Manheimer:
-;; - Work around the shell/tramp mishandling of remote+sudo+homedir problem!
-;; The work around is clean and simple, basically using high-level `cd'
-;; API and not messing with the low-level default-directory setting.
-;; (Turns out the problem was not in my local config. Good riddance to the
-;; awkward failure handler!)
-;; - Clean up code resolving the destination shell, starting to document the
-;; decision tree in the process. See getting-to-a-shell.md in the
-;; multishell repository, https://github.com/kenmanheimer/EmacsMultishell
-;; - There may be some shake-out on resolving the destination shell, but
-;; this release gets the fundamental functionality soundly in place.
-;; * 2016-01-23 1.0.7 Ken Manheimer:
-;; - Remove notes about tramp remote+sudo+homedir problem. Apparently it's
-;; due to something in my local site configuration (happens with -q but
-;; not -Q).
-;; * 2016-01-22 1.0.6 Ken Manheimer:
-;; - Add multishell-version function.
-;; - Tweak commentary/comments/docstrings.
-;; - Null old multishell-buffer-name-history var, if present.
-;; * 2016-01-16 1.0.5 Ken Manheimer:
-;; - History now includes paths, when designated.
-;; - Actively track current directory in history entries that have a path.
-;; Custom control: multishell-history-entry-tracks-current-directory
-;; - Offer to remove shell's history entry when buffer is killed.
-;; (Currently the only UI mechanism to remove history entries.)
-;; - Fix - prevent duplicate entries for same name but different paths
-;; - Fix - recognize and respect tramp path syntax to start in home dir
-;; - Simplify history var name, migrate existing history if any from old name
-;; * 2016-01-04 1.0.4 Ken Manheimer - Released to ELPA
-;; * 2016-01-02 Ken Manheimer - working on this in public, but not yet
released.
-;;
-;; TODO and Known Issues:
-;;
-;; * Add custom shell launch prep actions
-;; - for, eg, port knocking, interface activations
-;; - shell commands to execute when shell name or path matches a regexp
-;; - list of (regexp, which - name, path, or both, command)
-;; * Investigate whether we can recognize and provide for failed hops.
-;; - Tramp doesn't provide useful reactions for any hop but the first
-;; - Might be stuff we can do to detect and convey failures?
-;; - Might be no recourse but to seek tramp changes.
-;; * Try minibuffer field boundary at beginning of tramp path, to see whether
-;; the field boundary magically enables tramp path completion.
-
-;;; Code:
-
-(require 'comint)
-(require 'shell)
-(require 'savehist)
-(eval-when-compile (require 'cl-lib))
-
-(defvar multishell-version "1.1.9")
-(defun multishell-version (&optional here)
- "Return string describing the loaded multishell version."
- (interactive "P")
- (let ((msg (concat "Multishell " multishell-version)))
- (if here (insert msg)
- (if (called-interactively-p 'interactive)
- (message "%s" msg)
- msg))))
-
-(defgroup multishell nil
- "Allout extension that highlights outline structure graphically.
-
-Customize `allout-widgets-auto-activation' to activate allout-widgets
-with allout-mode."
- :group 'shell)
-
-(defcustom multishell-command-key "\M- "
- "The key to use if `multishell-activate-command-key' is true.
-
-You can instead manually bind `multishell-pop-to-shell' using emacs
-lisp, eg: (global-set-key \"\\M- \" \\='multishell-pop-to-shell)."
- :type 'key-sequence)
-
-(defvar multishell--responsible-for-command-key nil
- "Coordination for multishell key assignment.")
-(defun multishell-activate-command-key-setter (symbol setting)
- "Implement `multishell-activate-command-key' choice."
- (set-default symbol setting)
- (when (or setting multishell--responsible-for-command-key)
- (multishell-implement-command-key-choice (not setting))))
-(defun multishell-implement-command-key-choice (&optional unbind)
- "If settings dicate, implement binding of multishell command key.
-
-If optional UNBIND is true, globally unbind the key.
-
-* `multishell-activate-command-key' - Set this to get the binding or not.
-* `multishell-command-key' - The key to use for the binding, if appropriate."
- (when (bound-and-true-p multishell-command-key)
- (if unbind
- (global-unset-key multishell-command-key)
- (when (bound-and-true-p multishell-activate-command-key)
- (setq multishell--responsible-for-command-key t)
- (global-set-key multishell-command-key 'multishell-pop-to-shell)))))
-
-(defcustom multishell-activate-command-key nil
- "Set this to impose the `multishell-command-key' binding.
-
-You can instead manually bind `multishell-pop-to-shell' using emacs
-lisp, eg: (global-set-key \"\\M- \" \\='multishell-pop-to-shell)."
- :type 'boolean
- :set #'multishell-activate-command-key-setter)
-
-;; Implement the key customization whenever the package is loaded:
-(if (fboundp 'with-eval-after-load)
- (with-eval-after-load "multishell"
- (multishell-implement-command-key-choice))
- (eval-after-load "multishell"
- '(multishell-implement-command-key-choice)))
-
-(defcustom multishell-pop-to-frame nil
- "*If non-nil, jump to a frame already showing the shell, if another one is.
-
-Otherwise, disregard already-open windows on the shell if they're
-in another frame, and open a new window on the shell in the
-current frame.
-
-\(Use `pop-up-windows' to change multishell other-window vs
-current-window behavior.)"
- :type 'boolean)
-
-(defcustom multishell-history-entry-tracks-current-directory t
- "Maintain shell's current directory in its multishell history entry.
-
-When set, the history entry for shells started with explicit
-paths will track the shell's current working directory.
-
-If `savehist-save-minibuffer-history' is enabled, the current
-working directory of shells will be conveyed between Emacs sessions."
- :type 'boolean)
-
-(defvar multishell-history nil
- "Name/path entries, most recent first.")
-;; Migrate the few pre 1.0.5 users to changed history var:
-(when (and (not multishell-history)
- (boundp 'multishell-buffer-name-history)
- multishell-buffer-name-history)
- (setq multishell-history multishell-buffer-name-history
- multishell-buffer-name-history nil))
-
-(defvar multishell-primary-name "*shell*"
- "Default shell name for un-modified multishell-pop-to-shell buffer target.
-
-This is set by `multishell-pop-to-shell' as the current default,
-when invoked with doubled universal argument.
-
-If you want the designated primary that you have at the end of
-one emacs session to be resumed at the next, customize
-`savehist-additional-variables' to include the
-`multishell-primary-name'.")
-
-(defvar multishell-completing-read nil
- "Internal use, conveying whether or not we're in the midst of a multishell
-completing-read.")
-
-;; Multiple entries happen because completion also adds name to history.
-(defun multishell-register-name-to-path (name path)
- "Add or replace entry associating NAME with PATH in `multishell-history'.
-
-If NAME already had a PATH and new PATH is empty, retain the prior one.
-
-Promote added/changed entry to the front of the list."
- ;; Add or promote to the front, tracking path changes in the process.
- (let* ((entries (multishell-history-entries name))
- (path (or path "")))
- (dolist (entry entries)
- (when (string= path "")
- ;; Retain explicit established path.
- (setq path (cadr (multishell-split-entry entry))))
- (setq multishell-history (delete entry multishell-history)))
- (setq multishell-history (push (concat name path)
- multishell-history))))
-
-(defun multishell-replace-entry (entry revised)
- "Replace every instance of ENTRY in `multishell-history' with REVISED.
-
-Revised entry is situated where former one was.
-
-Returns non-nil iff any changes were made."
- (let ((candidates multishell-history)
- did-revisions)
- (while (setq candidates (member entry candidates))
- (setcar candidates revised)
- (setq candidates (cdr candidates)
- did-revisions t))
- did-revisions))
-
-(defun multishell-history-entries (name)
- "Return `multishell-history' entry that starts with NAME, or nil if none."
- (let (got)
- (dolist (entry multishell-history)
- (when (and (string-equal name (multishell-name-from-entry entry))
- (not (member entry got)))
- (push entry got)))
- got))
-
-;;;###autoload
-(defun multishell-pop-to-shell (&optional arg name here)
- "Easily navigate to and within multiple shell buffers, local and remote.
-
-Use a single `universal-argument' (\\[universal-argument]) to launch and
choose between
-nalternate shell buffers, and a doubled universal argument to also set your
-choice as the ongoing default. Append a path to a new shell name to launch
-a shell in that directory, and use Emacs tramp syntax to launch a remote
-shell. There is a shortcut to manage your list of current and
-historical shells, collectively, using `multishell-list' - see below.
-
-Customize-group `multishell' to set up a key binding and tweak behaviors.
-
-Manage your collection of current and historical shells by
-recursively invoking \\[multishell-pop-to-shell] at the
`multishell-pop-to-shell'
-universal argument prompts, eg:
-
- \\[universal-argument] \\[multishell-pop-to-shell]
\\[multishell-pop-to-shell]
-
-\(That will be just a few keys if you do the above customization.)
-
-Hit ? in the listing buffer for editing commands.
-
-==== Basic operation:
-
- - If the current buffer is in shell-mode then focus is moved to
- the process input point.
-
- \(Use a universal argument go to a different shell buffer
- when already in a buffer that has a process - see below.)
-
- - If not in a shell buffer, go to a window that is already
- showing a shell buffer, if any.
-
- In this case, the cursor is not moved to the process input
- point. Repeating the command once you're in the buffer will
- then move the cursor to the process input point.
-
- We respect `pop-up-windows', so you can adjust it to set the
- other-buffer/same-buffer behavior.
-
- - Otherwise, start a new shell buffer, using the current
- directory as the working directory.
-
-If a buffer with the resulting name exists and its shell process
-was disconnected or otherwise stopped, it's resumed.
-
-===== Universal arg to start and select between named shell buffers:
-
-You can assign a distinct name to new shell buffers by prefixing
-your \\[multishell-pop-to-shell] invocation with a single or double
-`universal-argument', \\[universal-argument]:
-
- - With a single universal argument, prompt for the buffer name
- to use (without the asterisks that shell mode will put around
- the name), defaulting to `shell'.
-
- Completion is available.
-
- This combination makes it easy to start and switch across
- multiple shell restarts.
-
- - A double universal argument will prompt for the name and set
- the default to that name, so the target shell becomes the
- primary.
-
- See `multishell-primary-name' for info about preserving the
- setting across emacs restarts.
-
- - Manage your collection of current and historical shells by
- recursively invoking \\[multishell-pop-to-shell] at the
`multishell-pop-to-shell'
- universal argument prompts, or at any time via
- \\[multishell-list]. Hit ? in the listing buffer for editing
- commands.
-
-===== Select starting directory and remote host:
-
-The shell buffer name you give to the prompt for a universal arg
-can include an appended path. That will be used for the startup
-directory. You can use tramp remote syntax to specify a remote
-shell. If there is an element after a final `/', that's used for
-the buffer name. Otherwise, the host, domain, or path is used.
-
-For example:
-
-* `#root/sudo:root@localhost:/etc' for a buffer named \"*#root*\" with a
- root shell starting in /etc.
-
-* `/ssh:example.net:' for a shell buffer in your homedir on example.net.
- The buffer will be named \"*example.net*\".
-
-* `#ex/ssh:example.net|sudo:root@example.net:/var/log' for a root shell
- starting in /var/log on example.net named \"*#ex*\".
-
-* `interior/ssh:gateway.corp.com|ssh:interior.corp.com:' to go
- via gateway.corp.com to your homedir on interior.corp.com. The
- buffer will be named \"*interior*\". You could append a sudo
- hop to the path, combining the previous example, and so on.
-
-File visits from the shell, and many common emacs activities like
-dired, will be on the host where the shell is running, in the
-auspices of the target account, and relative to the current
-directory.
-
-You can change the startup path for a shell buffer by editing it
-at the completion prompt. The new path will not take effect for
-an already-running shell.
-
-To remove a shell buffer's history entry, kill the buffer and
-affirm removal of the entry when prompted.
-
-===== Activate savehist to retain shell buffer names and paths across Emacs
restarts:
-
-To have emacs maintain your history of shell buffer names and paths,
-customize the savehist group to activate savehist."
-
- (interactive "P")
-
- (let ((token '(token)))
- (if (window-minibuffer-p)
- (throw 'multishell-minibuffer-exit token)
- (let ((got (catch 'multishell-minibuffer-exit
- (multishell-pop-to-shell-worker arg name here))))
- ;; Handle catch or plain fall-through - see cond comments for protocol.
- (cond
- ;; Caught token from recursive invocation in minibuffer:
- ((equal token got) (multishell-list))
- ;; Caught specifaction of multishell args, eg from multishell-list:
- ((listp got) (multishell-pop-to-shell-worker (nth 2 got)
- (nth 0 got)
- (nth 1 got)))
- ;; Regular fallthrough - just relay the result:
- (t got))))))
-
-(defun multishell-pop-to-shell-worker (&optional arg name here)
- "Do real work of `multishell-pop-to-shell', which see."
- (let* ((from-buffer (current-buffer))
- (from-buffer-is-shell (derived-mode-p 'shell-mode))
- (primary-name-unbracketed (multishell-unbracket
- multishell-primary-name))
- (fallthrough-name (if from-buffer-is-shell
- (buffer-name from-buffer)
- primary-name-unbracketed))
- (doublearg (equal arg '(16)))
- (target-name-and-path
- (multishell-resolve-target-name-and-path
- (cond (name name)
- (arg
- (or (multishell-read-unbracketed-entry
- (format "Shell buffer name [%s]%s "
- primary-name-unbracketed
- (if doublearg " <==" ":")))
- primary-name-unbracketed))
- (t fallthrough-name))))
- (use-path (cadr target-name-and-path))
- (target-shell-buffer-name (car target-name-and-path))
- (target-buffer (get-buffer target-shell-buffer-name))
- (curr-buff-proc (get-buffer-process from-buffer))
- inwin
- already-there)
-
- ;; Register early so the entry is pushed to the front:
- (multishell-register-name-to-path (multishell-unbracket
- target-shell-buffer-name)
- use-path)
-
- (when doublearg
- (setq multishell-primary-name target-shell-buffer-name))
-
- ;; Situate:
-
- (cond
-
- ((and (or curr-buff-proc from-buffer-is-shell)
- (not arg)
- (eq from-buffer target-buffer)
- (not (eq target-shell-buffer-name (buffer-name from-buffer))))
- ;; In a shell buffer, but not named - stay in buffer, but go to end.
- (setq already-there t))
-
- ((string= (buffer-name) target-shell-buffer-name)
- ;; Already in the specified shell buffer:
- (setq already-there t))
-
- ((or (not target-buffer)
- (not (setq inwin
- (multishell-get-visible-window-for-buffer
target-buffer))))
- ;; No preexisting shell buffer, or not in a visible window:
- (when (not (get-buffer target-shell-buffer-name))
- (message "Creating new shell buffer '%s'" target-shell-buffer-name))
- (if here
- (switch-to-buffer target-shell-buffer-name)
- (pop-to-buffer target-shell-buffer-name pop-up-windows)))
-
- ;; Buffer exists and already has a window - jump to it:
- (t (if (and multishell-pop-to-frame
- inwin
- (not (equal (window-frame (selected-window))
- (window-frame inwin))))
- (select-frame-set-input-focus (window-frame inwin)))
- (if (not (string= (buffer-name (current-buffer))
- target-shell-buffer-name))
- (if here
- (switch-to-buffer target-shell-buffer-name)
- (pop-to-buffer target-shell-buffer-name t)))))
-
- ;; We're in the buffer. Activate:
-
- (if (not (comint-check-proc (current-buffer)))
- (multishell-start-shell-in-buffer use-path))
-
- ;; If the destination buffer has a stopped process, resume it:
- (let ((process (get-buffer-process (current-buffer))))
- (if (and process (equal 'stop (process-status process)))
- (continue-process process)))
-
- (when (or already-there
- (equal (current-buffer) from-buffer))
- (goto-char (point-max))
- (and (get-buffer-process from-buffer)
- (goto-char (process-mark (get-buffer-process from-buffer)))))))
-
-(defun multishell-delete-history-name (name &optional ask)
- "Remove all multishell history entries for NAME.
-
-if optional ask is non-nil (default nil), ask before each deletion.
-
-Return the last entry deleted."
- (let (got)
- (dolist (entry (multishell-history-entries name) got)
- (when (and entry
- (or (not ask)
- (y-or-n-p (format "Remove multishell history entry `%s'? "
- entry))))
- (setq got entry
- multishell-history (delete entry multishell-history))))))
-
-(defun multishell-kill-buffer-query-function ()
- "Offer to remove multishell-history entry for buffer."
- ;; Removal choice is crucial, so users can, eg, kill a shell with huge
- ;; output backlog, while keeping the history entry to easily restart it.
- ;;
- ;; We use kill-buffer-query-functions instead of kill-buffer-hook because:
- ;;
- ;; 1. It enables the user to remove the history without actually killing a
- ;; running buffer, by not confirming the subsequent running-proc query.
- ;; 2. kill-buffer-hooks often fails to run when killing shell buffers!
- ;; It's probably due to failures in other hooks - beyond our control -
- ;; and anyway, I like the first reason well enough.
-
- ;; (Use condition-case to avoid inadvertant disruption of kill-buffer
- ;; activity. kill-buffer happens behind the scenes a whole lot.)
- (condition-case err
- (and (derived-mode-p 'shell-mode)
- (multishell-delete-history-name
- (multishell-unbracket (buffer-name))
- t))
- (error
- (message "multishell-kill-buffer-query-function error: %s" err)))
- t)
-(add-hook 'kill-buffer-query-functions #'multishell-kill-buffer-query-function)
-
-(defun multishell-get-visible-window-for-buffer (buffer)
- "Return visible window containing buffer."
- (catch 'got-a-vis
- (walk-windows
- (function (lambda (win)
- (if (and (eq (window-buffer win) buffer)
- (equal (frame-parameter
- (selected-frame) 'display)
- (frame-parameter
- (window-frame win) 'display)))
- (throw 'got-a-vis win))))
- nil 'visible)
- nil))
-
-(defun multishell-all-entries (&optional active-duplicated)
- "Return multishell history, with active buffers listed first.
-
-Optional ACTIVE-DUPLICATED will return a copy of
-`multishell-history' with unbracketed names of active buffers,
-sans paths, appended to the list, so they have short and long
-completions."
- ;; Reorder so active lead present lead historical entries:
- (let (active-entries active-names present past splat name buffer)
- (dolist (entry multishell-history)
- (setq splat (multishell-split-entry entry)
- name (car splat)
- buffer (and name (get-buffer (multishell-bracket name))))
- (if (buffer-live-p buffer)
- (if (comint-check-proc buffer)
- (setq active-entries (push entry active-entries)
- active-names (push name active-names))
- (setq present (push entry present)))
- (setq past (push entry past))))
- ;; Reverse present and past lists
- (setq multishell-history (append (reverse active-entries)
- (reverse present)
- (reverse past)))
- (if active-duplicated
- (append multishell-history active-names)
- multishell-history)))
-
-(defun multishell-read-unbracketed-entry (prompt &optional initial no-record)
- "PROMPT for shell buffer name, sans asterisks.
-
-Optional INITIAL is preliminary value to be edited.
-
-Optional NO-RECORD prevents changes to `multishell-history'
-across the activity.
-
-Input and completion can include associated path, if any.
-
-Return what's provided, if anything, else nil."
- (let* ((was-multishell-history multishell-history)
- (candidates (multishell-all-entries 'active-duplicated))
- (multishell-completing-read t)
- (got
- ;; Use `cl-letf' to dynamically bind multishell-list to
- ;; display-completion-list, so multishell-list is used when doing
- ;; minibuffer-completion-help.
- (cl-letf (((symbol-function 'display-completion-list)
- #'multishell-list))
- (completing-read prompt
- ;; COLLECTION:
- (reverse candidates)
- ;; PREDICATE:
- nil
- ;; REQUIRE-MATCH:
- 'confirm
- ;; INITIAL-INPUT
- initial
- ;; HIST:
- 'multishell-history))))
- (when no-record
- (setq multishell-history was-multishell-history))
- (if (not (string= got ""))
- got
- nil)))
-
-(defun multishell-resolve-target-name-and-path (shell-spec)
- "Given name/tramp-style address shell spec, resolve buffer name and
directory.
-
-The name is the part of the string up to the first `/' slash, if
-any. Missing pieces are filled in from remote path elements, if
-any, and multishell history. Given a tramp-style remote address
-and no name part, either the user@host is used for the buffer
-name, if a user is specified, or just the host.
-
-Return them as a list: (name path), with name asterisk-bracketed
-and path nil if none is resolved."
- (let* ((splat (multishell-split-entry (or shell-spec "")))
- (path (cadr splat))
- (name (or (car splat) (multishell-name-from-entry path))))
- (when (not path)
- ;; Get path from history, if present.
- (dolist (entry
- (multishell-history-entries
- (multishell-unbracket name)))
- (when (or (not path) (string= path ""))
- (setq path (cadr (multishell-split-entry entry))))))
- (list (multishell-bracket name) path)))
-
-(defun multishell-name-from-entry (entry)
- "Derive a name for a shell buffer according to ENTRY."
- (if (not entry)
- (multishell-unbracket multishell-primary-name)
- (let* ((splat (multishell-split-entry entry))
- (name (car splat))
- (path (cadr splat)))
- (or name
- (if (file-remote-p path)
- (let ((host (file-remote-p path 'host))
- (user (file-remote-p path 'user)))
- (cond ((and host user)
- (format "%s@%s" user host))
- (host host)
- (user user)
- ((system-name))))
- (multishell-unbracket multishell-primary-name))))))
-
-(declare-function tramp-dissect-file-name "tramp")
-(declare-function tramp-cleanup-connection "tramp")
-
-(defun multishell-start-shell-in-buffer (where)
- "Start, restart, or continue a shell in current-buffer on WHERE.
-
-If WHERE is remote and includes a directory, cd to that directory on the
-remote host.
-
-If cd fails to an included remote directory, try again without the cd."
- (let* ((is-active (comint-check-proc (current-buffer))))
-
- (when (and where (not is-active))
-
- ;; FIXME: file-remote-p does not imply Tramp.
- ;; Why do we need to do something special for Tramp here?
- (when (and (derived-mode-p 'shell-mode) (file-remote-p where))
- ;; Returning to disconnected remote shell - do some tidying.
- ;; FIXME: Without this cleanup, occasionally restarting a disconnected
- ;; remote session, particularly one that includes sudo, results in
- ;; an untraceable "Args out of range" error. That never happens if
- ;; we precedeed connection attempts with this cleanup -
- ;; prophylactic.
- (tramp-cleanup-connection
- (tramp-dissect-file-name default-directory 'noexpand)
- 'keep-debug 'keep-password))
-
- (if (not (file-remote-p where))
- (cd where)
- (message "Connecting to %s" where)
- (condition-case err
- (cd where)
- ;; "cd: No such directory found via CDPATH environment variable"
- (error
- (if (string=
- (cadr err)
- "No such directory found via CDPATH environment variable")
- ;; Try again without dir part of remote where:
- (let* ((final-colon-at (string-match ":[^:]+$" where))
- (sans-dir-path (substring where 0 (1+ final-colon-at)))
- (dir-path (substring where (1+ final-colon-at))))
- (message "Failed to cd to %s, trying again without..."
- dir-path)
- (sit-for .5)
- (cd sans-dir-path))
- (signal (car err) (cdr err)))))))
-
- (shell (current-buffer))))
-
-(defun multishell-homedir-shorthand-p (dirpath)
- "t if dirpath is an unexpanded remote homedir spec."
- ;; Workaround to recognize tramp-style homedir shorthand, "...:" and "...:~".
- (let ((localname (file-remote-p dirpath 'localname)))
- (and localname
- (or
- ;; No directory path and no connection to expand homedir:
- (string= localname "")
- ;; Original path doesn't equal expanded homedir:
- (save-match-data
- (not (string-match (concat (regexp-quote localname) "/?$")
- dirpath)))))))
-;; (assert (multishell-homedir-shorthand-p "/ssh:myhost.net:")
-;; (assert (not (multishell-homedir-shorthand-p "/home/klm")))
-;; (assert (not (multishell-homedir-shorthand-p "/ssh:myhost.net:/home/me")))
-
-(defun multishell-track-dirchange (name newpath)
- "Change multishell history entry to track current directory."
- (let* ((entries (multishell-history-entries name)))
- (dolist (entry entries)
- (let* ((name-path (multishell-split-entry entry))
- (path (or (cadr name-path) "")))
- (when path
- (let* ((old-localname (or (file-remote-p path 'localname)
- path))
- (newentry
- (if (multishell-homedir-shorthand-p path)
- (concat entry newpath)
- (replace-regexp-in-string (concat (regexp-quote
- old-localname)
- "$")
- ;; REPLACEMENT
- newpath
- ;; STRING
- entry
- ;; FIXEDCASE
- t
- ;; LITERAL
- t
- )))
- (membership (member entry multishell-history)))
- (when membership
- (setcar membership newentry))))))))
-
-(defvar multishell-was-default-directory ()
- "Provide for tracking directory changes.")
-(make-variable-buffer-local 'multishell-was-default-directory)
-(defun multishell-post-command-business ()
- "Do multishell bookkeeping."
- ;; Update multishell-history with dir changes.
- (condition-case err
- (when (and multishell-history-entry-tracks-current-directory
- (derived-mode-p 'shell-mode))
- (let ((curdir (if (file-remote-p default-directory)
- (file-remote-p default-directory 'localname)
- default-directory)))
- (when (not (string= curdir (or multishell-was-default-directory "")))
- (multishell-track-dirchange (multishell-unbracket (buffer-name))
- curdir))
- (setq multishell-was-default-directory curdir)))
- ;; To avoid disruption as a pervasive hook function, swallow all errors:
- (error
- (message "multishell-post-command-business error: %s" err))))
-(add-hook 'post-command-hook #'multishell-post-command-business)
-
-(defun multishell-split-entry (entry)
- "Given multishell name/path ENTRY, return the separated name and path pair.
-
-Returns nil for empty parts, rather than the empty string."
- (save-match-data
- (string-match "^\\([^/]*\\)\\(/?.*\\)?" entry)
- (let ((name (match-string 1 entry))
- (path (match-string 2 entry)))
- (and (string= name "") (setq name nil))
- (and (string= path "") (setq path nil))
- (list name path))))
-(defun multishell-bracket (name)
- "Return a copy of name, ensuring it has an asterisk at the beginning and
end."
- (if (not (string= (substring name 0 1) "*"))
- (setq name (concat "*" name)))
- (if (not (string= (substring name -1) "*"))
- (setq name (concat name "*")))
- name)
-(defun multishell-unbracket (name)
- "Return a copy of name, removing asterisks, if any, at beginning and end."
- (if (string= (substring name 0 1) "*")
- (setq name (substring name 1)))
- (if (string= (substring name -1) "*")
- (setq name (substring name 0 -1)))
- name)
-
-(provide 'multishell)
-
-;;; multishell.el ends here
diff --git a/packages/paced/.bzrignore b/packages/paced/.bzrignore
deleted file mode 100644
index fd9ec13..0000000
--- a/packages/paced/.bzrignore
+++ /dev/null
@@ -1,8 +0,0 @@
-*.elc
-*~
-paced-autoloads.el
-Makefile
-.deps
-test-files/paced-dictionary-case-sensitive
-paced.html
-paced.texi
\ No newline at end of file
diff --git a/packages/paced/.elpaignore b/packages/paced/.elpaignore
deleted file mode 100644
index 264b3e6..0000000
--- a/packages/paced/.elpaignore
+++ /dev/null
@@ -1,5 +0,0 @@
-Project.ede
-Makefile
-test.mk
-test-files
-paced-tests.el
\ No newline at end of file
diff --git a/packages/paced/COPYING b/packages/paced/COPYING
deleted file mode 100644
index 94a9ed0..0000000
--- a/packages/paced/COPYING
+++ /dev/null
@@ -1,674 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- 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.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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 <http://www.gnu.org/licenses/>.
-
-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:
-
- <program> Copyright (C) <year> <name of author>
- 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
-<http://www.gnu.org/licenses/>.
-
- 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
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/packages/paced/Project.ede b/packages/paced/Project.ede
deleted file mode 100644
index b4c6ed3..0000000
--- a/packages/paced/Project.ede
+++ /dev/null
@@ -1,48 +0,0 @@
-;; Object ede-proj-project
-
-;; Copyright (C) 2017-2018 Free Software Foundation, Inc.
-
-;; This file is part of GNU Emacs.
-
-;; 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 <http://www.gnu.org/licenses/>.
-
-;; EDE Project Files are auto generated: Do Not Edit
-
-(ede-proj-project "ede-proj-project"
- :file "Project.ede"
- :name "paced"
- :targets
- (list
- (ede-proj-target-elisp "ede-proj-target-elisp"
- :name "compile"
- :path ""
- :source '("paced.el" "paced-async.el")
- :aux-packages '("async" "paced"))
- (ede-proj-target-elisp-autoloads "ede-proj-target-elisp-autoloads"
- :name "autoloads"
- :path ""
- :source '("paced.el" "paced-async.el")
- :autoload-file "paced-autoloads.el")
- (ede-proj-target-makefile-miscelaneous
"ede-proj-target-makefile-miscelaneous"
- :name "check"
- :path ""
- :source '("paced-tests.el" "test.mk" "test-files/first.txt"
"test-files/second.cpp" "test-files/third.org")
- :partofall nil
- :submakefile "test.mk")
- (ede-proj-target-aux "ede-proj-target-aux"
- :name "extra"
- :path ""
- :source '("paced.org")))
- :web-site-url "https://savannah.nongnu.org/projects/paced-el"
- :configuration-variables nil)
diff --git a/packages/paced/dir b/packages/paced/dir
deleted file mode 100644
index 3424e60..0000000
--- a/packages/paced/dir
+++ /dev/null
@@ -1,19 +0,0 @@
-This is the file .../info/dir, which contains the
-topmost node of the Info hierarchy, called (dir)Top.
-The first time you invoke Info you start off looking at this node.
-
-File: dir, Node: Top This is the top of the INFO tree
-
- This (the Directory node) gives a menu of major topics.
- Typing "q" exits, "H" lists all Info commands, "d" returns here,
- "h" gives a primer for first-timers,
- "mEmacs<Return>" visits the Emacs manual, etc.
-
- In Emacs, you can click mouse button 2 on a menu item or cross reference
- to select it.
-
-* Menu:
-
-Emacs
-* Paced: (paced). Predictive Abbreviation Completion and
- Expansion using Dictionaries.
diff --git a/packages/paced/paced-async.el b/packages/paced/paced-async.el
deleted file mode 100644
index a0d5382..0000000
--- a/packages/paced/paced-async.el
+++ /dev/null
@@ -1,111 +0,0 @@
-;;; paced-async.el --- Support for asynchronous population -*-
lexical-binding: t; -*-
-
-;; Copyright (C) 2017-2018 Free Software Foundation, Inc.
-
-;; Author: Ian Dunn <dunni@gnu.org>
-;; Maintainer: Ian Dunn <dunni@gnu.org>
-;; Keywords: convenience, completion
-;; Package-Requires: ((emacs "25.1") (async "1.9.1"))
-;; URL: https://savannah.nongnu.org/projects/paced-el/
-;; Version: 1.1.1
-;; Created: 22 Jan 2017
-;; Modified: 05 Feb 2018
-
-;; This file is part of GNU Emacs.
-
-;; 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, 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 <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Population can be a slow task. The more files from which you want to
-;; populate a dictionary, the longer repopulation is going to take.
-
-;; This extension to paced takes advantage of John Wiegley's async package to
-;; repopulate a dictionary asynchronously.
-
-;;; Code:
-
-(require 'paced)
-(require 'async)
-
-(eval-when-compile (require 'subr-x))
-
-(defcustom paced-async-load-file (locate-user-emacs-file "paced-async.el")
- "File to load with user-specific population settings.
-
-This may contain commands required for running each dictionary's
-population commmands, or load additional files."
- :group 'paced
- :type 'file)
-
-(cl-defmethod paced-dictionary-repopulate-async ((dictionary paced-dictionary))
- "Repopulate DICTIONARY asynchronously.
-
-Note that DICTIONARY isn't modified directly by this process, but
-the updated dictionary is loaded when repopulation completes.
-Therefore, you can continue using it without issue during
-repopulation.
-
-Side note: All dictionaries are reloaded when this function
-finishes, so temporary changes to any dictionaries will be lost
-as a result."
- (let* ((variables '("load-path" ;; Find libraries, including paced
- ;; Settings
- "paced-thing-at-point-constituent"
- "paced-dictionary-directory"
- ;; The load file itself
- "paced-async-load-file"))
- (inject-string (concat "^\\("
- (mapconcat 'identity variables "\\|")
- "\\)$")))
- (message "Repopulating dictionary %s" (paced-dictionary-name dictionary))
- (async-start
- `(lambda ()
- ;; Inject the environment to get `load-path' and user settings
- ,(async-inject-variables inject-string)
- ;; Require paced and load the async settings file
- (require 'paced)
- (load-file paced-async-load-file)
- ;; Repopulate and save the dictionary
- (paced-dictionary-repopulate ,dictionary)
- (paced-dictionary-save ,dictionary))
- (lambda (_result)
- (message "Finished repopulating dictionary")
- (paced-load-all-dictionaries)))))
-
-;;;###autoload
-(defun paced-repopulate-named-dictionary-async (key)
- "Repopulate dictionary named KEY from its population commands,
asynchronously.
-
-Population commands are stored in the field of the same name.
-
-Note that this will empty the dictionary's contents."
- (interactive
- (list (paced-read-dictionary)))
- (paced-operate-on-named-dictionary key
- (paced-dictionary-repopulate-async dict)))
-
-;;;###autoload
-(defun paced-repopulate-current-dictionary-async ()
- "Repopulate current dictionary from its population commands, asynchronously.
-
-Population commands are stored in the field of the same name.
-
-Note that this will empty the dictionary's contents."
- (interactive)
- (paced-operate-on-current-dictionary
- (paced-dictionary-repopulate-async dict)))
-
-(provide 'paced-async)
-
-;;; paced-async.el ends here
diff --git a/packages/paced/paced-tests.el b/packages/paced/paced-tests.el
deleted file mode 100644
index 3f8d0ea..0000000
--- a/packages/paced/paced-tests.el
+++ /dev/null
@@ -1,507 +0,0 @@
-;;; paced-tests.el --- Tests for paced -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2017-2018 Free Software Foundation, Inc.
-
-;; Author: Ian Dunn <dunni@gnu.org>
-;; Maintainer: Ian Dunn <dunni@gnu.org>
-;; Keywords: convenience, completion
-;; Package-Requires: ((emacs "25.1") (async "1.9.1"))
-;; URL: https://savannah.nongnu.org/projects/paced-el/
-;; Version: 1.1
-;; Created: 22 Jan 2017
-;; Modified: 04 Feb 2018
-
-;; This file is part of GNU Emacs.
-
-;; 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, 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 <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'paced)
-(require 'ert)
-
-(defconst paced-test-dir
- (expand-file-name "test-files" (file-name-directory (or load-file-name
buffer-file-name))))
-
-(defsubst paced-test-file (base-name)
- (expand-file-name base-name paced-test-dir))
-
-(defconst paced-first-test-file (paced-test-file "first.txt"))
-(defconst paced-second-test-file (paced-test-file "second.cpp"))
-(defconst paced-third-test-file (paced-test-file "third.org"))
-(defconst paced-fourth-test-file (paced-test-file "fourth.org"))
-
-(defconst paced-test-dict-save-file (paced-test-file
"paced-dictionary-case-sensitive"))
-(defconst paced-test-default-registered-map (make-hash-table :test 'equal))
-
-(ert-deftest paced-handle-word-case ()
- (let* ((word "EiEiO"))
- (should (string-equal (paced--handle-word-case 'preserve word) "EiEiO"))
- (should (string-equal (paced--handle-word-case 'downcase word) "eieio"))
- (should (string-equal (paced--handle-word-case 'upcase word) "EIEIO"))
- (should (string-equal (paced--handle-word-case 'downcase-first word)
"eiEiO"))
- (should (string-equal (paced--handle-word-case 'upcase-first word)
"EiEiO"))
- (should (string-equal (paced--handle-word-case 'mixed-case word)
"EiEiO"))))
-
-(ert-deftest paced-mixed-case-word ()
- (should-not (paced-mixed-case-word-p "HAS"))
- (should (paced-mixed-case-word-p "HAs"))
- (should (paced-mixed-case-word-p "HaS"))
- (should-not (paced-mixed-case-word-p "Has"))
- (should (paced-mixed-case-word-p "hAS"))
- (should (paced-mixed-case-word-p "hAs"))
- (should (paced-mixed-case-word-p "haS"))
- (should-not (paced-mixed-case-word-p "has")))
-
-(ert-deftest paced-create-dictionary ()
- ;; Delete the old save file
- (when (file-exists-p paced-test-dict-save-file)
- (delete-file paced-test-dict-save-file))
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (new-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (= (map-length paced--registered-dictionaries) 1))
- (should (paced-dictionary-p new-dict))
- (oset new-dict updated t) ;; Mark it as updated so it saves
- (paced-dictionary-save new-dict)
- (should (file-exists-p paced-test-dict-save-file)))
- (let* ((paced--registered-dictionaries paced-test-default-registered-map))
- ;; Now verify that we can load it again
- (paced-load-dictionary-from-file paced-test-dict-save-file)
- (should (= (map-length paced--registered-dictionaries) 1))
- (should (map-contains-key paced--registered-dictionaries "test-dict-case"))
- (should (paced-dictionary-p (paced-named-dictionary "test-dict-case")))))
-
-(defvar paced-test-enable-symbol nil)
-
-(ert-deftest paced-enable-list-symbol ()
- "Test case for `paced-dictionary-enable-alist' being an arbitrary symbol."
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((paced-test-enable-symbol .
"test-dict-case")))
- (new-buffer (find-file-noselect paced-first-test-file)))
- (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)
- (with-current-buffer new-buffer
- (setq paced-test-enable-symbol nil)
- (should-not (paced-current-dictionary))
- (setq-local paced-test-enable-symbol t)
- (should (paced-dictionary-p (paced-current-dictionary)))
- (should (string-equal (paced-dictionary-name (paced-current-dictionary))
"test-dict-case")))
- (kill-buffer new-buffer)))
-
-(ert-deftest paced-enable-list-mode ()
- "Test case for `paced-dictionary-enable-alist' being a mode symbol."
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((text-mode .
"test-dict-case")))
- (buffer-one (find-file-noselect paced-first-test-file))
- (buffer-two (find-file-noselect paced-second-test-file)))
- (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)
- (with-current-buffer buffer-two
- (should-not (paced-current-dictionary)))
- (kill-buffer buffer-two)
- (with-current-buffer buffer-one
- (should (paced-dictionary-p (paced-current-dictionary)))
- (should (string-equal (paced-dictionary-name (paced-current-dictionary))
"test-dict-case")))
- (kill-buffer buffer-one)))
-
-(defun paced-test-function-symbol ()
- paced-test-enable-symbol)
-
-(ert-deftest paced-enable-list-function-symbol ()
- "Test case for `paced-dictionary-enable-alist' being a function symbol."
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((paced-test-function-symbol .
"test-dict-case")))
- (buffer-one (find-file-noselect paced-first-test-file)))
- (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)
- (with-current-buffer buffer-one
- (setq-local paced-test-enable-symbol nil)
- (should-not (paced-current-dictionary))
- (setq-local paced-test-enable-symbol t)
- (should (paced-dictionary-p (paced-current-dictionary)))
- (should (string-equal (paced-dictionary-name (paced-current-dictionary))
"test-dict-case")))
- (kill-buffer buffer-one)))
-
-(ert-deftest paced-enable-list-lambda-function ()
- "Test case for `paced-dictionary-enable-alist' being a lambda form."
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '(((lambda nil
paced-test-enable-symbol) . "test-dict-case")))
- (buffer-one (find-file-noselect paced-first-test-file)))
- (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)
- (with-current-buffer buffer-one
- (setq-local paced-test-enable-symbol nil)
- (should-not (paced-current-dictionary))
- (setq-local paced-test-enable-symbol t)
- (should (paced-dictionary-p (paced-current-dictionary)))
- (should (string-equal (paced-dictionary-name (paced-current-dictionary))
"test-dict-case")))
- (kill-buffer buffer-one)))
-
-(ert-deftest paced-enable-list-and-form ()
- "Test case for `paced-dictionary-enable-alist' being an 'and' form."
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '(((and text-mode
paced-test-enable-symbol) . "test-dict-case")))
- (buffer-one (find-file-noselect paced-first-test-file))
- (buffer-two (find-file-noselect paced-second-test-file)))
- (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)
- (with-current-buffer buffer-two
- (setq-local paced-test-enable-symbol nil)
- (should-not (paced-current-dictionary))
- (setq-local paced-test-enable-symbol t)
- (should-not (paced-current-dictionary)))
- (kill-buffer buffer-two)
- (with-current-buffer buffer-one
- (setq-local paced-test-enable-symbol nil)
- (should-not (paced-current-dictionary))
- (setq-local paced-test-enable-symbol t)
- (should (paced-dictionary-p (paced-current-dictionary)))
- (should (string-equal (paced-dictionary-name (paced-current-dictionary))
"test-dict-case")))
- (kill-buffer buffer-one)))
-
-(ert-deftest paced-enable-list-or-form ()
- "Test case for `paced-dictionary-enable-alist' being an 'or' form."
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '(((or text-mode
paced-test-enable-symbol) . "test-dict-case")))
- (buffer-one (find-file-noselect paced-first-test-file))
- (buffer-two (find-file-noselect paced-second-test-file)))
- (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)
- (with-current-buffer buffer-two
- (setq-local paced-test-enable-symbol nil)
- (should-not (paced-current-dictionary))
- (setq-local paced-test-enable-symbol t)
- (should (paced-dictionary-p (paced-current-dictionary)))
- (should (string-equal (paced-dictionary-name (paced-current-dictionary))
"test-dict-case")))
- (kill-buffer buffer-two)
- (with-current-buffer buffer-one
- (setq-local paced-test-enable-symbol nil)
- (should (paced-dictionary-p (paced-current-dictionary)))
- (should (string-equal (paced-dictionary-name (paced-current-dictionary))
"test-dict-case"))
- (setq-local paced-test-enable-symbol t)
- (should (paced-dictionary-p (paced-current-dictionary)))
- (should (string-equal (paced-dictionary-name (paced-current-dictionary))
"test-dict-case")))
- (kill-buffer buffer-one)))
-
-(ert-deftest paced-populate-file ()
- "Test case for single file populator."
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((text-mode .
"test-dict-case")))
- (cmd (paced-file-population-command :file paced-first-test-file))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd))
- (paced-dictionary-repopulate test-dict)
- (let ((usage-hash (oref test-dict usage-hash)))
- (should (eq (map-length usage-hash) 4))
- (should (seq-set-equal-p (map-keys usage-hash) '("one" "two" "three"
"four")))
- (should (eq (map-elt usage-hash "one") 1))
- (should (eq (map-elt usage-hash "two") 2))
- (should (eq (map-elt usage-hash "three") 3))
- (should (eq (map-elt usage-hash "four") 4)))))
-
-(ert-deftest paced-populate-buffer ()
- "Test case for single buffer populator."
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((text-mode .
"test-dict-case")))
- (buffer "first.txt")
- (buffer-one (find-file-noselect paced-first-test-file))
- (cmd (paced-buffer-population-command :buffer buffer))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd))
- (paced-dictionary-repopulate test-dict)
- (let ((usage-hash (oref test-dict usage-hash)))
- (should (eq (map-length usage-hash) 4))
- (should (seq-set-equal-p (map-keys usage-hash) '("one" "two" "three"
"four")))
- (should (eq (map-elt usage-hash "one") 1))
- (should (eq (map-elt usage-hash "two") 2))
- (should (eq (map-elt usage-hash "three") 3))
- (should (eq (map-elt usage-hash "four") 4)))
- (kill-buffer buffer-one)))
-
-(ert-deftest paced-populate-file-function ()
- "Test case for file-function populator."
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((text-mode .
"test-dict-case")))
- (pre-func (lambda () (insert (buffer-string)) t))
- (cmd (paced-file-function-population-command :file
paced-first-test-file
- :setup-func pre-func))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd))
- (paced-dictionary-repopulate test-dict)
- (let ((usage-hash (oref test-dict usage-hash)))
- (should (eq (map-length usage-hash) 4))
- (should (seq-set-equal-p (map-keys usage-hash) '("one" "two" "three"
"four")))
- (should (eq (map-elt usage-hash "one") 2))
- (should (eq (map-elt usage-hash "two") 4))
- (should (eq (map-elt usage-hash "three") 6))
- (should (eq (map-elt usage-hash "four") 8)))))
-
-(ert-deftest paced-populate-directory-regexp ()
- "Test case for directory-regexp populator."
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((text-mode .
"test-dict-case")))
- (cmd (paced-directory-regexp-population-command :directory
paced-test-dir
- :regexp ".*\\.txt"
- :recursive t))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd))
- (paced-dictionary-repopulate test-dict)
- (let ((usage-hash (oref test-dict usage-hash)))
- (should (eq (map-length usage-hash) 4))
- (should (seq-set-equal-p (map-keys usage-hash) '("one" "two" "three"
"four")))
- (should (eq (map-elt usage-hash "one") 1))
- (should (eq (map-elt usage-hash "two") 2))
- (should (eq (map-elt usage-hash "three") 3))
- (should (eq (map-elt usage-hash "four") 4)))))
-
-(ert-deftest paced-populate-file-list ()
- "Test case for file-list populator."
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((text-mode .
"test-dict-case")))
- (file-list (lambda () `(,paced-first-test-file)))
- (cmd (paced-file-list-population-command :generator file-list))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd))
- (paced-dictionary-repopulate test-dict)
- (let ((usage-hash (oref test-dict usage-hash)))
- (should (eq (map-length usage-hash) 4))
- (should (seq-set-equal-p (map-keys usage-hash) '("one" "two" "three"
"four")))
- (should (eq (map-elt usage-hash "one") 1))
- (should (eq (map-elt usage-hash "two") 2))
- (should (eq (map-elt usage-hash "three") 3))
- (should (eq (map-elt usage-hash "four") 4)))))
-
-(ert-deftest paced-multiple-population-commands ()
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((text-mode .
"test-dict-case")))
- (cmd1 (paced-file-population-command :file paced-first-test-file))
- (cmd2 (paced-file-population-command :file paced-third-test-file))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd1 cmd2))
- (paced-dictionary-repopulate test-dict)
- (let ((usage-hash (oref test-dict usage-hash)))
- (should (eq (map-length usage-hash) 7))
- (should (seq-set-equal-p (map-keys usage-hash) '("one" "two" "three"
"four" "five" "six" "seven")))
- (should (eq (map-elt usage-hash "one") 1))
- (should (eq (map-elt usage-hash "two") 2))
- (should (eq (map-elt usage-hash "three") 3))
- (should (eq (map-elt usage-hash "four") 4))
- (should (eq (map-elt usage-hash "five") 5))
- (should (eq (map-elt usage-hash "six") 3))
- (should (eq (map-elt usage-hash "seven") 1)))))
-
-(ert-deftest paced-populator-settings ()
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((text-mode .
"test-dict-case")))
- (exclude-command (lambda nil (nth 8 (syntax-ppss)))) ;; exclude
comments
- (cmd1 (paced-file-population-command :file paced-first-test-file))
- (cmd2 (paced-file-population-command :file paced-second-test-file
- :props `((paced-exclude-function
quote ,exclude-command))))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd1 cmd2))
- (paced-dictionary-repopulate test-dict)
- (let ((usage-hash (oref test-dict usage-hash)))
- (should (eq (map-length usage-hash) 4))
- (should (seq-set-equal-p (map-keys usage-hash) '("one" "two" "three"
"four")))
- (should (eq (map-elt usage-hash "one") 1))
- (should (eq (map-elt usage-hash "two") 2))
- (should (eq (map-elt usage-hash "three") 3))
- (should (eq (map-elt usage-hash "four") 4)))))
-
-(ert-deftest paced-populate-sort-order ()
- "Test case for sorting after population."
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((text-mode .
"test-dict-case")))
- (cmd (paced-file-population-command :file paced-first-test-file))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd))
- (paced-dictionary-repopulate test-dict)
- (let ((usage-hash (oref test-dict usage-hash)))
- (should (eq (map-length usage-hash) 4))
- (should (equal (map-keys usage-hash) '("four" "three" "two" "one")))
- (should (eq (map-elt usage-hash "one") 1))
- (should (eq (map-elt usage-hash "two") 2))
- (should (eq (map-elt usage-hash "three") 3))
- (should (eq (map-elt usage-hash "four") 4)))))
-
-(ert-deftest paced-populate-non-existent-file ()
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (file "first.txt")
- (cmd (paced-file-population-command :file file))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd))
- (paced-dictionary-repopulate test-dict)
- (let ((usage-hash (oref test-dict usage-hash)))
- (should (map-empty-p usage-hash)))))
-
-(ert-deftest paced-populate-non-existent-buffer ()
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (buffer "first.txt")
- (cmd (paced-buffer-population-command :buffer buffer))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd))
- (paced-dictionary-repopulate test-dict)
- (let ((usage-hash (oref test-dict usage-hash)))
- (should (map-empty-p usage-hash)))))
-
-(ert-deftest paced-completions-try-completion ()
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((text-mode .
"test-dict-case")))
- (cmd (paced-file-population-command :file paced-first-test-file))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd))
- (paced-dictionary-repopulate test-dict)
- (let ((completions (paced-dictionary-completions test-dict "o" nil)))
- (should (equal completions '("o"))))))
-
-(ert-deftest paced-completions-try-completion-mixed-case ()
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((text-mode .
"test-dict-case")))
- (cmd (paced-file-population-command :file paced-first-test-file))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'mixed-case)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd))
- (paced-dictionary-repopulate test-dict)
- (let ((completions (paced-dictionary-completions test-dict "o" nil)))
- (should (equal completions '("o"))))))
-
-(ert-deftest paced-completions-all-completions ()
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((text-mode .
"test-dict-case")))
- (cmd (paced-file-population-command :file paced-first-test-file))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd))
- (paced-dictionary-repopulate test-dict)
- (should (equal (paced-dictionary-completions test-dict "o" t)
- '("one")))
- (should (equal (paced-dictionary-completions test-dict "on" t)
- '("one")))
- (should (equal (paced-dictionary-completions test-dict "t" t)
- '("three" "two")))
- (should (equal (paced-dictionary-completions test-dict "v" t)
- nil))))
-
-(ert-deftest paced-completions-test-completion ()
- (let* ((paced--registered-dictionaries paced-test-default-registered-map)
- (paced-global-dictionary-enable-alist '((text-mode .
"test-dict-case")))
- (cmd (paced-file-population-command :file paced-first-test-file))
- (test-dict (paced-make-dictionary "test-dict-case"
- paced-test-dict-save-file
- 'downcase)))
- (should (paced-dictionary-p test-dict))
- (oset test-dict population-commands (list cmd))
- (paced-dictionary-repopulate test-dict)
- (should (paced-dictionary-completions test-dict "one" 'lambda))
- (should-not (paced-dictionary-completions test-dict "o" 'lambda))))
-
-(ert-deftest paced-merge-properties ()
- (let* ((prop-list-1 '((a . "abc") (b . "xyz")))
- (prop-list-2 '((a . "def") (c . "ghi")))
- (prop-list-3 nil)
- (merged-1 (paced-merge-properties prop-list-1 prop-list-2))
- (merged-2 (paced-merge-properties prop-list-3 prop-list-2)))
- (should (equal (map-elt merged-1 'a) '("def")))
- (should (equal (map-elt merged-1 'b) '("xyz")))
- (should (equal (map-elt merged-1 'c) '("ghi")))
- (should (equal (map-elt merged-2 'a) '("def")))
- (should (equal (map-elt merged-2 'c) '("ghi")))))
-
-(ert-deftest paced-beginning-end-of-thing-at-point ()
- "Test exclusion and `paced-point-in-thing-at-point-for-exclusion'."
- (let* ((paced-exclude-function (lambda () (looking-at-p "one")))
- (buffer-one (find-file-noselect paced-first-test-file)))
- (with-current-buffer buffer-one
- (goto-char (point-min))
- (should (equal (paced-thing-at-point) "one"))
- (let ((paced-point-in-thing-at-point-for-exclusion 'beginning))
- (should (paced-excluded-p)))
- (paced-forward-thing)
- (should (equal (paced-thing-at-point) "one"))
- (let ((paced-point-in-thing-at-point-for-exclusion 'end))
- (should-not (paced-excluded-p))))))
-
-(ert-deftest paced-character-limit ()
- "Test character limit."
- (let* ((paced-exclude-function (lambda () nil))
- (buffer-one (find-file-noselect paced-first-test-file)))
- (with-current-buffer buffer-one
- (goto-char (point-min))
- (should (equal (paced-thing-at-point) "one"))
- (let* ((paced-character-limit 0))
- (should-not (paced-excluded-p)))
- (let* ((paced-character-limit 1))
- (should (paced-excluded-p)))
- (let* ((paced-character-limit 3))
- (should-not (paced-excluded-p))))))
-
-(ert-deftest paced-no-thing-at-point ()
- "Test for non-existent thing at point."
- (let* ((org-element-use-cache nil) ;; Causes crashes, so disable it
- (paced-exclude-function (lambda () nil))
- (buffer-four (find-file-noselect paced-fourth-test-file)))
- (with-current-buffer buffer-four
- (goto-char (point-min))
- (should-not (paced-thing-at-point))
- (should (paced-excluded-p)))))
-
-(provide 'paced-tests)
-
-;;; paced-tests.el ends here
diff --git a/packages/paced/paced.el b/packages/paced/paced.el
deleted file mode 100644
index 53b7870..0000000
--- a/packages/paced/paced.el
+++ /dev/null
@@ -1,1356 +0,0 @@
-;;; paced.el --- Predictive Abbreviation Completion and Expansion using
Dictionaries -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2017-2018 Free Software Foundation, Inc.
-
-;; Author: Ian Dunn <dunni@gnu.org>
-;; Maintainer: Ian Dunn <dunni@gnu.org>
-;; Keywords: convenience, completion
-;; Package-Requires: ((emacs "25.1") (async "1.9.1"))
-;; URL: https://savannah.nongnu.org/projects/paced-el/
-;; Version: 1.1.3
-;; Created: 22 Jan 2017
-;; Modified: 05 Feb 2018
-
-;; This file is part of GNU Emacs.
-
-;; 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, 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 <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Paced (Predictive Abbreviation Completion and Expansion using Dictionaries)
-;; scans a group of files (determined by "population commands") to construct a
-;; usage table (dictionary). Words (or symbols) are sorted by their usage, and
-;; may be later presented to the user for completion. A dictionary can then be
-;; saved to a file, to be loaded later.
-
-;; Population commands determine how a dictionary should be filled with words
or
-;; symbols. A dictionary may have multiple population commands, and population
-;; may be performed asynchronously. Once population is finished, the contents
-;; are sorted, with more commonly used words at the front. Dictionaries may be
-;; edited through EIEIO's customize-object interface.
-
-;; Completion is done through `completion-at-point'. The dictionary to use for
-;; completion can be customized.
-
-;;; Code:
-
-(eval-when-compile (require 'subr-x))
-
-(require 'thingatpt)
-(require 'map)
-(require 'eieio-base)
-(require 'rx)
-
-;; Compatibility for Emacs < 26.1
-(unless (fboundp 'if-let*)
- (defalias 'if-let* 'if-let))
-(unless (fboundp 'when-let*)
- (defalias 'when-let* 'when-let))
-
-(defgroup paced nil
- "Predictive Abbreviation Completion and Expansion using Dictionaries"
- :group 'convenience)
-
-(defcustom paced-thing-at-point-constituent 'symbol
- "Symbol defining THING which function `paced-mode' works on.
-This symbol should be understandable by
-`bounds-of-thing-at-point'. This symbol defines what function `paced-mode'
-considers to be the basic unit of expansion. If if it set to `symbol',
-for example, \"paced-mode\" would be offered as an expansion, while
-if it is set to `word' \"paced\" and \"mode\" would be offered."
- :group 'paced
- :type 'symbol
- :options '(symbol word))
-
-(defcustom paced-completion-ignore-case t
- "Non-nil to ignore case when completing.
-
-Note that this does not affect dictionary population."
- :group 'paced
- :type 'boolean)
-
-(defcustom paced-dictionary-directory (locate-user-emacs-file
"paced-dictionaries/")
- "Directory in which the dictionaries are saved.
-
-This is only used in `paced-load-all-dictionaries', so it's up to
-the user whether to save dictionaries here."
- :group 'paced
- :type 'directory)
-
-(defcustom paced-dictionary-directory-whitelist-regexp (rx (zero-or-more
anything))
- "Regexp to match when reading from the dictionary directory.
-
-Any files that match this regexp will be loaded by
-`paced-load-all-dictionaries'."
- :group 'paced
- :type 'regexp)
-
-(defcustom paced-dictionary-directory-blacklist-regexp (rx string-end
string-start)
- "Regexp to match for files NOT to load with `paced-load-all-dictionaries'.
-
-This regexp by default matches nothing, thus allowing all files."
- :group 'paced
- :type 'regexp)
-
-(defcustom paced-load-all-dictionaries-recursively nil
- "Whether to recursively load all files with `paced-load-all-dictionaries'."
- :group 'paced
- :type 'boolean)
-
-(defcustom paced-repopulate-saves-dictionary t
- "Whether to save a dictionary after repopulation."
- :group 'paced
- :type 'boolean)
-
-(defcustom paced-populate-warn-about-reset t
- "Whether to warn the user about resetting a dictionary when repopulating."
- :group 'paced
- :type 'boolean)
-
-(defcustom paced-point-in-thing-at-point-for-exclusion 'beginning
- "Symbol to indicate from where exclusion should occur.
-
-If 'beginning, exclusion is checked at the beginning of the thing
-at point. If 'end, exclusion is checked at the end of the thing
-at point.
-
-See `paced-excluded-p' and `paced-exclude-function' for more
-information on exclusion."
- :group 'paced
- :type 'symbol
- :options '(beginning end))
-
-(defcustom paced-character-limit 0
- "Character limit for including things in paced.
-
-If set to 0, impose no limit. Otherwise, include words whose
-length is less than or equal to the value."
- :group 'paced
- :type 'number)
-
-
-
-(defun paced--default-dictionary-sort-func (usage-hash)
- "Default dictionary sort function.
-
-Sort hash-table USAGE-HASH by the weights (values) in the table."
- ;; Unfortunately, there's no way to sort a hash-table, so we first convert it
- ;; into an alist, and sort that.
- (let ((seq (map-into usage-hash 'list)))
- (setq seq
- (seq-sort
- (pcase-lambda (`(_ . ,usage-lhs)
- `(_ . ,usage-rhs))
- (> usage-lhs usage-rhs))
- seq))
- (map-into seq 'hash-table)))
-
-(defclass paced-dictionary (eieio-named eieio-persistent)
- ((object-name :initarg :object-name
- :documentation "Symbol to use to refer to this dictionary.")
- (usage-hash :initarg :usage-hash
- :initform (make-hash-table :test #'equal)
- :type hash-table
- :documentation "Stores the usage data for this dictionary.
-
-This is a hash table, mapping a word to the times it has been used.")
- (population-commands
- :initarg :population-commands
- :initform nil
- :type (list-of paced-population-command)
- :custom (repeat (object :objectcreatefcn
paced-new-population-command-custom))
- :label "Population Commands"
- :documentation "Commands to use when populating this dictionary.
-
-Each entry is a `paced-population-command'.")
- (file-header-line :type string
- :allocation :class
- :initform ";; Paced Dictionary"
- :documentation
- "Header line for the save file.
-This is used with the `object-write' method.")
- (case-handling :initarg :case-handling
- :initform downcase
- :type (member downcase upcase preserve downcase-first
upcase-first mixed-case)
- :custom (choice (const :tag "Downcase All Words" downcase)
- (const :tag "Upcase All Words" upcase)
- (const :tag "Preserve Case" preserve)
- (const :tag "Downcase Just the First Letter"
downcase-first)
- (const :tag "Upcase Just the First Letter"
upcase-first)
- (const :tag "Preserve Case on Mixed-Case
Words" mixed-case))
- :label "Case Handling"
- :documentation "How case should be handled during population.
-
-It can be one of the following:
-
-* downcase Downcase every word
-* upcase Upcase every word
-* preserve Preserve case
-* downcase-first Downcase the first letter of each word, leave the rest the
same
-* upcase-first Upcase the first letter of each word, leave the rest the same
-* mixed-case Preserve case on mixed-case words; single-case words
- are downcased. See `paced-mixed-case-word-p' for an
- explanation of how \"mixed-case\" is defined.")
- (updated :initarg :updated
- :initform nil
- :type boolean
- :documentation "Non-nil if this dictionary has been updated since
it was last saved.")
- (default-population-properties
- :initarg :default-population-properties
- :initform nil
- :type list
- :label "Default Properties"
- :custom (alist :tag "Properties" :key-type variable :value-type sexp)
- :documentation "Default properties for population commands.
-
-Each element is of the form (VAR VALUE). Each VAR will be set to
-VALUE during population for this dictionary.
-
-Properties set in the individual population commands will
-override settings here.
-
-Some suggested variables for this are `paced-exclude-function'
-and `paced-thing-at-point-constituent'.")
- (sort-method :initarg :sort-method
- :initform 'paced--default-dictionary-sort-func
- :type function
- :label "Sort Method"
- :custom function
- :documentation "Method by which this dictionary should sort
its usage table.
-
-This should be a function of one argument, the usage-hash slot,
-and return a sorted hash-table.
-
-This defaults to `paced--default-dictionary-sort-func'."))
- "Paced dictionary.")
-
-(defvar paced--registered-dictionaries (make-hash-table :test 'equal)
- "Internal list of registered dictionaries.
-
-Do not edit this list manually. Use `paced-make-dictionary'
-instead.")
-
-(defun paced-reset-registered-dictionaries ()
- "Reset the registered dictionary list.
-
-WARNING: This will result in the loss of all dictionaries. Only
-do this if you know what you're doing, or are under the
-supervision of someone who does."
- (interactive)
- (when (yes-or-no-p
- "Warning: This will result in loss of all dictionaries. Continue?")
- (setq paced--registered-dictionaries (make-hash-table :test 'equal))))
-
-(defsubst paced-named-dictionary (key)
- "Return a registered dictionary with name KEY.
-
-If none exists, return nil."
- (map-elt paced--registered-dictionaries key nil))
-
-(defsubst paced-dictionary-names ()
- "Get the names of the registered dictionaries."
- (map-keys paced--registered-dictionaries))
-
-(defsubst paced-read-dictionary ()
- "Read the name of a registered dictionary."
- (completing-read "Dictionary: " (map-keys paced--registered-dictionaries)))
-
-(defsubst paced-dictionary-key-registered-p (key)
- "Return non-nil if a dictionary with name KEY has been registered."
- (map-contains-key paced--registered-dictionaries key))
-
-(defvar paced-throw-error-on-no-registered t
- "Whether to throw an error when a named dictionary can't be found.")
-
-(defmacro paced-operate-on-named-dictionary (name &rest form)
- "Run FORM on the dictionary with name NAME, bound to `dict'.
-
-If no dictionary named NAME exists, throw an error."
- (declare (indent 1))
- `(if-let* ((dict (paced-named-dictionary ,name)))
- (progn ,@form)
- (when paced-throw-error-on-no-registered
- (error "No paced dictionary called '%s' has been registered" ,name))))
-
-(cl-defmethod paced-dictionary-register ((dict paced-dictionary))
- "Registered dictionary DICT."
- (map-put paced--registered-dictionaries (oref dict object-name) dict))
-
-(defsubst paced--ensure-dictionary-directory ()
- "Ensure that `paced-dictionary-directory' exists."
- (make-directory paced-dictionary-directory t))
-
-(defun paced-make-dictionary (name filename case-handling)
- "Make a paced dictionary called NAME.
-
-NAME is a string used to identify the new dictionary.
-
-If a paced dictionary is already registered with name NAME, then
-it is replaced with a new, empty one.
-
-FILENAME is a file in which to store the new dictionary.
-
-CASE-HANDLING is a symbol that denotes how to handle case during
-population. See the case-handling slot of class
-`paced-dictionary' for details.
-
-Return value is the new dictionary."
- (let ((new-dict (paced-dictionary
- :object-name name
- :file filename
- :case-handling case-handling)))
- (paced-dictionary-register new-dict)
- new-dict))
-
-(defun paced-create-new-dictionary (name file)
- "Create a new dictionary called NAME.
-
-FILE is the file in which to store the new dictionary.
-
-Once named, the dictionary can be edited through the EIEIO
-customization interface."
- (declare (interactive-only paced-make-dictionary))
- (interactive (list (read-string "Name: ")
- (read-file-name "Storage File: "
paced-dictionary-directory)))
- (let ((new-dict (paced-dictionary :object-name name
- :file file)))
- (customize-object new-dict)))
-
-(cl-defmethod paced-dictionary-name ((obj paced-dictionary))
- "Return the name of dictionary OBJ."
- (oref obj object-name))
-
-(cl-defmethod paced-dictionary-empty-p ((dict paced-dictionary))
- "Return non-nil if DICT is empty."
- (map-empty-p (oref dict usage-hash)))
-
-;;; Current Dictionary
-
-(defcustom paced-global-dictionary-enable-alist nil
- "List that determines which dictionaries should be active.
-
-Each entry has the form (CONDITION . DICT-KEY), where CONDITION
-is one of the following forms:
-
-- A mode name, such as `org-mode' or `text-mode', indicating that
- the named dictionary should be active in any mode derived from
- that mode.
-
-- A symbol, in which case the named dictionary is active whenever
- the value of that symbol is non-nil.
-
-- A function symbol, in which case the function is called with no
- arguments to determine if the given dictionary should be
- enabled. If the function returns non-nil the dictionary is enabled.
-
-- A lambda function, in which case it is called with no
- arguments, and if it returns non-nil, the dictionary is
- enabled.
-
-- The form (or CONDITION1 CONDITION2 ...), which enables the
- given dictionary if any of the conditions are met.
-
-- The form (and CONDITION1 CONDITION2 ...), which enables the
- given dictionary if all of the conditions are met.
-
-No matter what this list indicates, dictionaries will not be
-enabled unless `paced-mode' is active."
- :group 'paced
- :type '(alist :key-type sexp :value-type string))
-
-(define-obsolete-variable-alias 'paced-global-dict-enable-alist
- 'paced-global-dictionary-enable-alist
- "1.1")
-
-(defvar-local paced-local-dictionary-enable-alist nil
- "Local enable list.
-
-Has the same form as and takes priority over
-`paced-global-dictionary-enable-alist'.")
-
-(define-obsolete-variable-alias 'paced-local-dict-enable-alist
- 'paced-local-dictionary-enable-alist
- "1.1")
-
-(defun paced-dictionary-enable-list ()
- "Return the combination of the local and global enable-alists.
-
-See `paced-local-dictionary-enable-alist' and
-`paced-global-dictionary-enable-alist' for more information."
- (append paced-local-dictionary-enable-alist
- paced-global-dictionary-enable-alist))
-
-(define-obsolete-function-alias 'paced-dict-enable-list
- 'paced-dictionary-enable-list
- "1.1")
-
-(defun paced-mode-symbol-p (sym)
- "Return non-nil if SYM is a mode symbol."
- (string-match-p (rx "-mode" string-end) (symbol-name sym)))
-
-(defun paced-test-dictionary-enable-condition (condition)
- "Determines if CONDITION passes in the current buffer.
-
-See `paced-global-dictionary-enable-alist' for an explanation."
- (pcase condition
- ((and (pred symbolp)
- (pred paced-mode-symbol-p))
- (derived-mode-p condition))
- ((and (pred symbolp)
- (pred boundp))
- (symbol-value condition))
- ((and (pred symbolp)
- (pred fboundp))
- (funcall condition))
- ((pred functionp)
- (funcall condition))
- (`(or . ,rest)
- (seq-some 'paced-test-dictionary-enable-condition rest))
- (`(and . ,rest)
- (seq-every-p 'paced-test-dictionary-enable-condition rest))))
-
-(defun paced-current-dictionary ()
- "Determine the current dictionary.
-
-Returns nil if no dictionary should be enabled.
-
-If a dictionary is found in the list that doesn't exist, it will
-be skipped.
-
-See `paced-global-dictionary-enable-alist' or
-`paced-local-dictionary-enable-alist' for how to set the current
-dictionary conditions."
- (let ((conditions (paced-dictionary-enable-list))
- (dictionary))
- (while (and conditions
- (not dictionary))
- (pcase-let* ((`(,condition . ,dict) (pop conditions)))
- (when (and (paced-dictionary-key-registered-p dict)
- (paced-test-dictionary-enable-condition condition))
- (setq dictionary dict))))
- (when dictionary
- (paced-named-dictionary dictionary))))
-
-(defvar paced-throw-error-on-no-current nil
- "Whether to throw an error when no current dictionary can be found.")
-
-(defmacro paced-operate-on-current-dictionary (&rest form)
- "Run FORM with the current dictionary bound to `dict'.
-
-If no dictionary can be found for the buffer, throw an error. To
-suppress the error, set `paced-throw-error-on-no-current' to
-nil."
- `(if-let* ((dict (paced-current-dictionary)))
- (progn ,@form)
- (when paced-throw-error-on-no-current
- (user-error "No dictionary found for current buffer"))))
-
-;;; Saving and Loading
-
-(cl-defmethod paced-dictionary-save ((dict paced-dictionary) &optional force)
- "Save dictionary DICT according to its filename.
-
-If FORCE is non-nil, ignore the `updated' flag in DICT and save
-it anyway."
- (when (or force (oref dict updated))
- (eieio-persistent-save dict))
- (oset dict updated nil))
-
-(defun paced-save-named-dictionary (key force)
- "Save dictionary named KEY.
-
-If FORCE is non-nil (given with a prefix arg), forcibly save the
-dictionary if found."
- (declare (interactive-only paced-dictionary-save))
- (interactive (list (paced-read-dictionary) current-prefix-arg))
- (paced-operate-on-named-dictionary key
- (paced-dictionary-save dict force)))
-
-(defun paced-save-current-dictionary (force)
- "Save the dictionary for the current buffer.
-
-For how the current dictionary is determined, see
-`paced-current-dictionary'.
-
-With prefix argument FORCE, save the dictionary even if it hasn't
-been modified."
- (interactive "P")
- (paced-operate-on-current-dictionary
- (paced-dictionary-save dict force)))
-
-(defun paced-load-dictionary-from-file (file)
- "Load dictionary from FILE."
- (interactive
- (list (read-file-name "Dictionary File: " paced-dictionary-directory)))
- (when-let* ((new-dict (eieio-persistent-read file 'paced-dictionary)))
- (paced-dictionary-register new-dict)))
-
-(defun paced-save-all-dictionaries (&optional force)
- "Save all registered dictionaries.
-
-With prefix argument FORCE, save the dictionaries regardless of
-whether they've been modified."
- (interactive "P")
- (map-apply
- (lambda (_ dict)
- (paced-dictionary-save dict force))
- paced--registered-dictionaries))
-
-;;;###autoload
-(defun paced-load-all-dictionaries ()
- "Load all dictionaries in `paced-dictionary-directory'."
- (interactive)
- (message "Loading all dictionaries from %s" paced-dictionary-directory)
- (paced--ensure-dictionary-directory)
- (let ((files-to-load
- (if paced-load-all-dictionaries-recursively
- (directory-files-recursively paced-dictionary-directory
-
paced-dictionary-directory-whitelist-regexp)
- (directory-files paced-dictionary-directory t
- paced-dictionary-directory-whitelist-regexp))))
- (dolist (dict-file files-to-load)
- (when (and (file-regular-p dict-file)
- (not (string-match-p
paced-dictionary-directory-blacklist-regexp dict-file)))
- (paced-load-dictionary-from-file dict-file)))))
-
-(cl-defmethod eieio-done-customizing ((dict paced-dictionary))
- (paced-dictionary-register dict)
- (paced--ensure-dictionary-directory)
- (paced-dictionary-save dict t))
-
-
-;;; Handling of Thing at Point
-
-(defun paced-bounds-of-thing-at-point ()
- "Get the bounds of the thing at point."
- (bounds-of-thing-at-point paced-thing-at-point-constituent))
-
-(defun paced-thing-at-point ()
- "Return the current thing at point.
-
-The thing is determined by `paced-thing-at-point-constituent'.
-
-Text properties are excluded."
- (when-let* ((bounds (paced-bounds-of-thing-at-point)))
- (buffer-substring-no-properties
- (car bounds) (cdr bounds))))
-
-(defun paced-forward-thing (&optional number)
- "Move forward NUMBER things.
-
-Things is based on `paced-thing-at-point-constituent'."
- (interactive "p")
- (forward-thing paced-thing-at-point-constituent number))
-
-(defun paced-goto-beginning-of-thing-at-point ()
- "Move to the start of the current thing at point.
-
-Thing is based on `paced-thing-at-point-constituent'."
- (goto-char (car (paced-bounds-of-thing-at-point))))
-
-(defun paced-goto-end-of-thing-at-point ()
- "Move to the end of the current thing at point.
-
-Thing is based on `paced-thing-at-point-constituent'."
- (goto-char (cdr (paced-bounds-of-thing-at-point))))
-
-;;; Character Limits
-
-(defun paced-length-of-thing-at-point ()
- "Return the length, in characters, of the current thing at point."
- (length (paced-thing-at-point)))
-
-(defun paced-thing-meets-limit-p ()
- "Return non-nil if the current thing at point meets the limit requirement.
-
-The limit requirement is set with `paced-character-limit'."
- (or (eq paced-character-limit 0)
- (<= (paced-length-of-thing-at-point) paced-character-limit)))
-
-;;; Exclusion
-
-(defvar-local paced-exclude-function (lambda () nil)
- "Local predicate to determine if thing at point should be excluded.
-
-This should be a function of no arguments that returns non-nil if
-the current thing-at-point should be excluded from paced
-dictionaries. Exclusion is checked from the start or the end of
-the current thing, depending on `paced-point-in-thing-at-point-for-exclusion'.
-Point returns to its original position after the function is
-called.
-
-By default, this allows everything.
-
-A useful function for this is `paced-in-comment-p'.")
-
-(defun paced-in-comment-p (&optional pos)
- "Return non-nil if POS is in a comment.
-
-If POS is not specified, defaults to `point'."
- (nth 8 (syntax-ppss (or pos (point)))))
-
-(defun paced-excluded-p ()
- "Return non-nil to exclude current thing at point.
-
-See `paced-exclude-function' for more.
-
-Exclusion can be performed from either the beginning or end of
-the thing at point. See
-`paced-point-in-thing-at-point-for-exclusion' for how to set
-this.
-
-If there is no current \"thing\" at point, the text under point
-will be excluded, and paced will move on.
-
-This also handles character limits set by
-`paced-character-limit'."
- (or (not (paced-thing-meets-limit-p))
- (not (paced-bounds-of-thing-at-point)) ;; There's no thing at point
- (save-excursion
- (pcase paced-point-in-thing-at-point-for-exclusion
- (`beginning
- (paced-goto-beginning-of-thing-at-point))
- (`end
- (paced-goto-end-of-thing-at-point)))
- (funcall paced-exclude-function))))
-
-;;; Case Handling
-
-(defun paced-mixed-case-word-p (word)
- "Return non-nil if WORD is mixed-case.
-
-A mixed-case word is one with both uppercase and lowercase
-letters, but ignoring the first letter if it's uppercase. This
-is due to assuming the first letter is unimportant, as per
-sentence starting."
- ;; Mixed case would typically be an uppercase letter followed by a lowercase
- ;; letter, or a lowercase letter followed by an uppercase letter. Since
we're
- ;; ignoring the first letter of a word if it's uppercase, we need to check
for
- ;; two distinct uppercase letters, followed by a lowercase letter.
- (let ((case-fold-search nil)) ;; Case is important
- (string-match-p (rx (or (and lower upper) ;; lower followed by upper
- ;; Two distinct uppercase letters, as in HAs
- (and upper upper lower)))
- word)))
-
-(defun paced--handle-word-case (case-handling word)
- "Process WORD based on CASE-HANDLING.
-
-This is a separate function only for testing; use
-`paced-dictionary-process-word' instead."
- (pcase case-handling
- (`preserve word)
- (`downcase (downcase word))
- (`upcase (upcase word))
- (`downcase-first
- ;; Downcase the first letter
- (concat (downcase (substring word 0 1))
- (substring word 1)))
- ;; Upcase the first letter
- (`upcase-first
- (concat (upcase (substring word 0 1))
- (substring word 1)))
- (`mixed-case
- (if (paced-mixed-case-word-p word) word (downcase word)))))
-
-(cl-defmethod paced-dictionary-process-word ((dict paced-dictionary) word)
- "Return WORD, modified based on DICT's case handling."
- (paced--handle-word-case (oref dict case-handling) word))
-
-;;; Population
-
-(defvar-local paced--current-source nil
- "The source from which a dictionary is being populated.
-
-This is used internally to inform the user of the current source,
-since population mostly uses temporary buffers.")
-
-(cl-defmethod paced-dictionary-add-word ((dict paced-dictionary) word)
- "Add WORD to paced dictionary DICT."
- (let ((new-word (paced-dictionary-process-word dict word)))
- ;; Use the full name here to silence the byte-compiler
- (cl-incf (map-elt (oref dict usage-hash) new-word 0))
- (oset dict updated t)))
-
-(defun paced-add-word-to-current-dictionary (word)
- "Add WORD to the current dictionary.
-
-For how the current dictionary is determined, see
-`paced-current-dictionary'."
- (paced-operate-on-current-dictionary
- (paced-dictionary-add-word dict word)))
-
-(cl-defmethod paced-dictionary-populate-from-buffer ((dict paced-dictionary)
&optional buffer)
- "Repopulate DICT from BUFFER.
-
-If BUFFER is nil, use the current one."
- (with-current-buffer (or buffer (current-buffer))
- (save-excursion
- (goto-char (point-min))
- (let* ((reporter-string
- (concat (format "Populating dictionary %s"
(paced-dictionary-name dict))
- (when paced--current-source (format " from %s"
-
paced--current-source))
- "..."))
- (reporter (make-progress-reporter reporter-string 0 100)))
- (while (paced-forward-thing)
- (progress-reporter-do-update
- reporter
- (floor (* 100.0 (/ (float (point)) (point-max)))))
- (unless (paced-excluded-p)
- (paced-dictionary-add-word dict (paced-thing-at-point))))
- (progress-reporter-done reporter)))))
-
-(defun paced-populate-current-dictionary-from-buffer (&optional buffer)
- "Populate the current dictionary from BUFFER.
-
-This means add a usage of each included thing in BUFFER.
-
-BUFFER is either the name of a buffer, or the buffer itself. If
-not given, use the current buffer.
-
-In order to only populate the dictionary from a region,
-`paced-populate-current-dictionary-from-region'.
-
-Note that this doesn't add the buffer to the dictionary's
-population commands, so if it is later repopulated using
-`paced-dictionary-repopulate' or
-`paced-repopulate-named-dictionary', anything added with this
-command will be lost.
-
-In order to make changes permanent, use
-`paced-add-buffer-file-to-dictionary'.
-
-For how the current dictionary is determined, see
-`paced-current-dictionary'."
- (interactive "b")
- (paced-operate-on-current-dictionary
- (paced-dictionary-populate-from-buffer dict buffer)))
-
-(define-obsolete-function-alias 'paced-populate-buffer-dictionary
- 'paced-populate-current-dictionary-from-buffer
- "1.1")
-
-(defun paced-populate-named-dictionary-from-buffer (name &optional buffer)
- "Populate the dictionary named NAME from BUFFER.
-
-This means add a usage of each included thing in BUFFER.
-
-BUFFER is either the name of a buffer, or the buffer itself. If
-not given, use the current buffer.
-
-In order to only populate the dictionary from a region,
-`paced-populate-current-dictionary-from-region'.
-
-Note that this doesn't add the buffer to the dictionary's
-population commands, so if it is later repopulated using
-`paced-dictionary-repopulate' or
-`paced-repopulate-named-dictionary', anything added with this
-command will be lost.
-
-In order to make changes permanent, use
-`paced-add-buffer-file-to-dictionary'.
-
-For how the current dictionary is determined, see
-`paced-current-dictionary'."
- (interactive
- (list (paced-read-dictionary) (read-buffer "Buffer: " nil t)))
- (paced-operate-on-named-dictionary name
- (paced-dictionary-populate-from-buffer dict buffer)))
-
-(cl-defmethod paced-dictionary-populate-from-region ((dict paced-dictionary)
start end)
- "Populate DICT from the region in the current buffer between START and END.
-
-Note that this doesn't add the current buffer to DICT's
-population commands, so if DICT is later repopulated using
-`paced-dictionary-repopulate' or
-`paced-repopulate-named-dictionary', anything added with this
-command will be lost."
- (save-restriction
- (narrow-to-region start end)
- (paced-dictionary-populate-from-buffer dict)))
-
-(defun paced-populate-current-dictionary-from-region (start end)
- "Populate the current dictionary from the region START to END.
-
-Note that this doesn't add the current buffer to the dictionary's
-population commands, so if it is later repopulated using
-`paced-dictionary-repopulate' or
-`paced-repopulate-named-dictionary', anything added with this
-command will be lost."
- (interactive "r")
- (paced-operate-on-current-dictionary
- (paced-dictionary-populate-from-region dict start end)))
-
-(define-obsolete-function-alias 'paced-populate-from-region
- 'paced-populate-current-dictionary-from-region
- "1.1")
-
-(defun paced-add-current-thing-to-dictionary ()
- "Add the current thing at point to the current dictionary.
-
-No check is done to determine if the current thing should be
-excluded.
-
-Note that this doesn't add anything to the dictionary's
-population commands, so if it is later repopulated using
-`paced-dictionary-repopulate' or
-`paced-repopulate-named-dictionary', anything added with this
-command will be lost."
- (interactive)
- (paced-operate-on-current-dictionary
- (paced-dictionary-add-word dict (paced-thing-at-point))))
-
-;;; Dictionary Reset
-
-(cl-defmethod paced-dictionary-reset ((dict paced-dictionary))
- "Reset the usage-hash of paced-dictionary DICT."
- (oset dict usage-hash (oref-default dict usage-hash)))
-
-(defun paced-reset-named-dictionary (key)
- "Reset the paced dictionary with key KEY."
- (declare (interactive-only paced-dictionary-reset))
- (interactive
- (list (paced-read-dictionary)))
- (paced-operate-on-named-dictionary key
- (paced-dictionary-reset dict)))
-
-(defun paced-reset-current-dictionary ()
- "Reset the current dictionary.
-
-For how the current dictionary is determined, see
-`paced-current-dictionary'."
- (interactive)
- (paced-operate-on-current-dictionary
- (paced-dictionary-reset dict)))
-
-;;; Dictionary Sorting
-
-(cl-defmethod paced-dictionary-sort ((dict paced-dictionary))
- "Sort the words in dictionary DICT by usage."
- (oset dict usage-hash
- (funcall (oref dict sort-method)
- (oref dict usage-hash))))
-
-(defun paced-sort-named-dictionary (key)
- "Sort the paced dictionary with key KEY."
- (declare (interactive-only paced-dictionary-sort))
- (interactive (list (paced-read-dictionary)))
- (paced-operate-on-named-dictionary key
- (paced-dictionary-sort dict)))
-
-(defun paced-sort-current-dictionary ()
- "Sort the current paced dictionary.
-
-For how the current dictionary is determined, see
-`paced-current-dictionary'."
- (interactive)
- (paced-operate-on-current-dictionary
- (paced-dictionary-sort dict)))
-
-
-;;; The Minor Mode
-
-(define-minor-mode paced-mode
- "Toggle paced mode.
-
-This adds `paced-completion-at-point' to
-`completion-at-point-functions'."
- :init-value nil
- :lighter " paced"
- :group 'paced
- (if paced-mode
- (add-hook 'completion-at-point-functions 'paced-completion-at-point
'append 'local)
- (remove-hook 'completion-at-point-functions 'paced-completion-at-point
'local)))
-
-(define-globalized-minor-mode global-paced-mode paced-mode paced-mode
- :group 'paced)
-
-;;; Completion
-
-(cl-defmethod paced-dictionary-fix-completion-case ((dict paced-dictionary)
prefix completions)
- "Account for case differences in the prefix by prepending PREFIX to
COMPLETIONS.
-
-The specific case differences should mirror those handled by
-case-handling in `paced-dictionary-process-word'."
- ;; Anything we changed during population, we want to maintain that part of
the
- ;; prefix during completion.
- (if (not (listp completions))
- ;; If completions is not a list, it's likely 't', in which
- ;; case just return the original prefix.
- (list prefix)
- (pcase (oref dict case-handling)
- (`preserve completions)
- ((or `downcase `upcase)
- ;; Changed entire word, so maintain entire prefix
- (let ((prefix-length (length prefix)))
- (mapcar
- (lambda (completion)
- (when (stringp completion)
- (concat prefix (substring-no-properties completion
prefix-length))))
- completions)))
- ((or `downcase-first `upcase-first)
- ;; Only changed the first letter, so maintain just one letter of the
- ;; original prefix
- (let ((prefix-length 1))
- (mapcar
- (lambda (completion)
- (when (stringp completion)
- (concat (substring prefix 0 prefix-length)
- (substring-no-properties completion prefix-length))))
- completions)))
- (`mixed-case
- ;; Only change prefix on single-case completion options
- (let ((prefix-length (length prefix)))
- (mapcar
- (lambda (completion)
- (when (stringp completion)
- (if (paced-mixed-case-word-p completion)
- completion
- (concat (substring prefix 0 prefix-length)
- (substring-no-properties completion prefix-length)))))
- completions))))))
-
-(cl-defmethod paced-dictionary-completions ((dict paced-dictionary) prefix
action &optional pred)
- "Get the completions for PREFIX in DICT.
-
-ACTION is a completion action, one of 'nil, 't, or 'lambda. See
-Info node `(elisp)Programmed Completion' for an explanation of
-each of them.
-
-PRED is a predicate to supply to completion, and will return
-non-nil if the completion option should be allowed.
-
-Case handling is handled here; any part of a word that was
-modified by `paced-dictionary-process-word' will be replaced with
-the prefix before completions are returned."
- (let* ((completion-ignore-case paced-completion-ignore-case)
- (usage-hash (oref dict usage-hash))
- completions)
- (pcase action
- (`nil
- (setq completions (try-completion prefix usage-hash pred)))
- (`t
- (setq completions (all-completions prefix usage-hash pred)))
- (`lambda
- (setq completions (test-completion prefix usage-hash pred))))
- (paced-dictionary-fix-completion-case dict prefix completions)))
-
-(defun paced-completion-table-function (string pred action)
- "Completion table function for paced dictionaries."
- (let* ((completion-ignore-case paced-completion-ignore-case))
- (pcase action
- ((or `nil `t `lambda)
- ;; Intentionally don't throw an error here, so as not to disrupt
- ;; completion.
- (when-let* ((dict (paced-current-dictionary)))
- (paced-dictionary-completions dict string action pred)))
- (`(boundaries . _) nil)
- (`metadata
- `(metadata . ((category . paced)
- (annotation-function . nil)
- (display-sort-function . identity)
- (cycle-sort-function . identity)))))))
-
-(defcustom paced-auto-update-p nil
- "Whether to update from completions.
-
-This only works for an existing entry."
- :group 'paced
- :type 'boolean)
-
-(defun paced-completion-auto-update (word status)
- "Automatically update the current dictionary with WORD depending on STATUS.
-
-This should only be called from `paced-completion-at-point'."
- (cl-case status
- (sole
- ;; We're done with completion, but the user may still be typing.
- ;; Therefore, don't add it.
- )
- (exact
- ;; Might not be the entire completion, so don't add it.
- )
- (finished
- ;; We know there's a current dictionary, since this should only be called
- ;; from `paced-completion-at-point'.
- (when paced-auto-update-p
- (paced-add-word-to-current-dictionary word)))))
-
-(defun paced-completion-at-point ()
- "Function for `completion-at-point-functions' to get the paced completions."
- ;; Don't expand unless we're in a buffer with paced-mode enabled.
- (when (and paced-mode)
- (when-let* ((bounds (paced-bounds-of-thing-at-point)))
- (list (car bounds) (cdr bounds) 'paced-completion-table-function
- :exit-function 'paced-completion-auto-update
- :exclusive 'no))))
-
-
-;;; Repopulation
-
-(defun paced--insert-file-contents (file)
- "Insert the contents of FILE into the current buffer.
-
-Unlike `insert-file-contents', this handles mode hooks, which
-paced requires for repopulation (syntax tables, exclude functions, etc.).
-
-Returns nil if FILE doesn't exist."
- (if (not (file-exists-p file))
- (progn (message "Paced couldn't find file %s" file) nil)
- (insert-file-contents file)
- (let ((buffer-file-name file))
- (after-find-file))
- t))
-
-(defclass paced-population-command ()
- ((props :initarg :props
- :initform nil
- :type list
- :label "Properties"
- :custom (alist :tag "Options" :key-type variable :value-type sexp)
- :documentation "A list of variables to set during population.
-
-Each element is of the form (VAR VALUE).
-
-Some suggested variables for this are `paced-exclude-function'
-and `paced-thing-at-point-constituent'.")))
-
-(defun paced-merge-properties (&rest props)
- "Merge the properties in PROPS to a single form understood by `let'.
-
-PROPS is a list of alists, each mapping a variable to a value for
-that variable
-
-The maps in the end of PROPS take precedence over the beginning."
- (let ((merged-map (apply 'map-merge 'list props)))
- (map-apply (lambda (var val) (list var val)) merged-map)))
-
-(cl-defmethod paced-dictionary-prepare-properties ((dict paced-dictionary)
- (cmd
paced-population-command))
- "Merge the properties of DICT and CMD into a single form understood by `let'.
-
-Properties in CMD take precedence over those in DICT."
- (paced-merge-properties (oref dict default-population-properties)
- (oref cmd props)))
-
-(cl-defgeneric paced-population-command-source-list ((_cmd
paced-population-command)))
-
-(cl-defgeneric paced-population-command-setup-buffer ((_cmd
paced-population-command) _source)
- "Prepare a temporary buffer with SOURCE.
-
-Return non-nil if setup was successful and population can continue.")
-
-(cl-defmethod paced-population-command-populate-dictionary ((dict
paced-dictionary) (cmd paced-population-command))
- "Populate DICT from CMD."
- (let ((sources (paced-population-command-source-list cmd))
- ;; Turn props into a form understood by `let'.
- (props (paced-dictionary-prepare-properties dict cmd)))
- (dolist (source sources)
- (with-temp-buffer
- ;; If pre is nil, continue.
- ;; Otherwise, continue if pre returns non-nil
- ;; This allows users to specify conditions under which repopulation
- ;; should be disabled.
- (let ((paced--current-source source))
- (when (paced-population-command-setup-buffer cmd source)
- (eval (macroexp-let* props `(paced-dictionary-populate-from-buffer
,dict)))))))))
-
-(defclass paced-file-population-command (paced-population-command)
- ((file :initarg :file
- :initform ""
- :type string
- :label "File"
- :custom (file :tag "File")
- :documentation "File from which to populate."))
- "Populates a dictionary from all words in a single file.")
-
-(cl-defmethod paced-population-command-source-list ((cmd
paced-file-population-command))
- (list (oref cmd file)))
-
-(cl-defmethod paced-population-command-setup-buffer ((_cmd
paced-file-population-command) source)
- (paced--insert-file-contents source))
-
-(defclass paced-buffer-population-command (paced-population-command)
- ((buffer :initarg :buffer
- :initform ""
- :type string
- :label "Buffer"
- :custom (string :tag "Buffer")
- :documentation "Name of the buffer from which to populate."))
- "Populates a dictionary from all words in a given buffer.
-
-That buffer must be a string, and must exist during population.")
-
-(cl-defmethod paced-population-command-source-list ((cmd
paced-buffer-population-command))
- (list (oref cmd buffer)))
-
-(cl-defmethod paced-population-command-setup-buffer ((_cmd
paced-buffer-population-command) source)
- (cond
- ((not (stringp source))
- (message "Paced buffer populator got an invalid argument: %s" source)
- nil)
- ((not (get-buffer source))
- (message "Paced buffer populator got a buffer that doesn't exist: %s"
source)
- nil)
- (t
- (set-buffer source))))
-
-(defclass paced-file-function-population-command (paced-population-command)
- ((file :initarg :file
- :initform ""
- :type string
- :label "File"
- :custom (file :tag "File")
- :documentation "File from which to populate.")
- (setup-func :initarg :setup-func
- :initform (lambda () t)
- :type function
- :label "Setup Function"
- :custom (function :tag "Setup Function")
- :documentation "Additional setup function."))
- "Populate from a given file, using a setup function.
-
-That function is called with no arguments, with a temporary
-buffer containing the file's contents, and must return non-nil if
-population may continue.")
-
-(cl-defmethod paced-population-command-source-list ((cmd
paced-file-function-population-command))
- (list (oref cmd file)))
-
-(cl-defmethod paced-population-command-setup-buffer ((cmd
paced-file-function-population-command) source)
- (and (paced--insert-file-contents source)
- (funcall (oref cmd setup-func))))
-
-(defclass paced-directory-regexp-population-command (paced-population-command)
- ((directory :initarg :directory
- :initform ""
- :type string
- :label "Directory"
- :custom (directory :tag "Directory")
- :documentation "Directory to search for files from which to
populate.")
- (regexp :initarg :regexp
- :initform ".*"
- :type string
- :label "File Regexp"
- :custom (string :tag "File Regexp")
- :documentation "Regular expression to match files.")
- (recursive :initarg :recursive
- :initform t
- :type boolean
- :label "Recursive"
- :custom boolean
- :documentation "Whether to search through the directory
recursively."))
- "Population command to populate from files in a directory that
-match a regular expression.")
-
-(cl-defmethod paced-population-command-source-list ((cmd
paced-directory-regexp-population-command))
- (with-slots (directory regexp recursive) cmd
- (if recursive
- (directory-files-recursively directory regexp)
- (directory-files directory t regexp))))
-
-(cl-defmethod paced-population-command-setup-buffer ((_cmd
paced-directory-regexp-population-command) source)
- (paced--insert-file-contents source))
-
-(defclass paced-file-list-population-command (paced-population-command)
- ((generator :initarg :generator
- :initform (lambda () nil)
- :type function
- :label "Generator"
- :custom (function :tag "Generator")
- :documentation "Function of no arguments that returns a list of
files."))
- "Populate a dictionary from a list of files.")
-
-(cl-defmethod paced-population-command-source-list ((cmd
paced-file-list-population-command))
- (funcall (oref cmd generator)))
-
-(cl-defmethod paced-population-command-setup-buffer ((_cmd
paced-file-list-population-command) source)
- (paced--insert-file-contents source))
-
-(defun paced-new-population-command-custom ()
- "Prompt for a population command type and create a new command of that type."
- (let* ((type (completing-read "Command Type: "
- (eieio-class-children
'paced-population-command))))
- (funcall (intern type))))
-
-(cl-defmethod paced-dictionary-repopulate ((dict paced-dictionary))
- "Repopulate dictionary DICT from its population commands.
-
-Population commands are stored in the field of the same name.
-
-Note that this will empty the dictionary's contents before
-repopulating it."
- ;; Empty the dictionary
- (paced-dictionary-reset dict)
- (dolist (cmd (oref dict population-commands))
- (paced-population-command-populate-dictionary dict cmd))
- (paced-dictionary-sort dict)
- (when paced-repopulate-saves-dictionary
- (paced-dictionary-save dict)))
-
-(defun paced-repopulate-named-dictionary (key)
- "Repopulate dictionary named KEY from its population commands.
-
-Population commands are stored in the field of the same name.
-
-Note that this will empty the dictionary's contents before
-repopulating it. If `paced-populate-warn-about-reset' is
-non-nil, confirmation will be requested before continuing."
- (interactive
- (list (paced-read-dictionary)))
- (paced-operate-on-named-dictionary key
- (when (or (not paced-populate-warn-about-reset)
- (y-or-n-p "Warning: Repopulating dictionary will reset it.
Continue? "))
- (paced-dictionary-repopulate dict))))
-
-(defun paced-repopulate-current-dictionary ()
- "Repopulate the current dictionary.
-
-Note that this will empty the dictionary's contents before
-repopulating it. If `paced-populate-warn-about-reset' is
-non-nil, confirmation will be requested before continuing."
- (interactive)
- (paced-operate-on-current-dictionary
- (when (or (not paced-populate-warn-about-reset)
- (y-or-n-p "Warning: Repopulating dictionary will reset it.
Continue? "))
- (paced-dictionary-repopulate dict))))
-
-(cl-defmethod paced-dictionary-add-population-command ((dict paced-dictionary)
- (cmd
paced-population-command))
- "Add population command CMD to dictionary DICT."
- (cl-pushnew cmd (oref dict population-commands) :test 'equal))
-
-(defun paced-add-buffer-file-to-dictionary (&optional buffer)
- "Populate the current dictionary of BUFFER with BUFFER.
-
-The file corresponding to BUFFER is then added to the current
-dictionary's population commands.
-
-Custom settings for the populator, such as the exclude function,
-must be set with `paced-edit-named-dictionary' or
-`paced-edit-current-dictionary'."
- (interactive)
- (with-current-buffer (or buffer (current-buffer))
- (unless (buffer-file-name)
- (user-error "paced-add-buffer-file-to-dictionary called inside a
non-file buffer."))
- (paced-operate-on-current-dictionary
- (let* ((file-name (buffer-file-name))
- (cmd (paced-file-population-command :file file-name)))
- (paced-dictionary-populate-from-buffer dict buffer)
- (paced-dictionary-add-population-command dict cmd)))))
-
-
-
-;;; Edit a Dictionary
-
-(cl-defmethod paced-dictionary-edit ((dict paced-dictionary))
- "Edit paced-dictionary DICT."
- (customize-object dict))
-
-(defun paced-edit-named-dictionary (name)
- "Edit the `paced-dictionary' named NAME."
- (declare (interactive-only paced-dictionary-edit))
- (interactive (list (paced-read-dictionary)))
- (paced-operate-on-named-dictionary name
- (paced-dictionary-edit dict)))
-
-(defun paced-edit-current-dictionary ()
- "Edit the current paced dictionary.
-
-For how the current dictionary is determined, see
-`paced-current-dictionary'."
- (interactive)
- (paced-operate-on-current-dictionary
- (paced-dictionary-edit dict)))
-
-
-
-;;; Print a Dictionary in a Dedicated Buffer
-
-(defvar-local paced-tabulated-list-dictionary nil
- "Dictionary printed in a tabulated list buffer.")
-
-(cl-defmethod paced-dictionary-length-of-longest-word ((dict paced-dictionary))
- "Return the length of the longest word in DICT."
- (cond
- ;; If DICT is empty, seq-max throws an error.
- ((paced-dictionary-empty-p dict) 0)
- (t
- (seq-max
- (map-apply
- (lambda (key _value)
- (length key))
- (oref dict usage-hash))))))
-
-(cl-defmethod paced-dictionary-tabulated-list-entries ((dict paced-dictionary))
- "Create a value for `tabulated-list-entries' from DICT."
- (map-apply
- (lambda (key value)
- (list key (vector key (number-to-string value))))
- (oref dict usage-hash)))
-
-(defun paced-tabulated-list-revert ()
- "Revert a `tabulated-list-mode' buffer from its dictionary."
- (let* ((dict paced-tabulated-list-dictionary)
- (longest-length (paced-dictionary-length-of-longest-word dict)))
- (setq tabulated-list-format
- (vector `("Word" ,longest-length t . (:right-align t))
- `("Count" 10 t)))
- (setq tabulated-list-entries (paced-dictionary-tabulated-list-entries
dict))))
-
-(cl-defmethod paced-dictionary-print ((dict paced-dictionary))
- "Print the contents of DICT in a dedicated buffer."
- (let* ((buffer-name (format "*Paced Dictionary - %s*" (paced-dictionary-name
dict)))
- (buffer (get-buffer-create buffer-name)))
- (with-current-buffer buffer
- (tabulated-list-mode)
- (setq paced-tabulated-list-dictionary dict)
- (paced-tabulated-list-revert)
- (tabulated-list-init-header)
- (tabulated-list-print))
- (display-buffer buffer)))
-
-(defun paced-print-current-dictionary ()
- "Print the contents of the current dictionary in a dedicated buffer."
- (interactive)
- (paced-operate-on-current-dictionary
- (paced-dictionary-print dict)))
-
-(defun paced-print-named-dictionary (name)
- "Print the contents of the dictionary with name NAME."
- (declare (interactive-only paced-dictionary-print))
- (interactive (list (paced-read-dictionary)))
- (paced-operate-on-named-dictionary name
- (paced-dictionary-print dict)))
-
-
-
-(declare-function lm-report-bug "lisp-mnt" (topic))
-
-(defun paced-submit-bug-report (topic)
- "Report a bug with topic TOPIC."
- (interactive "sTopic: ")
- (require 'lisp-mnt)
- (let* ((src-file (locate-library "paced.el" t))
- (src-buf-live (find-buffer-visiting src-file))
- (src-buf (find-file-noselect src-file)))
- (with-current-buffer src-buf
- (lm-report-bug topic))
- ;; Kill the buffer if it wasn't live
- (unless src-buf-live
- (kill-buffer src-buf))))
-
-(provide 'paced)
-
-;;; paced.el ends here
diff --git a/packages/paced/paced.info b/packages/paced/paced.info
deleted file mode 100644
index 17249d1..0000000
--- a/packages/paced/paced.info
+++ /dev/null
@@ -1,1029 +0,0 @@
-This is paced.info, produced by makeinfo version 6.5 from paced.texi.
-
-INFO-DIR-SECTION Emacs
-START-INFO-DIR-ENTRY
-* Paced: (paced). Predictive Abbreviation Completion and Expansion using
Dictionaries.
-END-INFO-DIR-ENTRY
-
-
-File: paced.info, Node: Top, Next: Copying, Up: (dir)
-
-Paced
-*****
-
-* Menu:
-
-* Copying::
-* Introduction:: Brief Introduction to paced
-* Dictionaries:: Paced’s bread and butter
-* Population Commands:: The good stuff
-* Example Setups:: Some examples
-* Contributing:: I wanna help!
-* Changelog:: List of changes by version
-
-— The Detailed Node Listing —
-
-Introduction
-
-* Similar Packages:: Packages with similar goals
-* Installation:: How to install paced
-* Basic Setup:: The simplest setup
-
-Similar Packages
-
-* pabbrev::
-* predictive::
-
-
-Dictionaries
-
-* Creating a Dictionary:: First steps
-* Editing a Dictionary:: How to edit your new dictionary
-* Selective Dictionaries:: Enabling certain dictionaries under certain
conditions
-* Dictionary Files:: Loading and Saving the Dictionaries
-* Printing a Dictionary:: Seeing the contents of a dictionary
-
-Population Commands
-
-* Built-in Commands:: Basics
-* Properties:: Tweaking the defaults
-* Custom Commands:: Defining new population commands
-* Asynchronous Population:: Populating without blocking
-
-Example Setups
-
-* Org Agenda Files::
-* Project Files::
-* Markdown Files::
-* Repopulating Dictionary After Saving::
-* Repopulating Dictionary After Spellchecking the Buffer::
-
-Contributing
-
-* Bugs:: Submitting bug reports
-* Development:: Helping with development
-* Documentation:: Improving the documentation
-* Working with EDE:: And all its quirks
-
-Changelog
-
-* 1.1.3: 113.
-* 1.1.2: 112.
-* 1.1.1: 111.
-* 1.1: 11.
-* 1.0.1: 101.
-* 1.0: 10.
-
-
-
-File: paced.info, Node: Copying, Next: Introduction, Prev: Top, Up: Top
-
-Copying
-*******
-
-Copyright (C) 2017-2018 Free Software Foundation, Inc.
-
- 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
- <http://www.gnu.org/licenses/>.
-
-
-File: paced.info, Node: Introduction, Next: Dictionaries, Prev: Copying,
Up: Top
-
-Introduction
-************
-
-Paced (Predictive Abbreviation Completion and Expansion using
-Dictionaries) scans a group of files (determined by “population
-commands”) to construct a usage table (dictionary). Words (or symbols)
-are sorted by their usage, and may be later presented to the user for
-completion. A dictionary can then be saved to a file, to be loaded
-later.
-
- Population commands determine how a dictionary should be filled with
-words or symbols. A dictionary may have multiple population commands,
-and population may be performed asynchronously. Once population is
-finished, the contents are sorted, with more commonly used words at the
-front. Dictionaries may be edited through EIEIO’s customize-object
-interface.
-
- Completion is done through ‘completion-at-point’. The dictionary to
-use for completion can be customized.
-
-* Menu:
-
-* Similar Packages:: Packages with similar goals
-* Installation:: How to install paced
-* Basic Setup:: The simplest setup
-
-
-File: paced.info, Node: Similar Packages, Next: Installation, Up:
Introduction
-
-Similar Packages
-================
-
-There are a few Emacs packages that have similar goals to paced, and
-provided some of the inspiration and motivation behind it.
-
-* Menu:
-
-* pabbrev::
-* predictive::
-
-
-File: paced.info, Node: pabbrev, Next: predictive, Up: Similar Packages
-
-pabbrev
--------
-
-The pabbrev (https://github.com/phillord/pabbrev) package by Phillip
-Lord automatically scans text of the current buffer while Emacs is idle
-and presents the user with the most common completions.
-
- One of the major downsides to pabbrev is that the data it collects
-doesn’t persist between Emacs sessions. For a few files that are always
-open, such as org agenda files, pabbrev works great. If you want to
-train it from a few files that aren’t always open, you’ll have to open
-each file and retrain pabbrev from that file. And you’ll have to do
-this every time you restart Emacs.
-
- It keeps up-to-date usage and prefix hashes of all buffers of the
-same mode, and scanning, or “scavenging”, blends seamlessly into the
-background. Completion is just a hash table lookup, so it can handle
-completion in microseconds. There’s also no setup required; it will
-start working right away. The downside to this is that dictionaries
-aren’t flexible; each dictionary corresponds to a major mode, and
-there’s no way to change that.
-
-
-File: paced.info, Node: predictive, Prev: pabbrev, Up: Similar Packages
-
-predictive
-----------
-
-The predictive (https://www.dr-qubit.org/predictive.html) package by
-Toby Cubitt scans text of the current buffer on user command. The usage
-data is stored in a dictionary, which can then be saved to a disk.
-Extensions are provided to ‘completion-at-point’, or predictive’s
-built-in frontend can be used. It has a safety precaution where it only
-adds existing words to a dictionary, unless the user allows this. This
-is to avoid adding typos to a dictionary.
-
- Completion was also done intelligently, grouping commonly used words
-together and optionally suggesting shorter words before longer words.
-
- While the frontend and backend are separate, the frontend is required
-to populate a dictionary. There is no way to exclude part of the
-buffer’s text from dictionary population. The safety precaution
-predictive has where it only adds a word to a dictionary if it already
-exists was tedious, since I didn’t need it to do that.
-
-
-File: paced.info, Node: Installation, Next: Basic Setup, Prev: Similar
Packages, Up: Introduction
-
-Installation
-============
-
-*Requirements*
-
-Emacs 25.1
-async 1.9.1
-
- Paced may be installed from source, or from GNU ELPA.
-
- From ELPA:
-
- M-x package-install RET paced RET
-
- From Source:
-
- bzr branch https://bzr.savannah.gnu.org/r/paced-el paced
-
- After installing from source, add the following to your init file
-(typically .emacs):
-
- (add-to-list 'load-path "/full/path/to/paced/")
- (require 'paced)
-
- However you install paced, you must also make sure dictionaries are
-loaded on startup:
-
- (paced-load-all-dictionaries)
-
-
-File: paced.info, Node: Basic Setup, Prev: Installation, Up: Introduction
-
-Basic Setup
-===========
-
-Paced needn’t have a lot of setup to run. In fact, the simplest setup
-is as follows:
-
- 1. Create a new dictionary, “Default” (See *note Creating a
- Dictionary::)
- 2. Set ‘paced-global-dictionary-enable-alist’ to ‘((t . "Default"))’
- (See *note Selective Dictionaries::)
- 3. Run ‘M-x global-paced-mode’
- 4. To add a file to the dictionary, use ‘M-x
- paced-add-buffer-file-to-dictionary’
-
- This will create a default dictionary and populate it from buffers
-you specify.
-
-
-File: paced.info, Node: Dictionaries, Next: Population Commands, Prev:
Introduction, Up: Top
-
-Dictionaries
-************
-
-* Menu:
-
-* Creating a Dictionary:: First steps
-* Editing a Dictionary:: How to edit your new dictionary
-* Selective Dictionaries:: Enabling certain dictionaries under certain
conditions
-* Dictionary Files:: Loading and Saving the Dictionaries
-* Printing a Dictionary:: Seeing the contents of a dictionary
-
-
-File: paced.info, Node: Creating a Dictionary, Next: Editing a Dictionary,
Up: Dictionaries
-
-Creating a Dictionary
-=====================
-
-Now that you’ve got paced installed, it’s time to create a new
-dictionary.
-
- M-x paced-create-new-dictionary RET DICTIONARY_NAME RET DICTIONARY_FILE
RET
-
- Let’s explain those two arguments:
-
- First, you’ve got DICTIONARY_NAME. This is a string that will be used
-to reference the new dictionary. We recommend something short, like
-’new-dict’, ’my-dict’, ’writing’, etc.
-
- Next is the file where the dictionary will be stored. This is
-typically stored in ‘paced-dictionary-directory’, from which all
-dictionaries will be loaded with ‘paced-load-all-dictionaries’ (more on
-that later). For now, it’s important to know that
-‘paced-load-all-dictionaries’ is the easiest way to load dictionaries
-when paced is loaded.
-
- After you’ve run the above command, you will be taken to the
-customization buffer. This is where you can set population commands.
-
-
-File: paced.info, Node: Editing a Dictionary, Next: Selective Dictionaries,
Prev: Creating a Dictionary, Up: Dictionaries
-
-Editing a Dictionary
-====================
-
-In order to edit a dictionary, paced provides
-‘paced-edit-named-dictionary’ and ‘paced-edit-current-dictionary’.
-
- The edit buffer provides the options to change the population
-commands, case handling, dictionary storage name, and sort method. Each
-of these is documented in the edit buffer.
-
-
-File: paced.info, Node: Selective Dictionaries, Next: Dictionary Files,
Prev: Editing a Dictionary, Up: Dictionaries
-
-Selective Dictionaries
-======================
-
-Paced provides a mechanism called the “enable list”, that allows a user
-to enable certain dictionaries for completion given certain conditions.
-
- There are two enable lists: a global
-(‘paced-global-dictionary-enable-alist’) and local
-(‘paced-local-dictionary-enable-alist’) one. They both work the same,
-with the local one taking precedence. Each entry in the list has a
-condition and a key.
-
- The conditions are one of the following:
-
- • A mode name, such as ‘org-mode’ or ‘text-mode’, indicating that the
- named dictionary should be active in any mode derived from that
- mode.
-
- • A symbol, in which case the named dictionary is active whenever the
- value of that symbol is non-nil. This includes the symbol ‘t’.
-
- • A function symbol, in which case the function is called with no
- arguments to determine if the given dictionary should be enabled.
- If the function returns non-nil the dictionary is enabled.
-
- • A lambda function, in which case it is called with no arguments,
- and if it returns non-nil, the dictionary is enabled.
-
- • The form (or CONDITION1 CONDITION2 ...), which enables the given
- dictionary if any of the conditions are met.
-
- • The form (and CONDITION1 CONDITION2 ...), which enables the given
- dictionary if all of the conditions are met.
-
- Remember that paced-mode must be active for completion to occur.
-Neither list will activate it, just determine which dictionary is
-active.
-
- The key is the dictionary name you set during dictionary creation.
-
-
-File: paced.info, Node: Dictionary Files, Next: Printing a Dictionary,
Prev: Selective Dictionaries, Up: Dictionaries
-
-Dictionary Files
-================
-
-Paced provides ‘paced-load-all-dictionaries’ to load all dictionaries in
-‘paced-dictionary-directory’. Paced determines which dictionaries to
-load based on two variables:
-‘paced-dictionary-directory-whitelist-regexp’ and
-‘paced-dictionary-directory-blacklist-regexp’. Paced can also be told
-to search recursively by setting
-‘paced-load-all-dictionaries-recursively’ to t. All four of these
-variables may be set using Emacs’s customization interface.
-
- An individual dictionary file may also be loaded:
-
- M-x paced-load-dictionary-from-file RET /path/to/file RET
-
- Once a file has been modified, it may then be saved:
-
- M-x paced-save-named-dictionary RET dictionary name RET
-
- Or, all dictionaries may be saved:
-
- M-x paced-save-all-dictionaries RET
-
- Dictionaries may also be automatically saved whenever changed by
-setting ‘paced-repopulate-saves-dictionary’ to t. Population is covered
-in the next section.
-
-
-File: paced.info, Node: Printing a Dictionary, Prev: Dictionary Files, Up:
Dictionaries
-
-Printing a Dictionary
-=====================
-
-Paced allows a user to print the contents of a dictionary to a buffer.
-Uses for this might be to tweak population commands or exclude
-functions, or to simply make sure a dictionary is populating correctly.
-
- To use this feature, run:
-
- M-x paced-print-named-dictionary RET NAME-OF-DICTIONARY RET
-
- Or for the current dictionary:
-
- M-x paced-print-current-dictionary RET
-
-
-File: paced.info, Node: Population Commands, Next: Example Setups, Prev:
Dictionaries, Up: Top
-
-Population Commands
-*******************
-
-Part of the beauty of paced is the ease of reconstructing a dictionary.
-When you’ve got a bunch of files from which you want to populate your
-dictionary, it’d be a pain to go to each of them and say “populate from
-this one, next, populate from this one, next”.
-
- Instead, paced provides population commands. Each dictionary has one
-or more population commands it uses to recreate its contents, run in
-order during population.
-
- In order to trigger population, run the following:
-
- M-x paced-repopulate-named-dictionary RET DICTIONARY-NAME RET
-
-* Menu:
-
-* Built-in Commands:: Basics
-* Properties:: Tweaking the defaults
-* Custom Commands:: Defining new population commands
-* Asynchronous Population:: Populating without blocking
-
-
-File: paced.info, Node: Built-in Commands, Next: Properties, Up: Population
Commands
-
-Built-in Commands
-=================
-
-There are five built-in population commands:
-
-file
- Populates a dictionary from all words in a given file
-buffer
- Populates a dictionary from all words in a given buffer, which must
- exist during population
-file-function
- Like the file command, but allows a custom setup function. This
- function is called with no arguments in a temporary buffer
- containing the file’s contents, and must return non-nil if
- population may continue.
-directory-regexp
- Populates from all files in a directory that match the given
- regexp. Also optionally allows recursion.
-file-list
- Populates from all files returned by a generator function.
-
-
-File: paced.info, Node: Properties, Next: Custom Commands, Prev: Built-in
Commands, Up: Population Commands
-
-Properties
-==========
-
-When setting the population commands of a dictionary, one may also set
-certain properties. Each property is a variable binding, bound while
-the population command runs.
-
- A few variables are of note here:
-
-paced-exclude-function
- Function of no arguments that returns non-nil if the thing at point
- should be excluded from population.
-paced-thing-at-point-constituent
- Symbol defining thing on which population works. Typically set to
- either ’symbol or ’word.
-paced-character-limit
- Maximum length of a thing to include it in a dictionary. If set to
- 0 (default), no limit is imposed.
-
- For convenience, properties that are intended for all population
-commands of a given dictionary may be set in the dictionary itself. In
-the event of a conflict, population command properties take precedence
-over dictionary properties.
-
-
-File: paced.info, Node: Custom Commands, Next: Asynchronous Population,
Prev: Properties, Up: Population Commands
-
-Custom Commands
-===============
-
-Since the population commands all derive from paced-population-command,
-it’s possible to add additional commands.
-
- As an example, let’s make a population command that populates a
-dictionary from a file like so:
-
- alpha 5
- beta 7
- gamma 21
- delta 54
- epsilon 2
-
- We want to make a population command that takes a file like this,
-with word in one column and weight in the other, and add it to a
-dictionary.
-
- There are two ways to approach this, but we’re going to start with
-the basic one.
-
- We need to define two functions: paced-population-command-source-list
-and paced-population-command-setup-buffer. The first returns a list of
-sources from which to populate, and the second sets up a temporary
-buffer based on those sources.
-
- For our command, we want to return the specified file, and replicate
-each word by the amount given.
-
- Inheriting from ‘paced-file-population-command’ gives us the source
-list and file slot for free.
-
- (defclass paced-weight-file-population-command
(paced-file-population-command))
-
- Now, we need to set up the buffer to replicate the words.
-
- (cl-defmethod paced-population-command-setup-buffer ((cmd
paced-weight-file-population-command) source)
- ;; Use the built-in `paced--insert-file-contents' to insert contents.
- (paced--insert-file-contents source)
- ;; Jump to the start of the buffer
- (goto-char (point-min))
- ;; Search for lines with the form WORD WEIGHT
- (while (re-search-forward (rx line-start ;; Start of line
- (submatch (one-or-more (not (syntax
whitespace)))) ;; Our word
- (syntax whitespace) ;; Space between word
and weight
- (submatch (one-or-more (any digit))) ;;
Weight
- line-end) ;; End of line
- nil t)
- (let* ((word (match-string 1))
- (weight (string-to-number (match-string 2)))
- ;; Repeat WORD WEIGHT times
- (new-text (string-join (make-list weight word) " ")))
- ;; Replace the matched text with our repeated word
- (replace-match new-text))))
-
- That’s all there is to it. When you go to edit a dictionary, the
-“weight-file” population command will automatically be added as an
-option for a population command.
-
- The even easier way to do this would’ve been to use
-‘paced-file-function-population-command’, but it doesn’t make for a good
-example in this case.
-
-
-File: paced.info, Node: Asynchronous Population, Prev: Custom Commands, Up:
Population Commands
-
-Asynchronous Population
-=======================
-
-A common problem is that population can take a long time. Some of us
-populate dictionaries from org agenda files, which can get pretty big.
-
- To solve this, paced uses the async
-(https://github.com/jwiegley/emacs-async) package. Setup is seamless;
-just stick whatever code you need in ‘~/.emacs.d/paced-async.el’, and
-use one of the two population commands:
-
- A named dictionary:
-
- M-x paced-repopulate-named-dictionary-async RET NAME RET
-
- Or the current dictionary:
-
- M-x paced-repopulate-current-dictionary-async RET
-
- A few things to note about this:
-
- 1. Dictionaries will be automatically saved by this method after
- population
- 2. Asynchronous population doesn’t change anything until after
- population is finished, so a user may continue to use their
- dictionary while population is happening. This also means that
- multiple populations may run in parallel without interfering with
- one another.
- 3. Because async runs population in a separate Emacs process, any
- custom code required for population must be in paced-async.el.
- This includes additional population command types, but doesn’t
- include the following variables:
-
- • load-path
- • paced-thing-at-point-constituent
- • paced-async-load-file
-
-
-File: paced.info, Node: Example Setups, Next: Contributing, Prev:
Population Commands, Up: Top
-
-Example Setups
-**************
-
-* Menu:
-
-* Org Agenda Files::
-* Project Files::
-* Markdown Files::
-* Repopulating Dictionary After Saving::
-* Repopulating Dictionary After Spellchecking the Buffer::
-
-
-File: paced.info, Node: Org Agenda Files, Next: Project Files, Up: Example
Setups
-
-Org Agenda Files
-================
-
-As some of us record everything about our lives in our agenda files, it
-might be helpful to have a dictionary tuned to ourselves.
-
- We use a file-list command that returns the agenda files, and an
-exclude command to block out all of Org’s extra features such as source
-code and drawers.
-
- The generator for file-list is easy:
-
- org-agenda-files
-
- Done.
-
- Now, the exclude command, which sits inside the properties option.
-This can be added to ‘paced-async.el’:
-
- (require 'org)
-
- (defun org-at-tag-p ()
- (let* ((p (point)))
- ;; Ignore errors from `org-get-tags-string'.
- (ignore-errors
- ;; Checks the match string for a tag heading, setting match-string
1 to the
- ;; tags. Also sets match-beginning and match-end.
- (org-get-tags-string)
- (when (match-string 1)
- (<= (match-beginning 1) p (match-end 1))))))
-
- (defun org-at-keyword-p ()
- "Return non-nil if point is at a keyword such as #+TITLE."
- (save-excursion
- (beginning-of-line)
- (looking-at-p "^#\\+")))
-
- (defun org-at-heading-prefix-p ()
- "Return non-nil if looking at the leading stars of a heading."
- (looking-at outline-regexp))
-
- (defun org-at-hline-p ()
- (save-excursion
- (beginning-of-line)
- (looking-at-p "^-----")))
-
- (defun org-paced-exclude ()
- (or
- ;; Drawers
- (org-between-regexps-p org-drawer-regexp ":END:") ;; Doesn't catch END
- (org-in-regexp ":END:") ;; but this does
-
- (org-at-tag-p) ;; tags
- (org-at-keyword-p) ;; Keywords, such as #+TITLE
- (org-at-heading-prefix-p) ;; Leading stars of a heading
- (org-at-item-bullet-p) ;; Item Bullets
- (org-at-timestamp-p) ;; Timestamps
- (looking-at-p org-todo-regexp) ;; TODO keywords
- (org-at-hline-p) ;; H-lines
-
- (org-at-comment-p) ;; comments
- (org-in-regexp org-any-link-re) ;; links
- (org-in-block-p '("src" "quote" "verse")) ;; blocks
- (org-at-planning-p) ;; deadline, etc.
- (org-at-table-p) ;; tables
- ))
-
- As explained earlier, this can be put inside properties in the
-customize buffer as such:
-
- Properties :
- [INS] [DEL] Variable: paced-exclude-function
- Lisp expression: 'org-paced-exclude
-
- And you’re done. See how easy that was?
-
-
-File: paced.info, Node: Project Files, Next: Markdown Files, Prev: Org
Agenda Files, Up: Example Setups
-
-Project Files
-=============
-
-Now we get to the interesting one. There are tons of ways to collect
-project files in Emacs, so we’re going to stick with one for now, being
-Emacs’s built-in VC package.
-
- (defun vc-paced-find-project-files (path-to-project-root)
- "Use VC to collect all version-controlled files."
- (let ((file-list))
- (vc-file-tree-walk path-to-project-root (lambda (f) (push f
file-list)))
- file-list))
-
- We’d then need to use the following for our file-list generator:
-
- Generator : (lambda nil (vc-paced-find-project-files
"/home/me/programming/paced"))
-
- Now, we (probably) don’t want commented code to get in our way, so
-we’ll use a small function for excluding those:
-
- (defun paced-at-comment-p ()
- (nth 8 (syntax-ppss)))
-
- Use that for paced-exclude-function, and you’re done. We can’t
-necessarily recommend this for any programming language, as there are
-dedicated solutions for almost everything, but it makes an excellent
-fallback.
-
-
-File: paced.info, Node: Markdown Files, Next: Repopulating Dictionary After
Saving, Prev: Project Files, Up: Example Setups
-
-Markdown Files
-==============
-
-Another common request is markdown files. In order for this to work,
-you’ll need to install ‘markdown-mode’:
-
- M-x package-install RET markdown-mode RET
-
- After that, add the following to your ‘paced-async.el’ file:
-
- (require 'markdown-mode)
-
- (defun paced-markdown-exclude-p ()
- "Taken from `markdown-flyspell-check-word-p'."
- ;; Exclude anything markdown mode thinks flyspell should skip.
- (or
- ;; Ignore code blocks
- (markdown-code-block-at-point-p)
- (markdown-inline-code-at-point-p)
- ;; Ignore comments
- (markdown-in-comment-p)
- ;; Ignore special text
- (let ((faces (get-text-property (point) 'face)))
- (if (listp faces)
- (or (memq 'markdown-reference-face faces)
- (memq 'markdown-markup-face faces)
- (memq 'markdown-plain-url-face faces)
- (memq 'markdown-inline-code-face faces)
- (memq 'markdown-url-face faces))
- (memq faces '(markdown-reference-face
- markdown-markup-face
- markdown-plain-url-face
- markdown-inline-code-face
- markdown-url-face))))))
-
- That excludes anything that the developers of markdown-mode felt
-should be excluded from flyspell.
-
- Set this as your exclude function in your dictionary’s settings, then
-add each markdown file by hand.
-
-
-File: paced.info, Node: Repopulating Dictionary After Saving, Next:
Repopulating Dictionary After Spellchecking the Buffer, Prev: Markdown Files,
Up: Example Setups
-
-Repopulating Dictionary After Saving
-====================================
-
-This is a common request, although with the power of async, it’s an easy
-one to fulfill. This will repopulate the current buffer’s dictionary
-every time you save a file with a dictionary. This may seem daunting,
-but the dictionary will remain usable during population, and multiple
-populations won’t interfere with one another.
-
- ;; Repopulate the current dictionary after saving
- (add-hook 'after-save-hook 'paced-repopulate-current-dictionary-async)
-
- Add that to your .emacs file, and paced will take it from there.
-
- If you decide that’s too much, do the following:
-
- M-: (remove-hook 'after-save-hook
'paced-repopulate-current-dictionary-async) RET
-
-
-File: paced.info, Node: Repopulating Dictionary After Spellchecking the
Buffer, Prev: Repopulating Dictionary After Saving, Up: Example Setups
-
-Repopulating Dictionary After Spellchecking the Buffer
-======================================================
-
-Another request, although much trickier to do. This one involves using
-Emacs’s advice mechanism:
-
- (define-advice ispell-pdict-save (:after (&optional _no-query
_force-save) paced-populate)
- ;; Repopulate the current dictionary after running spell check
- (paced-repopulate-current-dictionary-async))
-
- If you decide this isn’t for you, do the following to revert the
-changes:
-
- M-: (advice-remove #'ispell-pdict-save
#'ispell-pdict-save@paced-populate) RET
-
-
-File: paced.info, Node: Contributing, Next: Changelog, Prev: Example
Setups, Up: Top
-
-Contributing
-************
-
-We are all happy for any help you may provide.
-
- First, check out the source code on Savannah:
-<https://savannah.nongnu.org/projects/paced-el>
-
- bzr branch https://bzr.savannah.gnu.org/r/paced-el/ paced
-
- Build the Makefile with EDE:
-
- 1. Open any file from paced (See *note Working with EDE:: if you
- encounter “Corrupt object on disk” error)
- 2. Run ‘C-c . C’ or ‘M-x ede-compile-project’
-
-* Menu:
-
-* Bugs:: Submitting bug reports
-* Development:: Helping with development
-* Documentation:: Improving the documentation
-* Working with EDE:: And all its quirks
-
-
-File: paced.info, Node: Bugs, Next: Development, Up: Contributing
-
-Bugs
-====
-
-There are two ways to submit bug reports:
-
- 1. Using the bug tracker at Savannah
- 2. Sending an email using ‘paced-submit-bug-report’
-
- When submitting a bug report, be sure to include a description of the
-dictionary or population command that caused the problem, with as much
-detail as possible.
-
-
-File: paced.info, Node: Development, Next: Documentation, Prev: Bugs, Up:
Contributing
-
-Development
-===========
-
-If you’re new to bazaar, we recommend using Emacs’s built-in VC package.
-It eases the overhead of dealing with a brand new VCS with a few
-standard commands. For more information, see the info page on it (In
-Emacs, this is C-h r m Introduction to VC RET).
-
- To contribute with bazaar, you can do the following:
-
- # Hack away and make your changes
- $ bzr commit -m "Changes I've made"
- $ bzr send -o file-name.txt
-
- Then, use ‘paced-submit-bug-report’ and attach “file-name.txt”. We
-can then merge that into the main development branch.
-
- There are a few rules to follow:
-
- • New population commands should be named
- paced-POPULATION-COMMAND-TYPE-population-command
- • Run ’make check’ to verify that your mods don’t break anything
- • Avoid additional or altered dependencies if at all possible
- • Dictionary commands come in threes (“the operation triad”):
- 1. paced-dictionary-OPERATION, a cl-defmethod which performs
- OPERATION on a dictionary
- 2. paced-OPERATION-on-named-dictionary, an interactive only
- function that prompts for a dictionary name and performs
- OPERATION on that dictionary:
- (interactive (list (paced-read-dictionary)))
- (paced-ensure-registered name)
- (paced-dictionary-OPERATION (paced-named-dictionary name))
- 3. paced-OPERATION-on-current-dictionary, an interactive function
- that performs OPERATION on the current dictionary
- (interactive)
- (paced-dictionary-OPERATION
(paced-current-dictionary-or-die))
-
-
-File: paced.info, Node: Documentation, Next: Working with EDE, Prev:
Development, Up: Contributing
-
-Documentation
-=============
-
-Documentation is always helpful to us. Please be sure to do the
-following after making any changes:
-
- 1. Update the info page in the repository with ‘C-c C-e i i’
- 2. If you’re updating the HTML documentation, switch to a theme that
- can easily be read on a white background; we recommend the
- “adwaita” theme
-
-
-File: paced.info, Node: Working with EDE, Prev: Documentation, Up:
Contributing
-
-Working with EDE
-================
-
-EDE can be a little finicky at times, but we feel the benefits, namely
-package dependency handling and Makefile generation, outweigh the costs.
-
- One of the issues that many will likely encounter is the error
-“Corrupt file on disk”. This is most often due to EDE not loading all
-its subprojects as needed. If you find yourself dealing with this error
-often, place the following in your .emacs file:
-
- ;; Target types needed for working with paced
- (require 'ede/proj-elisp)
- (require 'ede/proj-aux)
- (require 'ede/proj-misc)
-
- These are the three target types that paced uses: elisp for
-compilation and autoloads; aux for auxiliary files such as
-documentation; and misc for tests.
-
- When creating a new file, EDE will ask if you want to add it to a
-target. Consult with one of the paced devs for guidance, but usually
-selecting “none” and letting one of us handle it is a good way to go.
-
-
-File: paced.info, Node: Changelog, Prev: Contributing, Up: Top
-
-Changelog
-*********
-
-* Menu:
-
-* 1.1.3: 113.
-* 1.1.2: 112.
-* 1.1.1: 111.
-* 1.1: 11.
-* 1.0.1: 101.
-* 1.0: 10.
-
-
-File: paced.info, Node: 113, Next: 112, Up: Changelog
-
-1.1.3
-=====
-
- • Fixed bug with printing an empty dictionary
- • Fixed bug with paced crashing on non-existent thing at point
-
-
-File: paced.info, Node: 112, Next: 111, Prev: 113, Up: Changelog
-
-1.1.2
-=====
-
- • Fixed bug with printing dictionaries
-
-
-File: paced.info, Node: 111, Next: 11, Prev: 112, Up: Changelog
-
-1.1.1
-=====
-
- • Fixed bug with asynchronous population throwing an error on no
- dictionary
-
- • Set ‘paced-throw-error-on-no-current’ to nil by default
-
-
-File: paced.info, Node: 11, Next: 101, Prev: 111, Up: Changelog
-
-1.1
-===
-
- • Cleaned up the code to reflect the “operation triad”
- • -OP, OP-on-named, OP-on-current
- • Retained backwards compatibility by obsoleting a bunch of
- functions, but didn’t remove any of them
- • Also removed the use of dict- in global variables and
- functions
-
- • Added the ability to print the contents of a dictionary in a
- separate buffer
-
- • Added the option to limit the words added during population by size
-
- • Various documentation improvements
-
-
-File: paced.info, Node: 101, Next: 10, Prev: 11, Up: Changelog
-
-1.0.1
-=====
-
-Bug fix release
- • Save dictionaries right after they’re created
- • Added “force” parameter to save functions
-
-
-File: paced.info, Node: 10, Prev: 101, Up: Changelog
-
-1.0
-===
-
-Initial release.
-
-
-
-Tag Table:
-Node: Top228
-Node: Copying2013
-Node: Introduction2832
-Node: Similar Packages3952
-Node: pabbrev4238
-Node: predictive5381
-Node: Installation6429
-Node: Basic Setup7091
-Node: Dictionaries7706
-Node: Creating a Dictionary8179
-Node: Editing a Dictionary9219
-Node: Selective Dictionaries9695
-Node: Dictionary Files11433
-Node: Printing a Dictionary12554
-Node: Population Commands13076
-Node: Built-in Commands14012
-Node: Properties14809
-Node: Custom Commands15807
-Node: Asynchronous Population18534
-Node: Example Setups19983
-Node: Org Agenda Files20284
-Node: Project Files22782
-Node: Markdown Files23918
-Node: Repopulating Dictionary After Saving25543
-Node: Repopulating Dictionary After Spellchecking the Buffer26471
-Node: Contributing27216
-Node: Bugs27990
-Node: Development28379
-Node: Documentation30140
-Node: Working with EDE30607
-Node: Changelog31650
-Node: 11331828
-Node: 11232021
-Node: 11132151
-Node: 1132390
-Node: 10132997
-Node: 1033205
-
-End Tag Table
-
-
-Local Variables:
-coding: utf-8
-End:
diff --git a/packages/paced/paced.org b/packages/paced/paced.org
deleted file mode 100644
index 3ce0f44..0000000
--- a/packages/paced/paced.org
+++ /dev/null
@@ -1,783 +0,0 @@
-#+TITLE: Paced
-#+AUTHOR: Ian Dunn
-#+EMAIL: dunni@gnu.org
-#+DATE: {{{modification-time}}}
-
-#+STARTUP: overview
-#+STARTUP: indent
-#+TODO: FIXME | FIXED
-#+OPTIONS: toc:2 num:nil timestamp:nil \n:nil |:t ':t email:t
-#+OPTIONS: *:t <:t d:nil todo:nil pri:nil tags:not-in-toc
-
-#+TEXINFO_DIR_CATEGORY: Emacs
-#+TEXINFO_DIR_TITLE: Paced: (paced)
-#+TEXINFO_DIR_DESC: Predictive Abbreviation Completion and Expansion using
Dictionaries
-
-* Copying
-Copyright (C) 2017-2018 Free Software Foundation, Inc.
-
-#+BEGIN_QUOTE
-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 <http://www.gnu.org/licenses/>.
-#+END_QUOTE
-* Introduction
-:PROPERTIES:
-:DESCRIPTION: Brief Introduction to paced
-:END:
-Paced (Predictive Abbreviation Completion and Expansion using Dictionaries)
-scans a group of files (determined by "population commands") to construct a
-usage table (dictionary). Words (or symbols) are sorted by their usage, and
may
-be later presented to the user for completion. A dictionary can then be saved
-to a file, to be loaded later.
-
-Population commands determine how a dictionary should be filled with words or
-symbols. A dictionary may have multiple population commands, and population
may
-be performed asynchronously. Once population is finished, the contents are
-sorted, with more commonly used words at the front. Dictionaries may be edited
-through EIEIO's customize-object interface.
-
-Completion is done through ~completion-at-point~. The dictionary to use for
-completion can be customized.
-
-** Similar Packages
-:PROPERTIES:
-:DESCRIPTION: Packages with similar goals
-:END:
-There are a few Emacs packages that have similar goals to paced, and provided
-some of the inspiration and motivation behind it.
-*** pabbrev
-The [[https://github.com/phillord/pabbrev][pabbrev]] package by Phillip Lord
automatically scans text of the current
-buffer while Emacs is idle and presents the user with the most common
-completions.
-
-One of the major downsides to pabbrev is that the data it collects doesn't
-persist between Emacs sessions. For a few files that are always open, such as
-org agenda files, pabbrev works great. If you want to train it from a few
files
-that aren't always open, you'll have to open each file and retrain pabbrev from
-that file. And you'll have to do this every time you restart Emacs.
-
-It keeps up-to-date usage and prefix hashes of all buffers of the same mode,
and
-scanning, or "scavenging", blends seamlessly into the background. Completion
is
-just a hash table lookup, so it can handle completion in microseconds. There's
-also no setup required; it will start working right away. The downside to this
-is that dictionaries aren't flexible; each dictionary corresponds to a major
-mode, and there's no way to change that.
-*** predictive
-The [[https://www.dr-qubit.org/predictive.html][predictive]] package by Toby
Cubitt scans text of the current buffer on user
-command. The usage data is stored in a dictionary, which can then be saved to
a
-disk. Extensions are provided to ~completion-at-point~, or predictive's
built-in
-frontend can be used. It has a safety precaution where it only adds existing
-words to a dictionary, unless the user allows this. This is to avoid adding
-typos to a dictionary.
-
-Completion was also done intelligently, grouping commonly used words together
-and optionally suggesting shorter words before longer words.
-
-While the frontend and backend are separate, the frontend is required to
-populate a dictionary. There is no way to exclude part of the buffer's text
-from dictionary population. The safety precaution predictive has where it only
-adds a word to a dictionary if it already exists was tedious, since I didn't
-need it to do that.
-** Installation
-:PROPERTIES:
-:DESCRIPTION: How to install paced
-:END:
-
-*Requirements*
-
-| Emacs | 25.1 |
-| async | 1.9.1 |
-
-Paced may be installed from source, or from GNU ELPA.
-
-From ELPA:
-
-#+begin_example
-M-x package-install RET paced RET
-#+end_example
-
-From Source:
-
-#+begin_src shell
-bzr branch https://bzr.savannah.gnu.org/r/paced-el paced
-#+end_src
-
-After installing from source, add the following to your init file (typically
.emacs):
-
-#+BEGIN_SRC emacs-lisp
-(add-to-list 'load-path "/full/path/to/paced/")
-(require 'paced)
-#+END_SRC
-
-However you install paced, you must also make sure dictionaries are loaded on
-startup:
-
-#+begin_src emacs-lisp
-(paced-load-all-dictionaries)
-#+end_src
-
-** Basic Setup
-:PROPERTIES:
-:DESCRIPTION: The simplest setup
-:END:
-
-Paced needn't have a lot of setup to run. In fact, the simplest setup is as
-follows:
-
-1. Create a new dictionary, "Default" (See [[#dictionary_creation][Creating a
Dictionary]])
-2. Set ~paced-global-dictionary-enable-alist~ to ~((t . "Default"))~ (See
[[#selective_dictionaries][Selective Dictionaries]])
-3. Run ~M-x global-paced-mode~
-4. To add a file to the dictionary, use ~M-x
paced-add-buffer-file-to-dictionary~
-
-This will create a default dictionary and populate it from buffers you specify.
-
-* Dictionaries
-:PROPERTIES:
-:DESCRIPTION: Paced's bread and butter
-:END:
-** Creating a Dictionary
-:PROPERTIES:
-:DESCRIPTION: First steps
-:CUSTOM_ID: dictionary_creation
-:END:
-
-Now that you've got paced installed, it's time to create a new dictionary.
-
-#+begin_example
-M-x paced-create-new-dictionary RET DICTIONARY_NAME RET DICTIONARY_FILE RET
-#+end_example
-
-Let's explain those two arguments:
-
-First, you've got DICTIONARY_NAME. This is a string that will be used to
-reference the new dictionary. We recommend something short, like 'new-dict',
-'my-dict', 'writing', etc.
-
-Next is the file where the dictionary will be stored. This is typically stored
-in ~paced-dictionary-directory~, from which all dictionaries will be loaded
with
-~paced-load-all-dictionaries~ (more on that later). For now, it's important to
-know that ~paced-load-all-dictionaries~ is the easiest way to load dictionaries
-when paced is loaded.
-
-After you've run the above command, you will be taken to the customization
-buffer. This is where you can set population commands.
-** Editing a Dictionary
-:PROPERTIES:
-:DESCRIPTION: How to edit your new dictionary
-:END:
-In order to edit a dictionary, paced provides ~paced-edit-named-dictionary~ and
-~paced-edit-current-dictionary~.
-
-The edit buffer provides the options to change the population commands, case
-handling, dictionary storage name, and sort method. Each of these is
-documented in the edit buffer.
-** Selective Dictionaries
-:PROPERTIES:
-:DESCRIPTION: Enabling certain dictionaries under certain conditions
-:CUSTOM_ID: selective_dictionaries
-:END:
-
-Paced provides a mechanism called the "enable list", that allows a user to
-enable certain dictionaries for completion given certain conditions.
-
-There are two enable lists: a global (~paced-global-dictionary-enable-alist~)
-and local (~paced-local-dictionary-enable-alist~) one. They both work the
same,
-with the local one taking precedence. Each entry in the list has a condition
-and a key.
-
-The conditions are one of the following:
-
-- A mode name, such as ~org-mode~ or ~text-mode~, indicating that the named
- dictionary should be active in any mode derived from that mode.
-
-- A symbol, in which case the named dictionary is active whenever the value of
- that symbol is non-nil. This includes the symbol ~t~.
-
-- A function symbol, in which case the function is called with no arguments to
- determine if the given dictionary should be enabled. If the function returns
- non-nil the dictionary is enabled.
-
-- A lambda function, in which case it is called with no arguments, and if it
- returns non-nil, the dictionary is enabled.
-
-- The form (or CONDITION1 CONDITION2 ...), which enables the given dictionary
if
- any of the conditions are met.
-
-- The form (and CONDITION1 CONDITION2 ...), which enables the given dictionary
- if all of the conditions are met.
-
-Remember that paced-mode must be active for completion to occur. Neither list
-will activate it, just determine which dictionary is active.
-
-The key is the dictionary name you set during dictionary creation.
-** Dictionary Files
-:PROPERTIES:
-:DESCRIPTION: Loading and Saving the Dictionaries
-:END:
-
-Paced provides ~paced-load-all-dictionaries~ to load all dictionaries in
-~paced-dictionary-directory~. Paced determines which dictionaries to load
based
-on two variables: ~paced-dictionary-directory-whitelist-regexp~ and
-~paced-dictionary-directory-blacklist-regexp~. Paced can also be told to
search
-recursively by setting ~paced-load-all-dictionaries-recursively~ to t. All
four
-of these variables may be set using Emacs's customization interface.
-
-An individual dictionary file may also be loaded:
-
-#+begin_example
-M-x paced-load-dictionary-from-file RET /path/to/file RET
-#+end_example
-
-Once a file has been modified, it may then be saved:
-
-#+begin_example
-M-x paced-save-named-dictionary RET dictionary name RET
-#+end_example
-
-Or, all dictionaries may be saved:
-
-#+begin_example
-M-x paced-save-all-dictionaries RET
-#+end_example
-
-Dictionaries may also be automatically saved whenever changed by setting
-~paced-repopulate-saves-dictionary~ to t. Population is covered in the next
-section.
-** Printing a Dictionary
-:PROPERTIES:
-:DESCRIPTION: Seeing the contents of a dictionary
-:END:
-
-Paced allows a user to print the contents of a dictionary to a buffer. Uses
for
-this might be to tweak population commands or exclude functions, or to simply
-make sure a dictionary is populating correctly.
-
-To use this feature, run:
-
-#+begin_example
-M-x paced-print-named-dictionary RET NAME-OF-DICTIONARY RET
-#+end_example
-
-Or for the current dictionary:
-
-#+begin_example
-M-x paced-print-current-dictionary RET
-#+end_example
-
-* Population Commands
-:PROPERTIES:
-:DESCRIPTION: The good stuff
-:END:
-
-Part of the beauty of paced is the ease of reconstructing a dictionary. When
-you've got a bunch of files from which you want to populate your dictionary,
-it'd be a pain to go to each of them and say "populate from this one, next,
-populate from this one, next".
-
-Instead, paced provides population commands. Each dictionary has one or more
-population commands it uses to recreate its contents, run in order during
-population.
-
-In order to trigger population, run the following:
-
-#+begin_example
-M-x paced-repopulate-named-dictionary RET DICTIONARY-NAME RET
-#+end_example
-
-** Built-in Commands
-:PROPERTIES:
-:DESCRIPTION: Basics
-:END:
-
-There are five built-in population commands:
-
-- file :: Populates a dictionary from all words in a given file
-- buffer :: Populates a dictionary from all words in a given buffer, which must
- exist during population
-- file-function :: Like the file command, but allows a custom setup function.
- This function is called with no arguments in a temporary
- buffer containing the file's contents, and must return
- non-nil if population may continue.
-- directory-regexp :: Populates from all files in a directory that match the
- given regexp. Also optionally allows recursion.
-- file-list :: Populates from all files returned by a generator function.
-
-** Properties
-:PROPERTIES:
-:DESCRIPTION: Tweaking the defaults
-:END:
-
-When setting the population commands of a dictionary, one may also set certain
-properties. Each property is a variable binding, bound while the population
-command runs.
-
-A few variables are of note here:
-
-- paced-exclude-function :: Function of no arguments that returns non-nil if
the
- thing at point should be excluded from population.
-- paced-thing-at-point-constituent :: Symbol defining thing on which population
- works. Typically set to either 'symbol or 'word.
-- paced-character-limit :: Maximum length of a thing to include it in a
- dictionary. If set to 0 (default), no limit is imposed.
-
-For convenience, properties that are intended for all population commands of a
-given dictionary may be set in the dictionary itself. In the event of a
-conflict, population command properties take precedence over dictionary
-properties.
-
-** Custom Commands
-:PROPERTIES:
-:DESCRIPTION: Defining new population commands
-:END:
-Since the population commands all derive from paced-population-command, it's
-possible to add additional commands.
-
-As an example, let's make a population command that populates a dictionary from
-a file like so:
-
-#+begin_example
-alpha 5
-beta 7
-gamma 21
-delta 54
-epsilon 2
-#+end_example
-
-We want to make a population command that takes a file like this, with word in
-one column and weight in the other, and add it to a dictionary.
-
-There are two ways to approach this, but we're going to start with the basic
one.
-
-We need to define two functions: paced-population-command-source-list and
-paced-population-command-setup-buffer. The first returns a list of sources
from
-which to populate, and the second sets up a temporary buffer based on those
-sources.
-
-For our command, we want to return the specified file, and replicate each word
-by the amount given.
-
-Inheriting from ~paced-file-population-command~ gives us the source list and
file
-slot for free.
-
-#+begin_src emacs-lisp
-(defclass paced-weight-file-population-command (paced-file-population-command))
-#+end_src
-
-Now, we need to set up the buffer to replicate the words.
-
-#+begin_src emacs-lisp
-(cl-defmethod paced-population-command-setup-buffer ((cmd
paced-weight-file-population-command) source)
- ;; Use the built-in `paced--insert-file-contents' to insert contents.
- (paced--insert-file-contents source)
- ;; Jump to the start of the buffer
- (goto-char (point-min))
- ;; Search for lines with the form WORD WEIGHT
- (while (re-search-forward (rx line-start ;; Start of line
- (submatch (one-or-more (not (syntax
whitespace)))) ;; Our word
- (syntax whitespace) ;; Space between word and
weight
- (submatch (one-or-more (any digit))) ;; Weight
- line-end) ;; End of line
- nil t)
- (let* ((word (match-string 1))
- (weight (string-to-number (match-string 2)))
- ;; Repeat WORD WEIGHT times
- (new-text (string-join (make-list weight word) " ")))
- ;; Replace the matched text with our repeated word
- (replace-match new-text))))
-#+end_src
-
-That's all there is to it. When you go to edit a dictionary, the "weight-file"
-population command will automatically be added as an option for a population
-command.
-
-The even easier way to do this would've been to use
-~paced-file-function-population-command~, but it doesn't make for a good
example
-in this case.
-
-** Asynchronous Population
-:PROPERTIES:
-:DESCRIPTION: Populating without blocking
-:END:
-A common problem is that population can take a long time. Some of us populate
-dictionaries from org agenda files, which can get pretty big.
-
-To solve this, paced uses the
[[https://github.com/jwiegley/emacs-async][async]] package. Setup is seamless;
just stick
-whatever code you need in ~~/.emacs.d/paced-async.el~, and use one of the two
-population commands:
-
-A named dictionary:
-
-#+begin_example
-M-x paced-repopulate-named-dictionary-async RET NAME RET
-#+end_example
-
-Or the current dictionary:
-
-#+begin_example
-M-x paced-repopulate-current-dictionary-async RET
-#+end_example
-
-A few things to note about this:
-
-1. Dictionaries will be automatically saved by this method after population
-2. Asynchronous population doesn't change anything until after population is
- finished, so a user may continue to use their dictionary while population is
- happening. This also means that multiple populations may run in parallel
- without interfering with one another.
-3. Because async runs population in a separate Emacs process, any custom code
- required for population must be in paced-async.el. This includes additional
- population command types, but doesn't include the following variables:
-
- - load-path
- - paced-thing-at-point-constituent
- - paced-async-load-file
-
-* Example Setups
-:PROPERTIES:
-:DESCRIPTION: Some examples
-:END:
-** Org Agenda Files
-As some of us record everything about our lives in our agenda files, it might
be
-helpful to have a dictionary tuned to ourselves.
-
-We use a file-list command that returns the agenda files, and an exclude
command
-to block out all of Org's extra features such as source code and drawers.
-
-The generator for file-list is easy:
-
-#+begin_src emacs-lisp
-org-agenda-files
-#+end_src
-
-Done.
-
-Now, the exclude command, which sits inside the properties option. This can be
-added to ~paced-async.el~:
-
-#+begin_src emacs-lisp
-(require 'org)
-
-(defun org-at-tag-p ()
- (let* ((p (point)))
- ;; Ignore errors from `org-get-tags-string'.
- (ignore-errors
- ;; Checks the match string for a tag heading, setting match-string 1 to
the
- ;; tags. Also sets match-beginning and match-end.
- (org-get-tags-string)
- (when (match-string 1)
- (<= (match-beginning 1) p (match-end 1))))))
-
-(defun org-at-keyword-p ()
- "Return non-nil if point is at a keyword such as #+TITLE."
- (save-excursion
- (beginning-of-line)
- (looking-at-p "^#\\+")))
-
-(defun org-at-heading-prefix-p ()
- "Return non-nil if looking at the leading stars of a heading."
- (looking-at outline-regexp))
-
-(defun org-at-hline-p ()
- (save-excursion
- (beginning-of-line)
- (looking-at-p "^-----")))
-
-(defun org-paced-exclude ()
- (or
- ;; Drawers
- (org-between-regexps-p org-drawer-regexp ":END:") ;; Doesn't catch END
- (org-in-regexp ":END:") ;; but this does
-
- (org-at-tag-p) ;; tags
- (org-at-keyword-p) ;; Keywords, such as #+TITLE
- (org-at-heading-prefix-p) ;; Leading stars of a heading
- (org-at-item-bullet-p) ;; Item Bullets
- (org-at-timestamp-p) ;; Timestamps
- (looking-at-p org-todo-regexp) ;; TODO keywords
- (org-at-hline-p) ;; H-lines
-
- (org-at-comment-p) ;; comments
- (org-in-regexp org-any-link-re) ;; links
- (org-in-block-p '("src" "quote" "verse")) ;; blocks
- (org-at-planning-p) ;; deadline, etc.
- (org-at-table-p) ;; tables
- ))
-#+end_src
-
-As explained earlier, this can be put inside properties in the customize
buffer as such:
-
-#+begin_example
-Properties :
-[INS] [DEL] Variable: paced-exclude-function
-Lisp expression: 'org-paced-exclude
-#+end_example
-
-And you're done. See how easy that was?
-** Project Files
-Now we get to the interesting one. There are tons of ways to collect project
-files in Emacs, so we're going to stick with one for now, being Emacs's
built-in
-VC package.
-
-#+begin_src emacs-lisp
-(defun vc-paced-find-project-files (path-to-project-root)
- "Use VC to collect all version-controlled files."
- (let ((file-list))
- (vc-file-tree-walk path-to-project-root (lambda (f) (push f file-list)))
- file-list))
-#+end_src
-
-We'd then need to use the following for our file-list generator:
-
-#+begin_example
-Generator : (lambda nil (vc-paced-find-project-files
"/home/me/programming/paced"))
-#+end_example
-
-Now, we (probably) don't want commented code to get in our way, so we'll use a
-small function for excluding those:
-
-#+begin_src emacs-lisp
-(defun paced-at-comment-p ()
- (nth 8 (syntax-ppss)))
-#+end_src
-
-Use that for paced-exclude-function, and you're done. We can't necessarily
-recommend this for any programming language, as there are dedicated solutions
-for almost everything, but it makes an excellent fallback.
-** Markdown Files
-
-Another common request is markdown files. In order for this to work, you'll
need to install ~markdown-mode~:
-
-#+begin_example
-M-x package-install RET markdown-mode RET
-#+end_example
-
-After that, add the following to your ~paced-async.el~ file:
-
-#+begin_src emacs-lisp
-(require 'markdown-mode)
-
-(defun paced-markdown-exclude-p ()
- "Taken from `markdown-flyspell-check-word-p'."
- ;; Exclude anything markdown mode thinks flyspell should skip.
- (or
- ;; Ignore code blocks
- (markdown-code-block-at-point-p)
- (markdown-inline-code-at-point-p)
- ;; Ignore comments
- (markdown-in-comment-p)
- ;; Ignore special text
- (let ((faces (get-text-property (point) 'face)))
- (if (listp faces)
- (or (memq 'markdown-reference-face faces)
- (memq 'markdown-markup-face faces)
- (memq 'markdown-plain-url-face faces)
- (memq 'markdown-inline-code-face faces)
- (memq 'markdown-url-face faces))
- (memq faces '(markdown-reference-face
- markdown-markup-face
- markdown-plain-url-face
- markdown-inline-code-face
- markdown-url-face))))))
-#+end_src
-
-That excludes anything that the developers of markdown-mode felt should be
-excluded from flyspell.
-
-Set this as your exclude function in your dictionary's settings, then add each
-markdown file by hand.
-
-** Repopulating Dictionary After Saving
-
-This is a common request, although with the power of async, it's an easy one to
-fulfill. This will repopulate the current buffer's dictionary every time you
-save a file with a dictionary. This may seem daunting, but the dictionary will
-remain usable during population, and multiple populations won't interfere with
-one another.
-
-#+begin_src emacs-lisp
-;; Repopulate the current dictionary after saving
-(add-hook 'after-save-hook 'paced-repopulate-current-dictionary-async)
-#+end_src
-
-Add that to your .emacs file, and paced will take it from there.
-
-If you decide that's too much, do the following:
-
-#+begin_example
-M-: (remove-hook 'after-save-hook 'paced-repopulate-current-dictionary-async)
RET
-#+end_example
-
-** Repopulating Dictionary After Spellchecking the Buffer
-
-Another request, although much trickier to do. This one involves using Emacs's
-advice mechanism:
-
-#+begin_src emacs-lisp
-(define-advice ispell-pdict-save (:after (&optional _no-query _force-save)
paced-populate)
- ;; Repopulate the current dictionary after running spell check
- (paced-repopulate-current-dictionary-async))
-#+end_src
-
-If you decide this isn't for you, do the following to revert the changes:
-
-#+begin_example
-M-: (advice-remove #'ispell-pdict-save #'ispell-pdict-save@paced-populate) RET
-#+end_example
-
-* Contributing
-:PROPERTIES:
-:DESCRIPTION: I wanna help!
-:CUSTOM_ID: contributing
-:END:
-
-We are all happy for any help you may provide.
-
-First, check out the source code on Savannah:
https://savannah.nongnu.org/projects/paced-el
-
-#+BEGIN_SRC shell
-bzr branch https://bzr.savannah.gnu.org/r/paced-el/ paced
-#+END_SRC
-
-Build the Makefile with EDE:
-
-1. Open any file from paced (See [[#ede][Working with EDE]] if you encounter
"Corrupt object on disk" error)
-2. Run ~C-c . C~ or ~M-x ede-compile-project~
-
-** Bugs
-:PROPERTIES:
-:CUSTOM_ID: bugs
-:DESCRIPTION: Submitting bug reports
-:END:
-
-There are two ways to submit bug reports:
-
-1. Using the bug tracker at Savannah
-2. Sending an email using ~paced-submit-bug-report~
-
-When submitting a bug report, be sure to include a description of the
dictionary
-or population command that caused the problem, with as much detail as possible.
-
-** Development
-:PROPERTIES:
-:CUSTOM_ID: development
-:DESCRIPTION: Helping with development
-:END:
-
-If you're new to bazaar, we recommend using Emacs's built-in VC package. It
-eases the overhead of dealing with a brand new VCS with a few standard
commands.
-For more information, see the info page on it (In Emacs, this is
-C-h r m Introduction to VC RET).
-
-To contribute with bazaar, you can do the following:
-
-#+begin_src shell
-# Hack away and make your changes
-$ bzr commit -m "Changes I've made"
-$ bzr send -o file-name.txt
-#+end_src
-
-Then, use ~paced-submit-bug-report~ and attach "file-name.txt". We can then
merge
-that into the main development branch.
-
-There are a few rules to follow:
-
-- New population commands should be named
paced-POPULATION-COMMAND-TYPE-population-command
-- Run 'make check' to verify that your mods don't break anything
-- Avoid additional or altered dependencies if at all possible
-- Dictionary commands come in threes ("the operation triad"):
- 1. paced-dictionary-OPERATION, a cl-defmethod which performs OPERATION on a
dictionary
- 2. paced-OPERATION-on-named-dictionary, an interactive only function that
prompts
- for a dictionary name and performs OPERATION on that dictionary:
- #+begin_src emacs-lisp
- (interactive (list (paced-read-dictionary)))
- (paced-ensure-registered name)
- (paced-dictionary-OPERATION (paced-named-dictionary name))
- #+end_src
- 3. paced-OPERATION-on-current-dictionary, an interactive function that
- performs OPERATION on the current dictionary
- #+begin_src emacs-lisp
- (interactive)
- (paced-dictionary-OPERATION (paced-current-dictionary-or-die))
- #+end_src
-
-** Documentation
-:PROPERTIES:
-:CUSTOM_ID: docs
-:DESCRIPTION: Improving the documentation
-:END:
-
-Documentation is always helpful to us. Please be sure to do the following
after
-making any changes:
-
-1. Update the info page in the repository with ~C-c C-e i i~
-2. If you're updating the HTML documentation, switch to a theme that can easily
- be read on a white background; we recommend the "adwaita" theme
-
-** Working with EDE
-:PROPERTIES:
-:CUSTOM_ID: ede
-:DESCRIPTION: And all its quirks
-:END:
-
-EDE can be a little finicky at times, but we feel the benefits, namely package
-dependency handling and Makefile generation, outweigh the costs.
-
-One of the issues that many will likely encounter is the error "Corrupt file on
-disk". This is most often due to EDE not loading all its subprojects as
needed.
-If you find yourself dealing with this error often, place the following in your
-.emacs file:
-
-#+begin_src emacs-lisp
-;; Target types needed for working with paced
-(require 'ede/proj-elisp)
-(require 'ede/proj-aux)
-(require 'ede/proj-misc)
-#+end_src
-
-These are the three target types that paced uses: elisp for compilation and
-autoloads; aux for auxiliary files such as documentation; and misc for tests.
-
-When creating a new file, EDE will ask if you want to add it to a target.
-Consult with one of the paced devs for guidance, but usually selecting "none"
-and letting one of us handle it is a good way to go.
-
-* Changelog
-:PROPERTIES:
-:DESCRIPTION: List of changes by version
-:END:
-** 1.1.3
-- Fixed bug with printing an empty dictionary
-- Fixed bug with paced crashing on non-existent thing at point
-** 1.1.2
-- Fixed bug with printing dictionaries
-** 1.1.1
-- Fixed bug with asynchronous population throwing an error on no dictionary
-
-- Set ~paced-throw-error-on-no-current~ to nil by default
-** 1.1
-- Cleaned up the code to reflect the "operation triad"
- - -OP, OP-on-named, OP-on-current
- - Retained backwards compatibility by obsoleting a bunch of functions, but
didn't remove any of them
- - Also removed the use of dict- in global variables and functions
-
-- Added the ability to print the contents of a dictionary in a separate buffer
-
-- Added the option to limit the words added during population by size
-
-- Various documentation improvements
-** 1.0.1
-Bug fix release
-- Save dictionaries right after they're created
-- Added "force" parameter to save functions
-** 1.0
-Initial release.
diff --git a/packages/paced/test-files/first.txt
b/packages/paced/test-files/first.txt
deleted file mode 100644
index d20283f..0000000
--- a/packages/paced/test-files/first.txt
+++ /dev/null
@@ -1 +0,0 @@
-one two three four two three four three four four
diff --git a/packages/paced/test-files/fourth.org
b/packages/paced/test-files/fourth.org
deleted file mode 100644
index 2d7b9ad..0000000
--- a/packages/paced/test-files/fourth.org
+++ /dev/null
@@ -1,2 +0,0 @@
-#+CATEGORY: Testing
-Test1 Test2
diff --git a/packages/paced/test-files/second.cpp
b/packages/paced/test-files/second.cpp
deleted file mode 100644
index 2078554..0000000
--- a/packages/paced/test-files/second.cpp
+++ /dev/null
@@ -1 +0,0 @@
-// empty file that doesn't inherit from text mode
diff --git a/packages/paced/test-files/third.org
b/packages/paced/test-files/third.org
deleted file mode 100644
index 8c15311..0000000
--- a/packages/paced/test-files/third.org
+++ /dev/null
@@ -1 +0,0 @@
-five five five five five six six seven six
diff --git a/packages/paced/test.mk b/packages/paced/test.mk
deleted file mode 100644
index fa886a3..0000000
--- a/packages/paced/test.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2017-2018 Free Software Foundation, Inc.
-
-# 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 <http://www.gnu.org/licenses/>.
-
-# EDE only allows arbitrary code from an external makefile, so this is how
we've
-# got to do testing.
-
-test: compile
- @$(EMACS) \
- $(EMACSFLAGS) \
- -L "." \
- -l "ert" \
- -l "paced-tests.el" \
- -f ert-run-tests-batch-and-exit
-
-include Makefile
diff --git a/packages/swiper/swiper.el b/packages/swiper/swiper.el
deleted file mode 100644
index 10813a4..0000000
--- a/packages/swiper/swiper.el
+++ /dev/null
@@ -1,1673 +0,0 @@
-;;; swiper.el --- Isearch with an overview. Oh, man! -*- lexical-binding: t -*-
-
-;; Copyright (C) 2015-2019 Free Software Foundation, Inc.
-
-;; Author: Oleh Krehel <ohwoeowho@gmail.com>
-;; URL: https://github.com/abo-abo/swiper
-;; Version: 0.13.1
-;; Package-Requires: ((emacs "24.5") (ivy "0.13.1"))
-;; Keywords: matching
-
-;; This file is part of GNU 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, 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.
-
-;; For a full copy of the GNU General Public License
-;; see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This package gives an overview of the current regex search
-;; candidates. The search regex can be split into groups with a
-;; space. Each group is highlighted with a different face.
-;;
-;; It can double as a quick `regex-builder', although only single
-;; lines will be matched.
-
-;;; Code:
-
-(require 'ivy)
-
-(defgroup swiper nil
- "`isearch' with an overview."
- :group 'matching
- :prefix "swiper-")
-
-(defface swiper-match-face-1
- '((t (:inherit lazy-highlight)))
- "The background face for `swiper' matches."
- :group 'ivy-faces)
-
-(defface swiper-match-face-2
- '((t (:inherit isearch)))
- "Face for `swiper' matches modulo 1."
- :group 'ivy-faces)
-
-(defface swiper-match-face-3
- '((t (:inherit match)))
- "Face for `swiper' matches modulo 2."
- :group 'ivy-faces)
-
-(defface swiper-match-face-4
- '((t (:inherit isearch-fail)))
- "Face for `swiper' matches modulo 3."
- :group 'ivy-faces)
-
-(defface swiper-background-match-face-1
- '((t (:inherit swiper-match-face-1)))
- "The background face for non-current `swiper' matches."
- :group 'ivy-faces)
-
-(defface swiper-background-match-face-2
- '((t (:inherit swiper-match-face-2)))
- "Face for non-current `swiper' matches modulo 1."
- :group 'ivy-faces)
-
-(defface swiper-background-match-face-3
- '((t (:inherit swiper-match-face-3)))
- "Face for non-current `swiper' matches modulo 2."
- :group 'ivy-faces)
-
-(defface swiper-background-match-face-4
- '((t (:inherit swiper-match-face-4)))
- "Face for non-current `swiper' matches modulo 3."
- :group 'ivy-faces)
-
-(defface swiper-line-face
- '((t (:inherit highlight)))
- "Face for current `swiper' line."
- :group 'ivy-faces)
-
-(defcustom swiper-faces '(swiper-match-face-1
- swiper-match-face-2
- swiper-match-face-3
- swiper-match-face-4)
- "List of `swiper' faces for group matches."
- :group 'ivy-faces
- :type '(repeat face))
-
-(defvar swiper-background-faces
- '(swiper-background-match-face-1
- swiper-background-match-face-2
- swiper-background-match-face-3
- swiper-background-match-face-4)
- "Like `swiper-faces', but used for all matches except the current one.")
-
-(defun swiper--recompute-background-faces ()
- (let ((faces '(swiper-background-match-face-1
- swiper-background-match-face-2
- swiper-background-match-face-3
- swiper-background-match-face-4))
- (colir-compose-method #'colir-compose-soft-light))
- (cl-mapc (lambda (f1 f2)
- (let ((bg (face-background f1)))
- (when bg
- (set-face-background
- f2
- (colir-blend
- (colir-color-parse bg)
- (colir-color-parse "#ffffff"))))))
- swiper-faces
- faces)))
-(swiper--recompute-background-faces)
-
-(defcustom swiper-min-highlight 2
- "Only highlight matches for regexps at least this long."
- :type 'integer)
-
-(defcustom swiper-include-line-number-in-search nil
- "Include line number in text of search candidates."
- :type 'boolean
- :group 'swiper)
-
-(defcustom swiper-goto-start-of-match nil
- "When non-nil, go to the start of the match, not its end.
-Treated as non-nil when searching backwards."
- :type 'boolean
- :group 'swiper)
-
-(defvar swiper-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "M-q") 'swiper-query-replace)
- (define-key map (kbd "C-l") 'swiper-recenter-top-bottom)
- (define-key map (kbd "C-'") 'swiper-avy)
- (define-key map (kbd "C-7") 'swiper-mc)
- (define-key map (kbd "C-c C-f") 'swiper-toggle-face-matching)
- map)
- "Keymap for swiper.")
-
-(defvar swiper--query-replace-overlays nil)
-
-(defun swiper--query-replace-updatefn ()
- (let ((lisp (ignore-errors (nth 2 (query-replace-compile-replacement
ivy-text t)))))
- (dolist (ov swiper--query-replace-overlays)
- (when lisp
- (dolist (x (overlay-get ov 'matches))
- (setq lisp (cl-subst (cadr x) (car x) lisp :test #'equal)))
- (setq lisp (ignore-errors (eval lisp))))
- (overlay-put
- ov 'after-string
- (propertize
- (if (stringp lisp)
- lisp
- ivy-text)
- 'face 'error)))))
-
-(defun swiper--query-replace-cleanup ()
- (while swiper--query-replace-overlays
- (delete-overlay (pop swiper--query-replace-overlays))))
-
-(defun swiper--query-replace-setup ()
- (with-ivy-window
- (let ((end (window-end (selected-window) t))
- (re (ivy--regex ivy-text)))
- (save-excursion
- (beginning-of-line)
- (while (and (re-search-forward re end t)
- (not (eobp)))
- (let ((ov (make-overlay (1- (match-end 0)) (match-end 0)))
- (md (match-data)))
- (overlay-put
- ov 'matches
- (mapcar
- (lambda (x)
- (list `(match-string ,x) (match-string x)))
- (number-sequence 0 (1- (/ (length md) 2)))))
- (push ov swiper--query-replace-overlays))
- (unless (> (match-end 0) (match-beginning 0))
- (forward-char)))))))
-
-(defun swiper-query-replace ()
- "Start `query-replace' with string to replace from last search string."
- (interactive)
- (cond ((null (window-minibuffer-p))
- (user-error "Should only be called in the minibuffer through
`swiper-map'"))
- ((string= "" ivy-text)
- (user-error "Empty input"))
- (t
- (swiper--query-replace-setup)
- (unwind-protect
- (let* ((enable-recursive-minibuffers t)
- (from (ivy--regex ivy-text))
- (default
- (format "\\,(concat %s)"
- (if (<= ivy--subexps 1)
- "\\&"
- (mapconcat (lambda (i) (format "\\%d" i))
- (number-sequence 1 ivy--subexps)
- " \" \" "))))
- (to
- (query-replace-compile-replacement
- (ivy-read
- (format "Query replace %s with: " from) nil
- :def default
- :caller 'swiper-query-replace)
- t)))
- (swiper--cleanup)
- (ivy-exit-with-action
- (lambda (_)
- (with-ivy-window
- (move-beginning-of-line 1)
- (let ((inhibit-read-only t))
- (perform-replace from to
- t t nil))))))
- (swiper--query-replace-cleanup)))))
-
-(ivy-configure 'swiper-query-replace
- :update-fn #'swiper--query-replace-updatefn)
-
-(defvar inhibit-message)
-
-(defun swiper-all-query-replace ()
- "Start `query-replace' with string to replace from last search string."
- (interactive)
- (if (null (window-minibuffer-p))
- (user-error
- "Should only be called in the minibuffer through `swiper-all-map'")
- (let* ((enable-recursive-minibuffers t)
- (from (ivy--regex ivy-text))
- (to (query-replace-read-to from "Query replace" t)))
- (swiper--cleanup)
- (ivy-exit-with-action
- (lambda (_)
- (let ((wnd-conf (current-window-configuration))
- (inhibit-message t))
- (unwind-protect
- (dolist (cand ivy--old-cands)
- (let ((buffer (get-text-property 0 'buffer cand)))
- (switch-to-buffer buffer)
- (goto-char (point-min))
- (perform-replace from to t t nil)))
- (set-window-configuration wnd-conf))))))))
-
-(defvar avy-all-windows)
-(defvar avy-style)
-(defvar avy-keys)
-(declare-function avy--overlay-post "ext:avy")
-(declare-function avy-action-goto "ext:avy")
-(declare-function avy-candidate-beg "ext:avy")
-(declare-function avy--done "ext:avy")
-(declare-function avy--make-backgrounds "ext:avy")
-(declare-function avy-window-list "ext:avy")
-(declare-function avy-read "ext:avy")
-(declare-function avy-read-de-bruijn "ext:avy")
-(declare-function avy-tree "ext:avy")
-(declare-function avy-push-mark "ext:avy")
-(declare-function avy--remove-leading-chars "ext:avy")
-
-(defun swiper--avy-candidates ()
- (let* (
- ;; We'll have overlapping overlays, so we sort all the
- ;; overlays in the visible region by their start, and then
- ;; throw out non-Swiper overlays or overlapping Swiper
- ;; overlays.
- (visible-overlays (cl-sort (with-ivy-window
- (overlays-in (window-start)
- (window-end)))
- #'< :key #'overlay-start))
- (min-overlay-start 0)
- (overlays-for-avy
- (cl-remove-if-not
- (lambda (ov)
- (when (and (>= (overlay-start ov)
- min-overlay-start)
- (memq (overlay-get ov 'face)
- (append swiper-faces swiper-background-faces)))
- (setq min-overlay-start (overlay-start ov))))
- visible-overlays))
- (offset (if (eq (ivy-state-caller ivy-last) 'swiper) 1 0)))
- (nconc
- (mapcar (lambda (ov)
- (cons (overlay-start ov)
- (overlay-get ov 'window)))
- overlays-for-avy)
- (save-excursion
- (save-restriction
- (narrow-to-region (window-start) (window-end))
- (goto-char (point-min))
- (forward-line)
- (let ((win (selected-window))
- cands)
- (while (not (eobp))
- (push (cons (+ (point) offset) win)
- cands)
- (forward-line))
- cands))))))
-
-(defun swiper--avy-candidate ()
- (let ((candidates (swiper--avy-candidates))
- (avy-all-windows nil))
- (unwind-protect
- (prog2
- (avy--make-backgrounds
- (append (avy-window-list)
- (list (ivy-state-window ivy-last))))
- (if (eq avy-style 'de-bruijn)
- (avy-read-de-bruijn candidates avy-keys)
- (avy-read (avy-tree candidates avy-keys)
- #'avy--overlay-post
- #'avy--remove-leading-chars))
- (avy-push-mark))
- (avy--done))))
-
-(defun swiper--avy-goto (candidate)
- (cond ((let ((win (cdr-safe candidate)))
- (and win (window-minibuffer-p win)))
- (let ((nlines (count-lines (point-min) (point-max))))
- (ivy-set-index
- (+ (car (ivy--minibuffer-index-bounds
- ivy--index ivy--length ivy-height))
- (line-number-at-pos (car candidate))
- (if (or (= nlines (1+ ivy-height))
- (< ivy--length ivy-height))
- 0
- (- ivy-height nlines))
- -2)))
- (ivy--exhibit)
- (ivy-done)
- (ivy-call))
- ((or (consp candidate)
- (number-or-marker-p candidate))
- (ivy-quit-and-run
- (avy-action-goto (avy-candidate-beg candidate))))))
-
-;;;###autoload
-(defun swiper-avy ()
- "Jump to one of the current swiper candidates."
- (interactive)
- (unless (require 'avy nil 'noerror)
- (error "Package avy isn't installed"))
- (cl-case (length ivy-text)
- (0
- (user-error "Need at least one char of input"))
- (1
- (let ((swiper-min-highlight 1))
- (swiper--update-input-ivy))))
- (swiper--avy-goto (swiper--avy-candidate)))
-
-(declare-function mc/create-fake-cursor-at-point "ext:multiple-cursors-core")
-(declare-function multiple-cursors-mode "ext:multiple-cursors-core")
-
-(defun swiper-mc ()
- "Create a fake cursor for each `swiper' candidate.
-Make sure `swiper-mc' is on `mc/cmds-to-run-once' list."
- (interactive)
- (unless (require 'multiple-cursors nil t)
- (error "Multiple-cursors isn't installed"))
- (unless (window-minibuffer-p)
- (error "Call me only from `swiper'"))
- (let ((cands (nreverse ivy--old-cands))
- (action (ivy--get-action ivy-last)))
- (unless (string= ivy-text "")
- (ivy-exit-with-action
- (lambda (_)
- (let (cand)
- (while (setq cand (pop cands))
- (funcall action cand)
- (when cands
- (mc/create-fake-cursor-at-point))))
- (multiple-cursors-mode 1))))))
-
-(defvar swiper--current-window-start nil
- "Store `window-start' to restore it later.
-This prevents a \"jumping\" behavior which occurs when variables
-such as `scroll-conservatively' are set to a high value.")
-
-(defun swiper-recenter-top-bottom (&optional arg)
- "Call (`recenter-top-bottom' ARG)."
- (interactive "P")
- (with-ivy-window
- (recenter-top-bottom arg)
- (setq swiper--current-window-start (window-start))))
-
-(defvar swiper-font-lock-exclude
- '(Man-mode
- adoc-mode
- bbdb-mode
- bongo-library-mode
- bongo-mode
- bongo-playlist-mode
- bookmark-bmenu-mode
- circe-channel-mode
- circe-query-mode
- circe-server-mode
- deadgrep-mode
- debbugs-gnu-mode
- dired-mode
- elfeed-search-mode
- elfeed-show-mode
- emms-playlist-mode
- emms-stream-mode
- erc-mode
- eshell-mode
- eww-mode
- forth-block-mode
- forth-mode
- fundamental-mode
- gnus-article-mode
- gnus-group-mode
- gnus-summary-mode
- help-mode
- helpful-mode
- jabber-chat-mode
- magit-popup-mode
- matrix-client-mode
- matrix-client-room-list-mode
- mu4e-headers-mode
- mu4e-view-mode
- nix-mode
- notmuch-search-mode
- notmuch-tree-mode
- occur-edit-mode
- occur-mode
- org-agenda-mode
- package-menu-mode
- rcirc-mode
- sauron-mode
- treemacs-mode
- twittering-mode
- vc-dir-mode
- w3m-mode
- woman-mode
- xref--xref-buffer-mode)
- "List of major-modes that are incompatible with `font-lock-ensure'.")
-
-(defun swiper-font-lock-ensure-p ()
- "Return non-nil if we should `font-lock-ensure'."
- (or (derived-mode-p 'magit-mode)
- (bound-and-true-p magit-blame-mode)
- (memq major-mode swiper-font-lock-exclude)
- (not (derived-mode-p 'prog-mode))))
-
-(defun swiper-font-lock-ensure ()
- "Ensure the entire buffer is highlighted."
- (unless (swiper-font-lock-ensure-p)
- (unless (or (> (buffer-size) 100000) (null font-lock-mode))
- (if (fboundp 'font-lock-ensure)
- (font-lock-ensure)
- (with-no-warnings (font-lock-fontify-buffer))))))
-
-(defvar swiper--format-spec ""
- "Store the current candidates format spec.")
-
-(defvar swiper--width nil
- "Store the number of digits needed for the longest line number.")
-
-(defvar swiper-use-visual-line nil
- "When non-nil, use `line-move' instead of `forward-line'.")
-
-(defvar dired-isearch-filenames)
-(declare-function dired-move-to-filename "dired")
-
-(defun swiper--line ()
- (let* ((beg (cond ((and (eq major-mode 'dired-mode)
- (bound-and-true-p dired-isearch-filenames))
- (dired-move-to-filename)
- (point))
- (swiper-use-visual-line
- (save-excursion
- (beginning-of-visual-line)
- (point)))
- (t
- (point))))
- (end (if swiper-use-visual-line
- (save-excursion
- (end-of-visual-line)
- (point))
- (line-end-position))))
-
- (concat
- " "
- (buffer-substring beg end))))
-
-(declare-function outline-show-all "outline")
-
-(defvar swiper-use-visual-line-p
- (lambda (n-lines)
- (and visual-line-mode
- ;; super-slow otherwise
- (< (buffer-size) 20000)
- (< n-lines 400)))
- "A predicate that decides whether `line-move' or `forward-line' is used.
-Note that `line-move' can be very slow.")
-
-(defun swiper--candidates (&optional numbers-width)
- "Return a list of this buffer lines.
-
-NUMBERS-WIDTH, when specified, is used for width spec of line
-numbers; replaces calculating the width from buffer line count."
- (let* ((inhibit-field-text-motion t)
- (n-lines (count-lines (point-min) (point-max))))
- (if (funcall swiper-use-visual-line-p n-lines)
- (progn
- (when (eq major-mode 'org-mode)
- (require 'outline)
- (if (fboundp 'outline-show-all)
- (outline-show-all)
- (with-no-warnings
- (show-all))))
- (setq swiper-use-visual-line t))
- (setq swiper-use-visual-line nil))
- (unless (zerop n-lines)
- (setq swiper--width (or numbers-width
- (1+ (floor (log n-lines 10)))))
- (setq swiper--format-spec
- (format "%%-%dd " swiper--width))
- (let ((line-number 1)
- (advancer (if swiper-use-visual-line
- (lambda (arg) (line-move arg t))
- #'forward-line))
- candidates)
- (save-excursion
- (goto-char (point-min))
- (swiper-font-lock-ensure)
- (while (< (point) (point-max))
- (when (swiper-match-usable-p)
- (let ((str (swiper--line)))
- (setq str (ivy-cleanup-string str))
- (let ((line-number-str
- (format swiper--format-spec line-number)))
- (if swiper-include-line-number-in-search
- (setq str (concat line-number-str str))
- (put-text-property
- 0 1 'display line-number-str str))
- (put-text-property
- 0 1 'swiper-line-number line-number str))
- (push str candidates)))
- (funcall advancer 1)
- (cl-incf line-number))
- (nreverse candidates))))))
-
-(defvar swiper--opoint 1
- "The point when `swiper' starts.")
-
-;;;###autoload
-(defun swiper-backward (&optional initial-input)
- "`isearch-backward' with an overview.
-When non-nil, INITIAL-INPUT is the initial search pattern."
- (interactive)
- (let ((ivy-index-functions-alist
- '((swiper . ivy-recompute-index-swiper-backward))))
- (swiper initial-input)))
-
-;;;###autoload
-(defun swiper-thing-at-point ()
- "`swiper' with `ivy-thing-at-point'."
- (interactive)
- (let ((thing (ivy-thing-at-point)))
- (when (use-region-p)
- (deactivate-mark))
- (swiper thing)))
-
-;;;###autoload
-(defun swiper-all-thing-at-point ()
- "`swiper-all' with `ivy-thing-at-point'."
- (interactive)
- (let ((thing (ivy-thing-at-point)))
- (when (use-region-p)
- (deactivate-mark))
- (swiper-all thing)))
-
-(defun swiper--extract-matches (regex cands)
- "Extract captured REGEX groups from CANDS."
- (let (res)
- (dolist (cand cands)
- (setq cand (substring cand 1))
- (when (string-match regex cand)
- (push (mapconcat (lambda (n) (match-string-no-properties n cand))
- (number-sequence
- 1
- (/ (- (length (match-data)) 2) 2))
- " ")
- res)))
- (nreverse res)))
-
-(defun swiper--occur-cands (fname cands)
- (when cands
- (with-current-buffer (ivy-state-buffer ivy-last)
- (when (eq (ivy-state-caller ivy-last) 'swiper-isearch)
- (setq cands (mapcar #'swiper--line-at-point cands)))
- (let* ((pt-min (point-min))
- (line-delta
- (save-restriction
- (widen)
- (1- (line-number-at-pos pt-min))))
- (lines
- (if (eq (ivy-state-caller ivy-last) 'swiper-isearch)
- (swiper--isearch-occur-cands cands)
- (mapcar (lambda (s)
- (let ((n (get-text-property 0 'swiper-line-number
s)))
- (setq s (substring s 1))
- (add-text-properties 0 1 (list 'swiper-line-number
n) s)
- (cons n s)))
- cands)))
- (offset (+ (length fname) 2)))
- (mapcar (lambda (x)
- (let ((nn (number-to-string
- (+ (car x) line-delta))))
- (remove-text-properties 0 1 '(display) (cdr x))
- (put-text-property 0 (length nn) 'face
'ivy-grep-line-number nn)
- (put-text-property 0 1 'offset (+ offset (length nn))
fname)
- (format "%s:%s:%s" fname nn (cdr x))))
- lines)))))
-
-(defun swiper--isearch-occur-cands (cands)
- (let* ((last-pt (get-text-property 0 'point (car cands)))
- (line (1+ (line-number-at-pos last-pt)))
- res pt)
- (dolist (cand cands)
- (setq pt (get-text-property 0 'point cand))
- (cl-incf line (1- (count-lines last-pt pt)))
- (push (cons line cand) res)
- (setq last-pt pt))
- (nreverse res)))
-
-(defun swiper--occur-insert-lines (cands)
- (let ((inhibit-read-only t))
- ;; Need precise number of header lines for `wgrep' to work.
- (insert (format "-*- mode:grep; default-directory: %S -*-\n\n\n"
- default-directory))
- (insert (format "%d candidates:\n" (length cands)))
- (ivy--occur-insert-lines cands)
- (goto-char (point-min))
- (forward-line 4)))
-
-(defun swiper--occur-buffer ()
- (let ((buffer (ivy-state-buffer ivy-last)))
- (unless (buffer-live-p buffer)
- (setq buffer
- (setf (ivy-state-buffer ivy-last)
- (find-file-noselect
- (plist-get (ivy-state-extra-props ivy-last) :fname))))
- (save-selected-window
- (pop-to-buffer buffer))
- (setf (ivy-state-window ivy-last) (selected-window)))
- buffer))
-
-(defun swiper-occur (&optional cands)
- "Generate a custom occur buffer for `swiper'.
-When capture groups are present in the input, print them instead of lines."
- (let* ((buffer (swiper--occur-buffer))
- (fname (propertize
- (with-ivy-window
- (if (buffer-file-name buffer)
- (file-name-nondirectory
- (buffer-file-name buffer))
- (buffer-name buffer)))
- 'face
- 'ivy-grep-info))
- (ivy-text (progn (string-match "\"\\(.*\\)\"" (buffer-name))
- (match-string 1 (buffer-name))))
- (re (mapconcat #'identity (ivy--split ivy-text) ".*?"))
- (cands
- (swiper--occur-cands
- fname
- (or cands
- (save-window-excursion
- (setq ivy--old-re nil)
- (switch-to-buffer buffer)
- (if (eq (ivy-state-caller ivy-last) 'swiper)
- (let ((ivy--regex-function 'swiper--re-builder))
- (ivy--filter re (swiper--candidates)))
- (swiper-isearch-function ivy-text)))))))
- (if (string-match-p "\\\\(" re)
- (insert
- (mapconcat #'identity
- (swiper--extract-matches
- re (with-current-buffer buffer
- (swiper--candidates)))
- "\n"))
- (unless (eq major-mode 'ivy-occur-grep-mode)
- (ivy-occur-grep-mode)
- (font-lock-mode -1))
- (swiper--occur-insert-lines
- (mapcar (lambda (cand) (concat "./" cand)) cands)))))
-
-(declare-function evil-set-jump "ext:evil-jumps")
-
-(defvar swiper--current-line nil)
-(defvar swiper--current-match-start nil)
-(defvar swiper--point-min nil)
-(defvar swiper--point-max nil)
-(defvar swiper--reveal-mode nil)
-
-(defun swiper--init ()
- "Perform initialization common to both completion methods."
- (setq swiper--current-line nil)
- (setq swiper--current-match-start nil)
- (setq swiper--current-window-start nil)
- (setq swiper--opoint (point))
- (setq swiper--point-min (point-min))
- (setq swiper--point-max (point-max))
- (when (setq swiper--reveal-mode
- (bound-and-true-p reveal-mode))
- (reveal-mode -1))
- (lazy-highlight-cleanup t)
- (setq isearch-opened-overlays nil)
- (when (bound-and-true-p evil-mode)
- (evil-set-jump)))
-
-(declare-function char-fold-to-regexp "char-fold")
-
-(defun swiper--re-builder (str)
- "Transform STR into a swiper regex.
-This is the regex used in the minibuffer where candidates have
-line numbers. For the buffer, use `ivy--regex' instead."
- (let* ((re-builder (ivy-alist-setting ivy-re-builders-alist))
- (re (cond
- ((equal str "")
- "")
- ((equal str "^")
- (setq ivy--subexps 0)
- ".")
- ((= (aref str 0) ?^)
- (let* ((re (funcall re-builder (substring str 1)))
- (re (if (listp re)
- (mapconcat (lambda (x)
- (format "\\(%s\\)" (car x)))
- (cl-remove-if-not #'cdr re)
- ".*?")
- re)))
- (cond
- ((string= re "$")
- "^$")
- ((zerop ivy--subexps)
- (prog1 (format "^ ?\\(%s\\)" re)
- (setq ivy--subexps 1)))
- (t
- (format "^ %s" re)))))
- ((eq (bound-and-true-p search-default-mode)
'char-fold-to-regexp)
- (if (string-match "\\`\\\\_<\\(.+\\)\\\\_>\\'" str)
- (concat
- "\\_<"
- (char-fold-to-regexp (match-string 1 str))
- "\\_>")
- (let ((subs (ivy--split str)))
- (setq ivy--subexps (length subs))
- (mapconcat
- (lambda (s) (format "\\(%s\\)" (char-fold-to-regexp s)))
- subs
- ".*?"))))
- (t
- (funcall re-builder str)))))
- re))
-
-(defvar swiper-history nil
- "History for `swiper'.")
-
-(defvar swiper-invocation-face nil
- "The face at the point of invocation of `swiper'.")
-
-(defcustom swiper-stay-on-quit nil
- "When non-nil don't go back to search start on abort."
- :type 'boolean)
-
-;;;###autoload
-(defun swiper (&optional initial-input)
- "`isearch-forward' with an overview.
-When non-nil, INITIAL-INPUT is the initial search pattern."
- (interactive)
- (let ((candidates (swiper--candidates)))
- (swiper--init)
- (setq swiper-invocation-face
- (plist-get (text-properties-at (point)) 'face))
- (let ((preselect
- (if (or swiper-use-visual-line (null search-invisible))
- (count-screen-lines
- (point-min)
- (save-excursion (beginning-of-visual-line) (point)))
- (1- (line-number-at-pos))))
- (minibuffer-allow-text-properties t)
- res)
- (unwind-protect
- (and
- (setq res
- (ivy-read
- "Swiper: "
- candidates
- :initial-input initial-input
- :keymap swiper-map
- :preselect
- (if initial-input
- (cl-position-if
- (lambda (x)
- (= (1+ preselect) (get-text-property 0
'swiper-line-number x)))
- (progn
- (setq ivy--old-re nil)
- (ivy--filter initial-input candidates)))
- preselect)
- :require-match t
- :action #'swiper--action
- :re-builder #'swiper--re-builder
- :history 'swiper-history
- :extra-props (list :fname (buffer-file-name))
- :caller 'swiper))
- (point))
- (unless (or res swiper-stay-on-quit)
- (goto-char swiper--opoint))
- (unless (or res (string= ivy-text ""))
- (cl-pushnew ivy-text swiper-history))
- (setq swiper--current-window-start nil)
- (when swiper--reveal-mode
- (reveal-mode 1))))))
-
-(ivy-configure 'swiper
- :occur #'swiper-occur
- :update-fn #'swiper--update-input-ivy
- :unwind-fn #'swiper--cleanup
- :index-fn #'ivy-recompute-index-swiper)
-
-(defun swiper-toggle-face-matching ()
- "Toggle matching only the candidates with `swiper-invocation-face'."
- (interactive)
- (setf (ivy-state-matcher ivy-last)
- (if (ivy-state-matcher ivy-last)
- nil
- #'swiper--face-matcher))
- (setq ivy--old-re nil))
-
-(defun swiper--face-matcher (regexp candidates)
- "Return REGEXP matching CANDIDATES.
-Matched candidates should have `swiper-invocation-face'."
- (cl-remove-if-not
- (lambda (x)
- (and (string-match regexp x)
- (let* ((s (match-string 0 x))
- (n (length s))
- (i 0))
- (while (and (< i n)
- (text-property-any
- i (1+ i)
- 'face swiper-invocation-face
- s))
- (cl-incf i))
- (= i n))))
- candidates))
-
-(defun swiper--ensure-visible ()
- "Remove overlays hiding point."
- (let ((overlays (overlays-at (1- (point))))
- ov expose)
- (while (setq ov (pop overlays))
- (if (and (invisible-p (overlay-get ov 'invisible))
- (setq expose (overlay-get ov 'isearch-open-invisible)))
- (funcall expose ov)))))
-
-(defvar swiper--overlays nil
- "Store overlays.")
-
-(defvar swiper--isearch-highlight-timer nil
- "This timer used by `swiper--delayed-add-overlays'.")
-
-(defun swiper--cleanup ()
- "Clean up the overlays."
- (while swiper--overlays
- (delete-overlay (pop swiper--overlays)))
- ;; force cleanup unless it's :unwind
- (lazy-highlight-cleanup
- (if (eq ivy-exit 'done) lazy-highlight-cleanup t))
- (when (timerp swiper--isearch-highlight-timer)
- (cancel-timer swiper--isearch-highlight-timer)
- (setq swiper--isearch-highlight-timer nil)))
-
-(defun swiper--add-cursor-overlay (wnd)
- (let* ((special (or (eolp) (looking-at "\t")))
- (ov (make-overlay (point) (if special (point) (1+ (point))))))
- (if special
- (overlay-put ov 'after-string (propertize " " 'face 'ivy-cursor))
- (overlay-put ov 'face 'ivy-cursor))
- (overlay-put ov 'window wnd)
- (overlay-put ov 'priority 2)
- (push ov swiper--overlays)))
-
-(defun swiper--add-line-overlay (wnd)
- (let ((beg (if visual-line-mode
- (save-excursion
- (beginning-of-visual-line)
- (point))
- (line-beginning-position)))
- (end (if visual-line-mode
- (save-excursion
- (end-of-visual-line)
- (point))
- (1+ (line-end-position)))))
- (push (swiper--make-overlay beg end 'swiper-line-face wnd 0)
- swiper--overlays)))
-
-(defun swiper--make-overlay (beg end face wnd priority)
- "Create an overlay bound by BEG and END.
-FACE, WND and PRIORITY are properties corresponding to
-the face, window and priority of the overlay."
- (let ((overlay (make-overlay beg end)))
- (overlay-put overlay 'face face)
- (overlay-put overlay 'window wnd)
- (overlay-put overlay 'priority priority)
- overlay))
-
-(defun swiper--recenter-p ()
- (or (display-graphic-p)
- (not recenter-redisplay)))
-
-(defun swiper--positive-regexps (str)
- (let ((regexp-or-regexps
- (funcall ivy--regex-function str)))
- (if (listp regexp-or-regexps)
- (mapcar #'car (cl-remove-if-not #'cdr regexp-or-regexps))
- (list regexp-or-regexps))))
-
-(defun swiper--update-input-ivy ()
- "Called when `ivy' input is updated."
- (with-ivy-window
- (swiper--cleanup)
- (when (> (length (ivy-state-current ivy-last)) 0)
- (let ((regexps (swiper--positive-regexps ivy-text))
- (re-idx -1)
- (case-fold-search (ivy--case-fold-p ivy-text)))
- (dolist (re regexps)
- (setq re-idx (1+ re-idx))
- (let* ((re (replace-regexp-in-string
- " " "\t"
- re))
- (num (get-text-property 0 'swiper-line-number
(ivy-state-current ivy-last))))
- (unless (memq this-command '(ivy-yank-word
- ivy-yank-symbol
- ivy-yank-char
- scroll-other-window))
- (when (cl-plusp num)
- (unless (if swiper--current-line
- (eq swiper--current-line num)
- (eq (line-number-at-pos) num))
- (goto-char swiper--point-min)
- (if swiper-use-visual-line
- (line-move (1- num))
- (forward-line (1- num))))
- (if (and (equal ivy-text "")
- (>= swiper--opoint (line-beginning-position))
- (<= swiper--opoint (line-end-position)))
- (goto-char swiper--opoint)
- (if (eq swiper--current-line num)
- (when swiper--current-match-start
- (goto-char swiper--current-match-start))
- (setq swiper--current-line num))
- (when (re-search-forward re (line-end-position) t)
- (setq swiper--current-match-start (match-beginning 0))))
- (isearch-range-invisible (line-beginning-position)
- (line-end-position))
- (swiper--maybe-recenter)))
- (swiper--add-overlays
- re
- (max
- (if (swiper--recenter-p)
- (window-start)
- (line-beginning-position (- (window-height))))
- swiper--point-min)
- (min
- (if (swiper--recenter-p)
- (window-end (selected-window) t)
- (line-end-position (window-height)))
- swiper--point-max)
- nil
- re-idx)))))))
-
-(defun swiper--add-overlays (re &optional beg end wnd re-idx)
- "Add overlays for RE regexp in visible part of the current buffer.
-BEG and END, when specified, are the point bounds.
-WND, when specified is the window."
- (setq wnd (or wnd (ivy-state-window ivy-last)))
- (swiper--add-line-overlay wnd)
- (let* ((pt (point))
- (wh (window-height))
- (beg (or beg (save-excursion
- (forward-line (- wh))
- (point))))
- (end (or end (save-excursion
- (forward-line wh)
- (point))))
- (case-fold-search (ivy--case-fold-p re)))
- (when (>= (length re) swiper-min-highlight)
- (save-excursion
- (goto-char beg)
- ;; RE can become an invalid regexp
- (while (and (ignore-errors (re-search-forward re end t))
- (> (- (match-end 0) (match-beginning 0)) 0))
- ;; Don't highlight a match if it spans multiple
- ;; lines. `count-lines' returns 1 if the match is within a
- ;; single line, even if it includes the newline, and 2 or
- ;; greater otherwise. We hope that the inclusion of the
- ;; newline will not ever be a problem in practice.
- (when (< (count-lines (match-beginning 0) (match-end 0)) 2)
- (let* ((faces (if (= (match-end 0) pt)
- swiper-faces
- swiper-background-faces))
- (adder-fn (lambda (beg end face priority)
- (push (swiper--make-overlay beg end face wnd
priority)
- isearch-lazy-highlight-overlays))))
- (unless (and (consp ivy--old-re)
- (null
- (save-match-data
- (ivy--re-filter ivy--old-re
- (list
- (buffer-substring-no-properties
- (line-beginning-position)
- (line-end-position)))))))
- (swiper--add-properties faces adder-fn re-idx)))))))))
-
-(defun swiper--add-properties (faces adder-fn &optional re-idx)
- (let ((mb (match-beginning 0))
- (me (match-end 0)))
- (unless (> (- me mb) 2017)
- (funcall adder-fn
- mb me
- (if (zerop ivy--subexps)
- (nth (1+ (mod (or re-idx 0) (1- (length faces)))) faces)
- (car faces))
- 0)))
- (let ((i 1)
- (j 0))
- (while (<= (cl-incf j) ivy--subexps)
- (let ((bm (match-beginning j))
- (em (match-end j)))
- (when (and (integerp em)
- (integerp bm))
- (while (and (< j ivy--subexps)
- (integerp (match-beginning (+ j 1)))
- (= em (match-beginning (+ j 1))))
- (setq em (match-end (cl-incf j))))
- (funcall adder-fn
- bm em
- (nth (1+ (mod (+ i 2) (1- (length faces))))
- faces)
- i)
- (cl-incf i))))))
-
-(defcustom swiper-action-recenter nil
- "When non-nil, recenter after exiting `swiper'."
- :type 'boolean)
-(defvar evil-search-module)
-(defvar evil-ex-search-pattern)
-(defvar evil-ex-search-persistent-highlight)
-(defvar evil-ex-search-direction)
-(declare-function evil-ex-search-activate-highlight "evil-ex")
-
-(defun swiper--maybe-recenter ()
- (cond (swiper-action-recenter
- (recenter))
- ((swiper--recenter-p)
- (when swiper--current-window-start
- (set-window-start (selected-window) swiper--current-window-start))
- (when (or
- (< (point) (window-start))
- (> (point) (window-end (ivy-state-window ivy-last) t)))
- (recenter))))
- (setq swiper--current-window-start (window-start)))
-
-(defun swiper--action (x)
- "Goto line X."
- (let ((ln (1- (get-text-property 0 'swiper-line-number x)))
- (re (ivy--regex ivy-text))
- (case-fold-search (ivy--case-fold-p ivy-text)))
- (if (null x)
- (user-error "No candidates")
- (with-ivy-window
- (unless (equal (current-buffer)
- (ivy-state-buffer ivy-last))
- (switch-to-buffer (ivy-state-buffer ivy-last)))
- (goto-char
- (if (buffer-narrowed-p)
- swiper--point-min
- (point-min)))
- (funcall (if swiper-use-visual-line
- #'line-move
- #'forward-line)
- ln)
- (when (and (re-search-forward re (line-end-position) t)
swiper-goto-start-of-match)
- (goto-char (match-beginning 0)))
- (swiper--ensure-visible)
- (swiper--maybe-recenter)
- (when (/= (point) swiper--opoint)
- (unless (and transient-mark-mode mark-active)
- (when (eq ivy-exit 'done)
- (push-mark swiper--opoint t)
- (message "Mark saved where search started"))))
- (add-to-history
- 'regexp-search-ring
- re
- regexp-search-ring-max)
- ;; integration with evil-mode's search
- (when (bound-and-true-p evil-mode)
- (when (eq evil-search-module 'isearch)
- (setq isearch-string ivy-text))
- (when (eq evil-search-module 'evil-search)
- (add-to-history 'evil-ex-search-history re)
- (setq evil-ex-search-pattern (list re t t))
- (setq evil-ex-search-direction 'forward)
- (when evil-ex-search-persistent-highlight
- (evil-ex-search-activate-highlight evil-ex-search-pattern))))))))
-
-(defun swiper-from-isearch ()
- "Invoke `swiper' from isearch."
- (interactive)
- (let ((query (if isearch-regexp
- isearch-string
- (regexp-quote isearch-string))))
- (isearch-exit)
- (swiper query)))
-
-(defvar swiper-multi-buffers nil
- "Store the current list of buffers.")
-
-(defvar swiper-multi-candidates nil
- "Store the list of candidates for `swiper-multi'.")
-
-(defun swiper-multi-prompt ()
- "Return prompt for `swiper-multi'."
- (format "Buffers (%s): "
- (mapconcat #'identity swiper-multi-buffers ", ")))
-
-(defvar swiper-window-width 80)
-
-(defun swiper-multi ()
- "Select one or more buffers.
-Run `swiper' for those buffers."
- (interactive)
- (setq swiper-multi-buffers nil)
- (let ((ivy-use-virtual-buffers nil))
- (ivy-read (swiper-multi-prompt)
- #'internal-complete-buffer
- :action #'swiper-multi-action-1))
- (let ((swiper-window-width (- (- (frame-width) (if (display-graphic-p) 0 1))
4)))
- (ivy-read "Swiper: " swiper-multi-candidates
- :action #'swiper-multi-action-2
- :caller 'swiper-multi)))
-
-(ivy-configure 'swiper-multi
- :unwind-fn #'swiper--cleanup
- :index-fn #'ivy-recompute-index-swiper
- :format-fn #'swiper--all-format-function)
-
-(defun swiper-multi-action-1 (x)
- "Add X to list of selected buffers `swiper-multi-buffers'.
-If X is already part of the list, remove it instead. Quit the selection if
-X is selected by either `ivy-done', `ivy-alt-done' or `ivy-immediate-done',
-otherwise continue prompting for buffers."
- (if (member x swiper-multi-buffers)
- (progn
- (setq swiper-multi-buffers (delete x swiper-multi-buffers)))
- (unless (equal x "")
- (setq swiper-multi-buffers (append swiper-multi-buffers (list x)))))
- (let ((prompt (swiper-multi-prompt)))
- (setf (ivy-state-prompt ivy-last) prompt)
- (setq ivy--prompt (concat "%-4d " prompt)))
- (cond ((memq this-command '(ivy-done
- ivy-alt-done
- ivy-immediate-done))
- (setq swiper-multi-candidates
- (swiper--multi-candidates
- (mapcar #'get-buffer swiper-multi-buffers))))
- ((eq this-command 'ivy-call)
- (with-selected-window (active-minibuffer-window)
- (delete-minibuffer-contents)))))
-
-(defun swiper-multi-action-2 (x)
- "Move to candidate X from `swiper-multi'."
- (when (> (length x) 0)
- (let ((buffer-name (get-text-property 0 'buffer x)))
- (when buffer-name
- (with-ivy-window
- (switch-to-buffer buffer-name)
- (goto-char (point-min))
- (forward-line (1- (get-text-property 0 'swiper-line-number x)))
- (re-search-forward
- (ivy--regex ivy-text)
- (line-end-position) t)
- (isearch-range-invisible (line-beginning-position)
- (line-end-position))
- (unless (eq ivy-exit 'done)
- (swiper--cleanup)
- (swiper--add-overlays (ivy--regex ivy-text))))))))
-
-(defun swiper-all-buffer-p (buffer)
- "Return non-nil if BUFFER should be considered by `swiper-all'."
- (let ((mode (buffer-local-value 'major-mode (get-buffer buffer))))
- (cond
- ;; Ignore TAGS buffers, they tend to add duplicate results.
- ((eq mode #'tags-table-mode) nil)
- ;; Always consider dired buffers, even though they're not backed
- ;; by a file.
- ((eq mode #'dired-mode) t)
- ;; Always consider stash buffers too, as they may have
- ;; interesting content not present in any buffers. We don't #'
- ;; quote to satisfy the byte-compiler.
- ((eq mode 'magit-stash-mode) t)
- ;; Email buffers have no file, but are useful to search
- ((eq mode 'gnus-article-mode) t)
- ;; Otherwise, only consider the file if it's backed by a file.
- (t (buffer-file-name buffer)))))
-
-;;* `swiper-all'
-(defun swiper-all-function (str)
- "Search in all open buffers for STR."
- (or
- (ivy-more-chars)
- (let* ((buffers (cl-remove-if-not #'swiper-all-buffer-p (buffer-list)))
- (re-full (funcall ivy--regex-function str))
- re re-tail
- cands match
- (case-fold-search (ivy--case-fold-p str)))
- (setq re (ivy-re-to-str re-full))
- (when (consp re-full)
- (setq re-tail (cdr re-full)))
- (dolist (buffer buffers)
- (with-current-buffer buffer
- (save-excursion
- (goto-char (point-min))
- (while (re-search-forward re nil t)
- (setq match (if (memq major-mode '(org-mode dired-mode))
- (buffer-substring-no-properties
- (line-beginning-position)
- (line-end-position))
- (buffer-substring
- (line-beginning-position)
- (line-end-position))))
- (put-text-property
- 0 1 'buffer
- (buffer-name)
- match)
- (put-text-property 0 1 'point (point) match)
- (when (or (null re-tail) (ivy-re-match re-tail match))
- (push match cands))))))
- (setq ivy--old-re re-full)
- (if (null cands)
- (list "")
- (setq ivy--old-cands (nreverse cands))))))
-
-(defun swiper--all-format-function (cands)
- "Format CANDS for `swiper-all'.
-See `ivy-format-functions-alist' for further information."
- (let* ((ww swiper-window-width)
- (col2 1)
- (cands-with-buffer
- (mapcar (lambda (s)
- (let ((buffer (get-text-property 0 'buffer s)))
- (setq col2 (max col2 (length buffer)))
- (cons s buffer))) cands))
- (col1 (- ww 4 col2)))
- (setq cands
- (mapcar (lambda (x)
- (if (cdr x)
- (let ((s (ivy--truncate-string (car x) col1)))
- (concat
- s
- (make-string
- (max 0
- (- ww (string-width s) (length (cdr x))))
- ?\ )
- (cdr x)))
- (car x)))
- cands-with-buffer))
- (ivy--format-function-generic
- (lambda (str)
- (ivy--add-face str 'ivy-current-match))
- (lambda (str)
- str)
- cands
- "\n")))
-
-(defvar swiper-all-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "M-q") 'swiper-all-query-replace)
- map)
- "Keymap for `swiper-all'.")
-
-;;;###autoload
-(defun swiper-all (&optional initial-input)
- "Run `swiper' for all open buffers."
- (interactive)
- (let ((swiper-window-width (- (frame-width) (if (display-graphic-p) 0 1))))
- (ivy-read "swiper-all: " 'swiper-all-function
- :action #'swiper-all-action
- :dynamic-collection t
- :keymap swiper-all-map
- :initial-input initial-input
- :caller 'swiper-all)))
-
-(ivy-configure 'swiper-all
- :update-fn 'auto
- :unwind-fn #'swiper--cleanup
- :format-fn #'swiper--all-format-function)
-
-(defun swiper-all-action (x)
- "Move to candidate X from `swiper-all'."
- (when (> (length x) 0)
- (let ((buffer-name (get-text-property 0 'buffer x)))
- (when buffer-name
- (with-ivy-window
- (switch-to-buffer buffer-name)
- (goto-char (get-text-property 0 'point x))
- (isearch-range-invisible (line-beginning-position)
- (line-end-position))
- (unless (eq ivy-exit 'done)
- (swiper--cleanup)
- (swiper--add-overlays (ivy--regex ivy-text))))))))
-
-(defun swiper--multi-candidates (buffers)
- "Extract candidates from BUFFERS."
- (let ((res nil))
- (dolist (buf buffers)
- (with-current-buffer buf
- (setq res
- (nconc
- (mapcar
- (lambda (s) (put-text-property 0 1 'buffer (buffer-name) s) s)
- (swiper--candidates 4))
- res))))
- res))
-
-;;* `swiper-isearch'
-(defun swiper-isearch-function (str)
- "Collect STR matches in the current buffer for `swiper-isearch'."
- (with-ivy-window
- (swiper--isearch-function str)))
-
-(defun swiper-match-usable-p ()
- (or search-invisible
- (not (cl-find-if
- (lambda (ov)
- (invisible-p (overlay-get ov 'invisible)))
- (overlays-at (point))))))
-
-(defvar swiper--isearch-backward nil)
-(defvar swiper--isearch-start-point nil)
-
-(defun swiper--isearch-function-1 (re backward)
- (unless (string= re ".")
- (let (cands)
- (save-excursion
- (goto-char (if backward (point-max) (point-min)))
- (while (and (funcall (if backward #'re-search-backward
#'re-search-forward) re nil t)
- (not (if backward (bobp) (eobp))))
- (when (swiper-match-usable-p)
- (let ((pos (if (or backward swiper-goto-start-of-match)
- (match-beginning 0)
- (point))))
- (push pos cands)))
- (when (= (match-beginning 0) (match-end 0))
- (if backward
- (backward-char)
- (forward-char)))))
- (if backward
- cands
- (nreverse cands)))))
-
-(defun swiper--isearch-next-item (re cands)
- (if swiper--isearch-backward
- (or
- (cl-position-if
- (lambda (x)
- (and
- (< x swiper--isearch-start-point)
- (eq 0 (string-match-p
- re
- (buffer-substring-no-properties
- x swiper--isearch-start-point)))))
- cands
- :from-end t)
- 0)
- (or
- (cl-position-if
- (lambda (x) (> x swiper--isearch-start-point))
- cands)
- 0)))
-
-(defun swiper--isearch-filter-ignore-order (re-full cands)
- (let (filtered-cands)
- (dolist (re-cons re-full cands)
- (save-excursion
- (dolist (cand cands)
- (goto-char cand)
- (beginning-of-line)
- (unless (if (re-search-forward (car re-cons) (line-end-position) t)
- (not (cdr re-cons))
- (cdr re-cons))
- (push cand filtered-cands))))
- (setq cands (nreverse filtered-cands))
- (setq filtered-cands nil))))
-
-(defun swiper--isearch-function (str)
- (let ((re-full (funcall ivy--regex-function str)))
- (unless (equal re-full "")
- (let* ((case-fold-search (ivy--case-fold-p str))
- (re
- (if (stringp re-full)
- re-full
- (mapconcat
- #'ivy--regex-or-literal
- (delq nil (mapcar (lambda (x) (and (cdr x) (car x))) re-full))
- "\\|")))
- (cands (swiper--isearch-function-1 re swiper--isearch-backward)))
- (when (consp re-full)
- (setq cands (swiper--isearch-filter-ignore-order re-full cands)))
- (setq ivy--old-re re)
- (ivy-set-index (swiper--isearch-next-item re cands))
- (setq ivy--old-cands cands)))))
-
-(defcustom swiper-isearch-highlight-delay '(2 0.2)
- "When `ivy-text' is too short, delay showing the overlay.
-
-The default value will delay showing the overlay by 0.2 seconds
-if `ivy-text' is shorter than 2 characters.
-
-The aim is to reduce the visual clutter, since it's very rare
-that we search only for one character."
- :type '(list
- (integer :tag "Text length")
- (float :tag "Delay in seconds")))
-
-(defun swiper--delayed-add-overlays ()
- (if (and swiper-isearch-highlight-delay
- (< (length ivy-text) (car swiper-isearch-highlight-delay)))
- (setq swiper--isearch-highlight-timer
- (run-with-idle-timer
- (cadr swiper-isearch-highlight-delay) nil
- (lambda ()
- (with-ivy-window
- (swiper--add-overlays (ivy--regex ivy-text))))))
- (dolist (re (swiper--positive-regexps ivy-text))
- (swiper--add-overlays re))))
-
-(defun swiper-isearch-action (x)
- "Move to X for `swiper-isearch'."
- (if (or (numberp x)
- (and (> (length x) 0)
- (setq x (get-text-property 0 'point x))))
- (with-ivy-window
- (goto-char x)
- (when (and (or (eq this-command 'ivy-previous-line-or-history)
- (and (eq this-command 'ivy-done)
- (eq last-command 'ivy-previous-line-or-history)))
- (looking-back ivy--old-re (line-beginning-position)))
- (goto-char (match-beginning 0)))
- (isearch-range-invisible (point) (1+ (point)))
- (swiper--maybe-recenter)
- (unless (eq ivy-exit 'done)
- (swiper--cleanup)
- (swiper--delayed-add-overlays)
- (swiper--add-cursor-overlay
- (ivy-state-window ivy-last))))
- (swiper--cleanup)))
-
-(defun swiper-action-copy (_x)
- "Copy line at point and go back."
- (kill-new
- (buffer-substring-no-properties
- (line-beginning-position) (line-end-position)))
- (goto-char swiper--opoint))
-
-(ivy-add-actions 'swiper-isearch '(("w" swiper-action-copy "copy")))
-(ivy-add-actions 'swiper '(("w" swiper-action-copy "copy")))
-
-(defun swiper-isearch-thing-at-point ()
- "Insert `symbol-at-point' into the minibuffer of `swiper-isearch'.
-When not running `swiper-isearch' already, start it."
- (interactive)
- (if (window-minibuffer-p)
- (let (bnd str regionp)
- (with-ivy-window
- (setq bnd
- (if (setq regionp (region-active-p))
- (prog1 (cons (region-beginning) (region-end))
- (deactivate-mark))
- (bounds-of-thing-at-point 'symbol)))
- (setq str (buffer-substring-no-properties (car bnd) (cdr bnd))))
- (insert str)
- (unless regionp
- (ivy--insert-symbol-boundaries)))
- (let (thing)
- (if (use-region-p)
- (progn
- (setq thing (buffer-substring-no-properties
- (region-beginning) (region-end)))
- (goto-char (region-beginning))
- (deactivate-mark))
- (let ((bnd (bounds-of-thing-at-point 'symbol)))
- (when bnd
- (goto-char (car bnd)))
- (setq thing (ivy-thing-at-point))))
- (swiper-isearch thing))))
-
-(defvar swiper-isearch-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map swiper-map)
- (define-key map (kbd "M-n") 'swiper-isearch-thing-at-point)
- map)
- "Keymap for `swiper-isearch'.")
-
-(defun swiper--isearch-same-line-p (s1 s2)
- "Check if S1 and S2 are equal and on the same line."
- (and (equal s1 s2)
- (<= (count-lines
- (get-text-property 0 'point s2)
- (get-text-property 0 'point s1))
- 1)))
-
-(defun swiper-isearch-format-function (cands)
- (if (numberp (car-safe cands))
- (if (string= ivy--old-re "^$")
- ""
- (swiper--isearch-format
- ivy--index ivy--length ivy--old-cands
- ivy--old-re
- (ivy-state-current ivy-last)
- (ivy-state-buffer ivy-last)))
- (ivy-format-function-default cands)))
-
-(defun swiper--line-at-point (pt)
- (save-excursion
- (goto-char pt)
- (let ((s (buffer-substring
- (line-beginning-position)
- (line-end-position))))
- (put-text-property 0 1 'point pt s)
- (ivy-cleanup-string s))))
-
-(defun swiper--isearch-highlight (str &optional current)
- (let ((start 0)
- (i 0))
- (while (string-match ivy--old-re str start)
- (setq start (match-end 0))
- (swiper--add-properties
- (if (eq current i)
- swiper-faces
- swiper-background-faces)
- (lambda (beg end face _priority)
- (ivy-add-face-text-property
- beg end face str)))
- (cl-incf i))
- str))
-
-(defun swiper--isearch-format (index length cands regex current buffer)
- (let* ((half-height (/ ivy-height 2))
- (i (1- index))
- (j 0)
- (len 0)
- res s)
- (with-current-buffer buffer
- (while (and (>= i 0)
- (swiper--isearch-same-line-p
- (swiper--line-at-point (nth i cands))
- (swiper--line-at-point current)))
- (cl-decf i)
- (cl-incf j))
- (while (and (>= i 0)
- (< len half-height))
- (setq s (swiper--line-at-point (nth i cands)))
- (unless (swiper--isearch-same-line-p s (car res))
- (push (swiper--isearch-highlight s) res)
- (cl-incf len))
- (cl-decf i))
- (setq res (nreverse res))
- (let ((current-str
- (swiper--line-at-point current))
- (start 0))
- (dotimes (_ (1+ j))
- (string-match regex current-str start)
- (setq start (match-end 0)))
- (swiper--isearch-highlight current-str j)
- (font-lock-append-text-property
- 0 (length current-str)
- 'face 'swiper-line-face current-str)
- (push current-str res))
- (cl-incf len)
- (setq i (1+ index))
- (while (and (< i length)
- (swiper--isearch-same-line-p
- (swiper--line-at-point (nth i cands))
- (swiper--line-at-point current)))
- (cl-incf i))
- (while (and (< i length)
- (< len ivy-height))
- (setq s (swiper--line-at-point (nth i cands)))
- (unless (swiper--isearch-same-line-p s (car res))
- (push (swiper--isearch-highlight s) res)
- (cl-incf len))
- (cl-incf i))
- (mapconcat #'identity (nreverse res) "\n"))))
-
-;;;###autoload
-(defun swiper-isearch (&optional initial-input)
- "A `swiper' that's not line-based."
- (interactive)
- (swiper--init)
- (setq swiper--isearch-start-point (point))
- (swiper-font-lock-ensure)
- (let ((ivy-fixed-height-minibuffer t)
- (cursor-in-non-selected-windows nil)
- (swiper-min-highlight 1)
- res)
- (unwind-protect
- (and
- (setq res
- (ivy-read
- "Swiper: "
- #'swiper-isearch-function
- :initial-input initial-input
- :keymap swiper-isearch-map
- :dynamic-collection t
- :require-match t
- :action #'swiper-isearch-action
- :re-builder #'swiper--re-builder
- :history 'swiper-history
- :extra-props (list :fname (buffer-file-name))
- :caller 'swiper-isearch))
- (point))
- (unless (or res swiper-stay-on-quit)
- (goto-char swiper--opoint))
- (isearch-clean-overlays)
- (swiper--ensure-visible)
- (unless (or res (string= ivy-text ""))
- (cl-pushnew ivy-text swiper-history)))))
-
-(ivy-configure 'swiper-isearch
- :occur #'swiper-occur
- :update-fn 'auto
- :unwind-fn #'swiper--cleanup
- :format-fn #'swiper-isearch-format-function)
-
-;;;###autoload
-(defun swiper-isearch-backward (&optional initial-input)
- "Like `swiper-isearch' but the first result is before the point."
- (interactive)
- (let ((swiper--isearch-backward t))
- (swiper-isearch initial-input)))
-
-(defun swiper-isearch-toggle ()
- "Two-way toggle between `swiper-isearch' and isearch.
-Intended to be bound in `isearch-mode-map' and `swiper-map'."
- (interactive)
- (if isearch-mode
- (let ((query (if isearch-regexp
- isearch-string
- (regexp-quote isearch-string))))
- (isearch-exit)
- (goto-char (or (and isearch-forward isearch-other-end)
- (point)))
- (swiper-isearch query))
- (ivy-exit-with-action
- (lambda (_)
- (when (looking-back ivy--old-re (line-beginning-position))
- (goto-char (match-beginning 0)))
- (isearch-mode t)
- (unless (string= ivy-text "")
- (isearch-yank-string ivy-text))))))
-
-(provide 'swiper)
-
-;;; swiper.el ends here
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [elpa] master 85bec8d: * externals-list: Convert multishell, pcaed, and swiper to :external,
Stefan Monnier <=