+++ /dev/null
-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.
-\1f
-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 misc features
-* Transient: (transient). Transient Commands.
+++ /dev/null
-This is gpl.info, produced by makeinfo version 6.7 from gpl.texi.
-
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <https://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 <https://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 <https://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 <https://www.gnu.org/licenses/why-not-lgpl.html>.
-
-\1f
-Tag Table:
-\1f
-End Tag Table
-
-\1f
-Local Variables:
-coding: utf-8
-End:
+++ /dev/null
-;;; transient-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*-
-;;
-;;; Code:
-
-(add-to-list 'load-path (directory-file-name
- (or (file-name-directory #$) (car load-path))))
-
-\f
-;;;### (autoloads nil "transient" "transient.el" (0 0 0 0))
-;;; Generated autoloads from transient.el
-
-(autoload 'transient-insert-suffix "transient" "\
-Insert a SUFFIX into PREFIX before LOC.
-PREFIX is a prefix command, a symbol.
-SUFFIX is a suffix command or a group specification (of
- the same forms as expected by `transient-define-prefix').
-LOC is a command, a key vector, a key description (a string
- as returned by `key-description'), or a coordination list
- (whose last element may also be a command or key).
-Remove a conflicting binding unless optional KEEP-OTHER is
- non-nil.
-See info node `(transient)Modifying Existing Transients'.
-
-\(fn PREFIX LOC SUFFIX &optional KEEP-OTHER)" nil nil)
-
-(function-put 'transient-insert-suffix 'lisp-indent-function 'defun)
-
-(autoload 'transient-append-suffix "transient" "\
-Insert a SUFFIX into PREFIX after LOC.
-PREFIX is a prefix command, a symbol.
-SUFFIX is a suffix command or a group specification (of
- the same forms as expected by `transient-define-prefix').
-LOC is a command, a key vector, a key description (a string
- as returned by `key-description'), or a coordination list
- (whose last element may also be a command or key).
-Remove a conflicting binding unless optional KEEP-OTHER is
- non-nil.
-See info node `(transient)Modifying Existing Transients'.
-
-\(fn PREFIX LOC SUFFIX &optional KEEP-OTHER)" nil nil)
-
-(function-put 'transient-append-suffix 'lisp-indent-function 'defun)
-
-(autoload 'transient-replace-suffix "transient" "\
-Replace the suffix at LOC in PREFIX with SUFFIX.
-PREFIX is a prefix command, a symbol.
-SUFFIX is a suffix command or a group specification (of
- the same forms as expected by `transient-define-prefix').
-LOC is a command, a key vector, a key description (a string
- as returned by `key-description'), or a coordination list
- (whose last element may also be a command or key).
-See info node `(transient)Modifying Existing Transients'.
-
-\(fn PREFIX LOC SUFFIX)" nil nil)
-
-(function-put 'transient-replace-suffix 'lisp-indent-function 'defun)
-
-(autoload 'transient-remove-suffix "transient" "\
-Remove the suffix or group at LOC in PREFIX.
-PREFIX is a prefix command, a symbol.
-LOC is a command, a key vector, a key description (a string
- as returned by `key-description'), or a coordination list
- (whose last element may also be a command or key).
-See info node `(transient)Modifying Existing Transients'.
-
-\(fn PREFIX LOC)" nil nil)
-
-(function-put 'transient-remove-suffix 'lisp-indent-function 'defun)
-
-(register-definition-prefixes "transient" '("transient"))
-
-;;;***
-\f
-;;;### (autoloads nil nil ("transient-pkg.el") (0 0 0 0))
-
-;;;***
-\f
-;; Local Variables:
-;; version-control: never
-;; no-byte-compile: t
-;; no-update-autoloads: t
-;; coding: utf-8
-;; End:
-;;; transient-autoloads.el ends here
+++ /dev/null
-(define-package "transient" "20230602.2121" "Transient commands"
- '((emacs "25.1")
- (compat "29.1.4.1"))
- :commit "a1575e58331b1ff85ac97667df0130ae822ccf5f" :authors
- '(("Jonas Bernoulli" . "jonasNOSPAMbernoul.li"))
- :maintainers
- '(("Jonas Bernoulli" . "jonasNOSPAMbernoul.li"))
- :maintainer
- '("Jonas Bernoulli" . "jonasNOSPAMbernoul.li")
- :keywords
- '("extensions")
- :url "https://github.com/magit/transient")
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
+++ /dev/null
-;;; transient.el --- Transient commands -*- lexical-binding:t -*-
-
-;; Copyright (C) 2018-2023 Free Software Foundation, Inc.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Homepage: https://github.com/magit/transient
-;; Keywords: extensions
-
-;; Package-Version: 0.4.1
-;; Package-Requires: ((emacs "25.1") (compat "29.1.4.1"))
-
-;; SPDX-License-Identifier: GPL-3.0-or-later
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs 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.
-;;
-;; GNU Emacs 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 <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Taking inspiration from prefix keys and prefix arguments, Transient
-;; implements a similar abstraction involving a prefix command, infix
-;; arguments and suffix commands. We could call this abstraction a
-;; "transient command", but because it always involves at least two
-;; commands (a prefix and a suffix) we prefer to call it just a
-;; "transient".
-
-;; When the user calls a transient prefix command, then a transient
-;; (temporary) keymap is activated, which binds the transient's infix
-;; and suffix commands, and functions that control the transient state
-;; are added to `pre-command-hook' and `post-command-hook'. The
-;; available suffix and infix commands and their state are shown in
-;; the echo area until the transient is exited by invoking a suffix
-;; command.
-
-;; Calling an infix command causes its value to be changed, possibly
-;; by reading a new value in the minibuffer.
-
-;; Calling a suffix command usually causes the transient to be exited
-;; but suffix commands can also be configured to not exit the
-;; transient state.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'compat)
-(require 'eieio)
-(require 'edmacro)
-(require 'format-spec)
-(require 'seq)
-
-(eval-when-compile (require 'subr-x))
-
-(declare-function info "info" (&optional file-or-node buffer))
-(declare-function Man-find-section "man" (section))
-(declare-function Man-next-section "man" (n))
-(declare-function Man-getpage-in-background "man" (topic))
-
-(defvar display-line-numbers) ; since Emacs 26.1
-(defvar Man-notify-method)
-
-(defmacro transient--with-emergency-exit (&rest body)
- (declare (indent defun))
- `(condition-case err
- (let ((debugger #'transient--exit-and-debug))
- ,(macroexp-progn body))
- ((debug error)
- (transient--emergency-exit)
- (signal (car err) (cdr err)))))
-
-(defun transient--exit-and-debug (&rest args)
- (transient--emergency-exit)
- (apply #'debug args))
-
-;;; Options
-
-(defgroup transient nil
- "Transient commands."
- :group 'extensions)
-
-(defcustom transient-show-popup t
- "Whether to show the current transient in a popup buffer.
-\\<transient-map>
-- If t, then show the popup as soon as a transient prefix command
- is invoked.
-
-- If nil, then do not show the popup unless the user explicitly
- requests it, by pressing \\[transient-show] or a prefix key.
-
-- If a number, then delay displaying the popup and instead show
- a brief one-line summary. If zero or negative, then suppress
- even showing that summary and display the pressed key only.
-
- Show the popup when the user explicitly requests it by pressing
- \\[transient-show] or a prefix key. Unless zero, then also show the popup
- after that many seconds of inactivity (using the absolute value)."
- :package-version '(transient . "0.1.0")
- :group 'transient
- :type '(choice (const :tag "instantly" t)
- (const :tag "on demand" nil)
- (const :tag "on demand (no summary)" 0)
- (number :tag "after delay" 1)))
-
-(defcustom transient-enable-popup-navigation t
- "Whether navigation commands are enabled in the transient popup.
-
-While a transient is active the transient popup buffer is not the
-current buffer, making it necessary to use dedicated commands to
-act on that buffer itself. If this is non-nil, then the following
-bindings are available:
-
-\\<transient-popup-navigation-map>\
-- \\[transient-backward-button] moves the cursor to the previous suffix.
-- \\[transient-forward-button] moves the cursor to the next suffix.
-- \\[transient-push-button] invokes the suffix the cursor is on.
-\\<transient-button-map>\
-- \\`<mouse-1>' and \\`<mouse-2>' invoke the clicked on suffix.
-\\<transient-popup-navigation-map>\
-- \\[transient-isearch-backward]\
- and \\[transient-isearch-forward] start isearch in the popup buffer.
-
-\\`<mouse-1>' and \\`<mouse-2>' are bound in `transient-push-button'.
-All other bindings are in `transient-popup-navigation-map'.
-
-By default \\`M-RET' is bound to `transient-push-button', instead of
-\\`RET', because if a transient allows the invocation of non-suffixes
-then it is likely that you would want \\`RET' to do what it would do
-if no transient were active."
- :package-version '(transient . "0.4.0")
- :group 'transient
- :type 'boolean)
-
-(defcustom transient-display-buffer-action
- '(display-buffer-in-side-window
- (side . bottom)
- (dedicated . t)
- (inhibit-same-window . t)
- (window-parameters (no-other-window . t)))
- "The action used to display the transient popup buffer.
-
-The transient popup buffer is displayed in a window using
-
- (display-buffer BUFFER transient-display-buffer-action)
-
-The value of this option has the form (FUNCTION . ALIST),
-where FUNCTION is a function or a list of functions. Each such
-function should accept two arguments: a buffer to display and an
-alist of the same form as ALIST. See info node `(elisp)Choosing
-Window' for details.
-
-The default is:
-
- (display-buffer-in-side-window
- (side . bottom)
- (dedicated . t)
- (inhibit-same-window . t)
- (window-parameters (no-other-window . t)))
-
-This displays the window at the bottom of the selected frame.
-Another useful FUNCTION is `display-buffer-below-selected', which
-is what `magit-popup' used by default. For more alternatives see
-info node `(elisp)Display Action Functions' and info node
-`(elisp)Buffer Display Action Alists'.
-
-Note that the buffer that was current before the transient buffer
-is shown should remain the current buffer. Many suffix commands
-act on the thing at point, if appropriate, and if the transient
-buffer became the current buffer, then that would change what is
-at point. To that effect `inhibit-same-window' ensures that the
-selected window is not used to show the transient buffer.
-
-It may be possible to display the window in another frame, but
-whether that works in practice depends on the window-manager.
-If the window manager selects the new window (Emacs frame),
-then that unfortunately changes which buffer is current.
-
-If you change the value of this option, then you might also
-want to change the value of `transient-mode-line-format'."
- :package-version '(transient . "0.3.0")
- :group 'transient
- :type '(cons (choice function (repeat :tag "Functions" function))
- alist))
-
-(defcustom transient-mode-line-format 'line
- "The mode-line format for the transient popup buffer.
-
-If nil, then the buffer has no mode-line. If the buffer is not
-displayed right above the echo area, then this probably is not
-a good value.
-
-If `line' (the default), then the buffer also has no mode-line,
-but a thin line is drawn instead, using the background color of
-the face `transient-separator'. Termcap frames cannot display
-thin lines and therefore fallback to treating `line' like nil.
-
-Otherwise this can be any mode-line format.
-See `mode-line-format' for details."
- :package-version '(transient . "0.2.0")
- :group 'transient
- :type '(choice (const :tag "hide mode-line" nil)
- (const :tag "substitute thin line" line)
- (const :tag "name of prefix command"
- ("%e" mode-line-front-space
- mode-line-buffer-identification))
- (sexp :tag "custom mode-line format")))
-
-(defcustom transient-show-common-commands nil
- "Whether to show common transient suffixes in the popup buffer.
-
-These commands are always shown after typing the prefix key
-\"C-x\" when a transient command is active. To toggle the value
-of this variable use \"C-x t\" when a transient is active."
- :package-version '(transient . "0.1.0")
- :group 'transient
- :type 'boolean)
-
-(defcustom transient-read-with-initial-input nil
- "Whether to use the last history element as initial minibuffer input."
- :package-version '(transient . "0.2.0")
- :group 'transient
- :type 'boolean)
-
-(defcustom transient-highlight-mismatched-keys nil
- "Whether to highlight keys that do not match their argument.
-
-This only affects infix arguments that represent command-line
-arguments. When this option is non-nil, then the key binding
-for infix argument are highlighted when only a long argument
-\(e.g. \"--verbose\") is specified but no shor-thand (e.g \"-v\").
-In the rare case that a short-hand is specified but does not
-match the key binding, then it is highlighted differently.
-
-The highlighting is done using `transient-mismatched-key'
-and `transient-nonstandard-key'."
- :package-version '(transient . "0.1.0")
- :group 'transient
- :type 'boolean)
-
-(defcustom transient-highlight-higher-levels nil
- "Whether to highlight suffixes on higher levels.
-
-This is primarily intended for package authors.
-
-When non-nil then highlight the description of suffixes whose
-level is above 4, the default of `transient-default-level'.
-Assuming you have set that variable to 7, this highlights all
-suffixes that won't be available to users without them making
-the same customization."
- :package-version '(transient . "0.3.6")
- :group 'transient
- :type 'boolean)
-
-(defcustom transient-substitute-key-function nil
- "Function used to modify key bindings.
-
-This function is called with one argument, the prefix object,
-and must return a key binding description, either the existing
-key description it finds in the `key' slot, or a substitution.
-
-This is intended to let users replace certain prefix keys. It
-could also be used to make other substitutions, but that is
-discouraged.
-
-For example, \"=\" is hard to reach using my custom keyboard
-layout, so I substitute \"(\" for that, which is easy to reach
-using a layout optimized for Lisp.
-
- (setq transient-substitute-key-function
- (lambda (obj)
- (let ((key (oref obj key)))
- (if (string-match \"\\\\`\\\\(=\\\\)[a-zA-Z]\" key)
- (replace-match \"(\" t t key 1)
- key)))))"
- :package-version '(transient . "0.1.0")
- :group 'transient
- :type '(choice (const :tag "Transform no keys (nil)" nil) function))
-
-(defcustom transient-semantic-coloring nil
- "Whether to color prefixes and suffixes in Hydra-like fashion.
-This feature is experimental.
-
-If non-nil, then the key binding of each suffix is colorized to
-indicate whether it exits the transient state or not. The color
-of the prefix is indicated using the line that is drawn when the
-value of `transient-mode-line-format' is `line'.
-
-For more information about how Hydra uses colors see
-https://github.com/abo-abo/hydra#color and
-https://oremacs.com/2015/02/19/hydra-colors-reloaded."
- :package-version '(transient . "0.3.0")
- :group 'transient
- :type 'boolean)
-
-(defcustom transient-detect-key-conflicts nil
- "Whether to detect key binding conflicts.
-
-Conflicts are detected when a transient prefix command is invoked
-and results in an error, which prevents the transient from being
-used."
- :package-version '(transient . "0.1.0")
- :group 'transient
- :type 'boolean)
-
-(defcustom transient-align-variable-pitch nil
- "Whether to align columns pixel-wise in the popup buffer.
-
-If this is non-nil, then columns are aligned pixel-wise to
-support variable-pitch fonts. Keys are not aligned, so you
-should use a fixed-pitch font for the `transient-key' face.
-Other key faces inherit from that face unless a theme is
-used that breaks that relationship.
-
-This option is intended for users who use a variable-pitch
-font for the `default' face.
-
-Also see `transient-force-fixed-pitch'."
- :package-version '(transient . "0.4.0")
- :group 'transient
- :type 'boolean)
-
-(defcustom transient-force-fixed-pitch nil
- "Whether to force use of monospaced font in the popup buffer.
-
-Even if you use a proportional font for the `default' face,
-you might still want to use a monospaced font in transient's
-popup buffer. Setting this option to t causes `default' to
-be remapped to `fixed-pitch' in that buffer.
-
-Also see `transient-align-variable-pitch'."
- :package-version '(transient . "0.2.0")
- :group 'transient
- :type 'boolean)
-
-(defcustom transient-force-single-column nil
- "Whether to force use of a single column to display suffixes.
-
-This might be useful for users with low vision who use large
-text and might otherwise have to scroll in two dimensions."
- :package-version '(transient . "0.3.6")
- :group 'transient
- :type 'boolean)
-
-(defcustom transient-hide-during-minibuffer-read nil
- "Whether to hide the transient buffer while reading in the minibuffer."
- :package-version '(transient . "0.4.0")
- :group 'transient
- :type 'boolean)
-
-(defconst transient--default-child-level 1)
-
-(defconst transient--default-prefix-level 4)
-
-(defcustom transient-default-level transient--default-prefix-level
- "Control what suffix levels are made available by default.
-
-Each suffix command is placed on a level and each prefix command
-has a level, which controls which suffix commands are available.
-Integers between 1 and 7 (inclusive) are valid levels.
-
-The levels of individual transients and/or their individual
-suffixes can be changed individually, by invoking the prefix and
-then pressing \"C-x l\".
-
-The default level for both transients and their suffixes is 4.
-This option only controls the default for transients. The default
-suffix level is always 4. The author of a transient should place
-certain suffixes on a higher level if they expect that it won't be
-of use to most users, and they should place very important suffixes
-on a lower level so that they remain available even if the user
-lowers the transient level.
-
-\(Magit currently places nearly all suffixes on level 4 and lower
-levels are not used at all yet. So for the time being you should
-not set a lower level here and using a higher level might not
-give you as many additional suffixes as you hoped.)"
- :package-version '(transient . "0.1.0")
- :group 'transient
- :type '(choice (const :tag "1 - fewest suffixes" 1)
- (const 2)
- (const 3)
- (const :tag "4 - default" 4)
- (const 5)
- (const 6)
- (const :tag "7 - most suffixes" 7)))
-
-(defcustom transient-levels-file
- (locate-user-emacs-file "transient/levels.el")
- "File used to save levels of transients and their suffixes."
- :package-version '(transient . "0.1.0")
- :group 'transient
- :type 'file)
-
-(defcustom transient-values-file
- (locate-user-emacs-file "transient/values.el")
- "File used to save values of transients."
- :package-version '(transient . "0.1.0")
- :group 'transient
- :type 'file)
-
-(defcustom transient-history-file
- (locate-user-emacs-file "transient/history.el")
- "File used to save history of transients and their infixes."
- :package-version '(transient . "0.1.0")
- :group 'transient
- :type 'file)
-
-(defcustom transient-history-limit 10
- "Number of history elements to keep when saving to file."
- :package-version '(transient . "0.1.0")
- :group 'transient
- :type 'integer)
-
-(defcustom transient-save-history t
- "Whether to save history of transient commands when exiting Emacs."
- :package-version '(transient . "0.1.0")
- :group 'transient
- :type 'boolean)
-
-;;; Faces
-
-(defgroup transient-faces nil
- "Faces used by Transient."
- :group 'transient)
-
-(defface transient-heading '((t :inherit font-lock-keyword-face))
- "Face used for headings."
- :group 'transient-faces)
-
-(defface transient-key '((t :inherit font-lock-builtin-face))
- "Face used for keys."
- :group 'transient-faces)
-
-(defface transient-argument '((t :inherit font-lock-warning-face))
- "Face used for enabled arguments."
- :group 'transient-faces)
-
-(defface transient-value '((t :inherit font-lock-string-face))
- "Face used for values."
- :group 'transient-faces)
-
-(defface transient-inactive-argument '((t :inherit shadow))
- "Face used for inactive arguments."
- :group 'transient-faces)
-
-(defface transient-inactive-value '((t :inherit shadow))
- "Face used for inactive values."
- :group 'transient-faces)
-
-(defface transient-unreachable '((t :inherit shadow))
- "Face used for suffixes unreachable from the current prefix sequence."
- :group 'transient-faces)
-
-(defface transient-active-infix '((t :inherit secondary-selection))
- "Face used for the infix for which the value is being read."
- :group 'transient-faces)
-
-(defface transient-unreachable-key '((t :inherit (transient-key shadow)))
- "Face used for keys unreachable from the current prefix sequence."
- :group 'transient-faces)
-
-(defface transient-nonstandard-key '((t :underline t))
- "Face optionally used to highlight keys conflicting with short-argument.
-Also see option `transient-highlight-mismatched-keys'."
- :group 'transient-faces)
-
-(defface transient-mismatched-key '((t :underline t))
- "Face optionally used to highlight keys without a short-argument.
-Also see option `transient-highlight-mismatched-keys'."
- :group 'transient-faces)
-
-(defface transient-inapt-suffix '((t :inherit shadow :italic t))
- "Face used for suffixes that are inapt at this time."
- :group 'transient-faces)
-
-(defface transient-enabled-suffix
- '((t :background "green" :foreground "black" :weight bold))
- "Face used for enabled levels while editing suffix levels.
-See info node `(transient)Enabling and Disabling Suffixes'."
- :group 'transient-faces)
-
-(defface transient-disabled-suffix
- '((t :background "red" :foreground "black" :weight bold))
- "Face used for disabled levels while editing suffix levels.
-See info node `(transient)Enabling and Disabling Suffixes'."
- :group 'transient-faces)
-
-(defface transient-higher-level '((t :underline t))
- "Face optionally used to highlight suffixes on higher levels.
-Also see option `transient-highlight-higher-levels'."
- :group 'transient-faces)
-
-(defface transient-separator
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "grey80")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "grey30"))
- "Face used to draw line below transient popup window.
-This is only used if `transient-mode-line-format' is `line'.
-Only the background color is significant."
- :group 'transient-faces)
-
-(defgroup transient-color-faces
- '((transient-semantic-coloring custom-variable))
- "Faces used by Transient for Hydra-like command coloring.
-These faces are only used if `transient-semantic-coloring'
-\(which see) is non-nil."
- :group 'transient-faces)
-
-(defface transient-red
- '((t :inherit transient-key :foreground "red"))
- "Face used for red prefixes and suffixes."
- :group 'transient-color-faces)
-
-(defface transient-blue
- '((t :inherit transient-key :foreground "blue"))
- "Face used for blue prefixes and suffixes."
- :group 'transient-color-faces)
-
-(defface transient-amaranth
- '((t :inherit transient-key :foreground "#E52B50"))
- "Face used for amaranth prefixes."
- :group 'transient-color-faces)
-
-(defface transient-pink
- '((t :inherit transient-key :foreground "#FF6EB4"))
- "Face used for pink prefixes."
- :group 'transient-color-faces)
-
-(defface transient-teal
- '((t :inherit transient-key :foreground "#367588"))
- "Face used for teal prefixes."
- :group 'transient-color-faces)
-
-(defface transient-purple
- '((t :inherit transient-key :foreground "#a020f0"))
- "Face used for purple prefixes.
-
-This is an addition to the colors supported by Hydra. It is
-used by suffixes that quit the current prefix but return to
-the previous prefix."
- :group 'transient-color-faces)
-
-;;; Persistence
-
-(defun transient--read-file-contents (file)
- (with-demoted-errors "Transient error: %S"
- (and (file-exists-p file)
- (with-temp-buffer
- (insert-file-contents file)
- (read (current-buffer))))))
-
-(defun transient--pp-to-file (list file)
- (make-directory (file-name-directory file) t)
- (setq list (cl-sort (copy-sequence list) #'string< :key #'car))
- (with-temp-file file
- (let ((print-level nil)
- (print-length nil))
- (pp list (current-buffer)))))
-
-(defvar transient-values
- (transient--read-file-contents transient-values-file)
- "Values of transient commands.
-The value of this variable persists between Emacs sessions
-and you usually should not change it manually.")
-
-(defun transient-save-values ()
- (transient--pp-to-file transient-values transient-values-file))
-
-(defvar transient-levels
- (transient--read-file-contents transient-levels-file)
- "Levels of transient commands.
-The value of this variable persists between Emacs sessions
-and you usually should not change it manually.")
-
-(defun transient-save-levels ()
- (transient--pp-to-file transient-levels transient-levels-file))
-
-(defvar transient-history
- (transient--read-file-contents transient-history-file)
- "History of transient commands and infix arguments.
-The value of this variable persists between Emacs sessions
-\(unless `transient-save-history' is nil) and you usually
-should not change it manually.")
-
-(defun transient-save-history ()
- (setq transient-history
- (cl-sort (mapcar (pcase-lambda (`(,key . ,val))
- (cons key (seq-take (delete-dups val)
- transient-history-limit)))
- transient-history)
- #'string< :key #'car))
- (transient--pp-to-file transient-history transient-history-file))
-
-(defun transient-maybe-save-history ()
- "Save the value of `transient-history'.
-If `transient-save-history' is nil, then do nothing."
- (when transient-save-history
- (transient-save-history)))
-
-(unless noninteractive
- (add-hook 'kill-emacs-hook #'transient-maybe-save-history))
-
-;;; Classes
-;;;; Prefix
-
-(defclass transient-prefix ()
- ((prototype :initarg :prototype)
- (command :initarg :command)
- (level :initarg :level)
- (variable :initarg :variable :initform nil)
- (init-value :initarg :init-value)
- (value) (default-value :initarg :value)
- (scope :initarg :scope :initform nil)
- (history :initarg :history :initform nil)
- (history-pos :initarg :history-pos :initform 0)
- (history-key :initarg :history-key :initform nil)
- (show-help :initarg :show-help :initform nil)
- (info-manual :initarg :info-manual :initform nil)
- (man-page :initarg :man-page :initform nil)
- (transient-suffix :initarg :transient-suffix :initform nil)
- (transient-non-suffix :initarg :transient-non-suffix :initform nil)
- (incompatible :initarg :incompatible :initform nil)
- (suffix-description :initarg :suffix-description)
- (variable-pitch :initarg :variable-pitch :initform nil)
- (unwind-suffix :documentation "Internal use." :initform nil))
- "Transient prefix command.
-
-Each transient prefix command consists of a command, which is
-stored in a symbol's function slot and an object, which is
-stored in the `transient--prefix' property of the same symbol.
-
-When a transient prefix command is invoked, then a clone of that
-object is stored in the global variable `transient--prefix' and
-the prototype is stored in the clone's `prototype' slot.")
-
-;;;; Suffix
-
-(defclass transient-child ()
- ((level
- :initarg :level
- :initform (symbol-value 'transient--default-child-level)
- :documentation "Enable if level of prefix is equal or greater.")
- (if
- :initarg :if
- :initform nil
- :documentation "Enable if predicate returns non-nil.")
- (if-not
- :initarg :if-not
- :initform nil
- :documentation "Enable if predicate returns nil.")
- (if-non-nil
- :initarg :if-non-nil
- :initform nil
- :documentation "Enable if variable's value is non-nil.")
- (if-nil
- :initarg :if-nil
- :initform nil
- :documentation "Enable if variable's value is nil.")
- (if-mode
- :initarg :if-mode
- :initform nil
- :documentation "Enable if major-mode matches value.")
- (if-not-mode
- :initarg :if-not-mode
- :initform nil
- :documentation "Enable if major-mode does not match value.")
- (if-derived
- :initarg :if-derived
- :initform nil
- :documentation "Enable if major-mode derives from value.")
- (if-not-derived
- :initarg :if-not-derived
- :initform nil
- :documentation "Enable if major-mode does not derive from value."))
- "Abstract superclass for group and suffix classes.
-
-It is undefined what happens if more than one `if*' predicate
-slot is non-nil."
- :abstract t)
-
-(defclass transient-suffix (transient-child)
- ((key :initarg :key)
- (command :initarg :command)
- (transient :initarg :transient)
- (format :initarg :format :initform " %k %d")
- (description :initarg :description :initform nil)
- (show-help :initarg :show-help :initform nil)
- (inapt :initform nil)
- (inapt-if
- :initarg :inapt-if
- :initform nil
- :documentation "Inapt if predicate returns non-nil.")
- (inapt-if-not
- :initarg :inapt-if-not
- :initform nil
- :documentation "Inapt if predicate returns nil.")
- (inapt-if-non-nil
- :initarg :inapt-if-non-nil
- :initform nil
- :documentation "Inapt if variable's value is non-nil.")
- (inapt-if-nil
- :initarg :inapt-if-nil
- :initform nil
- :documentation "Inapt if variable's value is nil.")
- (inapt-if-mode
- :initarg :inapt-if-mode
- :initform nil
- :documentation "Inapt if major-mode matches value.")
- (inapt-if-not-mode
- :initarg :inapt-if-not-mode
- :initform nil
- :documentation "Inapt if major-mode does not match value.")
- (inapt-if-derived
- :initarg :inapt-if-derived
- :initform nil
- :documentation "Inapt if major-mode derives from value.")
- (inapt-if-not-derived
- :initarg :inapt-if-not-derived
- :initform nil
- :documentation "Inapt if major-mode does not derive from value."))
- "Superclass for suffix command.")
-
-(defclass transient-infix (transient-suffix)
- ((transient :initform t)
- (argument :initarg :argument)
- (shortarg :initarg :shortarg)
- (value :initform nil)
- (init-value :initarg :init-value)
- (unsavable :initarg :unsavable :initform nil)
- (multi-value :initarg :multi-value :initform nil)
- (always-read :initarg :always-read :initform nil)
- (allow-empty :initarg :allow-empty :initform nil)
- (history-key :initarg :history-key :initform nil)
- (reader :initarg :reader :initform nil)
- (prompt :initarg :prompt :initform nil)
- (choices :initarg :choices :initform nil)
- (format :initform " %k %d (%v)"))
- "Transient infix command."
- :abstract t)
-
-(defclass transient-argument (transient-infix) ()
- "Abstract superclass for infix arguments."
- :abstract t)
-
-(defclass transient-switch (transient-argument) ()
- "Class used for command-line argument that can be turned on and off.")
-
-(defclass transient-option (transient-argument) ()
- "Class used for command-line argument that can take a value.")
-
-(defclass transient-variable (transient-infix)
- ((variable :initarg :variable)
- (format :initform " %k %d %v"))
- "Abstract superclass for infix commands that set a variable."
- :abstract t)
-
-(defclass transient-switches (transient-argument)
- ((argument-format :initarg :argument-format)
- (argument-regexp :initarg :argument-regexp))
- "Class used for sets of mutually exclusive command-line switches.")
-
-(defclass transient-files (transient-option) ()
- ((key :initform "--")
- (argument :initform "--")
- (multi-value :initform rest)
- (reader :initform transient-read-files))
- "Class used for the \"--\" argument or similar.
-All remaining arguments are treated as files.
-They become the value of this argument.")
-
-;;;; Group
-
-(defclass transient-group (transient-child)
- ((suffixes :initarg :suffixes :initform nil)
- (hide :initarg :hide :initform nil)
- (description :initarg :description :initform nil)
- (setup-children :initarg :setup-children)
- (pad-keys :initarg :pad-keys))
- "Abstract superclass of all group classes."
- :abstract t)
-
-(defclass transient-column (transient-group) ()
- "Group class that displays each element on a separate line.")
-
-(defclass transient-row (transient-group) ()
- "Group class that displays all elements on a single line.")
-
-(defclass transient-columns (transient-group) ()
- "Group class that displays elements organized in columns.
-Direct elements have to be groups whose elements have to be
-commands or strings. Each subgroup represents a column.
-This class takes care of inserting the subgroups' elements.")
-
-(defclass transient-subgroups (transient-group) ()
- "Group class that wraps other groups.
-
-Direct elements have to be groups whose elements have to be
-commands or strings. This group inserts an empty line between
-subgroups. The subgroups are responsible for displaying their
-elements themselves.")
-
-;;; Define
-
-(defmacro transient-define-prefix (name arglist &rest args)
- "Define NAME as a transient prefix command.
-
-ARGLIST are the arguments that command takes.
-DOCSTRING is the documentation string and is optional.
-
-These arguments can optionally be followed by key-value pairs.
-Each key has to be a keyword symbol, either `:class' or a keyword
-argument supported by the constructor of that class. The
-`transient-prefix' class is used if the class is not specified
-explicitly.
-
-GROUPs add key bindings for infix and suffix commands and specify
-how these bindings are presented in the popup buffer. At least
-one GROUP has to be specified. See info node `(transient)Binding
-Suffix and Infix Commands'.
-
-The BODY is optional. If it is omitted, then ARGLIST is also
-ignored and the function definition becomes:
-
- (lambda ()
- (interactive)
- (transient-setup \\='NAME))
-
-If BODY is specified, then it must begin with an `interactive'
-form that matches ARGLIST, and it must call `transient-setup'.
-It may however call that function only when some condition is
-satisfied; that is one of the reason why you might want to use
-an explicit BODY.
-
-All transients have a (possibly nil) value, which is exported
-when suffix commands are called, so that they can consume that
-value. For some transients it might be necessary to have a sort
-of secondary value, called a scope. Such a scope would usually
-be set in the commands `interactive' form and has to be passed
-to the setup function:
-
- (transient-setup \\='NAME nil nil :scope SCOPE)
-
-\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]... GROUP... [BODY...])"
- (declare (debug ( &define name lambda-list
- [&optional lambda-doc]
- [&rest keywordp sexp]
- [&rest vectorp]
- [&optional ("interactive" interactive) def-body]))
- (indent defun)
- (doc-string 3))
- (pcase-let ((`(,class ,slots ,suffixes ,docstr ,body)
- (transient--expand-define-args args arglist)))
- `(progn
- (defalias ',name
- ,(if body
- `(lambda ,arglist ,@body)
- `(lambda ()
- (interactive)
- (transient-setup ',name))))
- (put ',name 'interactive-only t)
- (put ',name 'function-documentation ,docstr)
- (put ',name 'transient--prefix
- (,(or class 'transient-prefix) :command ',name ,@slots))
- (put ',name 'transient--layout
- (list ,@(cl-mapcan (lambda (s) (transient--parse-child name s))
- suffixes))))))
-
-(defmacro transient-define-suffix (name arglist &rest args)
- "Define NAME as a transient suffix command.
-
-ARGLIST are the arguments that the command takes.
-DOCSTRING is the documentation string and is optional.
-
-These arguments can optionally be followed by key-value pairs.
-Each key has to be a keyword symbol, either `:class' or a
-keyword argument supported by the constructor of that class.
-The `transient-suffix' class is used if the class is not
-specified explicitly.
-
-The BODY must begin with an `interactive' form that matches
-ARGLIST. The infix arguments are usually accessed by using
-`transient-args' inside `interactive'.
-
-\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]... BODY...)"
- (declare (debug ( &define name lambda-list
- [&optional lambda-doc]
- [&rest keywordp sexp]
- ("interactive" interactive)
- def-body))
- (indent defun)
- (doc-string 3))
- (pcase-let ((`(,class ,slots ,_ ,docstr ,body)
- (transient--expand-define-args args arglist)))
- `(progn
- (defalias ',name (lambda ,arglist ,@body))
- (put ',name 'interactive-only t)
- (put ',name 'function-documentation ,docstr)
- (put ',name 'transient--suffix
- (,(or class 'transient-suffix) :command ',name ,@slots)))))
-
-(defmacro transient-define-infix (name arglist &rest args)
- "Define NAME as a transient infix command.
-
-ARGLIST is always ignored and reserved for future use.
-DOCSTRING is the documentation string and is optional.
-
-The key-value pairs are mandatory. All transient infix commands
-are equal to each other (but not eq), so it is meaningless to
-define an infix command without also setting at least `:class'
-and one other keyword (which it is depends on the used class,
-usually `:argument' or `:variable').
-
-Each key has to be a keyword symbol, either `:class' or a keyword
-argument supported by the constructor of that class. The
-`transient-switch' class is used if the class is not specified
-explicitly.
-
-The function definitions is always:
-
- (lambda ()
- (interactive)
- (let ((obj (transient-suffix-object)))
- (transient-infix-set obj (transient-infix-read obj)))
- (transient--show))
-
-`transient-infix-read' and `transient-infix-set' are generic
-functions. Different infix commands behave differently because
-the concrete methods are different for different infix command
-classes. In rare case the above command function might not be
-suitable, even if you define your own infix command class. In
-that case you have to use `transient-define-suffix' to define
-the infix command and use t as the value of the `:transient'
-keyword.
-
-\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]...)"
- (declare (debug ( &define name lambda-list
- [&optional lambda-doc]
- [&rest keywordp sexp]))
- (indent defun)
- (doc-string 3))
- (pcase-let ((`(,class ,slots ,_ ,docstr ,_)
- (transient--expand-define-args args arglist)))
- `(progn
- (defalias ',name ,(transient--default-infix-command))
- (put ',name 'interactive-only t)
- (put ',name 'command-modes (list 'not-a-mode))
- (put ',name 'function-documentation ,docstr)
- (put ',name 'transient--suffix
- (,(or class 'transient-switch) :command ',name ,@slots)))))
-
-(defalias 'transient-define-argument #'transient-define-infix
- "Define NAME as a transient infix command.
-
-Only use this alias to define an infix command that actually
-sets an infix argument. To define a infix command that, for
-example, sets a variable, use `transient-define-infix' instead.
-
-\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]...)")
-
-(defun transient--expand-define-args (args &optional arglist)
- (unless (listp arglist)
- (error "Mandatory ARGLIST is missing"))
- (let (class keys suffixes docstr)
- (when (stringp (car args))
- (setq docstr (pop args)))
- (while (keywordp (car args))
- (let ((k (pop args))
- (v (pop args)))
- (if (eq k :class)
- (setq class v)
- (push k keys)
- (push v keys))))
- (while (let ((arg (car args)))
- (or (vectorp arg)
- (and arg (symbolp arg))))
- (push (pop args) suffixes))
- (list (if (eq (car-safe class) 'quote)
- (cadr class)
- class)
- (nreverse keys)
- (nreverse suffixes)
- docstr
- args)))
-
-(defun transient--parse-child (prefix spec)
- (cl-etypecase spec
- (symbol (let ((value (symbol-value spec)))
- (if (and (listp value)
- (or (listp (car value))
- (vectorp (car value))))
- (cl-mapcan (lambda (s) (transient--parse-child prefix s)) value)
- (transient--parse-child prefix value))))
- (vector (and-let* ((c (transient--parse-group prefix spec))) (list c)))
- (list (and-let* ((c (transient--parse-suffix prefix spec))) (list c)))
- (string (list spec))))
-
-(defun transient--parse-group (prefix spec)
- (setq spec (append spec nil))
- (cl-symbol-macrolet
- ((car (car spec))
- (pop (pop spec)))
- (let (level class args)
- (when (integerp car)
- (setq level pop))
- (when (stringp car)
- (setq args (plist-put args :description pop)))
- (while (keywordp car)
- (let ((key pop)
- (val pop))
- (cond ((eq key :class)
- (setq class (macroexp-quote val)))
- ((or (symbolp val)
- (and (listp val) (not (eq (car val) 'lambda))))
- (setq args (plist-put args key (macroexp-quote val))))
- ((setq args (plist-put args key val))))))
- (list 'vector
- (or level transient--default-child-level)
- (or class
- (if (vectorp car)
- (quote 'transient-columns)
- (quote 'transient-column)))
- (and args (cons 'list args))
- (cons 'list
- (cl-mapcan (lambda (s) (transient--parse-child prefix s))
- spec))))))
-
-(defun transient--parse-suffix (prefix spec)
- (let (level class args)
- (cl-symbol-macrolet
- ((car (car spec))
- (pop (pop spec)))
- (when (integerp car)
- (setq level pop))
- (when (or (stringp car)
- (vectorp car))
- (setq args (plist-put args :key pop)))
- (cond
- ((or (stringp car)
- (and (eq (car-safe car) 'lambda)
- (not (commandp car))))
- (setq args (plist-put args :description pop)))
- ((and (symbolp car)
- (not (keywordp car))
- (not (commandp car))
- (commandp (cadr spec)))
- (setq args (plist-put args :description (macroexp-quote pop)))))
- (cond
- ((keywordp car)
- (error "Need command, got `%s'" car))
- ((symbolp car)
- (setq args (plist-put args :command (macroexp-quote pop))))
- ((and (commandp car)
- (not (stringp car)))
- (let ((cmd pop)
- (sym (intern
- (format "transient:%s:%s"
- prefix
- (let ((desc (plist-get args :description)))
- (if (and desc (or (stringp desc) (symbolp desc)))
- desc
- (plist-get args :key)))))))
- (setq args (plist-put args :command
- `(defalias ',sym ,(macroexp-quote cmd))))))
- ((or (stringp car)
- (and car (listp car)))
- (let ((arg pop))
- (cl-typecase arg
- (list
- (setq args (plist-put args :shortarg (car arg)))
- (setq args (plist-put args :argument (cadr arg)))
- (setq arg (cadr arg)))
- (string
- (when-let ((shortarg (transient--derive-shortarg arg)))
- (setq args (plist-put args :shortarg shortarg)))
- (setq args (plist-put args :argument arg))))
- (setq args (plist-put args :command
- (list 'quote (intern (format "transient:%s:%s"
- prefix arg)))))
- (cond ((and car (not (keywordp car)))
- (setq class 'transient-option)
- (setq args (plist-put args :reader (macroexp-quote pop))))
- ((not (string-suffix-p "=" arg))
- (setq class 'transient-switch))
- (t
- (setq class 'transient-option)))))
- (t
- (error "Needed command or argument, got %S" car)))
- (while (keywordp car)
- (let ((key pop)
- (val pop))
- (cond ((eq key :class) (setq class val))
- ((eq key :level) (setq level val))
- ((eq (car-safe val) '\,)
- (setq args (plist-put args key (cadr val))))
- ((or (symbolp val)
- (and (listp val) (not (eq (car val) 'lambda))))
- (setq args (plist-put args key (macroexp-quote val))))
- ((setq args (plist-put args key val)))))))
- (unless (plist-get args :key)
- (when-let ((shortarg (plist-get args :shortarg)))
- (setq args (plist-put args :key shortarg))))
- (list 'list
- (or level transient--default-child-level)
- (macroexp-quote (or class 'transient-suffix))
- (cons 'list args))))
-
-(defun transient--default-infix-command ()
- (cons 'lambda
- '(()
- (interactive)
- (let ((obj (transient-suffix-object)))
- (transient-infix-set obj (transient-infix-read obj)))
- (transient--show))))
-
-(defun transient--ensure-infix-command (obj)
- (let ((cmd (oref obj command)))
- (unless (or (commandp cmd)
- (get cmd 'transient--infix-command))
- (if (or (cl-typep obj 'transient-switch)
- (cl-typep obj 'transient-option))
- (put cmd 'transient--infix-command
- (transient--default-infix-command))
- ;; This is not an anonymous infix argument.
- (when (transient--use-suffix-p obj)
- (error "Suffix %s is not defined or autoloaded as a command" cmd))))))
-
-(defun transient--derive-shortarg (arg)
- (save-match-data
- (and (string-match "\\`\\(-[a-zA-Z]\\)\\(\\'\\|=\\)" arg)
- (match-string 1 arg))))
-
-(defun transient-parse-suffix (prefix suffix)
- "Parse SUFFIX, to be added to PREFIX.
-PREFIX is a prefix command, a symbol.
-SUFFIX is a suffix command or a group specification (of
- the same forms as expected by `transient-define-prefix').
-Intended for use in a group's `:setup-children' function."
- (eval (car (transient--parse-child prefix suffix))))
-
-(defun transient-parse-suffixes (prefix suffixes)
- "Parse SUFFIXES, to be added to PREFIX.
-PREFIX is a prefix command, a symbol.
-SUFFIXES is a list of suffix command or a group specification
- (of the same forms as expected by `transient-define-prefix').
-Intended for use in a group's `:setup-children' function."
- (mapcar (apply-partially #'transient-parse-suffix prefix) suffixes))
-
-;;; Edit
-
-(defun transient--insert-suffix (prefix loc suffix action &optional keep-other)
- (let* ((suf (cl-etypecase suffix
- (vector (transient--parse-group prefix suffix))
- (list (transient--parse-suffix prefix suffix))
- (string suffix)))
- (mem (transient--layout-member loc prefix))
- (elt (car mem)))
- (setq suf (eval suf))
- (cond
- ((not mem)
- (message "Cannot insert %S into %s; %s not found"
- suffix prefix loc))
- ((or (and (vectorp suffix) (not (vectorp elt)))
- (and (listp suffix) (vectorp elt))
- (and (stringp suffix) (vectorp elt)))
- (message "Cannot place %S into %s at %s; %s"
- suffix prefix loc
- "suffixes and groups cannot be siblings"))
- (t
- (when-let* ((bindingp (listp suf))
- (key (transient--spec-key suf))
- (conflict (car (transient--layout-member key prefix)))
- (conflictp
- (and (not (and (eq action 'replace)
- (eq conflict elt)))
- (or (not keep-other)
- (eq (plist-get (nth 2 suf) :command)
- (plist-get (nth 2 conflict) :command)))
- (equal (transient--suffix-predicate suf)
- (transient--suffix-predicate conflict)))))
- (transient-remove-suffix prefix key))
- (cl-ecase action
- (insert (setcdr mem (cons elt (cdr mem)))
- (setcar mem suf))
- (append (setcdr mem (cons suf (cdr mem))))
- (replace (setcar mem suf)))))))
-
-;;;###autoload
-(defun transient-insert-suffix (prefix loc suffix &optional keep-other)
- "Insert a SUFFIX into PREFIX before LOC.
-PREFIX is a prefix command, a symbol.
-SUFFIX is a suffix command or a group specification (of
- the same forms as expected by `transient-define-prefix').
-LOC is a command, a key vector, a key description (a string
- as returned by `key-description'), or a coordination list
- (whose last element may also be a command or key).
-Remove a conflicting binding unless optional KEEP-OTHER is
- non-nil.
-See info node `(transient)Modifying Existing Transients'."
- (declare (indent defun))
- (transient--insert-suffix prefix loc suffix 'insert keep-other))
-
-;;;###autoload
-(defun transient-append-suffix (prefix loc suffix &optional keep-other)
- "Insert a SUFFIX into PREFIX after LOC.
-PREFIX is a prefix command, a symbol.
-SUFFIX is a suffix command or a group specification (of
- the same forms as expected by `transient-define-prefix').
-LOC is a command, a key vector, a key description (a string
- as returned by `key-description'), or a coordination list
- (whose last element may also be a command or key).
-Remove a conflicting binding unless optional KEEP-OTHER is
- non-nil.
-See info node `(transient)Modifying Existing Transients'."
- (declare (indent defun))
- (transient--insert-suffix prefix loc suffix 'append keep-other))
-
-;;;###autoload
-(defun transient-replace-suffix (prefix loc suffix)
- "Replace the suffix at LOC in PREFIX with SUFFIX.
-PREFIX is a prefix command, a symbol.
-SUFFIX is a suffix command or a group specification (of
- the same forms as expected by `transient-define-prefix').
-LOC is a command, a key vector, a key description (a string
- as returned by `key-description'), or a coordination list
- (whose last element may also be a command or key).
-See info node `(transient)Modifying Existing Transients'."
- (declare (indent defun))
- (transient--insert-suffix prefix loc suffix 'replace))
-
-;;;###autoload
-(defun transient-remove-suffix (prefix loc)
- "Remove the suffix or group at LOC in PREFIX.
-PREFIX is a prefix command, a symbol.
-LOC is a command, a key vector, a key description (a string
- as returned by `key-description'), or a coordination list
- (whose last element may also be a command or key).
-See info node `(transient)Modifying Existing Transients'."
- (declare (indent defun))
- (transient--layout-member loc prefix 'remove))
-
-(defun transient-get-suffix (prefix loc)
- "Return the suffix or group at LOC in PREFIX.
-PREFIX is a prefix command, a symbol.
-LOC is a command, a key vector, a key description (a string
- as returned by `key-description'), or a coordination list
- (whose last element may also be a command or key).
-See info node `(transient)Modifying Existing Transients'."
- (if-let ((mem (transient--layout-member loc prefix)))
- (car mem)
- (error "%s not found in %s" loc prefix)))
-
-(defun transient-suffix-put (prefix loc prop value)
- "Edit the suffix at LOC in PREFIX, setting PROP to VALUE.
-PREFIX is a prefix command, a symbol.
-SUFFIX is a suffix command or a group specification (of
- the same forms as expected by `transient-define-prefix').
-LOC is a command, a key vector, a key description (a string
- as returned by `key-description'), or a coordination list
- (whose last element may also be a command or key).
-See info node `(transient)Modifying Existing Transients'."
- (let ((suf (transient-get-suffix prefix loc)))
- (setf (elt suf 2)
- (plist-put (elt suf 2) prop value))))
-
-(defun transient--layout-member (loc prefix &optional remove)
- (let ((val (or (get prefix 'transient--layout)
- (error "%s is not a transient command" prefix))))
- (when (listp loc)
- (while (integerp (car loc))
- (let* ((children (if (vectorp val) (aref val 3) val))
- (mem (transient--nthcdr (pop loc) children)))
- (if (and remove (not loc))
- (let ((rest (delq (car mem) children)))
- (if (vectorp val)
- (aset val 3 rest)
- (put prefix 'transient--layout rest))
- (setq val nil))
- (setq val (if loc (car mem) mem)))))
- (setq loc (car loc)))
- (if loc
- (transient--layout-member-1 (transient--kbd loc) val remove)
- val)))
-
-(defun transient--layout-member-1 (loc layout remove)
- (cond ((listp layout)
- (seq-some (lambda (elt) (transient--layout-member-1 loc elt remove))
- layout))
- ((vectorp (car (aref layout 3)))
- (seq-some (lambda (elt) (transient--layout-member-1 loc elt remove))
- (aref layout 3)))
- (remove
- (aset layout 3
- (delq (car (transient--group-member loc layout))
- (aref layout 3)))
- nil)
- (t (transient--group-member loc layout))))
-
-(defun transient--group-member (loc group)
- (cl-member-if (lambda (suffix)
- (and (listp suffix)
- (let* ((def (nth 2 suffix))
- (cmd (plist-get def :command)))
- (if (symbolp loc)
- (eq cmd loc)
- (equal (transient--kbd
- (or (plist-get def :key)
- (transient--command-key cmd)))
- loc)))))
- (aref group 3)))
-
-(defun transient--kbd (keys)
- (when (vectorp keys)
- (setq keys (key-description keys)))
- (when (stringp keys)
- (setq keys (kbd keys)))
- keys)
-
-(defun transient--spec-key (spec)
- (let ((plist (nth 2 spec)))
- (or (plist-get plist :key)
- (transient--command-key
- (plist-get plist :command)))))
-
-(defun transient--command-key (cmd)
- (and-let* ((obj (get cmd 'transient--suffix)))
- (cond ((slot-boundp obj 'key)
- (oref obj key))
- ((slot-exists-p obj 'shortarg)
- (if (slot-boundp obj 'shortarg)
- (oref obj shortarg)
- (transient--derive-shortarg (oref obj argument)))))))
-
-(defun transient--nthcdr (n list)
- (nthcdr (if (< n 0) (- (length list) (abs n)) n) list))
-
-;;; Variables
-
-(defvar transient-current-prefix nil
- "The transient from which this suffix command was invoked.
-This is an object representing that transient, use
-`transient-current-command' to get the respective command.")
-
-(defvar transient-current-command nil
- "The transient from which this suffix command was invoked.
-This is a symbol representing that transient, use
-`transient-current-prefix' to get the respective object.")
-
-(defvar transient-current-suffixes nil
- "The suffixes of the transient from which this suffix command was invoked.
-This is a list of objects. Usually it is sufficient to instead
-use the function `transient-args', which returns a list of
-values. In complex cases it might be necessary to use this
-variable instead.")
-
-(defvar transient-exit-hook nil
- "Hook run after exiting a transient.")
-
-(defvar transient--prefix nil)
-(defvar transient--layout nil)
-(defvar transient--suffixes nil)
-
-(defconst transient--stay t "Do not exit the transient.")
-(defconst transient--exit nil "Do exit the transient.")
-
-(defvar transient--exitp nil "Whether to exit the transient.")
-(defvar transient--showp nil "Whether the transient is show in a popup buffer.")
-(defvar transient--helpp nil "Whether help-mode is active.")
-(defvar transient--editp nil "Whether edit-mode is active.")
-
-(defvar transient--active-infix nil "The active infix awaiting user input.")
-
-(defvar transient--timer nil)
-
-(defvar transient--stack nil)
-
-(defvar transient--minibuffer-depth 0)
-
-(defvar transient--buffer-name " *transient*"
- "Name of the transient buffer.")
-
-(defvar transient--window nil
- "The window used to display the transient popup.")
-
-(defvar transient--original-window nil
- "The window that was selected before the transient was invoked.
-Usually it remains selected while the transient is active.")
-
-(defvar transient--original-buffer nil
- "The buffer that was current before the transient was invoked.
-Usually it remains current while the transient is active.")
-
-(defvar transient--debug nil "Whether put debug information into *Messages*.")
-
-(defvar transient--history nil)
-
-(defvar transient--scroll-commands
- '(transient-scroll-up
- transient-scroll-down
- mwheel-scroll
- scroll-bar-toolkit-scroll))
-
-;;; Identities
-
-(defun transient-suffix-object (&optional command)
- "Return the object associated with the current suffix command.
-
-Each suffix commands is associated with an object, which holds
-additional information about the suffix, such as its value (in
-the case of an infix command, which is a kind of suffix command).
-
-This function is intended to be called by infix commands, whose
-command definition usually (at least when defined using
-`transient-define-infix') is this:
-
- (lambda ()
- (interactive)
- (let ((obj (transient-suffix-object)))
- (transient-infix-set obj (transient-infix-read obj)))
- (transient--show))
-
-\(User input is read outside of `interactive' to prevent the
-command from being added to `command-history'. See #23.)
-
-Such commands need to be able to access their associated object
-to guide how `transient-infix-read' reads the new value and to
-store the read value. Other suffix commands (including non-infix
-commands) may also need the object to guide their behavior.
-
-This function attempts to return the object associated with the
-current suffix command even if the suffix command was not invoked
-from a transient. (For some suffix command that is a valid thing
-to do, for others it is not.) In that case nil may be returned
-if the command was not defined using one of the macros intended
-to define such commands.
-
-The optional argument COMMAND is intended for internal use. If
-you are contemplating using it in your own code, then you should
-probably use this instead:
-
- (get COMMAND \\='transient--suffix)"
- (when command
- (cl-check-type command command))
- (if (or transient--prefix
- transient-current-prefix)
- (let ((suffixes
- (cl-remove-if-not
- (lambda (obj)
- (eq (transient--suffix-command obj)
- (or command
- (if (eq this-command 'transient-set-level)
- ;; This is how it can look up for which
- ;; command it is setting the level.
- this-original-command
- this-command))))
- (or transient--suffixes
- transient-current-suffixes))))
- (or (and (cdr suffixes)
- (cl-find-if
- (lambda (obj)
- (equal (listify-key-sequence (transient--kbd (oref obj key)))
- (listify-key-sequence (this-command-keys))))
- suffixes))
- (car suffixes)))
- (when-let* ((obj (get (or command this-command) 'transient--suffix))
- (obj (clone obj)))
- ;; Cannot use and-let* because of debbugs#31840.
- (transient-init-scope obj)
- (transient-init-value obj)
- obj)))
-
-(defun transient--suffix-command (object)
- "Return the command represented by OBJECT.
-
-If the value of OBJECT's `command' slot is a command, then return
-that. Otherwise it is a symbol whose `transient--infix-command'
-property holds an anonymous command, which is returned instead."
- (cl-check-type object transient-suffix)
- (let ((sym (oref object command)))
- (if (commandp sym)
- sym
- (get sym 'transient--infix-command))))
-
-(defun transient--suffix-symbol (arg)
- "Return a symbol representing ARG.
-
-ARG must be a command and/or a symbol. If it is a symbol,
-then just return it. Otherwise return the symbol whose
-`transient--infix-command' property's value is ARG."
- (or (cl-typep arg 'command)
- (cl-typep arg 'symbol)
- (signal 'wrong-type-argument `((command symbol) ,arg)))
- (if (symbolp arg)
- arg
- (let* ((obj (transient-suffix-object))
- (sym (oref obj command)))
- (if (eq (get sym 'transient--infix-command) arg)
- sym
- (catch 'found
- (mapatoms (lambda (sym)
- (when (eq (get sym 'transient--infix-command) arg)
- (throw 'found sym)))))))))
-
-;;; Keymaps
-
-(defvar-keymap transient-base-map
- :doc "Parent of other keymaps used by Transient.
-
-This is the parent keymap of all the keymaps that are used in
-all transients: `transient-map' (which in turn is the parent
-of the transient-specific keymaps), `transient-edit-map' and
-`transient-sticky-map'.
-
-If you change a binding here, then you might also have to edit
-`transient-sticky-map' and `transient-common-commands'. While
-the latter isn't a proper transient prefix command, it can be
-edited using the same functions as used for transients.
-
-If you add a new command here, then you must also add a binding
-to `transient-predicate-map'."
- "ESC ESC ESC" #'transient-quit-all
- "C-g" #'transient-quit-one
- "C-q" #'transient-quit-all
- "C-z" #'transient-suspend
- "C-v" #'transient-scroll-up
- "C-M-v" #'transient-scroll-down
- "<next>" #'transient-scroll-up
- "<prior>" #'transient-scroll-down)
-
-(defvar-keymap transient-map
- :doc "Top-level keymap used by all transients.
-
-If you add a new command here, then you must also add a binding
-to `transient-predicate-map'. Also see `transient-base-map'."
- :parent transient-base-map
- "C-u" #'universal-argument
- "C--" #'negative-argument
- "C-t" #'transient-show
- "?" #'transient-help
- "C-h" #'transient-help
- ;; Also bound to "C-x p" and "C-x n" in transient-common-commands.
- "C-M-p" #'transient-history-prev
- "C-M-n" #'transient-history-next)
-
-(defvar-keymap transient-edit-map
- :doc "Keymap that is active while a transient in is in \"edit mode\"."
- :parent transient-base-map
- "?" #'transient-help
- "C-h" #'transient-help
- "C-x l" #'transient-set-level)
-
-(defvar-keymap transient-sticky-map
- :doc "Keymap that is active while an incomplete key sequence is active."
- :parent transient-base-map
- "C-g" #'transient-quit-seq)
-
-(defvar transient--common-command-prefixes '(?\C-x))
-
-(put 'transient-common-commands
- 'transient--layout
- (list
- (eval
- (car (transient--parse-child
- 'transient-common-commands
- (vector
- :hide
- (lambda ()
- (and (not (memq
- (car (bound-and-true-p transient--redisplay-key))
- transient--common-command-prefixes))
- (not transient-show-common-commands)))
- (vector
- "Value commands"
- (list "C-x s " "Set" #'transient-set)
- (list "C-x C-s" "Save" #'transient-save)
- (list "C-x C-k" "Reset" #'transient-reset)
- (list "C-x p " "Previous value" #'transient-history-prev)
- (list "C-x n " "Next value" #'transient-history-next))
- (vector
- "Sticky commands"
- ;; Like `transient-sticky-map' except that
- ;; "C-g" has to be bound to a different command.
- (list "C-g" "Quit prefix or transient" #'transient-quit-one)
- (list "C-q" "Quit transient stack" #'transient-quit-all)
- (list "C-z" "Suspend transient stack" #'transient-suspend))
- (vector
- "Customize"
- (list "C-x t" 'transient-toggle-common :description
- (lambda ()
- (if transient-show-common-commands
- "Hide common commands"
- "Show common permanently")))
- (list "C-x l" "Show/hide suffixes" #'transient-set-level))))))))
-
-(defvar-keymap transient-popup-navigation-map
- :doc "One of the keymaps used when popup navigation is enabled.
-See `transient-enable-popup-navigation'."
- "<down-mouse-1>" #'transient-noop
- "<up>" #'transient-backward-button
- "<down>" #'transient-forward-button
- "C-r" #'transient-isearch-backward
- "C-s" #'transient-isearch-forward
- "M-RET" #'transient-push-button)
-
-(defvar-keymap transient-button-map
- :doc "One of the keymaps used when popup navigation is enabled.
-See `transient-enable-popup-navigation'."
- "<mouse-1>" #'transient-push-button
- "<mouse-2>" #'transient-push-button)
-
-(defvar-keymap transient-predicate-map
- :doc "Base keymap used to map common commands to their transient behavior.
-
-The \"transient behavior\" of a command controls, among other
-things, whether invoking the command causes the transient to be
-exited or not, and whether infix arguments are exported before
-doing so.
-
-Each \"key\" is a command that is common to all transients and
-that is bound in `transient-map', `transient-edit-map',
-`transient-sticky-map' and/or `transient-common-command'.
-
-Each binding is a \"pre-command\", a function that controls the
-transient behavior of the respective command.
-
-For transient commands that are bound in individual transients,
-the transient behavior is specified using the `:transient' slot
-of the corresponding object."
- "<transient-suspend>" #'transient--do-suspend
- "<transient-help>" #'transient--do-stay
- "<transient-set-level>" #'transient--do-stay
- "<transient-history-prev>" #'transient--do-stay
- "<transient-history-next>" #'transient--do-stay
- "<universal-argument>" #'transient--do-stay
- "<universal-argument-more>" #'transient--do-stay
- "<negative-argument>" #'transient--do-minus
- "<digit-argument>" #'transient--do-stay
- "<top-level>" #'transient--do-quit-all
- "<transient-quit-all>" #'transient--do-quit-all
- "<transient-quit-one>" #'transient--do-quit-one
- "<transient-quit-seq>" #'transient--do-stay
- "<transient-show>" #'transient--do-stay
- "<transient-update>" #'transient--do-stay
- "<transient-toggle-common>" #'transient--do-stay
- "<transient-set>" #'transient--do-call
- "<transient-save>" #'transient--do-call
- "<transient-reset>" #'transient--do-call
- "<describe-key-briefly>" #'transient--do-stay
- "<describe-key>" #'transient--do-stay
- "<transient-scroll-up>" #'transient--do-stay
- "<transient-scroll-down>" #'transient--do-stay
- "<mwheel-scroll>" #'transient--do-stay
- "<scroll-bar-toolkit-scroll>" #'transient--do-stay
- "<transient-noop>" #'transient--do-noop
- "<transient-mouse-push-button>" #'transient--do-move
- "<transient-push-button>" #'transient--do-push-button
- "<transient-backward-button>" #'transient--do-move
- "<transient-forward-button>" #'transient--do-move
- "<transient-isearch-backward>" #'transient--do-move
- "<transient-isearch-forward>" #'transient--do-move
- ;; If a valid but incomplete prefix sequence is followed by
- ;; an unbound key, then Emacs calls the `undefined' command
- ;; but does not set `this-command', `this-original-command'
- ;; or `real-this-command' accordingly. Instead they are nil.
- "<nil>" #'transient--do-warn)
-
-(defvar transient--transient-map nil)
-(defvar transient--predicate-map nil)
-(defvar transient--redisplay-map nil)
-(defvar transient--redisplay-key nil)
-
-(defun transient--push-keymap (var)
- (let ((map (symbol-value var)))
- (transient--debug " push %s%s" var (if map "" " VOID"))
- (when map
- (with-demoted-errors "transient--push-keymap: %S"
- (internal-push-keymap map 'overriding-terminal-local-map)))))
-
-(defun transient--pop-keymap (var)
- (let ((map (symbol-value var)))
- (when map
- (transient--debug " pop %s" var)
- (with-demoted-errors "transient--pop-keymap: %S"
- (internal-pop-keymap map 'overriding-terminal-local-map)))))
-
-(defun transient--make-transient-map ()
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map (if transient--editp
- transient-edit-map
- transient-map))
- (dolist (obj transient--suffixes)
- (let ((key (oref obj key)))
- (when (vectorp key)
- (setq key (key-description key))
- (oset obj key key))
- (when transient-substitute-key-function
- (setq key (save-match-data
- (funcall transient-substitute-key-function obj)))
- (oset obj key key))
- (let ((kbd (kbd key))
- (cmd (transient--suffix-command obj)))
- (when-let ((conflict (and transient-detect-key-conflicts
- (transient--lookup-key map kbd))))
- (unless (eq cmd conflict)
- (error "Cannot bind %S to %s and also %s"
- (string-trim key)
- cmd conflict)))
- (define-key map kbd cmd))))
- (when-let ((b (keymap-lookup map "-"))) (keymap-set map "<kp-subtract>" b))
- (when-let ((b (keymap-lookup map "="))) (keymap-set map "<kp-equal>" b))
- (when-let ((b (keymap-lookup map "+"))) (keymap-set map "<kp-add>" b))
- (when transient-enable-popup-navigation
- ;; `transient--make-redisplay-map' maps only over bindings that are
- ;; directly in the base keymap, so that cannot be a composed keymap.
- (set-keymap-parent
- map (make-composed-keymap
- (keymap-parent map)
- transient-popup-navigation-map)))
- map))
-
-(defun transient--make-predicate-map ()
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map transient-predicate-map)
- (when (memq (oref transient--prefix transient-non-suffix)
- '(nil transient--do-warn transient--do-noop))
- (keymap-set map "<handle-switch-frame>" #'transient--do-suspend))
- (dolist (obj transient--suffixes)
- (let* ((cmd (oref obj command))
- (sub-prefix (and (symbolp cmd) (get cmd 'transient--prefix) t))
- (sym (transient--suffix-symbol cmd)))
- (cond
- ((oref obj inapt)
- (define-key map (vector sym) #'transient--do-warn-inapt))
- ((slot-boundp obj 'transient)
- (define-key map (vector sym)
- (let ((do (oref obj transient)))
- (pcase (list do sub-prefix)
- ('(t t) #'transient--do-recurse)
- ('(t nil) (if (cl-typep obj 'transient-infix)
- #'transient--do-stay
- #'transient--do-call))
- ('(nil t) #'transient--do-replace)
- ('(nil nil) #'transient--do-exit)
- (_ do)))))
- ((not (lookup-key transient-predicate-map (vector sym)))
- (define-key map (vector sym)
- (if sub-prefix
- #'transient--do-replace
- (or (oref transient--prefix transient-suffix)
- #'transient--do-exit)))))))
- map))
-
-(defun transient--make-redisplay-map ()
- (setq transient--redisplay-key
- (cl-case this-command
- (transient-update
- (setq transient--showp t)
- (setq unread-command-events
- (listify-key-sequence (this-single-command-raw-keys))))
- (transient-quit-seq
- (setq unread-command-events
- (butlast (listify-key-sequence
- (this-single-command-raw-keys))
- 2))
- (butlast transient--redisplay-key))
- (t nil)))
- (let ((topmap (make-sparse-keymap))
- (submap (make-sparse-keymap)))
- (when transient--redisplay-key
- (define-key topmap (vconcat transient--redisplay-key) submap)
- (set-keymap-parent submap transient-sticky-map))
- (map-keymap-internal
- (lambda (key def)
- (when (and (not (eq key ?\e))
- (listp def)
- (keymapp def))
- (define-key topmap (vconcat transient--redisplay-key (list key))
- #'transient-update)))
- (if transient--redisplay-key
- (let ((key (vconcat transient--redisplay-key)))
- (or (lookup-key transient--transient-map key)
- (and-let* ((regular (lookup-key local-function-key-map key)))
- (lookup-key transient--transient-map (vconcat regular)))))
- transient--transient-map))
- topmap))
-
-;;; Setup
-
-(defun transient-setup (&optional name layout edit &rest params)
- "Setup the transient specified by NAME.
-
-This function is called by transient prefix commands to setup the
-transient. In that case NAME is mandatory, LAYOUT and EDIT must
-be nil and PARAMS may be (but usually is not) used to set, e.g.,
-the \"scope\" of the transient (see `transient-define-prefix').
-
-This function is also called internally in which case LAYOUT and
-EDIT may be non-nil."
- (transient--debug 'setup)
- (transient--with-emergency-exit
- (cond
- ((not name)
- ;; Switching between regular and edit mode.
- (transient--pop-keymap 'transient--transient-map)
- (transient--pop-keymap 'transient--redisplay-map)
- (setq name (oref transient--prefix command))
- (setq params (list :scope (oref transient--prefix scope))))
- (transient--prefix
- ;; Invoked as a ":transient-non-suffix 'transient--do-{stay,call}"
- ;; of an outer prefix. Unlike the usual `transient--do-replace',
- ;; these predicates fail to clean up after the outer prefix.
- (transient--pop-keymap 'transient--transient-map)
- (transient--pop-keymap 'transient--redisplay-map))
- ((not (or layout ; resuming parent/suspended prefix
- transient-current-command)) ; entering child prefix
- (transient--stack-zap)) ; replace suspended prefix, if any
- (edit
- ;; Returning from help to edit.
- (setq transient--editp t)))
- (transient--init-objects name layout params)
- (transient--history-init transient--prefix)
- (setq transient--predicate-map (transient--make-predicate-map))
- (setq transient--transient-map (transient--make-transient-map))
- (setq transient--redisplay-map (transient--make-redisplay-map))
- (setq transient--original-window (selected-window))
- (setq transient--original-buffer (current-buffer))
- (setq transient--minibuffer-depth (minibuffer-depth))
- (transient--redisplay)
- (transient--init-transient)
- (transient--suspend-which-key-mode)))
-
-(cl-defgeneric transient-setup-children (group children)
- "Setup the CHILDREN of GROUP.
-If the value of the `setup-children' slot is non-nil, then call
-that function with CHILDREN as the only argument and return the
-value. Otherwise return CHILDREN as is."
- (if (slot-boundp group 'setup-children)
- (funcall (oref group setup-children) children)
- children))
-
-(defun transient--init-objects (name layout params)
- (setq transient--prefix (transient--init-prefix name params))
- (setq transient--layout (or layout (transient--init-suffixes name)))
- (setq transient--suffixes (transient--flatten-suffixes transient--layout)))
-
-(defun transient--init-prefix (name &optional params)
- (let ((obj (let ((proto (get name 'transient--prefix)))
- (apply #'clone proto
- :prototype proto
- :level (or (alist-get t (alist-get name transient-levels))
- transient-default-level)
- params))))
- (transient--setup-recursion obj)
- (transient-init-value obj)
- obj))
-
-(defun transient--init-suffixes (name)
- (let ((levels (alist-get name transient-levels)))
- (cl-mapcan (lambda (c) (transient--init-child levels c))
- (append (get name 'transient--layout)
- (and (not transient--editp)
- (get 'transient-common-commands
- 'transient--layout))))))
-
-(defun transient--flatten-suffixes (layout)
- (cl-labels ((s (def)
- (cond
- ((stringp def) nil)
- ((listp def) (cl-mapcan #'s def))
- ((transient-group--eieio-childp def)
- (cl-mapcan #'s (oref def suffixes)))
- ((transient-suffix--eieio-childp def)
- (list def)))))
- (cl-mapcan #'s layout)))
-
-(defun transient--init-child (levels spec)
- (cl-etypecase spec
- (vector (transient--init-group levels spec))
- (list (transient--init-suffix levels spec))
- (string (list spec))))
-
-(defun transient--init-group (levels spec)
- (pcase-let ((`(,level ,class ,args ,children) (append spec nil)))
- (when-let* ((- (transient--use-level-p level))
- (obj (apply class :level level args))
- (- (transient--use-suffix-p obj))
- (suffixes (cl-mapcan (lambda (c) (transient--init-child levels c))
- (transient-setup-children obj children))))
- ;; Cannot use and-let* because of debbugs#31840.
- (oset obj suffixes suffixes)
- (list obj))))
-
-(defun transient--init-suffix (levels spec)
- (pcase-let* ((`(,level ,class ,args) spec)
- (cmd (plist-get args :command))
- (level (or (alist-get (transient--suffix-symbol cmd) levels)
- level)))
- (let ((fn (and (symbolp cmd)
- (symbol-function cmd))))
- (when (autoloadp fn)
- (transient--debug " autoload %s" cmd)
- (autoload-do-load fn)))
- (when (transient--use-level-p level)
- (let ((obj (if-let ((proto (and cmd
- (symbolp cmd)
- (get cmd 'transient--suffix))))
- (apply #'clone proto :level level args)
- (apply class :level level args))))
- (transient--init-suffix-key obj)
- (transient--ensure-infix-command obj)
- (when (transient--use-suffix-p obj)
- (if (transient--inapt-suffix-p obj)
- (oset obj inapt t)
- (transient-init-scope obj)
- (transient-init-value obj))
- (list obj))))))
-
-(cl-defmethod transient--init-suffix-key ((obj transient-suffix))
- (unless (slot-boundp obj 'key)
- (error "No key for %s" (oref obj command))))
-
-(cl-defmethod transient--init-suffix-key ((obj transient-argument))
- (if (transient-switches--eieio-childp obj)
- (cl-call-next-method obj)
- (unless (slot-boundp obj 'shortarg)
- (when-let ((shortarg (transient--derive-shortarg (oref obj argument))))
- (oset obj shortarg shortarg)))
- (unless (slot-boundp obj 'key)
- (if (slot-boundp obj 'shortarg)
- (oset obj key (oref obj shortarg))
- (error "No key for %s" (oref obj command))))))
-
-(defun transient--use-level-p (level &optional edit)
- (or (and transient--editp (not edit))
- (and (>= level 1)
- (<= level (oref transient--prefix level)))))
-
-(defun transient--use-suffix-p (obj)
- (transient--do-suffix-p
- (oref obj if)
- (oref obj if-not)
- (oref obj if-nil)
- (oref obj if-non-nil)
- (oref obj if-mode)
- (oref obj if-not-mode)
- (oref obj if-derived)
- (oref obj if-not-derived)
- t))
-
-(defun transient--inapt-suffix-p (obj)
- (transient--do-suffix-p
- (oref obj inapt-if)
- (oref obj inapt-if-not)
- (oref obj inapt-if-nil)
- (oref obj inapt-if-non-nil)
- (oref obj inapt-if-mode)
- (oref obj inapt-if-not-mode)
- (oref obj inapt-if-derived)
- (oref obj inapt-if-not-derived)
- nil))
-
-(defun transient--do-suffix-p
- (if if-not if-nil if-non-nil if-mode if-not-mode if-derived if-not-derived
- default)
- (cond
- (if (funcall if))
- (if-not (not (funcall if-not)))
- (if-non-nil (symbol-value if-non-nil))
- (if-nil (not (symbol-value if-nil)))
- (if-mode (if (atom if-mode)
- (eq major-mode if-mode)
- (memq major-mode if-mode)))
- (if-not-mode (not (if (atom if-not-mode)
- (eq major-mode if-not-mode)
- (memq major-mode if-not-mode))))
- (if-derived (if (atom if-derived)
- (derived-mode-p if-derived)
- (apply #'derived-mode-p if-derived)))
- (if-not-derived (not (if (atom if-not-derived)
- (derived-mode-p if-not-derived)
- (apply #'derived-mode-p if-not-derived))))
- (t default)))
-
-(defun transient--suffix-predicate (spec)
- (let ((plist (nth 2 spec)))
- (seq-some (lambda (prop)
- (and-let* ((pred (plist-get plist prop)))
- (list prop pred)))
- '( :if :if-not
- :if-nil :if-non-nil
- :if-mode :if-not-mode
- :if-derived :if-not-derived
- :inapt-if :inapt-if-not
- :inapt-if-nil :inapt-if-non-nil
- :inapt-if-mode :inapt-if-not-mode
- :inapt-if-derived :inapt-if-not-derived))))
-
-;;; Flow-Control
-
-(defun transient--init-transient ()
- (transient--debug 'init-transient)
- (transient--push-keymap 'transient--transient-map)
- (transient--push-keymap 'transient--redisplay-map)
- (add-hook 'pre-command-hook #'transient--pre-command)
- (add-hook 'post-command-hook #'transient--post-command)
- (advice-add 'recursive-edit :around #'transient--recursive-edit)
- (when transient--exitp
- ;; This prefix command was invoked as the suffix of another.
- ;; Prevent `transient--post-command' from removing the hooks
- ;; that we just added.
- (setq transient--exitp 'replace)))
-
-(defun transient--pre-command ()
- (transient--debug 'pre-command)
- (transient--with-emergency-exit
- ;; The use of `overriding-terminal-local-map' does not prevent the
- ;; lookup of command remappings in the overridden maps, which can
- ;; lead to a suffix being remapped to a non-suffix. We have to undo
- ;; the remapping in that case. However, remapping a non-suffix to
- ;; another should remain possible.
- (when (and (transient--get-predicate-for this-original-command 'suffix)
- (not (transient--get-predicate-for this-command 'suffix)))
- (setq this-command this-original-command))
- (cond
- ((memq this-command '(transient-update transient-quit-seq))
- (transient--pop-keymap 'transient--redisplay-map))
- ((and transient--helpp
- (not (memq this-command '(transient-quit-one
- transient-quit-all))))
- (cond
- ((transient-help)
- (transient--do-suspend)
- (setq this-command 'transient-suspend)
- (transient--pre-exit))
- ((not (transient--edebug-command-p))
- (setq this-command 'transient-undefined))))
- ((and transient--editp
- (transient-suffix-object)
- (not (memq this-command '(transient-quit-one
- transient-quit-all
- transient-help))))
- (setq this-command 'transient-set-level)
- (transient--wrap-command))
- (t
- (setq transient--exitp nil)
- (let ((exitp (eq (transient--do-pre-command) transient--exit)))
- (transient--wrap-command)
- (when exitp
- (transient--pre-exit)))))))
-
-(defun transient--do-pre-command ()
- (if-let ((fn (transient--get-predicate-for this-command)))
- (let ((action (funcall fn)))
- (when (eq action transient--exit)
- (setq transient--exitp (or transient--exitp t)))
- action)
- (if (let ((keys (this-command-keys-vector)))
- (eq (aref keys (1- (length keys))) ?\C-g))
- (setq this-command 'transient-noop)
- (unless (transient--edebug-command-p)
- (setq this-command 'transient-undefined)))
- transient--stay))
-
-(defun transient--get-predicate-for (cmd &optional suffix-only)
- (or (ignore-errors
- (lookup-key transient--predicate-map
- (vector (transient--suffix-symbol cmd))))
- (and (not suffix-only)
- (let ((pred (oref transient--prefix transient-non-suffix)))
- (pcase pred
- ('t #'transient--do-stay)
- ('nil #'transient--do-warn)
- (_ pred))))))
-
-(defun transient--pre-exit ()
- (transient--debug 'pre-exit)
- (transient--delete-window)
- (transient--timer-cancel)
- (transient--pop-keymap 'transient--transient-map)
- (transient--pop-keymap 'transient--redisplay-map)
- (unless transient--showp
- (let ((message-log-max nil))
- (message "")))
- (setq transient--transient-map nil)
- (setq transient--predicate-map nil)
- (setq transient--redisplay-map nil)
- (setq transient--redisplay-key nil)
- (setq transient--helpp nil)
- (setq transient--editp nil)
- (setq transient--prefix nil)
- (setq transient--layout nil)
- (setq transient--suffixes nil)
- (setq transient--original-window nil)
- (setq transient--original-buffer nil)
- (setq transient--window nil))
-
-(defun transient--delete-window ()
- (when (window-live-p transient--window)
- (let ((remain-in-minibuffer-window
- (and (minibuffer-selected-window)
- (selected-window)))
- (buf (window-buffer transient--window)))
- ;; Only delete the window if it never showed another buffer.
- (unless (eq (car (window-parameter transient--window 'quit-restore)) 'other)
- (with-demoted-errors "Error while exiting transient: %S"
- (delete-window transient--window)))
- (kill-buffer buf)
- (when remain-in-minibuffer-window
- (select-window remain-in-minibuffer-window)))))
-
-(defun transient--export ()
- (setq transient-current-prefix transient--prefix)
- (setq transient-current-command (oref transient--prefix command))
- (setq transient-current-suffixes transient--suffixes)
- (transient--history-push transient--prefix))
-
-(defun transient--suspend-override (&optional nohide)
- (transient--debug 'suspend-override)
- (transient--timer-cancel)
- (cond ((and (not nohide) transient-hide-during-minibuffer-read)
- (transient--delete-window))
- ((and transient--prefix transient--redisplay-key)
- (setq transient--redisplay-key nil)
- (when transient--showp
- (transient--show))))
- (transient--pop-keymap 'transient--transient-map)
- (transient--pop-keymap 'transient--redisplay-map)
- (remove-hook 'pre-command-hook #'transient--pre-command)
- (remove-hook 'post-command-hook #'transient--post-command))
-
-(defun transient--resume-override (&optional _ignore)
- (transient--debug 'resume-override)
- (when (and transient--showp transient-hide-during-minibuffer-read)
- (transient--show))
- (transient--push-keymap 'transient--transient-map)
- (transient--push-keymap 'transient--redisplay-map)
- (add-hook 'pre-command-hook #'transient--pre-command)
- (add-hook 'post-command-hook #'transient--post-command))
-
-(defun transient--recursive-edit (fn)
- (transient--debug 'recursive-edit)
- (if (not transient--prefix)
- (funcall fn)
- (transient--suspend-override (bound-and-true-p edebug-active))
- (funcall fn) ; Already unwind protected.
- (cond ((memq this-command '(top-level abort-recursive-edit))
- (setq transient--exitp t)
- (transient--post-exit)
- (transient--delete-window))
- (transient--prefix
- (transient--resume-override)))))
-
-(defmacro transient--with-suspended-override (&rest body)
- (let ((depth (make-symbol "depth"))
- (setup (make-symbol "setup"))
- (exit (make-symbol "exit")))
- `(if (and transient--transient-map
- (memq transient--transient-map
- overriding-terminal-local-map))
- (let ((,depth (1+ (minibuffer-depth))) ,setup ,exit)
- (setq ,setup
- (lambda () "@transient--with-suspended-override"
- (transient--debug 'minibuffer-setup)
- (remove-hook 'minibuffer-setup-hook ,setup)
- (transient--suspend-override)))
- (setq ,exit
- (lambda () "@transient--with-suspended-override"
- (transient--debug 'minibuffer-exit)
- (when (= (minibuffer-depth) ,depth)
- (transient--resume-override))))
- (unwind-protect
- (progn
- (add-hook 'minibuffer-setup-hook ,setup)
- (add-hook 'minibuffer-exit-hook ,exit)
- ,@body)
- (remove-hook 'minibuffer-setup-hook ,setup)
- (remove-hook 'minibuffer-exit-hook ,exit)))
- ,@body)))
-
-(defun transient--wrap-command ()
- (let* ((prefix transient--prefix)
- (suffix this-command)
- (advice nil)
- (advice-interactive
- (lambda (spec)
- (let ((abort t))
- (unwind-protect
- (prog1 (advice-eval-interactive-spec spec)
- (setq abort nil))
- (when abort
- (when-let ((unwind (oref prefix unwind-suffix)))
- (transient--debug 'unwind-interactive)
- (funcall unwind suffix))
- (if (symbolp suffix)
- (advice-remove suffix advice)
- (remove-function suffix advice))
- (oset prefix unwind-suffix nil))))))
- (advice-body
- (lambda (fn &rest args)
- (unwind-protect
- (apply fn args)
- (when-let ((unwind (oref prefix unwind-suffix)))
- (transient--debug 'unwind-command)
- (funcall unwind suffix))
- (if (symbolp suffix)
- (advice-remove suffix advice)
- (remove-function suffix advice))
- (oset prefix unwind-suffix nil)))))
- (setq advice `(lambda (fn &rest args)
- (interactive ,advice-interactive)
- (apply ',advice-body fn args)))
- (if (symbolp suffix)
- (advice-add suffix :around advice '((depth . -99)))
- (add-function :around (var suffix) advice '((depth . -99))))))
-
-(defun transient--premature-post-command ()
- (and (equal (this-command-keys-vector) [])
- (= (minibuffer-depth)
- (1+ transient--minibuffer-depth))
- (progn
- (transient--debug 'premature-post-command)
- (transient--suspend-override)
- (oset (or transient--prefix transient-current-prefix)
- unwind-suffix
- (if transient--exitp
- #'transient--post-exit
- #'transient--resume-override))
- t)))
-
-(defun transient--post-command ()
- (unless (transient--premature-post-command)
- (transient--debug 'post-command)
- (transient--with-emergency-exit
- (cond (transient--exitp (transient--post-exit))
- ((eq this-command (oref transient--prefix command)))
- ((let ((old transient--redisplay-map)
- (new (transient--make-redisplay-map)))
- (unless (equal old new)
- (transient--pop-keymap 'transient--redisplay-map)
- (setq transient--redisplay-map new)
- (transient--push-keymap 'transient--redisplay-map))
- (transient--redisplay)))))))
-
-(defun transient--post-exit (&optional command)
- (transient--debug 'post-exit)
- (unless (and (eq transient--exitp 'replace)
- (or transient--prefix
- ;; The current command could act as a prefix,
- ;; but decided not to call `transient-setup',
- ;; or it is prevented from doing so because it
- ;; uses the minibuffer and the user aborted
- ;; that.
- (prog1 nil
- (if (let ((obj (transient-suffix-object command)))
- (and (slot-boundp obj 'transient)
- (oref obj transient)))
- ;; This sub-prefix is a transient suffix;
- ;; go back to outer prefix, by calling
- ;; `transient--stack-pop' further down.
- (setq transient--exitp nil)
- (transient--stack-zap)))))
- (remove-hook 'pre-command-hook #'transient--pre-command)
- (remove-hook 'post-command-hook #'transient--post-command)
- (advice-remove 'recursive-edit #'transient--recursive-edit))
- (setq transient-current-prefix nil)
- (setq transient-current-command nil)
- (setq transient-current-suffixes nil)
- (let ((resume (and transient--stack
- (not (memq transient--exitp '(replace suspend))))))
- (unless (or resume (eq transient--exitp 'replace))
- (setq transient--showp nil))
- (setq transient--exitp nil)
- (setq transient--helpp nil)
- (setq transient--editp nil)
- (setq transient--minibuffer-depth 0)
- (run-hooks 'transient-exit-hook)
- (when resume
- (transient--stack-pop))))
-
-(defun transient--stack-push ()
- (transient--debug 'stack-push)
- (push (list (oref transient--prefix command)
- transient--layout
- transient--editp
- :scope (oref transient--prefix scope))
- transient--stack))
-
-(defun transient--stack-pop ()
- (transient--debug 'stack-pop)
- (and transient--stack
- (prog1 t (apply #'transient-setup (pop transient--stack)))))
-
-(defun transient--stack-zap ()
- (transient--debug 'stack-zap)
- (setq transient--stack nil))
-
-(defun transient--redisplay ()
- (if (or (eq transient-show-popup t)
- transient--showp)
- (unless
- (or (memq this-command transient--scroll-commands)
- (and (or (memq this-command '(mouse-drag-region
- mouse-set-region))
- (equal (key-description (this-command-keys-vector))
- "<mouse-movement>"))
- (and (eq (current-buffer)
- (get-buffer transient--buffer-name)))))
- (transient--show))
- (when (and (numberp transient-show-popup)
- (not (zerop transient-show-popup))
- (not transient--timer))
- (transient--timer-start))
- (transient--show-brief)))
-
-(defun transient--timer-start ()
- (setq transient--timer
- (run-at-time (abs transient-show-popup) nil
- (lambda ()
- (transient--timer-cancel)
- (transient--show)
- (let ((message-log-max nil))
- (message ""))))))
-
-(defun transient--timer-cancel ()
- (when transient--timer
- (cancel-timer transient--timer)
- (setq transient--timer nil)))
-
-(defun transient--debug (arg &rest args)
- (when transient--debug
- (let ((inhibit-message (not (eq transient--debug 'message))))
- (if (symbolp arg)
- (message "-- %-22s (cmd: %s, event: %S, exit: %s%s)"
- arg
- (or (ignore-errors (transient--suffix-symbol this-command))
- (if (byte-code-function-p this-command)
- "#[...]"
- this-command))
- (key-description (this-command-keys-vector))
- transient--exitp
- (cond ((stringp (car args))
- (concat ", " (apply #'format args)))
- (args
- (concat ", " (apply (car args) (cdr args))))
- (t "")))
- (apply #'message arg args)))))
-
-(defun transient--emergency-exit ()
- "Exit the current transient command after an error occurred.
-When no transient is active (i.e. when `transient--prefix' is
-nil) then do nothing."
- (transient--debug 'emergency-exit)
- (when transient--prefix
- (setq transient--stack nil)
- (setq transient--exitp t)
- (transient--pre-exit)
- (transient--post-exit)))
-
-;;; Pre-Commands
-
-(defun transient--do-stay ()
- "Call the command without exporting variables and stay transient."
- transient--stay)
-
-(defun transient--do-noop ()
- "Call `transient-noop' and stay transient."
- (setq this-command 'transient-noop)
- transient--stay)
-
-(defun transient--do-warn ()
- "Call `transient-undefined' and stay transient."
- (setq this-command 'transient-undefined)
- transient--stay)
-
-(defun transient--do-warn-inapt ()
- "Call `transient-inapt' and stay transient."
- (setq this-command 'transient-inapt)
- transient--stay)
-
-(defun transient--do-call ()
- "Call the command after exporting variables and stay transient."
- (transient--export)
- transient--stay)
-
-(defun transient--do-return ()
- "Call the command after exporting variables and return to parent prefix.
-If there is no parent prefix, then behave like `transient--do-exit'."
- (if (not transient--stack)
- (transient--do-exit)
- (transient--export)
- transient--exit))
-
-(defun transient--do-exit ()
- "Call the command after exporting variables and exit the transient."
- (transient--export)
- (transient--stack-zap)
- transient--exit)
-
-(defun transient--do-leave ()
- "Call the command without exporting variables and exit the transient."
- transient--stay)
-
-(defun transient--do-push-button ()
- "Call the command represented by the activated button.
-Use that command's pre-command to determine transient behavior."
- (if (and (mouse-event-p last-command-event)
- (not (eq (posn-window (event-start last-command-event))
- transient--window)))
- transient--stay
- (setq this-command
- (with-selected-window transient--window
- (get-text-property (if (mouse-event-p last-command-event)
- (posn-point (event-start last-command-event))
- (point))
- 'command)))
- (transient--do-pre-command)))
-
-(defun transient--do-recurse ()
- "Call the transient prefix command, preparing for return to active transient.
-If there is no parent prefix, then just call the command."
- (transient--do-replace))
-
-(defun transient--setup-recursion (prefix-obj)
- (when transient--stack
- (let ((command (oref prefix-obj command)))
- (when-let ((suffix-obj (transient-suffix-object command)))
- (when (and (slot-boundp suffix-obj 'transient)
- (memq (oref suffix-obj transient)
- (list t #'transient--do-recurse)))
- (oset prefix-obj transient-suffix 'transient--do-return))))))
-
-(defun transient--do-replace ()
- "Call the transient prefix command, replacing the active transient."
- (transient--export)
- (transient--stack-push)
- (setq transient--exitp 'replace)
- transient--exit)
-
-(defun transient--do-suspend ()
- "Suspend the active transient, saving the transient stack."
- (transient--stack-push)
- (setq transient--exitp 'suspend)
- transient--exit)
-
-(defun transient--do-quit-one ()
- "If active, quit help or edit mode, else exit the active transient."
- (cond (transient--helpp
- (setq transient--helpp nil)
- transient--stay)
- (transient--editp
- (setq transient--editp nil)
- (transient-setup)
- transient--stay)
- (t transient--exit)))
-
-(defun transient--do-quit-all ()
- "Exit all transients without saving the transient stack."
- (transient--stack-zap)
- transient--exit)
-
-(defun transient--do-move ()
- "Call the command if `transient-enable-popup-navigation' is non-nil.
-In that case behave like `transient--do-stay', otherwise similar
-to `transient--do-warn'."
- (unless transient-enable-popup-navigation
- (setq this-command 'transient-popup-navigation-help))
- transient--stay)
-
-(defun transient--do-minus ()
- "Call `negative-argument' or pivot to `transient-update'.
-If `negative-argument' is invoked using \"-\" then preserve the
-prefix argument and pivot to `transient-update'."
- (when (equal (this-command-keys) "-")
- (setq this-command 'transient-update))
- transient--stay)
-
-(put 'transient--do-stay 'transient-color 'transient-red)
-(put 'transient--do-noop 'transient-color 'transient-red)
-(put 'transient--do-warn 'transient-color 'transient-red)
-(put 'transient--do-warn-inapt 'transient-color 'transient-red)
-(put 'transient--do-call 'transient-color 'transient-red)
-(put 'transient--do-return 'transient-color 'transient-purple)
-(put 'transient--do-exit 'transient-color 'transient-blue)
-(put 'transient--do-recurse 'transient-color 'transient-red)
-(put 'transient--do-replace 'transient-color 'transient-blue)
-(put 'transient--do-suspend 'transient-color 'transient-blue)
-(put 'transient--do-quit-one 'transient-color 'transient-blue)
-(put 'transient--do-quit-all 'transient-color 'transient-blue)
-(put 'transient--do-move 'transient-color 'transient-red)
-(put 'transient--do-minus 'transient-color 'transient-red)
-
-;;; Commands
-
-(defun transient-noop ()
- "Do nothing at all."
- (interactive))
-
-(defun transient-undefined ()
- "Warn the user that the pressed key is not bound to any suffix."
- (interactive)
- (transient--invalid "Unbound suffix"))
-
-(defun transient-inapt ()
- "Warn the user that the invoked command is inapt."
- (interactive)
- (transient--invalid "Inapt command"))
-
-(defun transient--invalid (msg)
- (ding)
- (message "%s: `%s' (Use `%s' to abort, `%s' for help)%s"
- msg
- (propertize (key-description (this-single-command-keys))
- 'face 'font-lock-warning-face)
- (propertize "C-g" 'face 'transient-key)
- (propertize "?" 'face 'transient-key)
- ;; `this-command' is `transient-undefined' or `transient-inapt'.
- ;; Show the command (`this-original-command') the user actually
- ;; tried to invoke. For an anonymous inapt command that is a
- ;; lambda expression, which cannot be mapped to a symbol, so
- ;; forgo displaying the command.
- (if-let ((cmd (ignore-errors
- (symbol-name (transient--suffix-symbol
- this-original-command)))))
- (format " [%s]" (propertize cmd 'face 'font-lock-warning-face))
- ""))
- (unless (and transient--transient-map
- (memq transient--transient-map overriding-terminal-local-map))
- (let ((transient--prefix (or transient--prefix 'sic)))
- (transient--emergency-exit))
- (view-lossage)
- (other-window 1)
- (display-warning 'transient "Inconsistent transient state detected.
-This should never happen.
-Please open an issue and post the shown command log.
-This is a heisenbug, so any additional details might help.
-Thanks!" :error)))
-
-(defun transient-toggle-common ()
- "Toggle whether common commands are always shown."
- (interactive)
- (setq transient-show-common-commands (not transient-show-common-commands)))
-
-(defun transient-suspend ()
- "Suspend the current transient.
-It can later be resumed using `transient-resume' while no other
-transient is active."
- (interactive))
-
-(defun transient-quit-all ()
- "Exit all transients without saving the transient stack."
- (interactive))
-
-(defun transient-quit-one ()
- "Exit the current transients, possibly returning to the previous."
- (interactive))
-
-(defun transient-quit-seq ()
- "Abort the current incomplete key sequence."
- (interactive))
-
-(defun transient-update ()
- "Redraw the transient's state in the popup buffer."
- (interactive)
- (when (equal this-original-command 'negative-argument)
- (setq prefix-arg current-prefix-arg)))
-
-(defun transient-show ()
- "Show the transient's state in the popup buffer."
- (interactive)
- (setq transient--showp t))
-
-(defvar-local transient--restore-winconf nil)
-
-(defvar transient-resume-mode)
-
-(defun transient-help (&optional interactive)
- "Show help for the active transient or one of its suffixes.\n\n(fn)"
- (interactive (list t))
- (if interactive
- (setq transient--helpp t)
- (with-demoted-errors "transient-help: %S"
- (when (lookup-key transient--transient-map
- (this-single-command-raw-keys))
- (setq transient--helpp nil)
- (let ((winconf (current-window-configuration)))
- (transient-show-help
- (if (eq this-original-command 'transient-help)
- transient--prefix
- (or (transient-suffix-object)
- this-original-command)))
- (setq transient--restore-winconf winconf))
- (fit-window-to-buffer nil (frame-height) (window-height))
- (transient-resume-mode)
- (message "Type \"q\" to resume transient command.")
- t))))
-
-(defun transient-set-level (&optional command level)
- "Set the level of the transient or one of its suffix commands."
- (interactive
- (let ((command this-original-command)
- (prefix (oref transient--prefix command)))
- (and (or (not (eq command 'transient-set-level))
- (and transient--editp
- (setq command prefix)))
- (list command
- (let ((keys (this-single-command-raw-keys)))
- (and (lookup-key transient--transient-map keys)
- (string-to-number
- (let ((transient--active-infix
- (transient-suffix-object command)))
- (transient--show)
- (transient--read-number-N
- (format "Set level for `%s': "
- (transient--suffix-symbol command))
- nil nil (not (eq command prefix)))))))))))
- (cond
- ((not command)
- (setq transient--editp t)
- (transient-setup))
- (level
- (let* ((prefix (oref transient--prefix command))
- (alist (alist-get prefix transient-levels))
- (sym (transient--suffix-symbol command)))
- (if (eq command prefix)
- (progn (oset transient--prefix level level)
- (setq sym t))
- (oset (transient-suffix-object command) level level))
- (setf (alist-get sym alist) level)
- (setf (alist-get prefix transient-levels) alist))
- (transient-save-levels)
- (transient--show))
- (t
- (transient-undefined))))
-
-(defun transient-set ()
- "Save the value of the active transient for this Emacs session."
- (interactive)
- (transient-set-value (or transient--prefix transient-current-prefix)))
-
-(defun transient-save ()
- "Save the value of the active transient persistenly across Emacs sessions."
- (interactive)
- (transient-save-value (or transient--prefix transient-current-prefix)))
-
-(defun transient-reset ()
- "Clear the set and saved values of the active transient."
- (interactive)
- (transient-reset-value (or transient--prefix transient-current-prefix)))
-
-(defun transient-history-next ()
- "Switch to the next value used for the active transient."
- (interactive)
- (let* ((obj transient--prefix)
- (pos (1- (oref obj history-pos)))
- (hst (oref obj history)))
- (if (< pos 0)
- (user-error "End of history")
- (oset obj history-pos pos)
- (oset obj value (nth pos hst))
- (mapc #'transient-init-value transient--suffixes))))
-
-(defun transient-history-prev ()
- "Switch to the previous value used for the active transient."
- (interactive)
- (let* ((obj transient--prefix)
- (pos (1+ (oref obj history-pos)))
- (hst (oref obj history))
- (len (length hst)))
- (if (> pos (1- len))
- (user-error "End of history")
- (oset obj history-pos pos)
- (oset obj value (nth pos hst))
- (mapc #'transient-init-value transient--suffixes))))
-
-(defun transient-scroll-up (&optional arg)
- "Scroll text of transient popup window upward ARG lines.
-If ARG is nil scroll near full screen. This is a wrapper
-around `scroll-up-command' (which see)."
- (interactive "^P")
- (with-selected-window transient--window
- (scroll-up-command arg)))
-
-(defun transient-scroll-down (&optional arg)
- "Scroll text of transient popup window down ARG lines.
-If ARG is nil scroll near full screen. This is a wrapper
-around `scroll-down-command' (which see)."
- (interactive "^P")
- (with-selected-window transient--window
- (scroll-down-command arg)))
-
-(defun transient-push-button ()
- "Invoke the suffix command represented by this button."
- (interactive))
-
-(defun transient-resume ()
- "Resume a previously suspended stack of transients."
- (interactive)
- (cond (transient--stack
- (let ((winconf transient--restore-winconf))
- (kill-local-variable 'transient--restore-winconf)
- (when transient-resume-mode
- (transient-resume-mode -1)
- (quit-window))
- (when winconf
- (set-window-configuration winconf)))
- (transient--stack-pop))
- (transient-resume-mode
- (kill-local-variable 'transient--restore-winconf)
- (transient-resume-mode -1)
- (quit-window))
- (t
- (message "No suspended transient command"))))
-
-;;; Value
-;;;; Init
-
-(cl-defgeneric transient-init-scope (obj)
- "Set the scope of the suffix object OBJ.
-
-The scope is actually a property of the transient prefix, not of
-individual suffixes. However it is possible to invoke a suffix
-command directly instead of from a transient. In that case, if
-the suffix expects a scope, then it has to determine that itself
-and store it in its `scope' slot.
-
-This function is called for all suffix commands, but unless a
-concrete method is implemented this falls through to the default
-implementation, which is a noop.")
-
-(cl-defmethod transient-init-scope ((_ transient-suffix))
- "Noop." nil)
-
-(cl-defgeneric transient-init-value (_)
- "Set the initial value of the object OBJ.
-
-This function is called for all prefix and suffix commands.
-
-For suffix commands (including infix argument commands) the
-default implementation is a noop. Classes derived from the
-abstract `transient-infix' class must implement this function.
-Non-infix suffix commands usually don't have a value."
- nil)
-
-(cl-defmethod transient-init-value :around ((obj transient-prefix))
- "If bound, then call OBJ's `init-value' function.
-Otherwise call the primary method according to object's class."
- (if (slot-boundp obj 'init-value)
- (funcall (oref obj init-value) obj)
- (cl-call-next-method obj)))
-
-(cl-defmethod transient-init-value :around ((obj transient-infix))
- "If bound, then call OBJ's `init-value' function.
-Otherwise call the primary method according to object's class."
- (if (slot-boundp obj 'init-value)
- (funcall (oref obj init-value) obj)
- (cl-call-next-method obj)))
-
-(cl-defmethod transient-init-value ((obj transient-prefix))
- (if (slot-boundp obj 'value)
- (oref obj value)
- (oset obj value
- (if-let ((saved (assq (oref obj command) transient-values)))
- (cdr saved)
- (transient-default-value obj)))))
-
-(cl-defmethod transient-init-value ((obj transient-argument))
- (oset obj value
- (let ((value (oref transient--prefix value))
- (argument (and (slot-boundp obj 'argument)
- (oref obj argument)))
- (multi-value (oref obj multi-value))
- (case-fold-search nil)
- (regexp (if (slot-exists-p obj 'argument-regexp)
- (oref obj argument-regexp)
- (format "\\`%s\\(.*\\)" (oref obj argument)))))
- (if (memq multi-value '(t rest))
- (cdr (assoc argument value))
- (let ((match (lambda (v)
- (and (stringp v)
- (string-match regexp v)
- (match-string 1 v)))))
- (if multi-value
- (delq nil (mapcar match value))
- (cl-some match value)))))))
-
-(cl-defmethod transient-init-value ((obj transient-switch))
- (oset obj value
- (car (member (oref obj argument)
- (oref transient--prefix value)))))
-
-;;;; Default
-
-(cl-defgeneric transient-default-value (_)
- "Return the default value."
- nil)
-
-(cl-defmethod transient-default-value ((obj transient-prefix))
- (if-let ((default (and (slot-boundp obj 'default-value)
- (oref obj default-value))))
- (if (functionp default)
- (funcall default)
- default)
- nil))
-
-;;;; Read
-
-(cl-defgeneric transient-infix-read (obj)
- "Determine the new value of the infix object OBJ.
-
-This function merely determines the value; `transient-infix-set'
-is used to actually store the new value in the object.
-
-For most infix classes this is done by reading a value from the
-user using the reader specified by the `reader' slot (using the
-`transient-infix' method described below).
-
-For some infix classes the value is changed without reading
-anything in the minibuffer, i.e. the mere act of invoking the
-infix command determines what the new value should be, based
-on the previous value.")
-
-(cl-defmethod transient-infix-read :around ((obj transient-infix))
- "Highlight the infix in the popup buffer.
-
-This also wraps the call to `cl-call-next-method' with two
-macros.
-
-`transient--with-suspended-override' is necessary to allow
-reading user input using the minibuffer.
-
-`transient--with-emergency-exit' arranges for the transient to
-be exited in case of an error because otherwise Emacs would get
-stuck in an inconsistent state, which might make it necessary to
-kill it from the outside.
-
-If you replace this method, then you must make sure to always use
-the latter macro and most likely also the former."
- (let ((transient--active-infix obj))
- (transient--show))
- (transient--with-emergency-exit
- (transient--with-suspended-override
- (cl-call-next-method obj))))
-
-(cl-defmethod transient-infix-read ((obj transient-infix))
- "Read a value while taking care of history.
-
-This method is suitable for a wide variety of infix commands,
-including but not limited to inline arguments and variables.
-
-If you do not use this method for your own infix class, then
-you should likely replicate a lot of the behavior of this
-method. If you fail to do so, then users might not appreciate
-the lack of history, for example.
-
-Only for very simple classes that toggle or cycle through a very
-limited number of possible values should you replace this with a
-simple method that does not handle history. (E.g. for a command
-line switch the only possible values are \"use it\" and \"don't use
-it\", in which case it is pointless to preserve history.)"
- (with-slots (value multi-value always-read allow-empty choices) obj
- (if (and value
- (not multi-value)
- (not always-read)
- transient--prefix)
- (oset obj value nil)
- (let* ((enable-recursive-minibuffers t)
- (reader (oref obj reader))
- (prompt (transient-prompt obj))
- (value (if multi-value (mapconcat #'identity value ",") value))
- (history-key (or (oref obj history-key)
- (oref obj command)))
- (transient--history (alist-get history-key transient-history))
- (transient--history (if (or (null value)
- (eq value (car transient--history)))
- transient--history
- (cons value transient--history)))
- (initial-input (and transient-read-with-initial-input
- (car transient--history)))
- (history (if initial-input
- (cons 'transient--history 1)
- 'transient--history))
- (value
- (cond
- (reader (funcall reader prompt initial-input history))
- (multi-value
- (completing-read-multiple prompt choices nil nil
- initial-input history))
- (choices
- (completing-read prompt choices nil t initial-input history))
- (t (read-string prompt initial-input history)))))
- (cond ((and (equal value "") (not allow-empty))
- (setq value nil))
- ((and (equal value "\"\"") allow-empty)
- (setq value "")))
- (when value
- (when (and (bound-and-true-p ivy-mode)
- (stringp (car transient--history)))
- (set-text-properties 0 (length (car transient--history)) nil
- (car transient--history)))
- (setf (alist-get history-key transient-history)
- (delete-dups transient--history)))
- value))))
-
-(cl-defmethod transient-infix-read ((obj transient-switch))
- "Toggle the switch on or off."
- (if (oref obj value) nil (oref obj argument)))
-
-(cl-defmethod transient-infix-read ((obj transient-switches))
- "Cycle through the mutually exclusive switches.
-The last value is \"don't use any of these switches\"."
- (let ((choices (mapcar (apply-partially #'format (oref obj argument-format))
- (oref obj choices))))
- (if-let ((value (oref obj value)))
- (cadr (member value choices))
- (car choices))))
-
-(cl-defmethod transient-infix-read ((command symbol))
- "Elsewhere use the reader of the infix command COMMAND.
-Use this if you want to share an infix's history with a regular
-stand-alone command."
- (cl-letf (((symbol-function #'transient--show) #'ignore))
- (transient-infix-read (get command 'transient--suffix))))
-
-;;;; Readers
-
-(defun transient-read-file (prompt _initial-input _history)
- "Read a file."
- (file-local-name (expand-file-name (read-file-name prompt))))
-
-(defun transient-read-existing-file (prompt _initial-input _history)
- "Read an existing file."
- (file-local-name (expand-file-name (read-file-name prompt nil nil t))))
-
-(defun transient-read-directory (prompt _initial-input _history)
- "Read a directory."
- (file-local-name (expand-file-name (read-directory-name prompt))))
-
-(defun transient-read-existing-directory (prompt _initial-input _history)
- "Read an existing directory."
- (file-local-name (expand-file-name (read-directory-name prompt nil nil t))))
-
-(defun transient-read-number-N0 (prompt initial-input history)
- "Read a natural number (including zero) and return it as a string."
- (transient--read-number-N prompt initial-input history t))
-
-(defun transient-read-number-N+ (prompt initial-input history)
- "Read a natural number (excluding zero) and return it as a string."
- (transient--read-number-N prompt initial-input history nil))
-
-(defun transient--read-number-N (prompt initial-input history include-zero)
- (save-match-data
- (cl-block nil
- (while t
- (let ((str (read-from-minibuffer prompt initial-input nil nil history)))
- (when (or (string-equal str "")
- (string-match-p (if include-zero
- "\\`\\(0\\|[1-9][0-9]*\\)\\'"
- "\\`[1-9][0-9]*\\'")
- str))
- (cl-return str)))
- (message "Please enter a natural number (%s zero)."
- (if include-zero "including" "excluding"))
- (sit-for 1)))))
-
-(defun transient-read-date (prompt default-time _history)
- "Read a date using `org-read-date' (which see)."
- (require 'org)
- (when (fboundp 'org-read-date)
- (org-read-date 'with-time nil nil prompt default-time)))
-
-;;;; Prompt
-
-(cl-defgeneric transient-prompt (obj)
- "Return the prompt to be used to read infix object OBJ's value.")
-
-(cl-defmethod transient-prompt ((obj transient-infix))
- "Return the prompt to be used to read infix object OBJ's value.
-
-This implementation should be suitable for almost all infix
-commands.
-
-If the value of OBJ's `prompt' slot is non-nil, then it must be
-a string or a function. If it is a string, then use that. If
-it is a function, then call that with OBJ as the only argument.
-That function must return a string, which is then used as the
-prompt.
-
-Otherwise, if the value of either the `argument' or `variable'
-slot of OBJ is a string, then base the prompt on that (preferring
-the former), appending either \"=\" (if it appears to be a
-command-line option) or \": \".
-
-Finally fall through to using \"(BUG: no prompt): \" as the
-prompt."
- (if-let ((prompt (oref obj prompt)))
- (let ((prompt (if (functionp prompt)
- (funcall prompt obj)
- prompt)))
- (if (stringp prompt)
- prompt
- "(BUG: no prompt): "))
- (or (and-let* ((arg (and (slot-boundp obj 'argument) (oref obj argument))))
- (if (and (stringp arg) (string-suffix-p "=" arg))
- arg
- (concat arg ": ")))
- (and-let* ((var (and (slot-boundp obj 'variable) (oref obj variable))))
- (and (stringp var)
- (concat var ": ")))
- "(BUG: no prompt): ")))
-
-;;;; Set
-
-(defvar transient--unset-incompatible t)
-
-(cl-defgeneric transient-infix-set (obj value)
- "Set the value of infix object OBJ to value.")
-
-(cl-defmethod transient-infix-set ((obj transient-infix) value)
- "Set the value of infix object OBJ to value."
- (oset obj value value))
-
-(cl-defmethod transient-infix-set :around ((obj transient-argument) value)
- "Unset incompatible infix arguments."
- (let ((arg (if (slot-boundp obj 'argument)
- (oref obj argument)
- (oref obj argument-regexp))))
- (if-let ((sic (and value arg transient--unset-incompatible))
- (spec (oref transient--prefix incompatible))
- (incomp (cl-mapcan (lambda (rule)
- (and (member arg rule)
- (remove arg rule)))
- spec)))
- (progn
- (cl-call-next-method obj value)
- (dolist (arg incomp)
- (when-let ((obj (cl-find-if
- (lambda (obj)
- (and (slot-exists-p obj 'argument)
- (slot-boundp obj 'argument)
- (equal (oref obj argument) arg)))
- transient--suffixes)))
- (let ((transient--unset-incompatible nil))
- (transient-infix-set obj nil)))))
- (cl-call-next-method obj value))))
-
-(cl-defgeneric transient-set-value (obj)
- "Set the value of the transient prefix OBJ.")
-
-(cl-defmethod transient-set-value ((obj transient-prefix))
- (oset (oref obj prototype) value (transient-get-value))
- (transient--history-push obj))
-
-;;;; Save
-
-(cl-defgeneric transient-save-value (obj)
- "Save the value of the transient prefix OBJ.")
-
-(cl-defmethod transient-save-value ((obj transient-prefix))
- (let ((value (transient-get-value)))
- (oset (oref obj prototype) value value)
- (setf (alist-get (oref obj command) transient-values) value)
- (transient-save-values))
- (transient--history-push obj))
-
-;;;; Reset
-
-(cl-defgeneric transient-reset-value (obj)
- "Clear the set and saved values of the transient prefix OBJ.")
-
-(cl-defmethod transient-reset-value ((obj transient-prefix))
- (let ((value (transient-default-value obj)))
- (oset obj value value)
- (oset (oref obj prototype) value value)
- (setf (alist-get (oref obj command) transient-values nil 'remove) nil)
- (transient-save-values))
- (transient--history-push obj)
- (mapc #'transient-init-value transient--suffixes))
-
-;;;; Get
-
-(defun transient-args (prefix)
- "Return the value of the transient prefix command PREFIX.
-If the current command was invoked from the transient prefix
-command PREFIX, then return the active infix arguments. If
-the current command was not invoked from PREFIX, then return
-the set, saved or default value for PREFIX."
- (cl-mapcan #'transient--get-wrapped-value (transient-suffixes prefix)))
-
-(defun transient-suffixes (prefix)
- "Return the suffix objects of the transient prefix command PREFIX."
- (if (eq transient-current-command prefix)
- transient-current-suffixes
- (let ((transient--prefix (transient--init-prefix prefix)))
- (transient--flatten-suffixes
- (transient--init-suffixes prefix)))))
-
-(defun transient-get-value ()
- (transient--with-emergency-exit
- (cl-mapcan (lambda (obj)
- (and (or (not (slot-exists-p obj 'unsavable))
- (not (oref obj unsavable)))
- (transient--get-wrapped-value obj)))
- transient-current-suffixes)))
-
-(defun transient--get-wrapped-value (obj)
- (and-let* ((value (transient-infix-value obj)))
- (cl-ecase (and (slot-exists-p obj 'multi-value)
- (oref obj multi-value))
- ((nil) (list value))
- ((t rest) (list value))
- (repeat value))))
-
-(cl-defgeneric transient-infix-value (obj)
- "Return the value of the suffix object OBJ.
-
-This function is called by `transient-args' (which see), meaning
-this function is how the value of a transient is determined so
-that the invoked suffix command can use it.
-
-Currently most values are strings, but that is not set in stone.
-Nil is not a value, it means \"no value\".
-
-Usually only infixes have a value, but see the method for
-`transient-suffix'.")
-
-(cl-defmethod transient-infix-value ((_ transient-suffix))
- "Return nil, which means \"no value\".
-
-Infix arguments contribute the transient's value while suffix
-commands consume it. This function is called for suffixes anyway
-because a command that both contributes to the transient's value
-and also consumes it is not completely unconceivable.
-
-If you define such a command, then you must define a derived
-class and implement this function because this default method
-does nothing." nil)
-
-(cl-defmethod transient-infix-value ((obj transient-infix))
- "Return the value of OBJ's `value' slot."
- (oref obj value))
-
-(cl-defmethod transient-infix-value ((obj transient-option))
- "Return ARGUMENT and VALUE as a unit or nil if the latter is nil."
- (and-let* ((value (oref obj value)))
- (let ((arg (oref obj argument)))
- (cl-ecase (oref obj multi-value)
- ((nil) (concat arg value))
- ((t rest) (cons arg value))
- (repeat (mapcar (lambda (v) (concat arg v)) value))))))
-
-(cl-defmethod transient-infix-value ((_ transient-variable))
- "Return nil, which means \"no value\".
-
-Setting the value of a variable is done by, well, setting the
-value of the variable. I.e. this is a side-effect and does not
-contribute to the value of the transient."
- nil)
-
-;;;; Utilities
-
-(defun transient-arg-value (arg args)
- "Return the value of ARG as it appears in ARGS.
-
-For a switch return a boolean. For an option return the value as
-a string, using the empty string for the empty value, or nil if
-the option does not appear in ARGS."
- (if (string-suffix-p "=" arg)
- (save-match-data
- (and-let* ((match (let ((case-fold-search nil)
- (re (format "\\`%s\\(?:=\\(.+\\)\\)?\\'"
- (substring arg 0 -1))))
- (cl-find-if (lambda (a)
- (and (stringp a)
- (string-match re a)))
- args))))
- (or (match-string 1 match) "")))
- (and (member arg args) t)))
-
-;;; History
-
-(cl-defgeneric transient--history-key (obj)
- "Return OBJ's history key.
-If the value of the `history-key' slot is non-nil, then return
-that. Otherwise return the value of the `command' slot."
- (or (oref obj history-key)
- (oref obj command)))
-
-(cl-defgeneric transient--history-push (obj)
- "Push the current value of OBJ to its entry in `transient-history'."
- (let ((key (transient--history-key obj)))
- (setf (alist-get key transient-history)
- (let ((args (transient-get-value)))
- (cons args (delete args (alist-get key transient-history)))))))
-
-(cl-defgeneric transient--history-init (obj)
- "Initialize OBJ's `history' slot.
-This is the transient-wide history; many individual infixes also
-have a history of their own.")
-
-(cl-defmethod transient--history-init ((obj transient-prefix))
- "Initialize OBJ's `history' slot from the variable `transient-history'."
- (let ((val (oref obj value)))
- (oset obj history
- (cons val (delete val (alist-get (transient--history-key obj)
- transient-history))))))
-
-;;; Draw
-
-(defun transient--show-brief ()
- (let ((message-log-max nil))
- (if (and transient-show-popup (<= transient-show-popup 0))
- (message "%s-" (key-description (this-command-keys)))
- (message
- "%s- [%s] %s"
- (key-description (this-command-keys))
- (oref transient--prefix command)
- (mapconcat
- #'identity
- (sort
- (cl-mapcan
- (lambda (suffix)
- (let ((key (kbd (oref suffix key))))
- ;; Don't list any common commands.
- (and (not (memq (oref suffix command)
- `(,(lookup-key transient-map key)
- ,(lookup-key transient-sticky-map key)
- ;; From transient-common-commands:
- transient-set
- transient-save
- transient-history-prev
- transient-history-next
- transient-quit-one
- transient-toggle-common
- transient-set-level)))
- (list (propertize (oref suffix key) 'face 'transient-key)))))
- transient--suffixes)
- #'string<)
- (propertize "|" 'face 'transient-unreachable-key))))))
-
-(defun transient--show ()
- (transient--timer-cancel)
- (setq transient--showp t)
- (let ((buf (get-buffer-create transient--buffer-name))
- (focus nil))
- (with-current-buffer buf
- (when transient-enable-popup-navigation
- (setq focus (or (button-get (point) 'command)
- (and (not (bobp))
- (button-get (1- (point)) 'command))
- (transient--heading-at-point))))
- (erase-buffer)
- (setq window-size-fixed t)
- (when (bound-and-true-p tab-line-format)
- (setq tab-line-format nil))
- (setq header-line-format nil)
- (setq mode-line-format (if (eq transient-mode-line-format 'line)
- nil
- transient-mode-line-format))
- (setq mode-line-buffer-identification
- (symbol-name (oref transient--prefix command)))
- (if transient-enable-popup-navigation
- (setq-local cursor-in-non-selected-windows 'box)
- (setq cursor-type nil))
- (setq display-line-numbers nil)
- (setq show-trailing-whitespace nil)
- (transient--insert-groups)
- (when (or transient--helpp transient--editp)
- (transient--insert-help))
- (when (and (eq transient-mode-line-format 'line)
- window-system)
- (let ((face
- (if-let ((f (and (transient--semantic-coloring-p)
- (transient--prefix-color transient--prefix))))
- `(,@(and (>= emacs-major-version 27) '(:extend t))
- :background ,(face-foreground f))
- 'transient-separator)))
- (insert (propertize "__" 'face face 'display '(space :height (1))))
- (insert (propertize "\n" 'face face 'line-height t))))
- (when transient-force-fixed-pitch
- (transient--force-fixed-pitch)))
- (unless (window-live-p transient--window)
- (setq transient--window
- (display-buffer buf transient-display-buffer-action)))
- (when (window-live-p transient--window)
- (with-selected-window transient--window
- (goto-char (point-min))
- (when transient-enable-popup-navigation
- (transient--goto-button focus))
- (transient--fit-window-to-buffer transient--window)))))
-
-(defun transient--fit-window-to-buffer (window)
- (let ((window-resize-pixelwise t)
- (window-size-fixed nil))
- (if (eq (car (window-parameter window 'quit-restore)) 'other)
- ;; Grow but never shrink window that previously displayed
- ;; another buffer and is going to display that again.
- (fit-window-to-buffer window nil (window-height window))
- (fit-window-to-buffer window nil 1))))
-
-(defun transient--insert-groups ()
- (let ((groups (cl-mapcan (lambda (group)
- (let ((hide (oref group hide)))
- (and (not (and (functionp hide)
- (funcall hide)))
- (list group))))
- transient--layout))
- group)
- (while (setq group (pop groups))
- (transient--insert-group group)
- (when groups
- (insert ?\n)))))
-
-(defvar transient--max-group-level 1)
-
-(cl-defgeneric transient--insert-group (group)
- "Format GROUP and its elements and insert the result.")
-
-(cl-defmethod transient--insert-group :around ((group transient-group))
- "Insert GROUP's description, if any."
- (when-let ((desc (transient-format-description group)))
- (insert desc ?\n))
- (let ((transient--max-group-level
- (max (oref group level) transient--max-group-level)))
- (cl-call-next-method group)))
-
-(cl-defmethod transient--insert-group ((group transient-row))
- (transient--maybe-pad-keys group)
- (dolist (suffix (oref group suffixes))
- (insert (transient-format suffix))
- (insert " "))
- (insert ?\n))
-
-(cl-defmethod transient--insert-group ((group transient-column))
- (transient--maybe-pad-keys group)
- (dolist (suffix (oref group suffixes))
- (let ((str (transient-format suffix)))
- (insert str)
- (unless (string-match-p ".\n\\'" str)
- (insert ?\n)))))
-
-(cl-defmethod transient--insert-group ((group transient-columns))
- (let* ((columns
- (mapcar
- (lambda (column)
- (transient--maybe-pad-keys column group)
- (let ((rows (mapcar #'transient-format (oref column suffixes))))
- (when-let ((desc (transient-format-description column)))
- (push desc rows))
- (flatten-tree rows)))
- (oref group suffixes)))
- (vp (or (oref transient--prefix variable-pitch)
- transient-align-variable-pitch))
- (rs (apply #'max (mapcar #'length columns)))
- (cs (length columns))
- (cw (mapcar (lambda (col)
- (apply #'max
- (mapcar (if vp #'transient--pixel-width #'length)
- col)))
- columns))
- (cc (transient--seq-reductions-from
- (apply-partially #'+ (* 3 (if vp (transient--pixel-width " ") 1)))
- cw 0)))
- (if transient-force-single-column
- (dotimes (c cs)
- (dotimes (r rs)
- (when-let ((cell (nth r (nth c columns))))
- (unless (equal cell "")
- (insert cell ?\n))))
- (unless (= c (1- cs))
- (insert ?\n)))
- (dotimes (r rs)
- (dotimes (c cs)
- (if vp
- (progn
- (when-let ((cell (nth r (nth c columns))))
- (insert cell))
- (if (= c (1- cs))
- (insert ?\n)
- (insert (propertize " " 'display
- `(space :align-to (,(nth (1+ c) cc)))))))
- (when (> c 0)
- (insert (make-string (max 1 (- (nth c cc) (current-column)))
- ?\s)))
- (when-let ((cell (nth r (nth c columns))))
- (insert cell))
- (when (= c (1- cs))
- (insert ?\n))))))))
-
-(defun transient--pixel-width (string)
- (save-window-excursion
- (with-temp-buffer
- (insert string)
- (set-window-dedicated-p nil nil)
- (set-window-buffer nil (current-buffer))
- (car (window-text-pixel-size
- nil (line-beginning-position) (point))))))
-
-(cl-defmethod transient--insert-group ((group transient-subgroups))
- (let* ((subgroups (oref group suffixes))
- (n (length subgroups)))
- (dotimes (s n)
- (let ((subgroup (nth s subgroups)))
- (transient--maybe-pad-keys subgroup group)
- (transient--insert-group subgroup)
- (when (< s (1- n))
- (insert ?\n))))))
-
-(cl-defgeneric transient-format (obj)
- "Format and return OBJ for display.
-
-When this function is called, then the current buffer is some
-temporary buffer. If you need the buffer from which the prefix
-command was invoked to be current, then do so by temporarily
-making `transient--original-buffer' current.")
-
-(cl-defmethod transient-format ((arg string))
- "Return the string ARG after applying the `transient-heading' face."
- (propertize arg 'face 'transient-heading))
-
-(cl-defmethod transient-format ((_ null))
- "Return a string containing just the newline character."
- "\n")
-
-(cl-defmethod transient-format ((arg integer))
- "Return a string containing just the ARG character."
- (char-to-string arg))
-
-(cl-defmethod transient-format :around ((obj transient-infix))
- "When reading user input for this infix, then highlight it."
- (let ((str (cl-call-next-method obj)))
- (when (eq obj transient--active-infix)
- (setq str (concat str "\n"))
- (add-face-text-property
- (if (eq this-command 'transient-set-level) 3 0)
- (length str)
- 'transient-active-infix nil str))
- str))
-
-(cl-defmethod transient-format :around ((obj transient-suffix))
- "When edit-mode is enabled, then prepend the level information.
-Optional support for popup buttons is also implemented here."
- (let ((str (concat
- (and transient--editp
- (let ((level (oref obj level)))
- (propertize (format " %s " level)
- 'face (if (transient--use-level-p level t)
- 'transient-enabled-suffix
- 'transient-disabled-suffix))))
- (cl-call-next-method obj))))
- (when (oref obj inapt)
- (add-face-text-property 0 (length str) 'transient-inapt-suffix nil str))
- (if transient-enable-popup-navigation
- (make-text-button str nil
- 'type 'transient
- 'command (transient--suffix-command obj))
- str)))
-
-(cl-defmethod transient-format ((obj transient-infix))
- "Return a string generated using OBJ's `format'.
-%k is formatted using `transient-format-key'.
-%d is formatted using `transient-format-description'.
-%v is formatted using `transient-format-value'."
- (format-spec (oref obj format)
- `((?k . ,(transient-format-key obj))
- (?d . ,(transient-format-description obj))
- (?v . ,(transient-format-value obj)))))
-
-(cl-defmethod transient-format ((obj transient-suffix))
- "Return a string generated using OBJ's `format'.
-%k is formatted using `transient-format-key'.
-%d is formatted using `transient-format-description'."
- (format-spec (oref obj format)
- `((?k . ,(transient-format-key obj))
- (?d . ,(transient-format-description obj)))))
-
-(cl-defgeneric transient-format-key (obj)
- "Format OBJ's `key' for display and return the result.")
-
-(cl-defmethod transient-format-key ((obj transient-suffix))
- "Format OBJ's `key' for display and return the result."
- (let ((key (oref obj key))
- (cmd (oref obj command)))
- (if transient--redisplay-key
- (let ((len (length transient--redisplay-key))
- (seq (cl-coerce (edmacro-parse-keys key t) 'list)))
- (cond
- ((member (seq-take seq len)
- (list transient--redisplay-key
- (thread-last transient--redisplay-key
- (cl-substitute ?- 'kp-subtract)
- (cl-substitute ?= 'kp-equal)
- (cl-substitute ?+ 'kp-add))))
- (let ((pre (key-description (vconcat (seq-take seq len))))
- (suf (key-description (vconcat (seq-drop seq len)))))
- (setq pre (string-replace "RET" "C-m" pre))
- (setq pre (string-replace "TAB" "C-i" pre))
- (setq suf (string-replace "RET" "C-m" suf))
- (setq suf (string-replace "TAB" "C-i" suf))
- ;; We use e.g. "-k" instead of the more correct "- k",
- ;; because the former is prettier. If we did that in
- ;; the definition, then we want to drop the space that
- ;; is reinserted above. False-positives are possible
- ;; for silly bindings like "-C-c C-c".
- (unless (string-search " " key)
- (setq pre (string-replace " " "" pre))
- (setq suf (string-replace " " "" suf)))
- (concat (propertize pre 'face 'transient-unreachable-key)
- (and (string-prefix-p (concat pre " ") key) " ")
- (transient--colorize-key suf cmd)
- (save-excursion
- (and (string-match " +\\'" key)
- (propertize (match-string 0 key)
- 'face 'fixed-pitch))))))
- ((transient--lookup-key transient-sticky-map (kbd key))
- (transient--colorize-key key cmd))
- (t
- (propertize key 'face 'transient-unreachable-key))))
- (transient--colorize-key key cmd))))
-
-(defun transient--colorize-key (key command)
- (propertize key 'face
- (or (and (transient--semantic-coloring-p)
- (transient--suffix-color command))
- 'transient-key)))
-
-(cl-defmethod transient-format-key :around ((obj transient-argument))
- (let ((key (cl-call-next-method obj)))
- (cond ((not transient-highlight-mismatched-keys))
- ((not (slot-boundp obj 'shortarg))
- (add-face-text-property
- 0 (length key) 'transient-nonstandard-key nil key))
- ((not (string-equal key (oref obj shortarg)))
- (add-face-text-property
- 0 (length key) 'transient-mismatched-key nil key)))
- key))
-
-(cl-defgeneric transient-format-description (obj)
- "Format OBJ's `description' for display and return the result.")
-
-(cl-defmethod transient-format-description ((obj transient-child))
- "The `description' slot may be a function, in which case that is
-called inside the correct buffer (see `transient--insert-group')
-and its value is returned to the caller."
- (and-let* ((desc (oref obj description)))
- (if (functionp desc)
- (with-current-buffer transient--original-buffer
- (funcall desc))
- desc)))
-
-(cl-defmethod transient-format-description ((obj transient-group))
- "Format the description by calling the next method. If the result
-doesn't use the `face' property at all, then apply the face
-`transient-heading' to the complete string."
- (and-let* ((desc (cl-call-next-method obj)))
- (if (text-property-not-all 0 (length desc) 'face nil desc)
- desc
- (propertize desc 'face 'transient-heading))))
-
-(cl-defmethod transient-format-description :around ((obj transient-suffix))
- "Format the description by calling the next method. If the result
-is nil, then use \"(BUG: no description)\" as the description.
-If the OBJ's `key' is currently unreachable, then apply the face
-`transient-unreachable' to the complete string."
- (let ((desc (or (cl-call-next-method obj)
- (and (slot-boundp transient--prefix 'suffix-description)
- (funcall (oref transient--prefix suffix-description)
- obj))
- (propertize "(BUG: no description)" 'face 'error))))
- (cond ((transient--key-unreachable-p obj)
- (propertize desc 'face 'transient-unreachable))
- ((and transient-highlight-higher-levels
- (> (max (oref obj level) transient--max-group-level)
- transient--default-prefix-level))
- (add-face-text-property
- 0 (length desc) 'transient-higher-level nil desc)
- desc)
- (t
- desc))))
-
-(cl-defgeneric transient-format-value (obj)
- "Format OBJ's value for display and return the result.")
-
-(cl-defmethod transient-format-value ((obj transient-suffix))
- (propertize (oref obj argument)
- 'face (if (oref obj value)
- 'transient-argument
- 'transient-inactive-argument)))
-
-(cl-defmethod transient-format-value ((obj transient-option))
- (let ((argument (oref obj argument)))
- (if-let ((value (oref obj value)))
- (propertize
- (cl-ecase (oref obj multi-value)
- ((nil) (concat argument value))
- ((t rest) (concat argument
- (and (not (string-suffix-p " " argument)) " ")
- (mapconcat #'prin1-to-string value " ")))
- (repeat (mapconcat (lambda (v) (concat argument v)) value " ")))
- 'face 'transient-value)
- (propertize argument 'face 'transient-inactive-value))))
-
-(cl-defmethod transient-format-value ((obj transient-switches))
- (with-slots (value argument-format choices) obj
- (format (propertize argument-format
- 'face (if value
- 'transient-value
- 'transient-inactive-value))
- (concat
- (propertize "[" 'face 'transient-inactive-value)
- (mapconcat
- (lambda (choice)
- (propertize choice 'face
- (if (equal (format argument-format choice) value)
- 'transient-value
- 'transient-inactive-value)))
- choices
- (propertize "|" 'face 'transient-inactive-value))
- (propertize "]" 'face 'transient-inactive-value)))))
-
-(defun transient--key-unreachable-p (obj)
- (and transient--redisplay-key
- (let ((key (oref obj key)))
- (not (or (equal (seq-take (cl-coerce (edmacro-parse-keys key t) 'list)
- (length transient--redisplay-key))
- transient--redisplay-key)
- (transient--lookup-key transient-sticky-map (kbd key)))))))
-
-(defun transient--lookup-key (keymap key)
- (let ((val (lookup-key keymap key)))
- (and val (not (integerp val)) val)))
-
-(defun transient--maybe-pad-keys (group &optional parent)
- (when-let ((pad (if (slot-boundp group 'pad-keys)
- (oref group pad-keys)
- (and parent
- (slot-boundp parent 'pad-keys)
- (oref parent pad-keys)))))
- (let ((width (apply #'max
- (cons (if (integerp pad) pad 0)
- (mapcar (lambda (suffix)
- (length (oref suffix key)))
- (oref group suffixes))))))
- (dolist (suffix (oref group suffixes))
- (oset suffix key
- (truncate-string-to-width (oref suffix key) width nil ?\s))))))
-
-(defun transient-command-summary-or-name (obj)
- "Return the summary or name of the command represented by OBJ.
-
-If the command has a doc-string, then return the first line of
-that, else its name.
-
-Intended to be temporarily used as the `:suffix-description' of
-a prefix command, while porting a regular keymap to a transient."
- (let ((command (transient--suffix-symbol (oref obj command))))
- (if-let ((doc (documentation command)))
- (propertize (car (split-string doc "\n")) 'face 'font-lock-doc-face)
- (propertize (symbol-name command) 'face 'font-lock-function-name-face))))
-
-;;; Help
-
-(cl-defgeneric transient-show-help (obj)
- "Show documentation for the command represented by OBJ.")
-
-(cl-defmethod transient-show-help ((obj transient-prefix))
- "Call `show-help' if non-nil, else show `info-manual',
-if non-nil, else show the `man-page' if non-nil, else use
-`describe-function'."
- (with-slots (show-help info-manual man-page command) obj
- (cond (show-help (funcall show-help obj))
- (info-manual (transient--show-manual info-manual))
- (man-page (transient--show-manpage man-page))
- (t (transient--describe-function command)))))
-
-(cl-defmethod transient-show-help ((obj transient-suffix))
- "Call `show-help' if non-nil, else use `describe-function'.
-Also used to dispatch showing documentation for the current
-prefix. If the suffix is a sub-prefix, then also call the
-prefix method."
- (cond
- ((eq this-command 'transient-help)
- (transient-show-help transient--prefix))
- ((let ((prefix (get (transient--suffix-command obj)
- 'transient--prefix)))
- (and prefix (not (eq (oref transient--prefix command) this-command))
- (prog1 t (transient-show-help prefix)))))
- (t (if-let ((show-help (oref obj show-help)))
- (funcall show-help obj)
- (transient--describe-function this-command)))))
-
-(cl-defmethod transient-show-help ((obj transient-infix))
- "Call `show-help' if non-nil, else show the `man-page'
-if non-nil, else use `describe-function'. When showing the
-manpage, then try to jump to the correct location."
- (if-let ((show-help (oref obj show-help)))
- (funcall show-help obj)
- (if-let ((man-page (oref transient--prefix man-page))
- (argument (and (slot-boundp obj 'argument)
- (oref obj argument))))
- (transient--show-manpage man-page argument)
- (transient--describe-function this-command))))
-
-;; `cl-generic-generalizers' doesn't support `command' et al.
-(cl-defmethod transient-show-help (cmd)
- "Show the command doc-string."
- (transient--describe-function cmd))
-
-(defun transient--describe-function (fn)
- (describe-function (if (symbolp fn) fn 'transient--anonymous-infix-argument))
- (unless (derived-mode-p 'help-mode)
- (when-let* ((buf (get-buffer "*Help*"))
- (win (or (and buf (get-buffer-window buf))
- (cl-find-if (lambda (win)
- (with-current-buffer (window-buffer win)
- (derived-mode-p 'help-mode)))
- (window-list)))))
- (select-window win))))
-
-(defun transient--anonymous-infix-argument ()
- "Cannot show any documentation for this anonymous infix command.
-
-The infix command in question was defined anonymously, i.e.,
-it was define when the prefix command that it belongs to was
-defined, which means that it gets no docstring and also that
-no symbol is bound to it.
-
-When you request help for an infix command, then we usually
-show the respective man-page and jump to the location where
-the respective argument is being described.
-
-Because the containing prefix command does not specify any
-man-page, we cannot do that in this case. Sorry about that.")
-
-(defun transient--show-manual (manual)
- (info manual))
-
-(defun transient--show-manpage (manpage &optional argument)
- (require 'man)
- (let* ((Man-notify-method 'meek)
- (buf (Man-getpage-in-background manpage))
- (proc (get-buffer-process buf)))
- (while (and proc (eq (process-status proc) 'run))
- (accept-process-output proc))
- (switch-to-buffer buf)
- (when argument
- (transient--goto-argument-description argument))))
-
-(defun transient--goto-argument-description (arg)
- (goto-char (point-min))
- (let ((case-fold-search nil)
- ;; This matches preceding/proceeding options. Options
- ;; such as "-a", "-S[<keyid>]", and "--grep=<pattern>"
- ;; are matched by this regex without the shy group.
- ;; The ". " in the shy group is for options such as
- ;; "-m parent-number", and the "-[^[:space:]]+ " is
- ;; for options such as "--mainline parent-number"
- (others "-\\(?:. \\|-[^[:space:]]+ \\)?[^[:space:]]+"))
- (when (re-search-forward
- (if (equal arg "--")
- ;; Special case.
- "^[\t\s]+\\(--\\(?: \\|$\\)\\|\\[--\\]\\)"
- ;; Should start with whitespace and may have
- ;; any number of options before and/or after.
- (format
- "^[\t\s]+\\(?:%s, \\)*?\\(?1:%s\\)%s\\(?:, %s\\)*$"
- others
- ;; Options don't necessarily end in an "="
- ;; (e.g., "--gpg-sign[=<keyid>]")
- (string-remove-suffix "=" arg)
- ;; Simple options don't end in an "=". Splitting this
- ;; into 2 cases should make getting false positives
- ;; less likely.
- (if (string-suffix-p "=" arg)
- ;; "[^[:space:]]*[^.[:space:]]" matches the option
- ;; value, which is usually after the option name
- ;; and either '=' or '[='. The value can't end in
- ;; a period, as that means it's being used at the
- ;; end of a sentence. The space is for options
- ;; such as '--mainline parent-number'.
- "\\(?: \\|\\[?=\\)[^[:space:]]*[^.[:space:]]"
- ;; Either this doesn't match anything (e.g., "-a"),
- ;; or the option is followed by a value delimited
- ;; by a "[", "<", or ":". A space might appear
- ;; before this value, as in "-f <file>". The
- ;; space alternative is for options such as
- ;; "-m parent-number".
- "\\(?:\\(?: \\| ?[\\[<:]\\)[^[:space:]]*[^.[:space:]]\\)?")
- others))
- nil t)
- (goto-char (match-beginning 1)))))
-
-(defun transient--insert-help ()
- (unless (looking-back "\n\n" 2)
- (insert "\n"))
- (when transient--helpp
- (insert
- (format (propertize "\
-Type a %s to show help for that suffix command, or %s to show manual.
-Type %s to exit help.\n"
- 'face 'transient-heading)
- (propertize "<KEY>" 'face 'transient-key)
- (propertize "?" 'face 'transient-key)
- (propertize "C-g" 'face 'transient-key))))
- (when transient--editp
- (unless transient--helpp
- (insert
- (format (propertize "\
-Type a %s to set level for that suffix command.
-Type %s to set what levels are available for this prefix command.\n"
- 'face 'transient-heading)
- (propertize "<KEY>" 'face 'transient-key)
- (propertize "C-x l" 'face 'transient-key))))
- (with-slots (level) transient--prefix
- (insert
- (format (propertize "
-Suffixes on levels %s are available.
-Suffixes on levels %s and %s are unavailable.\n"
- 'face 'transient-heading)
- (propertize (format "1-%s" level)
- 'face 'transient-enabled-suffix)
- (propertize " 0 "
- 'face 'transient-disabled-suffix)
- (propertize (format ">=%s" (1+ level))
- 'face 'transient-disabled-suffix))))))
-
-(defvar-keymap transient-resume-mode-map
- :doc "Keymap for `transient-resume-mode'.
-
-This keymap remaps every command that would usually just quit the
-documentation buffer to `transient-resume', which additionally
-resumes the suspended transient."
- "<remap> <Man-quit>" #'transient-resume
- "<remap> <Info-exit>" #'transient-resume
- "<remap> <quit-window>" #'transient-resume)
-
-(define-minor-mode transient-resume-mode
- "Auxiliary minor-mode used to resume a transient after viewing help.")
-
-(defun transient-toggle-debug ()
- "Toggle debugging statements for transient commands."
- (interactive)
- (setq transient--debug (not transient--debug))
- (message "Debugging transient %s"
- (if transient--debug "enabled" "disabled")))
-
-;;; Popup Navigation
-
-(defun transient-popup-navigation-help ()
- "Inform the user how to enable popup navigation commands."
- (interactive)
- (message "This command is only available if `%s' is non-nil"
- 'transient-enable-popup-navigation))
-
-(define-button-type 'transient
- 'face nil
- 'keymap transient-button-map)
-
-(defun transient-backward-button (n)
- "Move to the previous button in the transient popup buffer.
-See `backward-button' for information about N."
- (interactive "p")
- (with-selected-window transient--window
- (backward-button n t)))
-
-(defun transient-forward-button (n)
- "Move to the next button in the transient popup buffer.
-See `forward-button' for information about N."
- (interactive "p")
- (with-selected-window transient--window
- (forward-button n t)))
-
-(defun transient--goto-button (command)
- (cond
- ((stringp command)
- (when (re-search-forward (concat "^" (regexp-quote command)) nil t)
- (goto-char (match-beginning 0))))
- (command
- (while (and (ignore-errors (forward-button 1))
- (not (eq (button-get (button-at (point)) 'command) command))))
- (unless (eq (button-get (button-at (point)) 'command) command)
- (goto-char (point-min))
- (forward-button 1)))))
-
-(defun transient--heading-at-point ()
- (and (eq (get-text-property (point) 'face) 'transient-heading)
- (let ((beg (line-beginning-position)))
- (buffer-substring-no-properties
- beg (next-single-property-change
- beg 'face nil (line-end-position))))))
-
-;;; Compatibility
-;;;; Popup Isearch
-
-(defvar-keymap transient--isearch-mode-map
- :parent isearch-mode-map
- "<remap> <isearch-exit>" #'transient-isearch-exit
- "<remap> <isearch-cancel>" #'transient-isearch-cancel
- "<remap> <isearch-abort>" #'transient-isearch-abort)
-
-(defun transient-isearch-backward (&optional regexp-p)
- "Do incremental search backward.
-With a prefix argument, do an incremental regular expression
-search instead."
- (interactive "P")
- (transient--isearch-setup)
- (let ((isearch-mode-map transient--isearch-mode-map))
- (isearch-mode nil regexp-p)))
-
-(defun transient-isearch-forward (&optional regexp-p)
- "Do incremental search forward.
-With a prefix argument, do an incremental regular expression
-search instead."
- (interactive "P")
- (transient--isearch-setup)
- (let ((isearch-mode-map transient--isearch-mode-map))
- (isearch-mode t regexp-p)))
-
-(defun transient-isearch-exit ()
- "Like `isearch-exit' but adapted for `transient'."
- (interactive)
- (isearch-exit)
- (transient--isearch-exit))
-
-(defun transient-isearch-cancel ()
- "Like `isearch-cancel' but adapted for `transient'."
- (interactive)
- (condition-case nil (isearch-cancel) (quit))
- (transient--isearch-exit))
-
-(defun transient-isearch-abort ()
- "Like `isearch-abort' but adapted for `transient'."
- (interactive)
- (let ((around (lambda (fn)
- (condition-case nil (funcall fn) (quit))
- (transient--isearch-exit))))
- (advice-add 'isearch-cancel :around around)
- (unwind-protect
- (isearch-abort)
- (advice-remove 'isearch-cancel around))))
-
-(defun transient--isearch-setup ()
- (select-window transient--window)
- (transient--suspend-override t))
-
-(defun transient--isearch-exit ()
- (select-window transient--original-window)
- (transient--resume-override))
-
-;;;; Hydra Color Emulation
-
-(defun transient--semantic-coloring-p ()
- (and transient-semantic-coloring
- (not transient--helpp)
- (not transient--editp)))
-
-(defun transient--suffix-color (command)
- (or (get command 'transient-color)
- (get (transient--get-predicate-for command) 'transient-color)))
-
-(defun transient--prefix-color (command)
- (let* ((nonsuf (or (oref command transient-non-suffix)
- 'transient--do-warn))
- (nonsuf (if (memq nonsuf '(transient--do-noop transient--do-warn))
- 'disallow
- (get nonsuf 'transient-color)))
- (suffix (if-let ((pred (oref command transient-suffix)))
- (get pred 'transient-color)
- (if (eq nonsuf 'transient-red)
- 'transient-red
- 'transient-blue))))
- (pcase (list suffix nonsuf)
- (`(transient-purple ,_) 'transient-purple)
- ('(transient-red disallow) 'transient-amaranth)
- ('(transient-blue disallow) 'transient-teal)
- ('(transient-red transient-red) 'transient-pink)
- ('(transient-red transient-blue) 'transient-red)
- ('(transient-blue transient-blue) 'transient-blue))))
-
-;;;; Edebug
-
-(defun transient--edebug-command-p ()
- (and (bound-and-true-p edebug-active)
- (or (memq this-command '(top-level abort-recursive-edit))
- (string-prefix-p "edebug" (symbol-name this-command)))))
-
-;;;; Miscellaneous
-
-(cl-pushnew (list nil (concat "^\\s-*("
- (eval-when-compile
- (regexp-opt
- '("transient-define-prefix"
- "transient-define-suffix"
- "transient-define-infix"
- "transient-define-argument")
- t))
- "\\s-+\\(" lisp-mode-symbol-regexp "\\)")
- 2)
- lisp-imenu-generic-expression :test #'equal)
-
-(declare-function which-key-mode "which-key" (&optional arg))
-
-(defun transient--suspend-which-key-mode ()
- (when (bound-and-true-p which-key-mode)
- (which-key-mode -1)
- (add-hook 'transient-exit-hook #'transient--resume-which-key-mode)))
-
-(defun transient--resume-which-key-mode ()
- (unless transient--prefix
- (which-key-mode 1)
- (remove-hook 'transient-exit-hook #'transient--resume-which-key-mode)))
-
-(defun transient-bind-q-to-quit ()
- "Modify some keymaps to bind \"q\" to the appropriate quit command.
-
-\"C-g\" is the default binding for such commands now, but Transient's
-predecessor Magit-Popup used \"q\" instead. If you would like to get
-that binding back, then call this function in your init file like so:
-
- (with-eval-after-load \\='transient
- (transient-bind-q-to-quit))
-
-Individual transients may already bind \"q\" to something else
-and such a binding would shadow the quit binding. If that is the
-case then \"Q\" is bound to whatever \"q\" would have been bound
-to by setting `transient-substitute-key-function' to a function
-that does that. Of course \"Q\" may already be bound to something
-else, so that function binds \"M-q\" to that command instead.
-Of course \"M-q\" may already be bound to something else, but
-we stop there."
- (keymap-set transient-base-map "q" #'transient-quit-one)
- (keymap-set transient-sticky-map "q" #'transient-quit-seq)
- (setq transient-substitute-key-function
- #'transient-rebind-quit-commands))
-
-(defun transient-rebind-quit-commands (obj)
- "See `transient-bind-q-to-quit'."
- (let ((key (oref obj key)))
- (cond ((string-equal key "q") "Q")
- ((string-equal key "Q") "M-q")
- (t key))))
-
-(defun transient--force-fixed-pitch ()
- (require 'face-remap)
- (face-remap-reset-base 'default)
- (face-remap-add-relative 'default 'fixed-pitch))
-
-;;;; Missing from Emacs
-
-(defun transient--seq-reductions-from (function sequence initial-value)
- (let ((acc (list initial-value)))
- (seq-doseq (elt sequence)
- (push (funcall function (car acc) elt) acc))
- (nreverse acc)))
-
-(defun transient-plist-to-alist (plist)
- (let (alist)
- (while plist
- (push (cons (let* ((symbol (pop plist))
- (name (symbol-name symbol)))
- (if (eq (aref name 0) ?:)
- (intern (substring name 1))
- symbol))
- (pop plist))
- alist))
- (nreverse alist)))
-
-;;; Font-Lock
-
-(defconst transient-font-lock-keywords
- (eval-when-compile
- `((,(concat "("
- (regexp-opt (list "transient-define-prefix"
- "transient-define-infix"
- "transient-define-argument"
- "transient-define-suffix"
- "transient-define-groups")
- t)
- "\\_>[ \t'(]*"
- "\\(\\(?:\\sw\\|\\s_\\)+\\)?")
- (1 'font-lock-keyword-face)
- (2 'font-lock-function-name-face nil t)))))
-
-(font-lock-add-keywords 'emacs-lisp-mode transient-font-lock-keywords)
-
-;;; Auxiliary Classes
-;;;; `transient-lisp-variable'
-
-(defclass transient-lisp-variable (transient-variable)
- ((reader :initform #'transient-lisp-variable--reader)
- (always-read :initform t)
- (set-value :initarg :set-value :initform #'set))
- "[Experimental] Class used for Lisp variables.")
-
-(cl-defmethod transient-init-value ((obj transient-lisp-variable))
- (oset obj value (symbol-value (oref obj variable))))
-
-(cl-defmethod transient-infix-set ((obj transient-lisp-variable) value)
- (funcall (oref obj set-value)
- (oref obj variable)
- (oset obj value value)))
-
-(cl-defmethod transient-format-description ((obj transient-lisp-variable))
- (or (cl-call-next-method obj)
- (symbol-name (oref obj variable))))
-
-(cl-defmethod transient-format-value ((obj transient-lisp-variable))
- (propertize (prin1-to-string (oref obj value))
- 'face 'transient-value))
-
-(cl-defmethod transient-prompt ((obj transient-lisp-variable))
- (if (and (slot-boundp obj 'prompt)
- (oref obj prompt))
- (cl-call-next-method obj)
- (format "Set %s: " (oref obj variable))))
-
-(defun transient-lisp-variable--reader (prompt initial-input _history)
- (read--expression prompt initial-input))
-
-;;; _
-(provide 'transient)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; checkdoc-symbol-words: ("command-line" "edit-mode" "help-mode")
-;; End:
-;;; transient.el ends here
+++ /dev/null
-This is transient.info, produced by makeinfo version 6.7 from
-transient.texi.
-
- Copyright (C) 2018–2023 Free Software Foundation, Inc.
-
- You can redistribute this document 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 document 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.
-
-INFO-DIR-SECTION Emacs misc features
-START-INFO-DIR-ENTRY
-* Transient: (transient). Transient Commands.
-END-INFO-DIR-ENTRY
-
-\1f
-File: transient.info, Node: Top, Next: Introduction, Up: (dir)
-
-Transient User and Developer Manual
-***********************************
-
-Taking inspiration from prefix keys and prefix arguments, Transient
-implements a similar abstraction involving a prefix command, infix
-arguments and suffix commands. We could call this abstraction a
-“transient command”, but because it always involves at least two
-commands (a prefix and a suffix) we prefer to call it just a
-“transient”.
-
- When the user calls a transient prefix command, a transient
-(temporary) keymap is activated, which binds the transient’s infix and
-suffix commands, and functions that control the transient state are
-added to ‘pre-command-hook’ and ‘post-command-hook’. The available
-suffix and infix commands and their state are shown in a popup buffer
-until the transient is exited by invoking a suffix command.
-
- Calling an infix command causes its value to be changed, possibly by
-reading a new value in the minibuffer.
-
- Calling a suffix command usually causes the transient to be exited
-but suffix commands can also be configured to not exit the transient.
-
- The second part of this manual, which describes how to modify
- existing transients and create new transients from scratch, can be
- hard to digest if you are just getting started. A useful resource
- to get over that hurdle is Psionic K’s interactive tutorial,
- available at
- <https://github.com/positron-solutions/transient-showcase>.
-
-This manual is for Transient version 0.4.1.
-
- Copyright (C) 2018–2023 Free Software Foundation, Inc.
-
- You can redistribute this document 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 document 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.
-
-* Menu:
-
-* Introduction::
-* Usage::
-* Modifying Existing Transients::
-* Defining New Commands::
-* Classes and Methods::
-* Related Abstractions and Packages::
-* FAQ::
-* Keystroke Index::
-* Command and Function Index::
-* Variable Index::
-* Concept Index::
-* GNU General Public License::
-
-— The Detailed Node Listing —
-
-Usage
-
-* Invoking Transients::
-* Aborting and Resuming Transients::
-* Common Suffix Commands::
-* Saving Values::
-* Using History::
-* Getting Help for Suffix Commands::
-* Enabling and Disabling Suffixes::
-* Other Commands::
-* Configuration::
-
-Defining New Commands
-
-* Defining Transients::
-* Binding Suffix and Infix Commands::
-* Defining Suffix and Infix Commands::
-* Using Infix Arguments::
-* Transient State::
-
-Binding Suffix and Infix Commands
-
-* Group Specifications::
-* Suffix Specifications::
-
-
-Classes and Methods
-
-* Group Classes::
-* Group Methods::
-* Prefix Classes::
-* Suffix Classes::
-* Suffix Methods::
-* Prefix Slots::
-* Suffix Slots::
-* Predicate Slots::
-
-Suffix Methods
-
-* Suffix Value Methods::
-* Suffix Format Methods::
-
-
-Related Abstractions and Packages
-
-* Comparison With Prefix Keys and Prefix Arguments::
-* Comparison With Other Packages::
-
-
-\1f
-File: transient.info, Node: Introduction, Next: Usage, Prev: Top, Up: Top
-
-1 Introduction
-**************
-
-Taking inspiration from prefix keys and prefix arguments, Transient
-implements a similar abstraction involving a prefix command, infix
-arguments and suffix commands. We could call this abstraction a
-“transient command”, but because it always involves at least two
-commands (a prefix and a suffix) we prefer to call it just a
-“transient”.
-
- Transient keymaps are a feature provided by Emacs. Transients as
- implemented by this package involve the use of transient keymaps.
-
- Emacs provides a feature that it calls “prefix commands”. When we
- talk about “prefix commands” in this manual, then we mean our own
- kind of “prefix commands”, unless specified otherwise. To avoid
- ambiguity we sometimes use the terms “transient prefix command” for
- our kind and “regular prefix command” for Emacs’ kind.
-
- When the user calls a transient prefix command, a transient
-(temporary) keymap is activated, which binds the transient’s infix and
-suffix commands, and functions that control the transient state are
-added to ‘pre-command-hook’ and ‘post-command-hook’. The available
-suffix and infix commands and their state are shown in a popup buffer
-until the transient state is exited by invoking a suffix command.
-
- Calling an infix command causes its value to be changed. How that is
-done depends on the type of the infix command. The simplest case is an
-infix command that represents a command-line argument that does not take
-a value. Invoking such an infix command causes the switch to be toggled
-on or off. More complex infix commands may read a value from the user,
-using the minibuffer.
-
- Calling a suffix command usually causes the transient to be exited;
-the transient keymaps and hook functions are removed, the popup buffer
-no longer shows information about the (no longer bound) suffix commands,
-the values of some public global variables are set, while some internal
-global variables are unset, and finally the command is actually called.
-Suffix commands can also be configured to not exit the transient.
-
- A suffix command can, but does not have to, use the infix arguments
-in much the same way any command can choose to use or ignore the prefix
-arguments. For a suffix command that was invoked from a transient, the
-variable ‘transient-current-suffixes’ and the function ‘transient-args’
-serve about the same purpose as the variables ‘prefix-arg’ and
-‘current-prefix-arg’ do for any command that was called after the prefix
-arguments have been set using a command such as ‘universal-argument’.
-
- The information shown in the popup buffer while a transient is active
-looks a bit like this:
-
- ,-----------------------------------------
- |Arguments
- | -f Force (--force)
- | -a Annotate (--annotate)
- |
- |Create
- | t tag
- | r release
- `-----------------------------------------
-
- This is a simplified version of ‘magit-tag’. Info manuals do not
- support images or colored text, so the above “screenshot” lacks
- some information; in practice you would be able to tell whether the
- arguments ‘--force’ and ‘--annotate’ are enabled or not based on
- their color.
-
- Transient can be used to implement simple “command dispatchers”. The
-main benefit then is that the user can see all the available commands in
-a popup buffer. That is useful by itself because it frees the user from
-having to remember all the keys that are valid after a certain prefix
-key or command. Magit’s ‘magit-dispatch’ (on ‘C-x M-g’) command is an
-example of using Transient to merely implement a command dispatcher.
-
- In addition to that, Transient also allows users to interactively
-pass arguments to commands. These arguments can be much more complex
-than what is reasonable when using prefix arguments. There is a limit
-to how many aspects of a command can be controlled using prefix
-arguments. Furthermore, what a certain prefix argument means for
-different commands can be completely different, and users have to read
-documentation to learn and then commit to memory what a certain prefix
-argument means to a certain command.
-
- Transient suffix commands, on the other hand, can accept dozens of
-different arguments without the user having to remember anything. When
-using Transient, one can call a command with arguments that are just as
-complex as when calling the same function non-interactively from Lisp.
-
- Invoking a transient command with arguments is similar to invoking a
-command in a shell with command-line completion and history enabled.
-One benefit of the Transient interface is that it remembers history not
-only on a global level (“this command was invoked using these arguments,
-and previously it was invoked using those other arguments”), but also
-remembers the values of individual arguments independently. See *note
-Using History::.
-
- After a transient prefix command is invoked, ‘C-h KEY’ can be used to
-show the documentation for the infix or suffix command that KEY is bound
-to (see *note Getting Help for Suffix Commands::), and infixes and
-suffixes can be removed from the transient using ‘C-x l KEY’. Infixes
-and suffixes that are disabled by default can be enabled the same way.
-See *note Enabling and Disabling Suffixes::.
-
- Transient ships with support for a few different types of specialized
-infix commands. A command that sets a command line option, for example,
-has different needs than a command that merely toggles a boolean flag.
-Additionally, Transient provides abstractions for defining new types,
-which the author of Transient did not anticipate (or didn’t get around
-to implementing yet).
-
-\1f
-File: transient.info, Node: Usage, Next: Modifying Existing Transients, Prev: Introduction, Up: Top
-
-2 Usage
-*******
-
-* Menu:
-
-* Invoking Transients::
-* Aborting and Resuming Transients::
-* Common Suffix Commands::
-* Saving Values::
-* Using History::
-* Getting Help for Suffix Commands::
-* Enabling and Disabling Suffixes::
-* Other Commands::
-* Configuration::
-
-\1f
-File: transient.info, Node: Invoking Transients, Next: Aborting and Resuming Transients, Up: Usage
-
-2.1 Invoking Transients
-=======================
-
-A transient prefix command is invoked like any other command by pressing
-the key that is bound to that command. The main difference to other
-commands is that a transient prefix command activates a transient
-keymap, which temporarily binds the transient’s infix and suffix
-commands. Bindings from other keymaps may, or may not, be disabled
-while the transient state is in effect.
-
- There are two kinds of commands that are available after invoking a
-transient prefix command; infix and suffix commands. Infix commands set
-some value (which is then shown in a popup buffer), without leaving the
-transient. Suffix commands, on the other hand, usually quit the
-transient and they may use the values set by the infix commands, i.e.,
-the infix *arguments*.
-
- Instead of setting arguments to be used by a suffix command, infix
-commands may also set some value by side-effect, e.g., by setting the
-value of some variable.
-
-\1f
-File: transient.info, Node: Aborting and Resuming Transients, Next: Common Suffix Commands, Prev: Invoking Transients, Up: Usage
-
-2.2 Aborting and Resuming Transients
-====================================
-
-To quit the transient without invoking a suffix command press ‘C-g’.
-
- Key bindings in transient keymaps may be longer than a single event.
-After pressing a valid prefix key, all commands whose bindings do not
-begin with that prefix key are temporarily unavailable and grayed out.
-To abort the prefix key press ‘C-g’ (which in this case only quits the
-prefix key, but not the complete transient).
-
- A transient prefix command can be bound as a suffix of another
-transient. Invoking such a suffix replaces the current transient state
-with a new transient state, i.e., the available bindings change and the
-information displayed in the popup buffer is updated accordingly.
-Pressing ‘C-g’ while a nested transient is active only quits the
-innermost transient, causing a return to the previous transient.
-
- ‘C-q’ or ‘C-z’ on the other hand always exits all transients. If you
-use the latter, then you can later resume the stack of transients using
-‘M-x transient-resume’.
-
-‘C-g’ (‘transient-quit-seq’)
-‘C-g’ (‘transient-quit-one’)
- This key quits the currently active incomplete key sequence, if
- any, or else the current transient. When quitting the current
- transient, it returns to the previous transient, if any.
-
- Transient’s predecessor bound ‘q’ instead of ‘C-g’ to the quit
-command. To learn how to get that binding back see
-‘transient-bind-q-to-quit’’s doc string.
-
-‘C-q’ (‘transient-quit-all’)
- This command quits the currently active incomplete key sequence, if
- any, and all transients, including the active transient and all
- suspended transients, if any.
-
-‘C-z’ (‘transient-suspend’)
- Like ‘transient-quit-all’, this command quits an incomplete key
- sequence, if any, and all transients. Additionally, it saves the
- stack of transients so that it can easily be resumed (which is
- particularly useful if you quickly need to do “something else” and
- the stack is deeper than a single transient, and/or you have
- already changed the values of some infix arguments).
-
- Note that only a single stack of transients can be saved at a time.
- If another stack is already saved, then saving a new stack discards
- the previous stack.
-
-‘M-x transient-resume’
- This command resumes the previously suspended stack of transients,
- if any.
-
-\1f
-File: transient.info, Node: Common Suffix Commands, Next: Saving Values, Prev: Aborting and Resuming Transients, Up: Usage
-
-2.3 Common Suffix Commands
-==========================
-
-A few shared suffix commands are available in all transients. These
-suffix commands are not shown in the popup buffer by default.
-
- This includes the aborting commands mentioned in the previous
-section, as well as some other commands that are all bound to ‘C-x KEY’.
-After ‘C-x’ is pressed, a section featuring all these common commands is
-temporarily shown in the popup buffer. After invoking one of them, the
-section disappears again. Note, however, that one of these commands is
-described as “Show common permanently”; invoke that if you want the
-common commands to always be shown for all transients.
-
-‘C-x t’ (‘transient-toggle-common’)
- This command toggles whether the generic commands that are common
- to all transients are always displayed or only after typing the
- incomplete prefix key sequence ‘C-x’. This only affects the
- current Emacs session.
-
- -- User Option: transient-show-common-commands
- This option controls whether shared suffix commands are shown
- alongside the transient-specific infix and suffix commands. By
- default, the shared commands are not shown to avoid overwhelming
- the user with too many options.
-
- While a transient is active, pressing ‘C-x’ always shows the common
- commands. The value of this option can be changed for the current
- Emacs session by typing ‘C-x t’ while a transient is active.
-
- The other common commands are described in either the previous or in
-one of the following sections.
-
- Some of Transient’s key bindings differ from the respective bindings
-of Magit-Popup; see *note FAQ:: for more information.
-
-\1f
-File: transient.info, Node: Saving Values, Next: Using History, Prev: Common Suffix Commands, Up: Usage
-
-2.4 Saving Values
-=================
-
-After setting the infix arguments in a transient, the user can save
-those arguments for future invocations.
-
- Most transients will start out with the saved arguments when they are
-invoked. There are a few exceptions, though. Some transients are
-designed so that the value that they use is stored externally as the
-buffer-local value of some variable. Invoking such a transient again
-uses the buffer-local value. (1)
-
- If the user does not save the value and just exits using a regular
-suffix command, then the value is merely saved to the transient’s
-history. That value won’t be used when the transient is next invoked,
-but it is easily accessible (see *note Using History::).
-
-‘C-x s’ (‘transient-set’)
- This command saves the value of the active transient for this Emacs
- session.
-
-‘C-x C-s’ (‘transient-save’)
- Save the value of the active transient persistently across Emacs
- sessions.
-
-‘C-x C-k’ (‘transient-reset’)
- Clear the set and saved values of the active transient.
-
- -- User Option: transient-values-file
- This option names the file that is used to persist the values of
- transients between Emacs sessions.
-
- ---------- Footnotes ----------
-
- (1) ‘magit-diff’ and ‘magit-log’ are two prominent examples, and
-their handling of buffer-local values is actually a bit more complicated
-than outlined above and even customizable.
-
-\1f
-File: transient.info, Node: Using History, Next: Getting Help for Suffix Commands, Prev: Saving Values, Up: Usage
-
-2.5 Using History
-=================
-
-Every time the user invokes a suffix command the transient’s current
-value is saved to its history. These values can be cycled through the
-same way one can cycle through the history of commands that read
-user-input in the minibuffer.
-
-‘C-M-p’ (‘transient-history-prev’)
-‘C-x p’
- This command switches to the previous value used for the active
- transient.
-
-‘C-M-n’ (‘transient-history-next’)
-‘C-x n’
- This command switches to the next value used for the active
- transient.
-
- In addition to the transient-wide history, Transient of course
-supports per-infix history. When an infix reads user-input using the
-minibuffer, the user can use the regular minibuffer history commands to
-cycle through previously used values. Usually the same keys as those
-mentioned above are bound to those commands.
-
- Authors of transients should arrange for different infix commands
-that read the same kind of value to also use the same history key (see
-*note Suffix Slots::).
-
- Both kinds of history are saved to a file when Emacs is exited.
-
- -- User Option: transient-history-file
- This option names the file that is used to persist the history of
- transients and their infixes between Emacs sessions.
-
- -- User Option: transient-history-limit
- This option controls how many history elements are kept at the time
- the history is saved in ‘transient-history-file’.
-
-\1f
-File: transient.info, Node: Getting Help for Suffix Commands, Next: Enabling and Disabling Suffixes, Prev: Using History, Up: Usage
-
-2.6 Getting Help for Suffix Commands
-====================================
-
-Transients can have many suffixes and infixes that the user might not be
-familiar with. To make it trivial to get help for these, Transient
-provides access to the documentation directly from the active transient.
-
-‘C-h’ (‘transient-help’)
- This command enters help mode. When help mode is active, typing a
- key shows information about the suffix command that the key
- normally is bound to (instead of invoking it). Pressing ‘C-h’ a
- second time shows information about the _prefix_ command.
-
- After typing a key, the stack of transient states is suspended and
- information about the suffix command is shown instead. Typing ‘q’
- in the help buffer buries that buffer and resumes the transient
- state.
-
- What sort of documentation is shown depends on how the transient was
-defined. For infix commands that represent command-line arguments this
-ideally shows the appropriate manpage. ‘transient-help’ then tries to
-jump to the correct location within that. Info manuals are also
-supported. The fallback is to show the command’s doc string, for
-non-infix suffixes this is usually appropriate.
-
-\1f
-File: transient.info, Node: Enabling and Disabling Suffixes, Next: Other Commands, Prev: Getting Help for Suffix Commands, Up: Usage
-
-2.7 Enabling and Disabling Suffixes
-===================================
-
-The user base of a package that uses transients can be very diverse.
-This is certainly the case for Magit; some users have been using it and
-Git for a decade, while others are just getting started now.
-
- For that reason a mechanism is needed that authors can use to
-classify a transient’s infixes and suffixes along the
-essentials...everything spectrum. We use the term “levels” to describe
-that mechanism.
-
- Each suffix command is placed on a level and each transient has a
-level (called “transient-level”), which controls which suffix commands
-are available. Integers between 1 and 7 (inclusive) are valid levels.
-For suffixes, 0 is also valid; it means that the suffix is not displayed
-at any level.
-
- The levels of individual transients and/or their individual suffixes
-can be changed interactively, by invoking the transient and then
-pressing ‘C-x l’ to enter the “edit” mode, see below.
-
- The default level for both transients and their suffixes is 4. The
-‘transient-default-level’ option only controls the default for
-transients. The default suffix level is always 4. The authors of
-transients should place certain suffixes on a higher level, if they
-expect that it won’t be of use to most users, and they should place very
-important suffixes on a lower level, so that they remain available even
-if the user lowers the transient level.
-
- -- User Option: transient-default-level
- This option controls which suffix levels are made available by
- default. It sets the transient-level for transients for which the
- user has not set that individually.
-
- -- User Option: transient-levels-file
- This option names the file that is used to persist the levels of
- transients and their suffixes between Emacs sessions.
-
-‘C-x l’ (‘transient-set-level’)
- This command enters edit mode. When edit mode is active, then all
- infixes and suffixes that are currently usable are displayed along
- with their levels. The colors of the levels indicate whether they
- are enabled or not. The level of the transient is also displayed
- along with some usage information.
-
- In edit mode, pressing the key that would usually invoke a certain
- suffix instead prompts the user for the level that suffix should be
- placed on.
-
- Help mode is available in edit mode.
-
- To change the transient level press ‘C-x l’ again.
-
- To exit edit mode press ‘C-g’.
-
- Note that edit mode does not display any suffixes that are not
- currently usable. ‘magit-rebase’, for example, shows different
- suffixes depending on whether a rebase is already in progress or
- not. The predicates also apply in edit mode.
-
- Therefore, to control which suffixes are available given a certain
- state, you have to make sure that that state is currently active.
-
-\1f
-File: transient.info, Node: Other Commands, Next: Configuration, Prev: Enabling and Disabling Suffixes, Up: Usage
-
-2.8 Other Commands
-==================
-
-When invoking a transient in a small frame, the transient window may not
-show the complete buffer, making it necessary to scroll, using the
-following commands. These commands are never shown in the transient
-window, and the key bindings are the same as for ‘scroll-up-command’ and
-‘scroll-down-command’ in other buffers.
-
- -- Command: transient-scroll-up arg
- This command scrolls text of transient popup window upward ARG
- lines. If ARG is ‘nil’, then it scrolls near full screen. This is
- a wrapper around ‘scroll-up-command’ (which see).
-
- -- Command: transient-scroll-down arg
- This command scrolls text of transient popup window down ARG lines.
- If ARG is ‘nil’, then it scrolls near full screen. This is a
- wrapper around ‘scroll-down-command’ (which see).
-
-\1f
-File: transient.info, Node: Configuration, Prev: Other Commands, Up: Usage
-
-2.9 Configuration
-=================
-
-More options are described in *note Common Suffix Commands::, in *note
-Saving Values::, in *note Using History:: and in *note Enabling and
-Disabling Suffixes::.
-
-Essential Options
------------------
-
-Also see *note Common Suffix Commands::.
-
- -- User Option: transient-show-popup
- This option controls whether the current transient’s infix and
- suffix commands are shown in the popup buffer.
-
- • If ‘t’ (the default) then the popup buffer is shown as soon as
- a transient prefix command is invoked.
-
- • If ‘nil’, then the popup buffer is not shown unless the user
- explicitly requests it, by pressing an incomplete prefix key
- sequence.
-
- • If a number, then the a brief one-line summary is shown
- instead of the popup buffer. If zero or negative, then not
- even that summary is shown; only the pressed key itself is
- shown.
-
- The popup is shown when the user explicitly requests it by
- pressing an incomplete prefix key sequence. Unless this is
- zero, the popup is shown after that many seconds of inactivity
- (using the absolute value).
-
- -- User Option: transient-enable-popup-navigation
- This option controls whether navigation commands are enabled in the
- transient popup buffer.
-
- While a transient is active the transient popup buffer is not the
- current buffer, making it necessary to use dedicated commands to
- act on that buffer itself. This is disabled by default. If this
- option is non-‘nil’, then the following features are available:
-
- • ‘<UP>’ moves the cursor to the previous suffix.
- • ‘<DOWN>’ moves the cursor to the next suffix.
- • ‘<RET>’ invokes the suffix the cursor is on.
- • ‘mouse-1’ invokes the clicked on suffix.
- • ‘C-s’ and ‘C-r’ start isearch in the popup buffer.
-
- -- User Option: transient-display-buffer-action
- This option specifies the action used to display the transient
- popup buffer. The transient popup buffer is displayed in a window
- using ‘(display-buffer BUFFER transient-display-buffer-action)’.
-
- The value of this option has the form ‘(FUNCTION . ALIST)’, where
- FUNCTION is a function or a list of functions. Each such function
- should accept two arguments: a buffer to display and an alist of
- the same form as ALIST. See *note (elisp)Choosing Window::, for
- details.
-
- The default is:
-
- (display-buffer-in-side-window
- (side . bottom)
- (inhibit-same-window . t)
- (window-parameters (no-other-window . t)))
-
- This displays the window at the bottom of the selected frame.
- Another useful FUNCTION is ‘display-buffer-below-selected’, which
- is what ‘magit-popup’ used by default. For more alternatives see
- *note (elisp)Buffer Display Action Functions::, and *note
- (elisp)Buffer Display Action Alists::.
-
- Note that the buffer that was current before the transient buffer
- is shown should remain the current buffer. Many suffix commands
- act on the thing at point, if appropriate, and if the transient
- buffer became the current buffer, then that would change what is at
- point. To that effect ‘inhibit-same-window’ ensures that the
- selected window is not used to show the transient buffer.
-
- It may be possible to display the window in another frame, but
- whether that works in practice depends on the window-manager. If
- the window manager selects the new window (Emacs frame), then that
- unfortunately changes which buffer is current.
-
- If you change the value of this option, then you might also want to
- change the value of ‘transient-mode-line-format’.
-
-Accessibility Options
----------------------
-
- -- User Option: transient-force-single-column
- This option controls whether the use of a single column to display
- suffixes is enforced. This might be useful for users with low
- vision who use large text and might otherwise have to scroll in two
- dimensions.
-
-Auxiliary Options
------------------
-
- -- User Option: transient-mode-line-format
- This option controls whether the transient popup buffer has a
- mode-line, separator line, or neither.
-
- If ‘nil’, then the buffer has no mode-line. If the buffer is not
- displayed right above the echo area, then this probably is not a
- good value.
-
- If ‘line’ (the default), then the buffer also has no mode-line, but
- a thin line is drawn instead, using the background color of the
- face ‘transient-separator’. Text-mode frames cannot display thin
- lines, and therefore fall back to treating ‘line’ like ‘nil’.
-
- Otherwise this can be any mode-line format. See *note (elisp)Mode
- Line Format::, for details.
-
- -- User Option: transient-semantic-coloring
- This option controls whether prefixes and suffixes are colored in a
- Hydra-like fashion.
-
- If non-‘nil’, then the key binding of each suffix is colorized to
- indicate whether it exits the transient state or not. The color of
- the prefix is indicated using the line that is drawn when the value
- of ‘transient-mode-line-format’ is ‘line’.
-
- For more information about how Hydra uses colors see
- <https://github.com/abo-abo/hydra#color> and
- <https://oremacs.com/2015/02/19/hydra-colors-reloaded>.
-
- -- User Option: transient-highlight-mismatched-keys
- This option controls whether key bindings of infix commands that do
- not match the respective command-line argument should be
- highlighted. For other infix commands this option has no effect.
-
- When this option is non-‘nil’, the key binding for an infix
- argument is highlighted when only a long argument (e.g.,
- ‘--verbose’) is specified but no shorthand (e.g., ‘-v’). In the
- rare case that a shorthand is specified but the key binding does
- not match, then it is highlighted differently.
-
- Highlighting mismatched key bindings is useful when learning the
- arguments of the underlying command-line tool; you wouldn’t want to
- learn any short-hands that do not actually exist.
-
- The highlighting is done using one of the faces
- ‘transient-mismatched-key’ and ‘transient-nonstandard-key’.
-
- -- User Option: transient-substitute-key-function
- This function is used to modify key bindings. If the value of this
- option is ‘nil’ (the default), then no substitution is performed.
-
- This function is called with one argument, the prefix object, and
- must return a key binding description, either the existing key
- description it finds in the ‘key’ slot, or the key description that
- replaces the prefix key. It could be used to make other
- substitutions, but that is discouraged.
-
- For example, ‘=’ is hard to reach using my custom keyboard layout,
- so I substitute ‘(’ for that, which is easy to reach using a layout
- optimized for lisp.
-
- (setq transient-substitute-key-function
- (lambda (obj)
- (let ((key (oref obj key)))
- (if (string-match "\\`\\(=\\)[a-zA-Z]" key)
- (replace-match "(" t t key 1)
- key))))
-
- -- User Option: transient-read-with-initial-input
- This option controls whether the last history element is used as
- the initial minibuffer input when reading the value of an infix
- argument from the user. If ‘nil’, there is no initial input and
- the first element has to be accessed the same way as the older
- elements.
-
- -- User Option: transient-hide-during-minibuffer-read
- This option controls whether the transient buffer is hidden while
- user input is being read in the minibuffer.
-
- -- User Option: transient-align-variable-pitch
- This option controls whether columns are aligned pixel-wise in the
- popup buffer.
-
- If this is non-‘nil’, then columns are aligned pixel-wise to
- support variable-pitch fonts. Keys are not aligned, so you should
- use a fixed-pitch font for the ‘transient-key’ face. Other key
- faces inherit from that face unless a theme is used that breaks
- that relationship.
-
- This option is intended for users who use a variable-pitch font for
- the ‘default’ face.
-
- -- User Option: transient-force-fixed-pitch
- This option controls whether to force the use of a monospaced font
- in popup buffer. Even if you use a proportional font for the
- ‘default’ face, you might still want to use a monospaced font in
- transient’s popup buffer. Setting this option to ‘t’ causes
- ‘default’ to be remapped to ‘fixed-pitch’ in that buffer.
-
-Developer Options
------------------
-
-These options are mainly intended for developers.
-
- -- User Option: transient-detect-key-conflicts
- This option controls whether key binding conflicts should be
- detected at the time the transient is invoked. If so, this results
- in an error, which prevents the transient from being used. Because
- of that, conflicts are ignored by default.
-
- Conflicts cannot be determined earlier, i.e., when the transient is
- being defined and when new suffixes are being added, because at
- that time there can be false-positives. It is actually valid for
- multiple suffixes to share a common key binding, provided the
- predicates of those suffixes prevent that more than one of them is
- enabled at a time.
-
- -- User Option: transient-highlight-higher-levels
- This option controls whether suffixes that would not be available
- by default are highlighted.
-
- When non-‘nil’ then the descriptions of suffixes are highlighted if
- their level is above 4, the default of ‘transient-default-level’.
- Assuming you have set that variable to 7, this highlights all
- suffixes that won’t be available to users without them making the
- same customization.
-
-\1f
-File: transient.info, Node: Modifying Existing Transients, Next: Defining New Commands, Prev: Usage, Up: Top
-
-3 Modifying Existing Transients
-*******************************
-
-To an extent, transients can be customized interactively, see *note
-Enabling and Disabling Suffixes::. This section explains how existing
-transients can be further modified non-interactively. Let’s begin with
-an example:
-
- (transient-append-suffix 'magit-patch-apply "-3"
- '("-R" "Apply in reverse" "--reverse"))
-
- This inserts a new infix argument to toggle the ‘--reverse’ argument
-after the infix argument that toggles ‘-3’ in ‘magit-patch-apply’.
-
- The following functions share a few arguments:
-
- • PREFIX is a transient prefix command, a symbol.
-
- • SUFFIX is a transient infix or suffix specification in the same
- form as expected by ‘transient-define-prefix’. Note that an infix
- is a special kind of suffix. Depending on context “suffixes” means
- “suffixes (including infixes)” or “non-infix suffixes”. Here it
- means the former. See *note Suffix Specifications::.
-
- SUFFIX may also be a group in the same form as expected by
- ‘transient-define-prefix’. See *note Group Specifications::.
-
- • LOC is a command, a key vector, a key description (a string as
- returned by ‘key-description’), or a list specifying coordinates
- (the last element may also be a command or key). For example ‘(1 0
- -1)’ identifies the last suffix (‘-1’) of the first subgroup (‘0’)
- of the second group (‘1’).
-
- If LOC is a list of coordinates, then it can be used to identify a
- group, not just an individual suffix command.
-
- The function ‘transient-get-suffix’ can be useful to determine
- whether a certain coordination list identifies the suffix or group
- that you expect it to identify. In hairy cases it may be necessary
- to look at the definition of the transient prefix command.
-
- These functions operate on the information stored in the
-‘transient--layout’ property of the PREFIX symbol. Suffix entries in
-that tree are not objects but have the form ‘(LEVEL CLASS PLIST)’, where
-PLIST should set at least ‘:key’, ‘:description’ and ‘:command’.
-
- -- Function: transient-insert-suffix prefix loc suffix &optional
- keep-other
- -- Function: transient-append-suffix prefix loc suffix &optional
- keep-other
- These functions insert the suffix or group SUFFIX into PREFIX
- before or after LOC.
-
- Conceptually adding a binding to a transient prefix is similar to
- adding a binding to a keymap, but this is complicated by the fact
- that multiple suffix commands can be bound to the same key,
- provided they are never active at the same time, see *note
- Predicate Slots::.
-
- Unfortunately both false-positives and false-negatives are
- possible. To deal with the former use non-‘nil’ KEEP-OTHER. To
- deal with the latter remove the conflicting binding explicitly.
-
- -- Function: transient-replace-suffix prefix loc suffix
- This function replaces the suffix or group at LOC in PREFIX with
- suffix or group SUFFIX.
-
- -- Function: transient-remove-suffix prefix loc
- This function removes the suffix or group at LOC in PREFIX.
-
- -- Function: transient-get-suffix prefix loc
- This function returns the suffix or group at LOC in PREFIX. The
- returned value has the form mentioned above.
-
- -- Function: transient-suffix-put prefix loc prop value
- This function edits the suffix or group at LOC in PREFIX, by
- setting the PROP of its plist to VALUE.
-
- Most of these functions do not signal an error if they cannot perform
-the requested modification. The functions that insert new suffixes show
-a warning if LOC cannot be found in PREFIX without signaling an error.
-The reason for doing it like this is that establishing a key binding
-(and that is what we essentially are trying to do here) should not
-prevent the rest of the configuration from loading. Among these
-functions only ‘transient-get-suffix’ and ‘transient-suffix-put’ may
-signal an error.
-
-\1f
-File: transient.info, Node: Defining New Commands, Next: Classes and Methods, Prev: Modifying Existing Transients, Up: Top
-
-4 Defining New Commands
-***********************
-
-* Menu:
-
-* Defining Transients::
-* Binding Suffix and Infix Commands::
-* Defining Suffix and Infix Commands::
-* Using Infix Arguments::
-* Transient State::
-
-\1f
-File: transient.info, Node: Defining Transients, Next: Binding Suffix and Infix Commands, Up: Defining New Commands
-
-4.1 Defining Transients
-=======================
-
-A transient consists of a prefix command and at least one suffix
-command, though usually a transient has several infix and suffix
-commands. The below macro defines the transient prefix command *and*
-binds the transient’s infix and suffix commands. In other words, it
-defines the complete transient, not just the transient prefix command
-that is used to invoke that transient.
-
- -- Macro: transient-define-prefix name arglist [docstring] [keyword
- value]... group... [body...]
- This macro defines NAME as a transient prefix command and binds the
- transient’s infix and suffix commands.
-
- ARGLIST are the arguments that the prefix command takes. DOCSTRING
- is the documentation string and is optional.
-
- These arguments can optionally be followed by keyword-value pairs.
- Each key has to be a keyword symbol, either ‘:class’ or a keyword
- argument supported by the constructor of that class. The
- ‘transient-prefix’ class is used if the class is not specified
- explicitly.
-
- GROUPs add key bindings for infix and suffix commands and specify
- how these bindings are presented in the popup buffer. At least one
- GROUP has to be specified. See *note Binding Suffix and Infix
- Commands::.
-
- The BODY is optional. If it is omitted, then ARGLIST is ignored
- and the function definition becomes:
-
- (lambda ()
- (interactive)
- (transient-setup 'NAME))
-
- If BODY is specified, then it must begin with an ‘interactive’ form
- that matches ARGLIST, and it must call ‘transient-setup’. It may,
- however, call that function only when some condition is satisfied.
-
- All transients have a (possibly ‘nil’) value, which is exported
- when suffix commands are called, so that they can consume that
- value. For some transients it might be necessary to have a sort of
- secondary value, called a “scope”. Such a scope would usually be
- set in the command’s ‘interactive’ form and has to be passed to the
- setup function:
-
- (transient-setup 'NAME nil nil :scope SCOPE)
-
- For example, the scope of the ‘magit-branch-configure’ transient is
- the branch whose variables are being configured.
-
-\1f
-File: transient.info, Node: Binding Suffix and Infix Commands, Next: Defining Suffix and Infix Commands, Prev: Defining Transients, Up: Defining New Commands
-
-4.2 Binding Suffix and Infix Commands
-=====================================
-
-The macro ‘transient-define-prefix’ is used to define a transient. This
-defines the actual transient prefix command (see *note Defining
-Transients::) and adds the transient’s infix and suffix bindings, as
-described below.
-
- Users and third-party packages can add additional bindings using
-functions such as ‘transient-insert-suffix’ (See *note Modifying
-Existing Transients::). These functions take a “suffix specification”
-as one of their arguments, which has the same form as the specifications
-used in ‘transient-define-prefix’.
-
-* Menu:
-
-* Group Specifications::
-* Suffix Specifications::
-
-\1f
-File: transient.info, Node: Group Specifications, Next: Suffix Specifications, Up: Binding Suffix and Infix Commands
-
-4.2.1 Group Specifications
---------------------------
-
-The suffix and infix commands of a transient are organized in groups.
-The grouping controls how the descriptions of the suffixes are outlined
-visually but also makes it possible to set certain properties for a set
-of suffixes.
-
- Several group classes exist, some of which organize suffixes in
-subgroups. In most cases the class does not have to be specified
-explicitly, but see *note Group Classes::.
-
- Groups are specified in the call to ‘transient-define-prefix’, using
-vectors. Because groups are represented using vectors, we cannot use
-square brackets to indicate an optional element and instead use curly
-brackets to do the latter.
-
- Group specifications then have this form:
-
- [{LEVEL} {DESCRIPTION} {KEYWORD VALUE}... ELEMENT...]
-
- The LEVEL is optional and defaults to 4. See *note Enabling and
-Disabling Suffixes::.
-
- The DESCRIPTION is optional. If present, it is used as the heading
-of the group.
-
- The KEYWORD-VALUE pairs are optional. Each keyword has to be a
-keyword symbol, either ‘:class’ or a keyword argument supported by the
-constructor of that class.
-
- • One of these keywords, ‘:description’, is equivalent to specifying
- DESCRIPTION at the very beginning of the vector. The
- recommendation is to use ‘:description’ if some other keyword is
- also used, for consistency, or DESCRIPTION otherwise, because it
- looks better.
-
- • Likewise ‘:level’ is equivalent to LEVEL.
-
- • Other important keywords include the ‘:if...’ keywords. These
- keywords control whether the group is available in a certain
- situation.
-
- For example, one group of the ‘magit-rebase’ transient uses ‘:if
- magit-rebase-in-progress-p’, which contains the suffixes that are
- useful while rebase is already in progress; and another that uses
- ‘:if-not magit-rebase-in-progress-p’, which contains the suffixes
- that initiate a rebase.
-
- These predicates can also be used on individual suffixes and are
- only documented once, see *note Predicate Slots::.
-
- • The value of ‘:hide’, if non-‘nil’, is a predicate that controls
- whether the group is hidden by default. The key bindings for
- suffixes of a hidden group should all use the same prefix key.
- Pressing that prefix key should temporarily show the group and its
- suffixes, which assumes that a predicate like this is used:
-
- (lambda ()
- (eq (car transient--redisplay-key)
- ?\C-c)) ; the prefix key shared by all bindings
-
- • The value of ‘:setup-children’, if non-‘nil’, is a function that
- takes one argument, a potentially list of children, and must return
- a list of children or an empty list. This can either be used to
- somehow transform the group’s children that were defined the normal
- way, or to dynamically create the children from scratch.
-
- The returned children must have the same form as stored in the
- prefix’s ‘transient--layout’ property, but it is often more
- convenient to use the same form as understood by
- ‘transient-define-prefix’, described below. If you use the latter
- approach, you can use the ‘transient-parse-child’ and
- ‘transient-parse-children’ functions to transform them from the
- convenient to the expected form.
-
- • The boolean ‘:pad-keys’ argument controls whether keys of all
- suffixes contained in a group are right padded, effectively
- aligning the descriptions.
-
- The ELEMENTs are either all subgroups, or all suffixes and strings.
-(At least currently no group type exists that would allow mixing
-subgroups with commands at the same level, though in principle there is
-nothing that prevents that.)
-
- If the ELEMENTs are not subgroups, then they can be a mixture of
-lists that specify commands and strings. Strings are inserted verbatim
-into the buffer. The empty string can be used to insert gaps between
-suffixes, which is particularly useful if the suffixes are outlined as a
-table.
-
- Inside group specifications, including inside contained suffix
-specifications, nothing has to be quoted and quoting anyway is invalid.
-The value following a keyword, can be explicitly unquoted using ‘,’.
-This feature is experimental and should be avoided.
-
- The form of suffix specifications is documented in the next node.
-
-\1f
-File: transient.info, Node: Suffix Specifications, Prev: Group Specifications, Up: Binding Suffix and Infix Commands
-
-4.2.2 Suffix Specifications
----------------------------
-
-A transient’s suffix and infix commands are bound when the transient
-prefix command is defined using ‘transient-define-prefix’, see *note
-Defining Transients::. The commands are organized into groups, see
-*note Group Specifications::. Here we describe the form used to bind an
-individual suffix command.
-
- The same form is also used when later binding additional commands
-using functions such as ‘transient-insert-suffix’, see *note Modifying
-Existing Transients::.
-
- Note that an infix is a special kind of suffix. Depending on context
-“suffixes” means “suffixes (including infixes)” or “non-infix suffixes”.
-Here it means the former.
-
- Suffix specifications have this form:
-
- ([LEVEL] [KEY [DESCRIPTION]] COMMAND|ARGUMENT [KEYWORD VALUE]...)
-
- LEVEL, KEY and DESCRIPTION can also be specified using the KEYWORDs
-‘:level’, ‘:key’ and ‘:description’. If the object that is associated
-with COMMAND sets these properties, then they do not have to be
-specified here. You can however specify them here anyway, possibly
-overriding the object’s values just for the binding inside this
-transient.
-
- • LEVEL is the suffix level, an integer between 1 and 7. See *note
- Enabling and Disabling Suffixes::.
-
- • KEY is the key binding, either a vector or key description string.
-
- • DESCRIPTION is the description, either a string or a function that
- returns a string. The function should be a lambda expression to
- avoid ambiguity. In some cases a symbol that is bound as a
- function would also work but to be safe you should use
- ‘:description’ in that case.
-
- The next element is either a command or an argument. This is the
-only argument that is mandatory in all cases.
-
- • COMMAND should be a symbol that is bound as a function, which has
- to be defined or at least autoloaded as a command by the time the
- containing prefix command is invoked.
-
- Any command will do; it does not need to have an object associated
- with it (as would be the case if ‘transient-define-suffix’ or
- ‘transient-define-infix’ were used to define it).
-
- COMMAND can also be a ‘lambda’ expression.
-
- As mentioned above, the object that is associated with a command
- can be used to set the default for certain values that otherwise
- have to be set in the suffix specification. Therefore if there is
- no object, then you have to make sure to specify the KEY and the
- DESCRIPTION.
-
- As a special case, if you want to add a command that might be
- neither defined nor autoloaded, you can use a workaround like:
-
- (transient-insert-suffix 'some-prefix "k"
- '("!" "Ceci n'est pas une commande" no-command
- :if (lambda () (featurep 'no-library))))
-
- Instead of ‘featurep’ you could also use ‘require’ with a non-‘nil’
- value for NOERROR.
-
- • The mandatory argument can also be a command-line argument, a
- string. In that case an anonymous command is defined and bound.
-
- Instead of a string, this can also be a list of two strings, in
- which case the first string is used as the short argument (which
- can also be specified using ‘:shortarg’) and the second as the long
- argument (which can also be specified using ‘:argument’).
-
- Only the long argument is displayed in the popup buffer. See
- ‘transient-detect-key-conflicts’ for how the short argument may be
- used.
-
- Unless the class is specified explicitly, the appropriate class is
- guessed based on the long argument. If the argument ends with ‘=’
- (e.g., ‘--format=’) then ‘transient-option’ is used, otherwise
- ‘transient-switch’.
-
- Finally, details can be specified using optional KEYWORD-VALUE pairs.
-Each keyword has to be a keyword symbol, either ‘:class’ or a keyword
-argument supported by the constructor of that class. See *note Suffix
-Slots::.
-
-\1f
-File: transient.info, Node: Defining Suffix and Infix Commands, Next: Using Infix Arguments, Prev: Binding Suffix and Infix Commands, Up: Defining New Commands
-
-4.3 Defining Suffix and Infix Commands
-======================================
-
-Note that an infix is a special kind of suffix. Depending on context
-“suffixes” means “suffixes (including infixes)” or “non-infix suffixes”.
-
- -- Macro: transient-define-suffix name arglist [docstring] [keyword
- value]... body...
- This macro defines NAME as a transient suffix command.
-
- ARGLIST are the arguments that the command takes. DOCSTRING is the
- documentation string and is optional.
-
- These arguments can optionally be followed by keyword-value pairs.
- Each keyword has to be a keyword symbol, either ‘:class’ or a
- keyword argument supported by the constructor of that class. The
- ‘transient-suffix’ class is used if the class is not specified
- explicitly.
-
- The BODY must begin with an ‘interactive’ form that matches
- ARGLIST. The infix arguments are usually accessed by using
- ‘transient-args’ inside ‘interactive’.
-
- -- Macro: transient-define-infix name arglist [docstring] [keyword
- value]...
- This macro defines NAME as a transient infix command.
-
- ARGLIST is always ignored (but mandatory never-the-less) and
- reserved for future use. DOCSTRING is the documentation string and
- is optional.
-
- The keyword-value pairs are mandatory. All transient infix
- commands are ‘equal’ to each other (but not ‘eq’), so it is
- meaningless to define an infix command without also setting at
- least ‘:class’ and one other keyword (which it is depends on the
- used class, usually ‘:argument’ or ‘:variable’).
-
- Each keyword has to be a keyword symbol, either ‘:class’ or a
- keyword argument supported by the constructor of that class. The
- ‘transient-switch’ class is used if the class is not specified
- explicitly.
-
- The function definition is always:
-
- (lambda ()
- (interactive)
- (let ((obj (transient-suffix-object)))
- (transient-infix-set obj (transient-infix-read obj)))
- (transient--show))
-
- ‘transient-infix-read’ and ‘transient-infix-set’ are generic
- functions. Different infix commands behave differently because the
- concrete methods are different for different infix command classes.
- In rare cases the above command function might not be suitable,
- even if you define your own infix command class. In that case you
- have to use ‘transient-define-suffix’ to define the infix command
- and use ‘t’ as the value of the ‘:transient’ keyword.
-
- -- Macro: transient-define-argument name arglist [docstring] [keyword
- value]...
- This macro defines NAME as a transient infix command.
-
- This is an alias for ‘transient-define-infix’. Only use this alias
- to define an infix command that actually sets an infix argument.
- To define an infix command that, for example, sets a variable, use
- ‘transient-define-infix’ instead.
-
-\1f
-File: transient.info, Node: Using Infix Arguments, Next: Transient State, Prev: Defining Suffix and Infix Commands, Up: Defining New Commands
-
-4.4 Using Infix Arguments
-=========================
-
-The functions and the variables described below allow suffix commands to
-access the value of the transient from which they were invoked; which is
-the value of its infix arguments. These variables are set when the user
-invokes a suffix command that exits the transient, but before actually
-calling the command.
-
- When returning to the command-loop after calling the suffix command,
-the arguments are reset to ‘nil’ (which causes the function to return
-‘nil’ too).
-
- Like for Emacs’ prefix arguments, it is advisable, but not mandatory,
-to access the infix arguments inside the command’s ‘interactive’ form.
-The preferred way of doing that is to call the ‘transient-args’
-function, which for infix arguments serves about the same purpose as
-‘prefix-arg’ serves for prefix arguments.
-
- -- Function: transient-args prefix
- This function returns the value of the transient prefix command
- PREFIX.
-
- If the current command was invoked from the transient prefix
- command PREFIX, then it returns the active infix arguments. If the
- current command was not invoked from PREFIX, then it returns the
- set, saved or default value for PREFIX.
-
- -- Function: transient-arg-value arg args
- This function return the value of ARG as it appears in ARGS.
-
- For a switch a boolean is returned. For an option the value is
- returned as a string, using the empty string for the empty value,
- or ‘nil’ if the option does not appear in ARGS.
-
- -- Function: transient-suffixes prefix
- This function returns the suffixes of the transient prefix command
- PREFIX. This is a list of objects. This function should only be
- used if you need the objects (as opposed to just their values) and
- if the current command is not being invoked from PREFIX.
-
- -- Variable: transient-current-suffixes
- The suffixes of the transient from which this suffix command was
- invoked. This is a list of objects. Usually it is sufficient to
- instead use the function ‘transient-args’, which returns a list of
- values. In complex cases it might be necessary to use this
- variable instead, i.e., if you need access to information beside
- the value.
-
- -- Variable: transient-current-prefix
- The transient from which this suffix command was invoked. The
- returned value is a ‘transient-prefix’ object, which holds
- information associated with the transient prefix command.
-
- -- Variable: transient-current-command
- The transient from which this suffix command was invoked. The
- returned value is a symbol, the transient prefix command.
-
-\1f
-File: transient.info, Node: Transient State, Prev: Using Infix Arguments, Up: Defining New Commands
-
-4.5 Transient State
-===================
-
-Invoking a transient prefix command “activates” the respective
-transient, i.e., it puts a transient keymap into effect, which binds the
-transient’s infix and suffix commands.
-
- The default behavior while a transient is active is as follows:
-
- • Invoking an infix command does not affect the transient state; the
- transient remains active.
-
- • Invoking a (non-infix) suffix command “deactivates” the transient
- state by removing the transient keymap and performing some
- additional cleanup.
-
- • Invoking a command that is bound in a keymap other than the
- transient keymap is disallowed and trying to do so results in a
- warning. This does not “deactivate” the transient.
-
- But these are just the defaults. Whether a certain command
-deactivates or “exits” the transient is configurable. There is more
-than one way in which a command can be “transient” or “non-transient”;
-the exact behavior is implemented by calling a so-called “pre-command”
-function. Whether non-suffix commands are allowed to be called is
-configurable per transient.
-
- • The transient-ness of suffix commands (including infix commands) is
- controlled by the value of their ‘transient’ slot, which can be set
- either when defining the command or when adding a binding to a
- transient while defining the respective transient prefix command.
-
- Valid values are booleans and the pre-commands described below.
-
- • ‘t’ is equivalent to ‘transient--do-stay’.
- • ‘nil’ is equivalent to ‘transient--do-exit’.
- • If ‘transient’ is unbound (and that is actually the default
- for non-infix suffixes) then the value of the prefix’s
- ‘transient-suffix’ slot is used instead. The default value of
- that slot is ‘nil’, so the suffix’s ‘transient’ slot being
- unbound is essentially equivalent to it being ‘nil’.
-
- • A suffix command can be a prefix command itself, i.e., a
- “sub-prefix”. While a sub-prefix is active we nearly always want
- ‘C-g’ to take the user back to the “super-prefix”. However in rare
- cases this may not be desirable, and that makes the following
- complication necessary:
-
- For ‘transient-suffix’ objects the ‘transient’ slot is unbound. We
- can ignore that for the most part because, as stated above, ‘nil’
- and the slot being unbound are equivalent, and mean “do exit”.
- That isn’t actually true for suffixes that are sub-prefixes though.
- For such suffixes unbound means “do exit but allow going back”,
- which is the default, while ‘nil’ means “do exit permanently”,
- which requires that slot to be explicitly set to that value.
-
- • The transient-ness of certain built-in suffix commands is specified
- using ‘transient-predicate-map’. This is a special keymap, which
- binds commands to pre-commands (as opposed to keys to commands) and
- takes precedence over the ‘transient’ slot.
-
- The available pre-command functions are documented below. They are
-called by ‘transient--pre-command’, a function on ‘pre-command-hook’ and
-the value that they return determines whether the transient is exited.
-To do so the value of one of the constants ‘transient--exit’ or
-‘transient--stay’ is used (that way we don’t have to remember if ‘t’
-means “exit” or “stay”).
-
- Additionally, these functions may change the value of ‘this-command’
-(which explains why they have to be called using ‘pre-command-hook’),
-call ‘transient-export’, ‘transient--stack-zap’ or
-‘transient--stack-push’; and set the values of ‘transient--exitp’,
-‘transient--helpp’ or ‘transient--editp’.
-
-Pre-commands for Infixes
-------------------------
-
-The default for infixes is ‘transient--do-stay’. This is also the only
-function that makes sense for infixes.
-
- -- Function: transient--do-stay
- Call the command without exporting variables and stay transient.
-
-Pre-commands for Suffixes
--------------------------
-
-By default, invoking a suffix causes the transient to be exited.
-
- If you want a different default behavior for a certain transient
-prefix command, then set its ‘:transient-suffix’ slot. The value can be
-a boolean, answering the question "does the transient stay active, when
-a suffix command is invoked?" ‘t’ means that the transient stays
-active, while ‘nil’ means that invoking a suffix exits the transient.
-In either case, the exact behavior depends on whether the suffix is
-itself a prefix (i.e., a sub-prefix), an infix or a regular suffix.
-
- The behavior for an individual suffix command can be changed by
-setting its ‘transient’ slot to one of the following pre-commands.
-
- -- Function: transient--do-exit
- Call the command after exporting variables and exit the transient.
-
- -- Function: transient--do-return
- Call the command after exporting variables and return to parent
- prefix. If there is no parent prefix, then call
- ‘transient--do-exit’.
-
- -- Function: transient--do-call
- Call the command after exporting variables and stay transient.
-
- The following pre-commands are suitable for sub-prefixes. Only the
-first should ever explicitly be set as the value of the ‘transient’
-slot.
-
- -- Function: transient--do-recurse
- Call the transient prefix command, preparing for return to active
- transient.
-
- Whether we actually return to the parent transient is ultimately
- under the control of each invoked suffix. The difference between
- this pre-command and ‘transient--do-replace’ is that it changes the
- value of the ‘transient-suffix’ slot to ‘transient--do-return’.
-
- If there is no parent transient, then only call this command and
- skip the second step.
-
- -- Function: transient--do-replace
- Call the transient prefix command, replacing the active transient.
-
- Unless ‘transient--do-recurse’ is explicitly used, this pre-command
- is automatically used for suffixes that are prefixes themselves,
- i.e., for sub-prefixes.
-
- -- Function: transient--do-suspend
- Suspend the active transient, saving the transient stack.
-
- This is used by the command ‘transient-suspend’ and optionally also
- by “external events” such as ‘handle-switch-frame’. Such bindings
- should be added to ‘transient-predicate-map’.
-
-Pre-commands for Non-Suffixes
------------------------------
-
-By default, non-suffixes (commands that are bound in other keymaps
-beside the transient keymap) cannot be invoked. Trying to invoke such a
-command results in a warning and the transient stays active.
-
- If you want a different behavior, then set the
-‘:transient-non-suffix’ slot of the transient prefix command. The value
-can be a boolean, answering the question, "is it allowed to invoke
-non-suffix commands?"
-
- If the value is ‘t’ or ‘transient--do-stay’, then non-suffixes can be
-invoked, when it is ‘nil’ or ‘transient--do-warn’ (the default) then
-they cannot be invoked.
-
- The only other recommended value is ‘transient--do-leave’. If that
-is used, then non-suffixes can be invoked, but if one is invoked, then
-that exits the transient.
-
- -- Function: transient--do-warn
- Call ‘transient-undefined’ and stay transient.
-
- -- Function: transient--do-stay
- Call the command without exporting variables and stay transient.
-
- -- Function: transient--do-leave
- Call the command without exporting variables and exit the
- transient.
-
-Special Pre-Commands
---------------------
-
- -- Function: transient--do-quit-one
- If active, quit help or edit mode, else exit the active transient.
-
- This is used when the user pressed ‘C-g’.
-
- -- Function: transient--do-quit-all
- Exit all transients without saving the transient stack.
-
- This is used when the user pressed ‘C-q’.
-
- -- Function: transient--do-suspend
- Suspend the active transient, saving the transient stack.
-
- This is used when the user pressed ‘C-z’.
-
-\1f
-File: transient.info, Node: Classes and Methods, Next: Related Abstractions and Packages, Prev: Defining New Commands, Up: Top
-
-5 Classes and Methods
-*********************
-
-Transient uses classes and generic functions to make it possible to
-define new types of suffix commands that are similar to existing types,
-but behave differently in some aspects. It does the same for groups and
-prefix commands, though at least for prefix commands that *currently*
-appears to be less important.
-
- Every prefix, infix and suffix command is associated with an object,
-which holds information that controls certain aspects of its behavior.
-This happens in two ways.
-
- • Associating a command with a certain class gives the command a
- type. This makes it possible to use generic functions to do
- certain things that have to be done differently depending on what
- type of command it acts on.
-
- That in turn makes it possible for third-parties to add new types
- without having to convince the maintainer of Transient that that
- new type is important enough to justify adding a special case to a
- dozen or so functions.
-
- • Associating a command with an object makes it possible to easily
- store information that is specific to that particular command.
-
- Two commands may have the same type, but obviously their key
- bindings and descriptions still have to be different, for example.
-
- The values of some slots are functions. The ‘reader’ slot for
- example holds a function that is used to read a new value for an
- infix command. The values of such slots are regular functions.
-
- Generic functions are used when a function should do something
- different based on the type of the command, i.e., when all commands
- of a certain type should behave the same way but different from the
- behavior for other types. Object slots that hold a regular
- function as value are used when the task that they perform is
- likely to differ even between different commands of the same type.
-
-* Menu:
-
-* Group Classes::
-* Group Methods::
-* Prefix Classes::
-* Suffix Classes::
-* Suffix Methods::
-* Prefix Slots::
-* Suffix Slots::
-* Predicate Slots::
-
-\1f
-File: transient.info, Node: Group Classes, Next: Group Methods, Up: Classes and Methods
-
-5.1 Group Classes
-=================
-
-The type of a group can be specified using the ‘:class’ property at the
-beginning of the class specification, e.g., ‘[:class transient-columns
-...]’ in a call to ‘transient-define-prefix’.
-
- • The abstract ‘transient-child’ class is the base class of both
- ‘transient-group’ (and therefore all groups) as well as of
- ‘transient-suffix’ (and therefore all suffix and infix commands).
-
- This class exists because the elements (or “children”) of certain
- groups can be other groups instead of suffix and infix commands.
-
- • The abstract ‘transient-group’ class is the superclass of all other
- group classes.
-
- • The ‘transient-column’ class is the simplest group.
-
- This is the default “flat” group. If the class is not specified
- explicitly and the first element is not a vector (i.e., not a
- group), then this class is used.
-
- This class displays each element on a separate line.
-
- • The ‘transient-row’ class displays all elements on a single line.
-
- • The ‘transient-columns’ class displays commands organized in
- columns.
-
- Direct elements have to be groups whose elements have to be
- commands or strings. Each subgroup represents a column. This
- class takes care of inserting the subgroups’ elements.
-
- This is the default “nested” group. If the class is not specified
- explicitly and the first element is a vector (i.e., a group), then
- this class is used.
-
- • The ‘transient-subgroups’ class wraps other groups.
-
- Direct elements have to be groups whose elements have to be
- commands or strings. This group inserts an empty line between
- subgroups. The subgroups themselves are responsible for displaying
- their elements.
-
-\1f
-File: transient.info, Node: Group Methods, Next: Prefix Classes, Prev: Group Classes, Up: Classes and Methods
-
-5.2 Group Methods
-=================
-
- -- Function: transient-setup-children group children
- This generic function can be used to setup the children or a group.
-
- The default implementation usually just returns the children
- unchanged, but if the ‘setup-children’ slot of GROUP is non-‘nil’,
- then it calls that function with CHILDREN as the only argument and
- returns the value.
-
- The children are given as a (potentially empty) list consisting of
- either group or suffix specifications. These functions can make
- arbitrary changes to the children including constructing new
- children from scratch.
-
- -- Function: transient--insert-group group
- This generic function formats the group and its elements and
- inserts the result into the current buffer, which is a temporary
- buffer. The contents of that buffer are later inserted into the
- popup buffer.
-
- Functions that are called by this function may need to operate in
- the buffer from which the transient was called. To do so they can
- temporarily make the ‘transient--source-buffer’ the current buffer.
-
-\1f
-File: transient.info, Node: Prefix Classes, Next: Suffix Classes, Prev: Group Methods, Up: Classes and Methods
-
-5.3 Prefix Classes
-==================
-
-Currently the ‘transient-prefix’ class is being used for all prefix
-commands and there is only a single generic function that can be
-specialized based on the class of a prefix command.
-
- -- Function: transient--history-init obj
- This generic function is called while setting up the transient and
- is responsible for initializing the ‘history’ slot. This is the
- transient-wide history; many individual infixes also have a history
- of their own.
-
- The default (and currently only) method extracts the value from the
- global variable ‘transient-history’.
-
- A transient prefix command’s object is stored in the
-‘transient--prefix’ property of the command symbol. While a transient
-is active, a clone of that object is stored in the variable
-‘transient--prefix’. A clone is used because some changes that are made
-to the active transient’s object should not affect later invocations.
-
-\1f
-File: transient.info, Node: Suffix Classes, Next: Suffix Methods, Prev: Prefix Classes, Up: Classes and Methods
-
-5.4 Suffix Classes
-==================
-
- • All suffix and infix classes derive from ‘transient-suffix’, which
- in turn derives from ‘transient-child’, from which
- ‘transient-group’ also derives (see *note Group Classes::).
-
- • All infix classes derive from the abstract ‘transient-infix’ class,
- which in turn derives from the ‘transient-suffix’ class.
-
- Infixes are a special type of suffixes. The primary difference is
- that infixes always use the ‘transient--do-stay’ pre-command, while
- non-infix suffixes use a variety of pre-commands (see *note
- Transient State::). Doing that is most easily achieved by using
- this class, though theoretically it would be possible to define an
- infix class that does not do so. If you do that then you get to
- implement many methods.
-
- Also, infixes and non-infix suffixes are usually defined using
- different macros (see *note Defining Suffix and Infix Commands::).
-
- • Classes used for infix commands that represent arguments should be
- derived from the abstract ‘transient-argument’ class.
-
- • The ‘transient-switch’ class (or a derived class) is used for infix
- arguments that represent command-line switches (arguments that do
- not take a value).
-
- • The ‘transient-option’ class (or a derived class) is used for infix
- arguments that represent command-line options (arguments that do
- take a value).
-
- • The ‘transient-switches’ class can be used for a set of mutually
- exclusive command-line switches.
-
- • The ‘transient-files’ class can be used for a ‘--’ argument that
- indicates that all remaining arguments are files.
-
- • Classes used for infix commands that represent variables should
- derived from the abstract ‘transient-variable’ class.
-
- Magit defines additional classes, which can serve as examples for the
-fancy things you can do without modifying Transient. Some of these
-classes will likely get generalized and added to Transient. For now
-they are very much subject to change and not documented.
-
-\1f
-File: transient.info, Node: Suffix Methods, Next: Prefix Slots, Prev: Suffix Classes, Up: Classes and Methods
-
-5.5 Suffix Methods
-==================
-
-To get information about the methods implementing these generic
-functions use ‘describe-function’.
-
-* Menu:
-
-* Suffix Value Methods::
-* Suffix Format Methods::
-
-\1f
-File: transient.info, Node: Suffix Value Methods, Next: Suffix Format Methods, Up: Suffix Methods
-
-5.5.1 Suffix Value Methods
---------------------------
-
- -- Function: transient-init-value obj
- This generic function sets the initial value of the object OBJ.
-
- This function is called for all suffix commands, but unless a
- concrete method is implemented this falls through to the default
- implementation, which is a noop. In other words this usually only
- does something for infix commands, but note that this is not
- implemented for the abstract class ‘transient-infix’, so if your
- class derives from that directly, then you must implement a method.
-
- -- Function: transient-infix-read obj
- This generic function determines the new value of the infix object
- OBJ.
-
- This function merely determines the value; ‘transient-infix-set’ is
- used to actually store the new value in the object.
-
- For most infix classes this is done by reading a value from the
- user using the reader specified by the ‘reader’ slot (using the
- ‘transient-infix-value’ method described below).
-
- For some infix classes the value is changed without reading
- anything in the minibuffer, i.e., the mere act of invoking the
- infix command determines what the new value should be, based on the
- previous value.
-
- -- Function: transient-prompt obj
- This generic function returns the prompt to be used to read infix
- object OBJ’s value.
-
- -- Function: transient-infix-set obj value
- This generic function sets the value of infix object OBJ to VALUE.
-
- -- Function: transient-infix-value obj
- This generic function returns the value of the suffix object OBJ.
-
- This function is called by ‘transient-args’ (which see), meaning
- this function is how the value of a transient is determined so that
- the invoked suffix command can use it.
-
- Currently most values are strings, but that is not set in stone.
- ‘nil’ is not a value, it means “no value”.
-
- Usually only infixes have a value, but see the method for
- ‘transient-suffix’.
-
- -- Function: transient-init-scope obj
- This generic function sets the scope of the suffix object OBJ.
-
- The scope is actually a property of the transient prefix, not of
- individual suffixes. However it is possible to invoke a suffix
- command directly instead of from a transient. In that case, if the
- suffix expects a scope, then it has to determine that itself and
- store it in its ‘scope’ slot.
-
- This function is called for all suffix commands, but unless a
- concrete method is implemented this falls through to the default
- implementation, which is a noop.
-
-\1f
-File: transient.info, Node: Suffix Format Methods, Prev: Suffix Value Methods, Up: Suffix Methods
-
-5.5.2 Suffix Format Methods
----------------------------
-
- -- Function: transient-format obj
- This generic function formats and returns OBJ for display.
-
- When this function is called, then the current buffer is some
- temporary buffer. If you need the buffer from which the prefix
- command was invoked to be current, then do so by temporarily making
- ‘transient--source-buffer’ current.
-
- -- Function: transient-format-key obj
- This generic function formats OBJ’s ‘key’ for display and returns
- the result.
-
- -- Function: transient-format-description obj
- This generic function formats OBJ’s ‘description’ for display and
- returns the result.
-
- -- Function: transient-format-value obj
- This generic function formats OBJ’s value for display and returns
- the result.
-
- -- Function: transient-show-help obj
- Show help for the prefix, infix or suffix command represented by
- OBJ.
-
- For prefixes, show the info manual, if that is specified using the
- ‘info-manual’ slot. Otherwise, show the manpage if that is
- specified using the ‘man-page’ slot. Otherwise, show the command’s
- doc string.
-
- For suffixes, show the command’s doc string.
-
- For infixes, show the manpage if that is specified. Otherwise show
- the command’s doc string.
-
-\1f
-File: transient.info, Node: Prefix Slots, Next: Suffix Slots, Prev: Suffix Methods, Up: Classes and Methods
-
-5.6 Prefix Slots
-================
-
- • ‘show-help’, ‘man-page’ or ‘info-manual’ can be used to specify the
- documentation for the prefix and its suffixes. The command
- ‘transient-help’ uses the method ‘transient-show-help’ (which see)
- to lookup and use these values.
-
- • ‘history-key’ If multiple prefix commands should share a single
- value, then this slot has to be set to the same value for all of
- them. You probably don’t want that.
-
- • ‘transient-suffix’ and ‘transient-non-suffix’ play a part when
- determining whether the currently active transient prefix command
- remains active/transient when a suffix or arbitrary non-suffix
- command is invoked. See *note Transient State::.
-
- • ‘incompatible’ A list of lists. Each sub-list specifies a set of
- mutually exclusive arguments. Enabling one of these arguments
- causes the others to be disabled. An argument may appear in
- multiple sub-lists.
-
- • ‘scope’ For some transients it might be necessary to have a sort of
- secondary value, called a “scope”. See ‘transient-define-prefix’.
-
-Internal Prefix Slots
----------------------
-
-These slots are mostly intended for internal use. They should not be
-set in calls to ‘transient-define-prefix’.
-
- • ‘prototype’ When a transient prefix command is invoked, then a
- clone of that object is stored in the global variable
- ‘transient--prefix’ and the prototype is stored in the clone’s
- ‘prototype’ slot.
-
- • ‘command’ The command, a symbol. Each transient prefix command
- consists of a command, which is stored in a symbol’s function slot
- and an object, which is stored in the ‘transient--prefix’ property
- of the same symbol.
-
- • ‘level’ The level of the prefix commands. The suffix commands
- whose layer is equal or lower are displayed. See *note Enabling
- and Disabling Suffixes::.
-
- • ‘value’ The likely outdated value of the prefix. Instead of
- accessing this slot directly you should use the function
- ‘transient-get-value’, which is guaranteed to return the up-to-date
- value.
-
- • ‘history’ and ‘history-pos’ are used to keep track of historic
- values. Unless you implement your own ‘transient-infix-read’
- method you should not have to deal with these slots.
-
-\1f
-File: transient.info, Node: Suffix Slots, Next: Predicate Slots, Prev: Prefix Slots, Up: Classes and Methods
-
-5.7 Suffix Slots
-================
-
-Here we document most of the slots that are only available for suffix
-objects. Some slots are shared by suffix and group objects, they are
-documented in *note Predicate Slots::.
-
- Also see *note Suffix Classes::.
-
-Slots of ‘transient-suffix’
----------------------------
-
- • ‘key’ The key, a key vector or a key description string.
-
- • ‘command’ The command, a symbol.
-
- • ‘transient’ Whether to stay transient. See *note Transient
- State::.
-
- • ‘format’ The format used to display the suffix in the popup buffer.
- It must contain the following %-placeholders:
-
- • ‘%k’ For the key.
- • ‘%d’ For the description.
- • ‘%v’ For the infix value. Non-infix suffixes don’t have a
- value.
-
- • ‘description’ The description, either a string or a function that
- is called with no argument and returns a string.
-
- • ‘show-help’ A function used to display help for the suffix. If
- unspecified, the prefix controls how help is displayed for its
- suffixes.
-
-Slots of ‘transient-infix’
---------------------------
-
-Some of these slots are only meaningful for some of the subclasses.
-They are defined here anyway to allow sharing certain methods.
-
- • ‘argument’ The long argument, e.g., ‘--verbose’.
-
- • ‘shortarg’ The short argument, e.g., ‘-v’.
-
- • ‘value’ The value. Should not be accessed directly.
-
- • ‘init-value’ Function that is responsible for setting the object’s
- value. If bound, then this is called with the object as the only
- argument. Usually this is not bound, in which case the object’s
- primary ‘transient-init-value’ method is called instead.
-
- • ‘unsavable’ Whether the value of the suffix is not saved as part of
- the prefixes.
-
- • ‘multi-value’ For options, whether the option can have multiple
- values. If this is non-‘nil’, then the values are read using
- ‘completing-read-multiple’ by default and if you specify your own
- reader, then it should read the values using that function or
- similar.
-
- Supported non-‘nil’ values are:
-
- • Use ‘rest’ for an option that can have multiple values. This
- is useful e.g., for an ‘--’ argument that indicates that all
- remaining arguments are files (such as ‘git log -- file1
- file2’).
-
- In the list returned by ‘transient-args’ such an option and
- its values are represented by a single list of the form
- ‘(ARGUMENT . VALUES)’.
-
- • Use ‘repeat’ for an option that can be specified multiple
- times.
-
- In the list returned by ‘transient-args’ each instance of the
- option and its value appears separately in the usual from, for
- example: ‘("--another-argument" "--option=first"
- "--option=second")’.
-
- In both cases the option’s values have to be specified in the
- default value of a prefix using the same format as returned by
- ‘transient-args’, e.g., ‘("--other" "--o=1" "--o=2" ("--" "f1"
- "f2"))’.
-
- • ‘always-read’ For options, whether to read a value on every
- invocation. If this is ‘nil’, then options that have a value are
- simply unset and have to be invoked a second time to set a new
- value.
-
- • ‘allow-empty’ For options, whether the empty string is a valid
- value.
-
- • ‘history-key’ The key used to store the history. This defaults to
- the command name. This is useful when multiple infixes should
- share the same history because their values are of the same kind.
-
- • ‘reader’ The function used to read the value of an infix. Not used
- for switches. The function takes three arguments, PROMPT,
- INITIAL-INPUT and HISTORY, and must return a string.
-
- • ‘prompt’ The prompt used when reading the value, either a string or
- a function that takes the object as the only argument and which
- returns a prompt string.
-
- • ‘choices’ A list of valid values. How exactly that is used depends
- on the class of the object.
-
-Slots of ‘transient-variable’
------------------------------
-
- • ‘variable’ The variable.
-
-Slots of ‘transient-switches’
------------------------------
-
- • ‘argument-format’ The display format. Must contain ‘%s’, one of
- the ‘choices’ is substituted for that. E.g., ‘--%s-order’.
-
- • ‘argument-regexp’ The regexp used to match any one of the switches.
- E.g., ‘\\(--\\(topo\\|author-date\\|date\\)-order\\)’.
-
-\1f
-File: transient.info, Node: Predicate Slots, Prev: Suffix Slots, Up: Classes and Methods
-
-5.8 Predicate Slots
-===================
-
-Suffix and group objects share some predicate slots that control whether
-a group or suffix should be available depending on some state. Only one
-of these slots can be used at the same time. It is undefined what
-happens if you use more than one.
-
- • ‘if’ Enable if predicate returns non-‘nil’.
- • ‘if-not’ Enable if predicate returns ‘nil’.
- • ‘if-non-nil’ Enable if variable’s value is non-‘nil’.
- • ‘if-nil’ Enable if variable’s value is ‘nil’.
- • ‘if-mode’ Enable if major-mode matches value.
- • ‘if-not-mode’ Enable if major-mode does not match value.
- • ‘if-derived’ Enable if major-mode derives from value.
- • ‘if-not-derived’ Enable if major-mode does not derive from value.
-
- One more slot is shared between group and suffix classes, ‘level’.
-Like the slots documented above, it is a predicate, but it is used for a
-different purpose. The value has to be an integer between 1 and 7.
-‘level’ controls whether a suffix or a group should be available
-depending on user preference. See *note Enabling and Disabling
-Suffixes::.
-
-\1f
-File: transient.info, Node: Related Abstractions and Packages, Next: FAQ, Prev: Classes and Methods, Up: Top
-
-6 Related Abstractions and Packages
-***********************************
-
-* Menu:
-
-* Comparison With Prefix Keys and Prefix Arguments::
-* Comparison With Other Packages::
-
-\1f
-File: transient.info, Node: Comparison With Prefix Keys and Prefix Arguments, Next: Comparison With Other Packages, Up: Related Abstractions and Packages
-
-6.1 Comparison With Prefix Keys and Prefix Arguments
-====================================================
-
-While transient commands were inspired by regular prefix keys and prefix
-arguments, they are also quite different and much more complex.
-
- The following diagrams illustrate some of the differences.
-
- • ‘(c)’ represents a return to the command loop.
- • ‘(+)’ represents the user’s choice to press one key or another.
- • ‘{WORD}’ are possible behaviors.
- • ‘{NUMBER}’ is a footnote.
-
-Regular Prefix Commands
------------------------
-
-See *note (elisp)Prefix Keys::.
-
- ,--> command1 --> (c)
- |
- (c)-(+)-> prefix command or key --+--> command2 --> (c)
- |
- `--> command3 --> (c)
-
-Regular Prefix Arguments
-------------------------
-
-See *note (elisp)Prefix Command Arguments::.
-
- ,----------------------------------,
- | |
- v |
- (c)-(+)---> prefix argument command --(c)-(+)-> any command --> (c)
- | ^ |
- | | |
- `-- sets or changes --, ,-- maybe used --' |
- | | |
- v | |
- prefix argument state |
- ^ |
- | |
- `-------- discards --------'
-
-Transients
-----------
-
-(∩`-´)⊃━☆゚.*・。゚
-
- This diagram ignores the infix value and external state:
-
- (c)
- | ,- {stay} ------<-,-<------------<-,-<---,
- (+) | | | |
- | | | | |
- | | ,--> infix1 --| | |
- | | | | | |
- | | |--> infix2 --| | |
- v v | | | |
- prefix -(c)-(+)-> infix3 --' ^ |
- | | |
- |---------------> suffix1 -->--| |
- | | |
- |---------------> suffix2 ----{1}------> {exit} --> (c)
- | |
- |---------------> suffix3 -------------> {exit} --> (c)
- | |
- `--> any command --{2}-> {warn} -->--|
- | |
- |--> {noop} -->--|
- | |
- |--> {call} -->--'
- |
- `------------------> {exit} --> (c)
-
- This diagram takes the infix value into account to an extend, while
-still ignoring external state:
-
- (c)
- | ,- {stay} ------<-,-<------------<-,-<---,
- (+) | | | |
- | | | | |
- | | ,--> infix1 --| | |
- | | | | | | |
- | | ,--> infix2 --| | |
- v v | | | | |
- prefix -(c)-(+)-> infix3 --' | |
- | | ^ |
- | | | |
- |---------------> suffix1 -->--| |
- | | ^ | |
- | | | | |
- |---------------> suffix2 ----{1}------> {exit} --> (c)
- | | ^ | |
- | | | | v
- | | | | |
- |---------------> suffix3 -------------> {exit} --> (c)
- | | ^ | |
- | sets | | v
- | | maybe | |
- | | used | |
- | | | | |
- | | infix --' | |
- | `---> value | |
- | ^ | |
- | | | |
- | hides | |
- | | | |
- | `--------------------------<---|
- | | |
- `--> any command --{2}-> {warn} -->--| |
- | | |
- |--> {noop} -->--| |
- | | |
- |--> {call} -->--' ^
- | |
- `------------------> {exit} --> (c)
-
- This diagram provides more information about the infix value and also
-takes external state into account.
-
- ,----sets--- "anything"
- |
- v
- ,---------> external
- | state
- | | |
- | initialized | ☉‿⚆
- sets from |
- | | maybe
- | ,----------' used
- | | |
- (c) | | v
- | ,- {stay} --|---<-,-<------|-----<-,-<---,
- (+) | | | | | | |
- | | | v | | | |
- | | ,--> infix1 --| | | |
- | | | | | | | | |
- | | | | v | | | |
- | | ,--> infix2 --| | | |
- | | | | ^ | | | |
- v v | | | | | | |
- prefix -(c)-(+)-> infix3 --' | | |
- | | ^ | ^ |
- | | | v | |
- |---------------> suffix1 -->--| |
- | | | ^ | | |
- | | | | v | |
- |---------------> suffix2 ----{1}------> {exit} --> (c)
- | | | ^ | | |
- | | | | | | v
- | | | | v | |
- |---------------> suffix3 -------------> {exit} --> (c)
- | | | ^ | |
- | sets | | | v
- | | initialized maybe | |
- | | from used | |
- | | | | | |
- | | `-- infix ---' | |
- | `---> value -----------------------------> persistent
- | ^ ^ | | across
- | | | | | invocations -,
- | hides | | | |
- | | `----------------------------------------------'
- | | | |
- | `--------------------------<---|
- | | |
- `--> any command --{2}-> {warn} -->--| |
- | | |
- |--> {noop} -->--| |
- | | |
- |--> {call} -->--' ^
- | |
- `------------------> {exit} --> (c)
-
- • ‘{1}’ Transients can be configured to be exited when a suffix
- command is invoked. The default is to do so for all suffixes
- except for those that are common to all transients and which are
- used to perform tasks such as providing help and saving the value
- of the infix arguments for future invocations. The behavior can
- also be specified for individual suffix commands and may even
- depend on state.
-
- • ‘{2}’ Transients can be configured to allow the user to invoke
- non-suffix commands. The default is to not allow that and instead
- warn the user.
-
- Despite already being rather complex, even the last diagram leaves
-out many details. Most importantly it implies that the decision whether
-to remain transient is made later than it actually is made (for the most
-part a function on ‘pre-command-hook’ is responsible). But such
-implementation details are of little relevance to users and are covered
-elsewhere.
-
-\1f
-File: transient.info, Node: Comparison With Other Packages, Prev: Comparison With Prefix Keys and Prefix Arguments, Up: Related Abstractions and Packages
-
-6.2 Comparison With Other Packages
-==================================
-
-Magit-Popup
------------
-
-Transient is the successor to Magit-Popup (see *note
-(magit-popup)Top::).
-
- One major difference between these two implementations of the same
-ideas is that while Transient uses transient keymaps and embraces the
-command-loop, Magit-Popup implemented an inferior mechanism that does
-not use transient keymaps and that instead of using the command-loop
-implements a naive alternative based on ‘read-char’.
-
- Magit-Popup does not use classes and generic functions and defining a
-new command type is near impossible as it involves adding hard-coded
-special-cases to many functions. Because of that only a single new type
-was added, which was not already part of Magit-Popup’s initial release.
-
- A lot of things are hard-coded in Magit-Popup. One random example is
-that the key bindings for switches must begin with ‘-’ and those for
-options must begin with ‘=’.
-
-Hydra
------
-
-Hydra (see <https://github.com/abo-abo/hydra>) is another package that
-provides features similar to those of Transient.
-
- Both packages use transient keymaps to make a set of commands
-temporarily available and show the available commands in a popup buffer.
-
- A Hydra “body” is equivalent to a Transient “prefix” and a Hydra
-“head” is equivalent to a Transient “suffix”. Hydra has no equivalent
-of a Transient “infix”.
-
- Both hydras and transients can be used as simple command dispatchers.
-Used like this they are similar to regular prefix commands and prefix
-keys, except that the available commands are shown in the popup buffer.
-
- (Another package that does this is ‘which-key’. It does so
-automatically for any incomplete key sequence. The advantage of that
-approach is that no additional work is necessary; the disadvantage is
-that the available commands are not organized semantically.)
-
- Both Hydra and Transient provide features that go beyond simple
-command dispatchers:
-
- • Invoking a command from a hydra does not necessarily exit the
- hydra. That makes it possible to invoke the same command again,
- but using a shorter key sequence (i.e., the key that was used to
- enter the hydra does not have to be pressed again).
-
- Transient supports that too, but for now this feature is not a
- focus and the interface is a bit more complicated. A very basic
- example using the current interface:
-
- (transient-define-prefix outline-navigate ()
- :transient-suffix 'transient--do-stay
- :transient-non-suffix 'transient--do-warn
- [("p" "previous visible heading" outline-previous-visible-heading)
- ("n" "next visible heading" outline-next-visible-heading)])
-
- • Transient supports infix arguments; values that are set by infix
- commands and then consumed by the invoked suffix command(s).
-
- To my knowledge, Hydra does not support that.
-
- Both packages make it possible to specify how exactly the available
-commands are outlined:
-
- • With Hydra this is often done using an explicit format string,
- which gives authors a lot of flexibility and makes it possible to
- do fancy things.
-
- The downside of this is that it becomes harder for a user to add
- additional commands to an existing hydra and to change key
- bindings.
-
- • Transient allows the author of a transient to organize the commands
- into groups and the use of generic functions allows authors of
- transients to control exactly how a certain command type is
- displayed.
-
- However while Transient supports giving sections a heading it does
- not currently support giving the displayed information more
- structure by, for example, using box-drawing characters.
-
- That could be implemented by defining a new group class, which lets
- the author specify a format string. It should be possible to
- implement that without modifying any existing code, but it does not
- currently exist.
-
-\1f
-File: transient.info, Node: FAQ, Next: Keystroke Index, Prev: Related Abstractions and Packages, Up: Top
-
-Appendix A FAQ
-**************
-
-A.1 Can I control how the popup buffer is displayed?
-====================================================
-
-Yes, see ‘transient-display-buffer-action’ in *note Configuration::.
-
-A.2 How can I copy text from the popup buffer?
-==============================================
-
-To be able to mark text in any transient popup buffer using the mouse,
-you have to add the following binding. Note that the region won’t be
-visualized, while doing so. After you have quit the transient popup,
-you will be able to yank it another buffer.
-
- (keymap-set transient-predicate-map
- "<mouse-set-region>"
- #'transient--do-stay)
-
-A.3 Why did some of the key bindings change?
-============================================
-
-You may have noticed that the bindings for some of the common commands
-do *not* have the prefix ‘C-x’ and that furthermore some of these
-commands are grayed out while others are not. That unfortunately is a
-bit confusing if the section of common commands is not shown
-permanently, making the following explanation necessary.
-
- The purpose of usually hiding that section but showing it after the
-user pressed the respective prefix key is to conserve space and not
-overwhelm users with too much noise, while allowing the user to quickly
-list common bindings on demand.
-
- That however should not keep us from using the best possible key
-bindings. The bindings that do use a prefix do so to avoid wasting too
-many non-prefix bindings, keeping them available for use in individual
-transients. The bindings that do not use a prefix and that are *not*
-grayed out are very important bindings that are *always* available, even
-when invoking the “common command key prefix” or *any other*
-transient-specific prefix. The non-prefix keys that *are* grayed out
-however, are not available when any incomplete prefix key sequence is
-active. They do not use the “common command key prefix” because it is
-likely that users want to invoke them several times in a row and e.g.,
-‘M-p M-p M-p’ is much more convenient than ‘C-x M-p C-x M-p C-x M-p’.
-
- You may also have noticed that the “Set” command is bound to ‘C-x s’,
-while Magit-Popup used to bind ‘C-c C-c’ instead. I have seen several
-users praise the latter binding (sic), so I did not change it
-willy-nilly. The reason that I changed it is that using different
-prefix keys for different common commands, would have made the temporary
-display of the common commands even more confusing, i.e., after pressing
-‘C-c’ all the bindings that begin with the ‘C-x’ prefix would be grayed
-out.
-
- Using a single prefix for common commands key means that all other
-potential prefix keys can be used for transient-specific commands
-*without* the section of common commands also popping up. ‘C-c’ in
-particular is a prefix that I want to (and already do) use for Magit,
-and also using that for a common command would prevent me from doing so.
-
- (Also see the next question.)
-
-A.4 Why does ‘q’ not quit popups anymore?
-=========================================
-
-I agree that ‘q’ is a good binding for commands that quit something.
-This includes quitting whatever transient is currently active, but it
-also includes quitting whatever it is that some specific transient is
-controlling. The transient ‘magit-blame’ for example binds ‘q’ to the
-command that turns ‘magit-blame-mode’ off.
-
- So I had to decide if ‘q’ should quit the active transient (like
-Magit-Popup used to) or whether ‘C-g’ should do that instead, so that
-‘q’ could be bound in individual transient to whatever commands make
-sense for them. Because all other letters are already reserved for use
-by individual transients, I have decided to no longer make an exception
-for ‘q’.
-
- If you want to get ‘q’’s old binding back then you can do so. Doing
-that is a bit more complicated than changing a single key binding, so I
-have implemented a function, ‘transient-bind-q-to-quit’ that makes the
-necessary changes. See its doc string for more information.
-
-\1f
-File: transient.info, Node: Keystroke Index, Next: Command and Function Index, Prev: FAQ, Up: Top
-
-Appendix B Keystroke Index
-**************************
-
-\0\b[index\0\b]
-* Menu:
-
-* C-g: Aborting and Resuming Transients.
- (line 27)
-* C-g <1>: Aborting and Resuming Transients.
- (line 27)
-* C-h: Getting Help for Suffix Commands.
- (line 11)
-* C-M-n: Using History. (line 18)
-* C-M-p: Using History. (line 13)
-* C-q: Aborting and Resuming Transients.
- (line 36)
-* C-x C-k: Saving Values. (line 29)
-* C-x C-s: Saving Values. (line 25)
-* C-x l: Enabling and Disabling Suffixes.
- (line 43)
-* C-x n: Using History. (line 18)
-* C-x p: Using History. (line 13)
-* C-x s: Saving Values. (line 21)
-* C-x t: Common Suffix Commands.
- (line 18)
-* C-z: Aborting and Resuming Transients.
- (line 41)
-
-\1f
-File: transient.info, Node: Command and Function Index, Next: Variable Index, Prev: Keystroke Index, Up: Top
-
-Appendix C Command and Function Index
-*************************************
-
-\0\b[index\0\b]
-* Menu:
-
-* transient--do-call: Transient State. (line 110)
-* transient--do-exit: Transient State. (line 102)
-* transient--do-leave: Transient State. (line 169)
-* transient--do-quit-all: Transient State. (line 181)
-* transient--do-quit-one: Transient State. (line 176)
-* transient--do-recurse: Transient State. (line 117)
-* transient--do-replace: Transient State. (line 129)
-* transient--do-return: Transient State. (line 105)
-* transient--do-stay: Transient State. (line 83)
-* transient--do-stay <1>: Transient State. (line 166)
-* transient--do-suspend: Transient State. (line 136)
-* transient--do-suspend <1>: Transient State. (line 186)
-* transient--do-warn: Transient State. (line 163)
-* transient--history-init: Prefix Classes. (line 10)
-* transient--insert-group: Group Methods. (line 19)
-* transient-append-suffix: Modifying Existing Transients.
- (line 51)
-* transient-arg-value: Using Infix Arguments.
- (line 31)
-* transient-args: Using Infix Arguments.
- (line 22)
-* transient-define-argument: Defining Suffix and Infix Commands.
- (line 61)
-* transient-define-infix: Defining Suffix and Infix Commands.
- (line 26)
-* transient-define-prefix: Defining Transients. (line 13)
-* transient-define-suffix: Defining Suffix and Infix Commands.
- (line 9)
-* transient-format: Suffix Format Methods.
- (line 6)
-* transient-format-description: Suffix Format Methods.
- (line 18)
-* transient-format-key: Suffix Format Methods.
- (line 14)
-* transient-format-value: Suffix Format Methods.
- (line 22)
-* transient-get-suffix: Modifying Existing Transients.
- (line 73)
-* transient-help: Getting Help for Suffix Commands.
- (line 11)
-* transient-history-next: Using History. (line 18)
-* transient-history-prev: Using History. (line 13)
-* transient-infix-read: Suffix Value Methods.
- (line 16)
-* transient-infix-set: Suffix Value Methods.
- (line 36)
-* transient-infix-value: Suffix Value Methods.
- (line 39)
-* transient-init-scope: Suffix Value Methods.
- (line 52)
-* transient-init-value: Suffix Value Methods.
- (line 6)
-* transient-insert-suffix: Modifying Existing Transients.
- (line 49)
-* transient-prompt: Suffix Value Methods.
- (line 32)
-* transient-quit-all: Aborting and Resuming Transients.
- (line 36)
-* transient-quit-one: Aborting and Resuming Transients.
- (line 27)
-* transient-quit-seq: Aborting and Resuming Transients.
- (line 27)
-* transient-remove-suffix: Modifying Existing Transients.
- (line 70)
-* transient-replace-suffix: Modifying Existing Transients.
- (line 66)
-* transient-reset: Saving Values. (line 29)
-* transient-resume: Aborting and Resuming Transients.
- (line 53)
-* transient-save: Saving Values. (line 25)
-* transient-scroll-down: Other Commands. (line 17)
-* transient-scroll-up: Other Commands. (line 12)
-* transient-set: Saving Values. (line 21)
-* transient-set-level: Enabling and Disabling Suffixes.
- (line 43)
-* transient-setup-children: Group Methods. (line 6)
-* transient-show-help: Suffix Format Methods.
- (line 26)
-* transient-suffix-put: Modifying Existing Transients.
- (line 77)
-* transient-suffixes: Using Infix Arguments.
- (line 38)
-* transient-suspend: Aborting and Resuming Transients.
- (line 41)
-* transient-toggle-common: Common Suffix Commands.
- (line 18)
-
-\1f
-File: transient.info, Node: Variable Index, Next: Concept Index, Prev: Command and Function Index, Up: Top
-
-Appendix D Variable Index
-*************************
-
-\0\b[index\0\b]
-* Menu:
-
-* transient-align-variable-pitch: Configuration. (line 181)
-* transient-current-command: Using Infix Arguments.
- (line 57)
-* transient-current-prefix: Using Infix Arguments.
- (line 52)
-* transient-current-suffixes: Using Infix Arguments.
- (line 44)
-* transient-default-level: Enabling and Disabling Suffixes.
- (line 33)
-* transient-detect-key-conflicts: Configuration. (line 206)
-* transient-display-buffer-action: Configuration. (line 51)
-* transient-enable-popup-navigation: Configuration. (line 36)
-* transient-force-fixed-pitch: Configuration. (line 194)
-* transient-force-single-column: Configuration. (line 93)
-* transient-hide-during-minibuffer-read: Configuration. (line 177)
-* transient-highlight-higher-levels: Configuration. (line 219)
-* transient-highlight-mismatched-keys: Configuration. (line 131)
-* transient-history-file: Using History. (line 33)
-* transient-history-limit: Using History. (line 37)
-* transient-levels-file: Enabling and Disabling Suffixes.
- (line 38)
-* transient-mode-line-format: Configuration. (line 102)
-* transient-read-with-initial-input: Configuration. (line 170)
-* transient-semantic-coloring: Configuration. (line 118)
-* transient-show-common-commands: Common Suffix Commands.
- (line 23)
-* transient-show-popup: Configuration. (line 15)
-* transient-substitute-key-function: Configuration. (line 149)
-* transient-values-file: Saving Values. (line 31)
-
-\1f
-File: transient.info, Node: Concept Index, Next: GNU General Public License, Prev: Variable Index, Up: Top
-
-Appendix E Concept Index
-************************
-
-\0\b[index\0\b]
-* Menu:
-
-* aborting transients: Aborting and Resuming Transients.
- (line 6)
-* classes and methods: Classes and Methods. (line 6)
-* command dispatchers: Introduction. (line 70)
-* common suffix commands: Common Suffix Commands.
- (line 6)
-* defining infix commands: Defining Suffix and Infix Commands.
- (line 6)
-* defining suffix commands: Defining Suffix and Infix Commands.
- (line 6)
-* disabling suffixes: Enabling and Disabling Suffixes.
- (line 6)
-* enabling suffixes: Enabling and Disabling Suffixes.
- (line 6)
-* getting help: Getting Help for Suffix Commands.
- (line 6)
-* group specifications: Group Specifications. (line 6)
-* invoking transients: Invoking Transients. (line 6)
-* levels: Enabling and Disabling Suffixes.
- (line 10)
-* modifying existing transients: Modifying Existing Transients.
- (line 6)
-* quit transient: Aborting and Resuming Transients.
- (line 6)
-* resuming transients: Aborting and Resuming Transients.
- (line 6)
-* saving values of arguments: Saving Values. (line 6)
-* scope of a transient: Defining Transients. (line 43)
-* suffix specifications: Suffix Specifications.
- (line 6)
-* transient prefix command: Introduction. (line 13)
-* transient state: Transient State. (line 6)
-* transient-level: Enabling and Disabling Suffixes.
- (line 15)
-* value history: Using History. (line 6)
-
-\1f
-File: transient.info, Node: GNU General Public License, Prev: Concept Index, Up: Top
-
-Appendix F GNU General Public License
-*************************************
-
- Version 3, 29 June 2007
-
- Copyright © 2007 Free Software Foundation, Inc. <https://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 <https://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 <https://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 <https://www.gnu.org/licenses/why-not-lgpl.html>.
-
-
-\1f
-Tag Table:
-Node: Top\7f763
-Node: Introduction\7f4070
-Node: Usage\7f9912
-Node: Invoking Transients\7f10280
-Node: Aborting and Resuming Transients\7f11359
-Node: Common Suffix Commands\7f13970
-Node: Saving Values\7f15806
-Ref: Saving Values-Footnote-1\7f17177
-Node: Using History\7f17370
-Node: Getting Help for Suffix Commands\7f18944
-Node: Enabling and Disabling Suffixes\7f20312
-Node: Other Commands\7f23380
-Node: Configuration\7f24356
-Ref: Essential Options\7f24636
-Ref: Accessibility Options\7f28297
-Ref: Auxiliary Options\7f28620
-Ref: Developer Options\7f33347
-Node: Modifying Existing Transients\7f34595
-Node: Defining New Commands\7f38787
-Node: Defining Transients\7f39123
-Node: Binding Suffix and Infix Commands\7f41559
-Node: Group Specifications\7f42417
-Node: Suffix Specifications\7f46986
-Node: Defining Suffix and Infix Commands\7f51142
-Node: Using Infix Arguments\7f54348
-Node: Transient State\7f57182
-Ref: Pre-commands for Infixes\7f61145
-Ref: Pre-commands for Suffixes\7f61416
-Ref: Pre-commands for Non-Suffixes\7f63837
-Ref: Special Pre-Commands\7f64981
-Node: Classes and Methods\7f65489
-Node: Group Classes\7f67703
-Node: Group Methods\7f69630
-Node: Prefix Classes\7f70883
-Node: Suffix Classes\7f71974
-Node: Suffix Methods\7f74220
-Node: Suffix Value Methods\7f74541
-Node: Suffix Format Methods\7f77299
-Node: Prefix Slots\7f78748
-Ref: Internal Prefix Slots\7f80028
-Node: Suffix Slots\7f81285
-Ref: Slots of transient-suffix\7f81653
-Ref: Slots of transient-infix\7f82507
-Ref: Slots of transient-variable\7f85633
-Ref: Slots of transient-switches\7f85735
-Node: Predicate Slots\7f86098
-Node: Related Abstractions and Packages\7f87363
-Node: Comparison With Prefix Keys and Prefix Arguments\7f87650
-Ref: Regular Prefix Commands\7f88335
-Ref: Regular Prefix Arguments\7f88683
-Ref: Transients\7f89652
-Node: Comparison With Other Packages\7f97923
-Ref: Magit-Popup\7f98154
-Ref: Hydra\7f99061
-Node: FAQ\7f102117
-Ref: Can I control how the popup buffer is displayed?\7f102260
-Ref: How can I copy text from the popup buffer?\7f102441
-Ref: Why did some of the key bindings change?\7f102913
-Ref: Why does q not quit popups anymore?\7f105266
-Node: Keystroke Index\7f106359
-Node: Command and Function Index\7f108077
-Node: Variable Index\7f114449
-Node: Concept Index\7f116722
-Node: GNU General Public License\7f119466
-\1f
-End Tag Table
-
-\1f
-Local Variables:
-coding: utf-8
-End:
--- /dev/null
+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.
+\1f
+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 misc features
+* Transient: (transient). Transient Commands.
--- /dev/null
+This is gpl.info, produced by makeinfo version 6.7 from gpl.texi.
+
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://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 <https://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 <https://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 <https://www.gnu.org/licenses/why-not-lgpl.html>.
+
+\1f
+Tag Table:
+\1f
+End Tag Table
+
+\1f
+Local Variables:
+coding: utf-8
+End:
--- /dev/null
+;;; transient-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
+;; Generated by the `loaddefs-generate' function.
+
+;; This file is part of GNU Emacs.
+
+;;; Code:
+
+(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
+
+
+\f
+;;; Generated autoloads from transient.el
+
+(autoload 'transient-insert-suffix "transient" "\
+Insert a SUFFIX into PREFIX before LOC.
+PREFIX is a prefix command, a symbol.
+SUFFIX is a suffix command or a group specification (of
+ the same forms as expected by `transient-define-prefix').
+LOC is a command, a key vector, a key description (a string
+ as returned by `key-description'), or a coordination list
+ (whose last element may also be a command or key).
+Remove a conflicting binding unless optional KEEP-OTHER is
+ non-nil.
+See info node `(transient)Modifying Existing Transients'.
+
+(fn PREFIX LOC SUFFIX &optional KEEP-OTHER)")
+(function-put 'transient-insert-suffix 'lisp-indent-function 'defun)
+(autoload 'transient-append-suffix "transient" "\
+Insert a SUFFIX into PREFIX after LOC.
+PREFIX is a prefix command, a symbol.
+SUFFIX is a suffix command or a group specification (of
+ the same forms as expected by `transient-define-prefix').
+LOC is a command, a key vector, a key description (a string
+ as returned by `key-description'), or a coordination list
+ (whose last element may also be a command or key).
+Remove a conflicting binding unless optional KEEP-OTHER is
+ non-nil.
+See info node `(transient)Modifying Existing Transients'.
+
+(fn PREFIX LOC SUFFIX &optional KEEP-OTHER)")
+(function-put 'transient-append-suffix 'lisp-indent-function 'defun)
+(autoload 'transient-replace-suffix "transient" "\
+Replace the suffix at LOC in PREFIX with SUFFIX.
+PREFIX is a prefix command, a symbol.
+SUFFIX is a suffix command or a group specification (of
+ the same forms as expected by `transient-define-prefix').
+LOC is a command, a key vector, a key description (a string
+ as returned by `key-description'), or a coordination list
+ (whose last element may also be a command or key).
+See info node `(transient)Modifying Existing Transients'.
+
+(fn PREFIX LOC SUFFIX)")
+(function-put 'transient-replace-suffix 'lisp-indent-function 'defun)
+(autoload 'transient-remove-suffix "transient" "\
+Remove the suffix or group at LOC in PREFIX.
+PREFIX is a prefix command, a symbol.
+LOC is a command, a key vector, a key description (a string
+ as returned by `key-description'), or a coordination list
+ (whose last element may also be a command or key).
+See info node `(transient)Modifying Existing Transients'.
+
+(fn PREFIX LOC)")
+(function-put 'transient-remove-suffix 'lisp-indent-function 'defun)
+(register-definition-prefixes "transient" '("static-if" "transient"))
+\f
+;;; End of scraped data
+
+(provide 'transient-autoloads)
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; no-native-compile: t
+;; coding: utf-8-emacs-unix
+;; End:
+
+;;; transient-autoloads.el ends here
--- /dev/null
+(define-package "transient" "20240421.1737" "Transient commands"
+ '((emacs "26.1")
+ (compat "29.1.4.4")
+ (seq "2.24"))
+ :commit "2dd0102ec3df901d421fc338e5c768467cc54ecf" :authors
+ '(("Jonas Bernoulli" . "emacs.transientNOSPAMjonas.bernoulli.dev"))
+ :maintainers
+ '(("Jonas Bernoulli" . "emacs.transientNOSPAMjonas.bernoulli.dev"))
+ :maintainer
+ '("Jonas Bernoulli" . "emacs.transientNOSPAMjonas.bernoulli.dev")
+ :keywords
+ '("extensions")
+ :url "https://github.com/magit/transient")
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
--- /dev/null
+;;; transient.el --- Transient commands -*- lexical-binding:t -*-
+
+;; Copyright (C) 2018-2024 Free Software Foundation, Inc.
+
+;; Author: Jonas Bernoulli <emacs.transientNOSPAMjonas.bernoulli.dev>
+;; Homepage: https://github.com/magit/transient
+;; Keywords: extensions
+
+;; Package-Version: 0.6.0
+;; Package-Requires: ((emacs "26.1") (compat "29.1.4.4") (seq "2.24"))
+
+;; SPDX-License-Identifier: GPL-3.0-or-later
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+;;
+;; GNU Emacs 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 <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Transient is the library used to implement the keyboard-driven menus
+;; in Magit. It is distributed as a separate package, so that it can be
+;; used to implement similar menus in other packages.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'compat)
+(require 'eieio)
+(require 'edmacro)
+(require 'format-spec)
+
+(eval-and-compile
+ (when (and (featurep' seq)
+ (not (fboundp 'seq-keep)))
+ (unload-feature 'seq 'force)))
+(require 'seq)
+(unless (fboundp 'seq-keep)
+ (display-warning 'transient (substitute-command-keys "\
+Transient requires `seq' >= 2.24,
+but due to bad defaults, Emacs' package manager, refuses to
+upgrade this and other built-in packages to higher releases
+from GNU Elpa, when a package specifies that this is needed.
+
+To fix this, you have to add this to your init file:
+
+ (setq package-install-upgrade-built-in t)
+
+Then evaluate that expression by placing the cursor after it
+and typing \\[eval-last-sexp].
+
+Once you have done that, you have to explicitly upgrade `seq':
+
+ \\[package-upgrade] seq \\`RET'
+
+Then you also must make sure the updated version is loaded,
+by evaluating this form:
+
+ (progn (unload-feature 'seq t) (require 'seq))
+
+Until you do this, you will get random errors about `seq-keep'
+being undefined while using Transient.
+
+If you don't use the `package' package manager but still get
+this warning, then your chosen package manager likely has a
+similar defect.") :emergency))
+
+(eval-when-compile (require 'subr-x))
+
+(declare-function info "info" (&optional file-or-node buffer))
+(declare-function Man-find-section "man" (section))
+(declare-function Man-next-section "man" (n))
+(declare-function Man-getpage-in-background "man" (topic))
+
+(defvar Man-notify-method)
+(defvar pp-default-function) ; since Emacs 29.1
+
+(defmacro static-if (condition then-form &rest else-forms)
+ "A conditional compilation macro.
+Evaluate CONDITION at macro-expansion time. If it is non-nil,
+expand the macro to THEN-FORM. Otherwise expand it to ELSE-FORMS
+enclosed in a `progn' form. ELSE-FORMS may be empty."
+ (declare (indent 2)
+ (debug (sexp sexp &rest sexp)))
+ (if (eval condition lexical-binding)
+ then-form
+ (cons 'progn else-forms)))
+
+(defmacro transient--with-emergency-exit (id &rest body)
+ (declare (indent defun))
+ (unless (keywordp id)
+ (setq body (cons id body))
+ (setq id nil))
+ `(condition-case err
+ (let ((debugger #'transient--exit-and-debug))
+ ,(macroexp-progn body))
+ ((debug error)
+ (transient--emergency-exit ,id)
+ (signal (car err) (cdr err)))))
+
+(defun transient--exit-and-debug (&rest args)
+ (transient--emergency-exit :debugger)
+ (apply #'debug args))
+
+;;; Options
+
+(defgroup transient nil
+ "Transient commands."
+ :group 'extensions)
+
+(defcustom transient-show-popup t
+ "Whether to show the current transient in a popup buffer.
+\\<transient-map>
+- If t, then show the popup as soon as a transient prefix command
+ is invoked.
+
+- If nil, then do not show the popup unless the user explicitly
+ requests it, by pressing \\[transient-show] or a prefix key.
+
+- If a number, then delay displaying the popup and instead show
+ a brief one-line summary. If zero or negative, then suppress
+ even showing that summary and display the pressed key only.
+
+ Show the popup when the user explicitly requests it by pressing
+ \\[transient-show] or a prefix key. Unless zero, then also show the popup
+ after that many seconds of inactivity (using the absolute value)."
+ :package-version '(transient . "0.1.0")
+ :group 'transient
+ :type '(choice (const :tag "instantly" t)
+ (const :tag "on demand" nil)
+ (const :tag "on demand (no summary)" 0)
+ (number :tag "after delay" 1)))
+
+(defcustom transient-enable-popup-navigation t
+ "Whether navigation commands are enabled in the transient popup.
+
+While a transient is active the transient popup buffer is not the
+current buffer, making it necessary to use dedicated commands to
+act on that buffer itself. If this is non-nil, then the following
+bindings are available:
+
+\\<transient-popup-navigation-map>\
+- \\[transient-backward-button] moves the cursor to the previous suffix.
+- \\[transient-forward-button] moves the cursor to the next suffix.
+- \\[transient-push-button] invokes the suffix the cursor is on.
+\\<transient-button-map>\
+- \\`<mouse-1>' and \\`<mouse-2>' invoke the clicked on suffix.
+\\<transient-popup-navigation-map>\
+- \\[transient-isearch-backward]\
+ and \\[transient-isearch-forward] start isearch in the popup buffer.
+
+\\`<mouse-1>' and \\`<mouse-2>' are bound in `transient-push-button'.
+All other bindings are in `transient-popup-navigation-map'.
+
+By default \\`M-RET' is bound to `transient-push-button', instead of
+\\`RET', because if a transient allows the invocation of non-suffixes
+then it is likely that you would want \\`RET' to do what it would do
+if no transient were active."
+ :package-version '(transient . "0.4.0")
+ :group 'transient
+ :type 'boolean)
+
+(defcustom transient-display-buffer-action
+ '(display-buffer-in-side-window
+ (side . bottom)
+ (dedicated . t)
+ (inhibit-same-window . t)
+ (window-parameters (no-other-window . t)))
+ "The action used to display the transient popup buffer.
+
+The transient popup buffer is displayed in a window using
+
+ (display-buffer BUFFER transient-display-buffer-action)
+
+The value of this option has the form (FUNCTION . ALIST),
+where FUNCTION is a function or a list of functions. Each such
+function should accept two arguments: a buffer to display and an
+alist of the same form as ALIST. See info node `(elisp)Choosing
+Window' for details.
+
+The default is:
+
+ (display-buffer-in-side-window
+ (side . bottom)
+ (dedicated . t)
+ (inhibit-same-window . t)
+ (window-parameters (no-other-window . t)))
+
+This displays the window at the bottom of the selected frame.
+Another useful FUNCTION is `display-buffer-below-selected', which
+is what `magit-popup' used by default. For more alternatives see
+info node `(elisp)Display Action Functions' and info node
+`(elisp)Buffer Display Action Alists'.
+
+Note that the buffer that was current before the transient buffer
+is shown should remain the current buffer. Many suffix commands
+act on the thing at point, if appropriate, and if the transient
+buffer became the current buffer, then that would change what is
+at point. To that effect `inhibit-same-window' ensures that the
+selected window is not used to show the transient buffer.
+
+It may be possible to display the window in another frame, but
+whether that works in practice depends on the window-manager.
+If the window manager selects the new window (Emacs frame),
+then that unfortunately changes which buffer is current.
+
+If you change the value of this option, then you might also
+want to change the value of `transient-mode-line-format'."
+ :package-version '(transient . "0.3.0")
+ :group 'transient
+ :type '(cons (choice function (repeat :tag "Functions" function))
+ alist))
+
+(defcustom transient-mode-line-format 'line
+ "The mode-line format for the transient popup buffer.
+
+If nil, then the buffer has no mode-line. If the buffer is not
+displayed right above the echo area, then this probably is not
+a good value.
+
+If `line' (the default) or a natural number, then the buffer
+has no mode-line, but a line is drawn is drawn in its place.
+If a number is used, that specifies the thickness of the line.
+On termcap frames we cannot draw lines, so there `line' and
+numbers are synonyms for nil.
+
+The color of the line is used to indicate if non-suffixes are
+allowed and whether they exit the transient. The foreground
+color of `transient-key-noop' (if non-suffix are disallowed),
+`transient-key-stay' (if allowed and transient stays active), or
+`transient-key-exit' (if allowed and they exit the transient) is
+used to draw the line.
+
+Otherwise this can be any mode-line format.
+See `mode-line-format' for details."
+ :package-version '(transient . "0.2.0")
+ :group 'transient
+ :type '(choice (const :tag "hide mode-line" nil)
+ (const :tag "substitute thin line" line)
+ (number :tag "substitute line with thickness")
+ (const :tag "name of prefix command"
+ ("%e" mode-line-front-space
+ mode-line-buffer-identification))
+ (sexp :tag "custom mode-line format")))
+
+(defcustom transient-show-common-commands nil
+ "Whether to show common transient suffixes in the popup buffer.
+
+These commands are always shown after typing the prefix key
+\"C-x\" when a transient command is active. To toggle the value
+of this variable use \"C-x t\" when a transient is active."
+ :package-version '(transient . "0.1.0")
+ :group 'transient
+ :type 'boolean)
+
+(defcustom transient-read-with-initial-input nil
+ "Whether to use the last history element as initial minibuffer input."
+ :package-version '(transient . "0.2.0")
+ :group 'transient
+ :type 'boolean)
+
+(defcustom transient-highlight-mismatched-keys nil
+ "Whether to highlight keys that do not match their argument.
+
+This only affects infix arguments that represent command-line
+arguments. When this option is non-nil, then the key binding
+for infix argument are highlighted when only a long argument
+\(e.g., \"--verbose\") is specified but no shorthand (e.g., \"-v\").
+In the rare case that a short-hand is specified but does not
+match the key binding, then it is highlighted differently.
+
+The highlighting is done using `transient-mismatched-key'
+and `transient-nonstandard-key'."
+ :package-version '(transient . "0.1.0")
+ :group 'transient
+ :type 'boolean)
+
+(defcustom transient-highlight-higher-levels nil
+ "Whether to highlight suffixes on higher levels.
+
+This is primarily intended for package authors.
+
+When non-nil then highlight the description of suffixes whose
+level is above 4, the default of `transient-default-level'.
+Assuming you have set that variable to 7, this highlights all
+suffixes that won't be available to users without them making
+the same customization."
+ :package-version '(transient . "0.3.6")
+ :group 'transient
+ :type 'boolean)
+
+(defcustom transient-substitute-key-function nil
+ "Function used to modify key bindings.
+
+This function is called with one argument, the prefix object,
+and must return a key binding description, either the existing
+key description it finds in the `key' slot, or a substitution.
+
+This is intended to let users replace certain prefix keys. It
+could also be used to make other substitutions, but that is
+discouraged.
+
+For example, \"=\" is hard to reach using my custom keyboard
+layout, so I substitute \"(\" for that, which is easy to reach
+using a layout optimized for Lisp.
+
+ (setq transient-substitute-key-function
+ (lambda (obj)
+ (let ((key (oref obj key)))
+ (if (string-match \"\\\\`\\\\(=\\\\)[a-zA-Z]\" key)
+ (replace-match \"(\" t t key 1)
+ key)))))"
+ :package-version '(transient . "0.1.0")
+ :group 'transient
+ :type '(choice (const :tag "Transform no keys (nil)" nil) function))
+
+(defcustom transient-semantic-coloring t
+ "Whether to use colors to indicate transient behavior.
+
+If non-nil, then the key binding of each suffix is colorized to
+indicate whether it exits the transient state or not, and the
+line that is drawn below the transient popup buffer is used to
+indicate the behavior of non-suffix commands."
+ :package-version '(transient . "0.5.0")
+ :group 'transient
+ :type 'boolean)
+
+(defcustom transient-detect-key-conflicts nil
+ "Whether to detect key binding conflicts.
+
+Conflicts are detected when a transient prefix command is invoked
+and results in an error, which prevents the transient from being
+used."
+ :package-version '(transient . "0.1.0")
+ :group 'transient
+ :type 'boolean)
+
+(defcustom transient-align-variable-pitch nil
+ "Whether to align columns pixel-wise in the popup buffer.
+
+If this is non-nil, then columns are aligned pixel-wise to
+support variable-pitch fonts. Keys are not aligned, so you
+should use a fixed-pitch font for the `transient-key' face.
+Other key faces inherit from that face unless a theme is
+used that breaks that relationship.
+
+This option is intended for users who use a variable-pitch
+font for the `default' face.
+
+Also see `transient-force-fixed-pitch'."
+ :package-version '(transient . "0.4.0")
+ :group 'transient
+ :type 'boolean)
+
+(defcustom transient-force-fixed-pitch nil
+ "Whether to force use of monospaced font in the popup buffer.
+
+Even if you use a proportional font for the `default' face,
+you might still want to use a monospaced font in transient's
+popup buffer. Setting this option to t causes `default' to
+be remapped to `fixed-pitch' in that buffer.
+
+Also see `transient-align-variable-pitch'."
+ :package-version '(transient . "0.2.0")
+ :group 'transient
+ :type 'boolean)
+
+(defcustom transient-force-single-column nil
+ "Whether to force use of a single column to display suffixes.
+
+This might be useful for users with low vision who use large
+text and might otherwise have to scroll in two dimensions."
+ :package-version '(transient . "0.3.6")
+ :group 'transient
+ :type 'boolean)
+
+(defcustom transient-hide-during-minibuffer-read nil
+ "Whether to hide the transient buffer while reading in the minibuffer."
+ :package-version '(transient . "0.4.0")
+ :group 'transient
+ :type 'boolean)
+
+(defconst transient--max-level 7)
+(defconst transient--default-child-level 1)
+(defconst transient--default-prefix-level 4)
+
+(defcustom transient-default-level transient--default-prefix-level
+ "Control what suffix levels are made available by default.
+
+Each suffix command is placed on a level and each prefix command
+has a level, which controls which suffix commands are available.
+Integers between 1 and 7 (inclusive) are valid levels.
+
+The levels of individual transients and/or their individual
+suffixes can be changed individually, by invoking the prefix and
+then pressing \"C-x l\".
+
+The default level for both transients and their suffixes is 4.
+This option only controls the default for transients. The default
+suffix level is always 4. The author of a transient should place
+certain suffixes on a higher level if they expect that it won't be
+of use to most users, and they should place very important suffixes
+on a lower level so that they remain available even if the user
+lowers the transient level.
+
+\(Magit currently places nearly all suffixes on level 4 and lower
+levels are not used at all yet. So for the time being you should
+not set a lower level here and using a higher level might not
+give you as many additional suffixes as you hoped.)"
+ :package-version '(transient . "0.1.0")
+ :group 'transient
+ :type '(choice (const :tag "1 - fewest suffixes" 1)
+ (const 2)
+ (const 3)
+ (const :tag "4 - default" 4)
+ (const 5)
+ (const 6)
+ (const :tag "7 - most suffixes" 7)))
+
+(defcustom transient-levels-file
+ (locate-user-emacs-file "transient/levels.el")
+ "File used to save levels of transients and their suffixes."
+ :package-version '(transient . "0.1.0")
+ :group 'transient
+ :type 'file)
+
+(defcustom transient-values-file
+ (locate-user-emacs-file "transient/values.el")
+ "File used to save values of transients."
+ :package-version '(transient . "0.1.0")
+ :group 'transient
+ :type 'file)
+
+(defcustom transient-history-file
+ (locate-user-emacs-file "transient/history.el")
+ "File used to save history of transients and their infixes."
+ :package-version '(transient . "0.1.0")
+ :group 'transient
+ :type 'file)
+
+(defcustom transient-history-limit 10
+ "Number of history elements to keep when saving to file."
+ :package-version '(transient . "0.1.0")
+ :group 'transient
+ :type 'integer)
+
+(defcustom transient-save-history t
+ "Whether to save history of transient commands when exiting Emacs."
+ :package-version '(transient . "0.1.0")
+ :group 'transient
+ :type 'boolean)
+
+;;; Faces
+
+(defgroup transient-faces nil
+ "Faces used by Transient."
+ :group 'transient)
+
+(defface transient-heading '((t :inherit font-lock-keyword-face))
+ "Face used for headings."
+ :group 'transient-faces)
+
+(defface transient-argument '((t :inherit font-lock-string-face :weight bold))
+ "Face used for enabled arguments."
+ :group 'transient-faces)
+
+(defface transient-inactive-argument '((t :inherit shadow))
+ "Face used for inactive arguments."
+ :group 'transient-faces)
+
+(defface transient-value '((t :inherit font-lock-string-face :weight bold))
+ "Face used for values."
+ :group 'transient-faces)
+
+(defface transient-inactive-value '((t :inherit shadow))
+ "Face used for inactive values."
+ :group 'transient-faces)
+
+(defface transient-unreachable '((t :inherit shadow))
+ "Face used for suffixes unreachable from the current prefix sequence."
+ :group 'transient-faces)
+
+(defface transient-inapt-suffix '((t :inherit shadow :italic t))
+ "Face used for suffixes that are inapt at this time."
+ :group 'transient-faces)
+
+(defface transient-active-infix '((t :inherit highlight))
+ "Face used for the infix for which the value is being read."
+ :group 'transient-faces)
+
+(defface transient-enabled-suffix
+ '((t :background "green" :foreground "black" :weight bold))
+ "Face used for enabled levels while editing suffix levels.
+See info node `(transient)Enabling and Disabling Suffixes'."
+ :group 'transient-faces)
+
+(defface transient-disabled-suffix
+ '((t :background "red" :foreground "black" :weight bold))
+ "Face used for disabled levels while editing suffix levels.
+See info node `(transient)Enabling and Disabling Suffixes'."
+ :group 'transient-faces)
+
+(defface transient-higher-level
+ `((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1)
+ :color ,(let ((color (face-attribute 'shadow :foreground nil t)))
+ (or (and (not (eq color 'unspecified)) color)
+ "grey60")))))
+ "Face optionally used to highlight suffixes on higher levels.
+Also see option `transient-highlight-higher-levels'."
+ :group 'transient-faces)
+
+(defface transient-delimiter '((t :inherit shadow))
+ "Face used for delimiters and separators.
+This includes the parentheses around values and the pipe
+character used to separate possible values from each other."
+ :group 'transient-faces)
+
+(defface transient-key '((t :inherit font-lock-builtin-face))
+ "Face used for keys."
+ :group 'transient-faces)
+
+(defface transient-key-stay
+ `((((class color) (background light))
+ :inherit transient-key
+ :foreground "#22aa22")
+ (((class color) (background dark))
+ :inherit transient-key
+ :foreground "#ddffdd"))
+ "Face used for keys of suffixes that don't exit transient state."
+ :group 'transient-faces)
+
+(defface transient-key-noop
+ `((((class color) (background light))
+ :inherit transient-key
+ :foreground "grey80")
+ (((class color) (background dark))
+ :inherit transient-key
+ :foreground "grey30"))
+ "Face used for keys of suffixes that currently cannot be invoked."
+ :group 'transient-faces)
+
+(defface transient-key-return
+ `((((class color) (background light))
+ :inherit transient-key
+ :foreground "#aaaa11")
+ (((class color) (background dark))
+ :inherit transient-key
+ :foreground "#ffffcc"))
+ "Face used for keys of suffixes that return to the parent transient."
+ :group 'transient-faces)
+
+(defface transient-key-exit
+ `((((class color) (background light))
+ :inherit transient-key
+ :foreground "#aa2222")
+ (((class color) (background dark))
+ :inherit transient-key
+ :foreground "#ffdddd"))
+ "Face used for keys of suffixes that exit transient state."
+ :group 'transient-faces)
+
+(defface transient-unreachable-key
+ '((t :inherit (shadow transient-key) :weight normal))
+ "Face used for keys unreachable from the current prefix sequence."
+ :group 'transient-faces)
+
+(defface transient-nonstandard-key
+ `((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1)
+ :color "cyan")))
+ "Face optionally used to highlight keys conflicting with short-argument.
+Also see option `transient-highlight-mismatched-keys'."
+ :group 'transient-faces)
+
+(defface transient-mismatched-key
+ `((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1)
+ :color "magenta")))
+ "Face optionally used to highlight keys without a short-argument.
+Also see option `transient-highlight-mismatched-keys'."
+ :group 'transient-faces)
+
+;;; Persistence
+
+(defun transient--read-file-contents (file)
+ (with-demoted-errors "Transient error: %S"
+ (and (file-exists-p file)
+ (with-temp-buffer
+ (insert-file-contents file)
+ (read (current-buffer))))))
+
+(defun transient--pp-to-file (list file)
+ (make-directory (file-name-directory file) t)
+ (setq list (cl-sort (copy-sequence list) #'string< :key #'car))
+ (with-temp-file file
+ (let ((print-level nil)
+ (print-length nil)
+ (pp-default-function 'pp-28)
+ (fill-column 999))
+ (pp list (current-buffer)))))
+
+(defvar transient-values
+ (transient--read-file-contents transient-values-file)
+ "Values of transient commands.
+The value of this variable persists between Emacs sessions
+and you usually should not change it manually.")
+
+(defun transient-save-values ()
+ (transient--pp-to-file transient-values transient-values-file))
+
+(defvar transient-levels
+ (transient--read-file-contents transient-levels-file)
+ "Levels of transient commands.
+The value of this variable persists between Emacs sessions
+and you usually should not change it manually.")
+
+(defun transient-save-levels ()
+ (transient--pp-to-file transient-levels transient-levels-file))
+
+(defvar transient-history
+ (transient--read-file-contents transient-history-file)
+ "History of transient commands and infix arguments.
+The value of this variable persists between Emacs sessions
+\(unless `transient-save-history' is nil) and you usually
+should not change it manually.")
+
+(defun transient-save-history ()
+ (setq transient-history
+ (cl-sort (mapcar (pcase-lambda (`(,key . ,val))
+ (cons key (seq-take (delete-dups val)
+ transient-history-limit)))
+ transient-history)
+ #'string< :key #'car))
+ (transient--pp-to-file transient-history transient-history-file))
+
+(defun transient-maybe-save-history ()
+ "Save the value of `transient-history'.
+If `transient-save-history' is nil, then do nothing."
+ (when transient-save-history
+ (transient-save-history)))
+
+(unless noninteractive
+ (add-hook 'kill-emacs-hook #'transient-maybe-save-history))
+
+;;; Classes
+;;;; Prefix
+
+(defclass transient-prefix ()
+ ((prototype :initarg :prototype)
+ (command :initarg :command)
+ (level :initarg :level)
+ (variable :initarg :variable :initform nil)
+ (init-value :initarg :init-value)
+ (value) (default-value :initarg :value)
+ (scope :initarg :scope :initform nil)
+ (history :initarg :history :initform nil)
+ (history-pos :initarg :history-pos :initform 0)
+ (history-key :initarg :history-key :initform nil)
+ (show-help :initarg :show-help :initform nil)
+ (info-manual :initarg :info-manual :initform nil)
+ (man-page :initarg :man-page :initform nil)
+ (transient-suffix :initarg :transient-suffix :initform nil)
+ (transient-non-suffix :initarg :transient-non-suffix :initform nil)
+ (transient-switch-frame :initarg :transient-switch-frame)
+ (refresh-suffixes :initarg :refresh-suffixes :initform nil)
+ (incompatible :initarg :incompatible :initform nil)
+ (suffix-description :initarg :suffix-description)
+ (variable-pitch :initarg :variable-pitch :initform nil)
+ (column-widths :initarg :column-widths :initform nil)
+ (unwind-suffix :documentation "Internal use." :initform nil))
+ "Transient prefix command.
+
+Each transient prefix command consists of a command, which is
+stored in a symbol's function slot and an object, which is
+stored in the `transient--prefix' property of the same symbol.
+
+When a transient prefix command is invoked, then a clone of that
+object is stored in the global variable `transient--prefix' and
+the prototype is stored in the clone's `prototype' slot.")
+
+;;;; Suffix
+
+(defclass transient-child ()
+ ((level
+ :initarg :level
+ :initform (symbol-value 'transient--default-child-level)
+ :documentation "Enable if level of prefix is equal or greater.")
+ (if
+ :initarg :if
+ :initform nil
+ :documentation "Enable if predicate returns non-nil.")
+ (if-not
+ :initarg :if-not
+ :initform nil
+ :documentation "Enable if predicate returns nil.")
+ (if-non-nil
+ :initarg :if-non-nil
+ :initform nil
+ :documentation "Enable if variable's value is non-nil.")
+ (if-nil
+ :initarg :if-nil
+ :initform nil
+ :documentation "Enable if variable's value is nil.")
+ (if-mode
+ :initarg :if-mode
+ :initform nil
+ :documentation "Enable if major-mode matches value.")
+ (if-not-mode
+ :initarg :if-not-mode
+ :initform nil
+ :documentation "Enable if major-mode does not match value.")
+ (if-derived
+ :initarg :if-derived
+ :initform nil
+ :documentation "Enable if major-mode derives from value.")
+ (if-not-derived
+ :initarg :if-not-derived
+ :initform nil
+ :documentation "Enable if major-mode does not derive from value."))
+ "Abstract superclass for group and suffix classes.
+
+It is undefined what happens if more than one `if*' predicate
+slot is non-nil."
+ :abstract t)
+
+(defclass transient-suffix (transient-child)
+ ((definition :allocation :class :initform nil)
+ (key :initarg :key)
+ (command :initarg :command)
+ (transient :initarg :transient)
+ (format :initarg :format :initform " %k %d")
+ (description :initarg :description :initform nil)
+ (face :initarg :face :initform nil)
+ (show-help :initarg :show-help :initform nil)
+ (inapt-face :initarg :inapt-face :initform 'transient-inapt-suffix)
+ (inapt :initform nil)
+ (inapt-if
+ :initarg :inapt-if
+ :initform nil
+ :documentation "Inapt if predicate returns non-nil.")
+ (inapt-if-not
+ :initarg :inapt-if-not
+ :initform nil
+ :documentation "Inapt if predicate returns nil.")
+ (inapt-if-non-nil
+ :initarg :inapt-if-non-nil
+ :initform nil
+ :documentation "Inapt if variable's value is non-nil.")
+ (inapt-if-nil
+ :initarg :inapt-if-nil
+ :initform nil
+ :documentation "Inapt if variable's value is nil.")
+ (inapt-if-mode
+ :initarg :inapt-if-mode
+ :initform nil
+ :documentation "Inapt if major-mode matches value.")
+ (inapt-if-not-mode
+ :initarg :inapt-if-not-mode
+ :initform nil
+ :documentation "Inapt if major-mode does not match value.")
+ (inapt-if-derived
+ :initarg :inapt-if-derived
+ :initform nil
+ :documentation "Inapt if major-mode derives from value.")
+ (inapt-if-not-derived
+ :initarg :inapt-if-not-derived
+ :initform nil
+ :documentation "Inapt if major-mode does not derive from value."))
+ "Superclass for suffix command.")
+
+(defclass transient-information (transient-suffix)
+ ((format :initform " %k %d")
+ (key :initform " "))
+ "Display-only information, aligned with suffix keys.
+Technically a suffix object with no associated command.")
+
+(defclass transient-information* (transient-information)
+ ((format :initform " %d"))
+ "Display-only information, aligned with suffix descriptions.
+Technically a suffix object with no associated command.")
+
+(defclass transient-infix (transient-suffix)
+ ((transient :initform t)
+ (argument :initarg :argument)
+ (shortarg :initarg :shortarg)
+ (value :initform nil)
+ (init-value :initarg :init-value)
+ (unsavable :initarg :unsavable :initform nil)
+ (multi-value :initarg :multi-value :initform nil)
+ (always-read :initarg :always-read :initform nil)
+ (allow-empty :initarg :allow-empty :initform nil)
+ (history-key :initarg :history-key :initform nil)
+ (reader :initarg :reader :initform nil)
+ (prompt :initarg :prompt :initform nil)
+ (choices :initarg :choices :initform nil)
+ (format :initform " %k %d (%v)"))
+ "Transient infix command."
+ :abstract t)
+
+(defclass transient-argument (transient-infix) ()
+ "Abstract superclass for infix arguments."
+ :abstract t)
+
+(defclass transient-switch (transient-argument) ()
+ "Class used for command-line argument that can be turned on and off.")
+
+(defclass transient-option (transient-argument) ()
+ "Class used for command-line argument that can take a value.")
+
+(defclass transient-variable (transient-infix)
+ ((variable :initarg :variable)
+ (format :initform " %k %d %v"))
+ "Abstract superclass for infix commands that set a variable."
+ :abstract t)
+
+(defclass transient-switches (transient-argument)
+ ((argument-format :initarg :argument-format)
+ (argument-regexp :initarg :argument-regexp))
+ "Class used for sets of mutually exclusive command-line switches.")
+
+(defclass transient-files (transient-option) ()
+ ((key :initform "--")
+ (argument :initform "--")
+ (multi-value :initform rest)
+ (reader :initform transient-read-files))
+ "Class used for the \"--\" argument or similar.
+All remaining arguments are treated as files.
+They become the value of this argument.")
+
+;;;; Group
+
+(defclass transient-group (transient-child)
+ ((suffixes :initarg :suffixes :initform nil)
+ (hide :initarg :hide :initform nil)
+ (description :initarg :description :initform nil)
+ (pad-keys :initarg :pad-keys :initform nil)
+ (info-format :initarg :info-format :initform nil)
+ (setup-children :initarg :setup-children))
+ "Abstract superclass of all group classes."
+ :abstract t)
+
+(defclass transient-column (transient-group) ()
+ "Group class that displays each element on a separate line.")
+
+(defclass transient-row (transient-group) ()
+ "Group class that displays all elements on a single line.")
+
+(defclass transient-columns (transient-group) ()
+ "Group class that displays elements organized in columns.
+Direct elements have to be groups whose elements have to be
+commands or strings. Each subgroup represents a column.
+This class takes care of inserting the subgroups' elements.")
+
+(defclass transient-subgroups (transient-group) ()
+ "Group class that wraps other groups.
+
+Direct elements have to be groups whose elements have to be
+commands or strings. This group inserts an empty line between
+subgroups. The subgroups are responsible for displaying their
+elements themselves.")
+
+;;; Define
+
+(defmacro transient-define-prefix (name arglist &rest args)
+ "Define NAME as a transient prefix command.
+
+ARGLIST are the arguments that command takes.
+DOCSTRING is the documentation string and is optional.
+
+These arguments can optionally be followed by key-value pairs.
+Each key has to be a keyword symbol, either `:class' or a keyword
+argument supported by the constructor of that class. The
+`transient-prefix' class is used if the class is not specified
+explicitly.
+
+GROUPs add key bindings for infix and suffix commands and specify
+how these bindings are presented in the popup buffer. At least
+one GROUP has to be specified. See info node `(transient)Binding
+Suffix and Infix Commands'.
+
+The BODY is optional. If it is omitted, then ARGLIST is also
+ignored and the function definition becomes:
+
+ (lambda ()
+ (interactive)
+ (transient-setup \\='NAME))
+
+If BODY is specified, then it must begin with an `interactive'
+form that matches ARGLIST, and it must call `transient-setup'.
+It may however call that function only when some condition is
+satisfied; that is one of the reason why you might want to use
+an explicit BODY.
+
+All transients have a (possibly nil) value, which is exported
+when suffix commands are called, so that they can consume that
+value. For some transients it might be necessary to have a sort
+of secondary value, called a scope. Such a scope would usually
+be set in the commands `interactive' form and has to be passed
+to the setup function:
+
+ (transient-setup \\='NAME nil nil :scope SCOPE)
+
+\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]... GROUP... [BODY...])"
+ (declare (debug ( &define name lambda-list
+ [&optional lambda-doc]
+ [&rest keywordp sexp]
+ [&rest vectorp]
+ [&optional ("interactive" interactive) def-body]))
+ (indent defun)
+ (doc-string 3))
+ (pcase-let ((`(,class ,slots ,suffixes ,docstr ,body ,interactive-only)
+ (transient--expand-define-args args arglist)))
+ `(progn
+ (defalias ',name
+ ,(if body
+ `(lambda ,arglist ,@body)
+ `(lambda ()
+ (interactive)
+ (transient-setup ',name))))
+ (put ',name 'interactive-only ,interactive-only)
+ (put ',name 'function-documentation ,docstr)
+ (put ',name 'transient--prefix
+ (,(or class 'transient-prefix) :command ',name ,@slots))
+ (put ',name 'transient--layout
+ (list ,@(cl-mapcan (lambda (s) (transient--parse-child name s))
+ suffixes))))))
+
+(defmacro transient-define-suffix (name arglist &rest args)
+ "Define NAME as a transient suffix command.
+
+ARGLIST are the arguments that the command takes.
+DOCSTRING is the documentation string and is optional.
+
+These arguments can optionally be followed by key-value pairs.
+Each key has to be a keyword symbol, either `:class' or a
+keyword argument supported by the constructor of that class.
+The `transient-suffix' class is used if the class is not
+specified explicitly.
+
+The BODY must begin with an `interactive' form that matches
+ARGLIST. The infix arguments are usually accessed by using
+`transient-args' inside `interactive'.
+
+\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]... [BODY...])"
+ (declare (debug ( &define name lambda-list
+ [&optional lambda-doc]
+ [&rest keywordp sexp]
+ [&optional ("interactive" interactive) def-body]))
+ (indent defun)
+ (doc-string 3))
+ (pcase-let ((`(,class ,slots ,_ ,docstr ,body ,interactive-only)
+ (transient--expand-define-args args arglist)))
+ `(progn
+ (defalias ',name
+ ,(if (and (not body) class (oref-default class definition))
+ `(oref-default ',class definition)
+ `(lambda ,arglist ,@body)))
+ (put ',name 'interactive-only ,interactive-only)
+ (put ',name 'function-documentation ,docstr)
+ (put ',name 'transient--suffix
+ (,(or class 'transient-suffix) :command ',name ,@slots)))))
+
+(defmacro transient-define-infix (name arglist &rest args)
+ "Define NAME as a transient infix command.
+
+ARGLIST is always ignored and reserved for future use.
+DOCSTRING is the documentation string and is optional.
+
+At least one key-value pair is required. All transient infix
+commands are equal to each other (but not eq). It is meaning-
+less to define an infix command, without providing at least one
+keyword argument (usually `:argument' or `:variable', depending
+on the class). The suffix class defaults to `transient-switch'
+and can be set using the `:class' keyword.
+
+The function definitions is always:
+
+ (lambda ()
+ (interactive)
+ (let ((obj (transient-suffix-object)))
+ (transient-infix-set obj (transient-infix-read obj)))
+ (transient--show))
+
+`transient-infix-read' and `transient-infix-set' are generic
+functions. Different infix commands behave differently because
+the concrete methods are different for different infix command
+classes. In rare case the above command function might not be
+suitable, even if you define your own infix command class. In
+that case you have to use `transient-define-suffix' to define
+the infix command and use t as the value of the `:transient'
+keyword.
+
+\(fn NAME ARGLIST [DOCSTRING] KEYWORD VALUE [KEYWORD VALUE]...)"
+ (declare (debug ( &define name lambda-list
+ [&optional lambda-doc]
+ keywordp sexp
+ [&rest keywordp sexp]))
+ (indent defun)
+ (doc-string 3))
+ (pcase-let ((`(,class ,slots ,_ ,docstr ,_ ,interactive-only)
+ (transient--expand-define-args args arglist t)))
+ `(progn
+ (defalias ',name #'transient--default-infix-command)
+ (put ',name 'interactive-only ,interactive-only)
+ (put ',name 'completion-predicate #'transient--suffix-only)
+ (put ',name 'function-documentation ,docstr)
+ (put ',name 'transient--suffix
+ (,(or class 'transient-switch) :command ',name ,@slots)))))
+
+(defalias 'transient-define-argument #'transient-define-infix
+ "Define NAME as a transient infix command.
+
+Only use this alias to define an infix command that actually
+sets an infix argument. To define a infix command that, for
+example, sets a variable, use `transient-define-infix' instead.
+
+\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]...)")
+
+(defun transient--default-infix-command ()
+ ;; Most infix commands are but an alias for this command.
+ "Cannot show any documentation for this transient infix command.
+
+When you request help for an infix command using `transient-help', that
+usually shows the respective man-page and tries to jump to the location
+where the respective argument is being described.
+
+If no man-page is specified for the containing transient menu, then the
+docstring is displayed instead, if any.
+
+If the infix command doesn't have a docstring, as is the case here, then
+this docstring is displayed instead, because technically infix commands
+are aliases for `transient--default-infix-command'.
+
+`describe-function' also shows the docstring of the infix command,
+falling back to that of the same aliased command."
+ (interactive)
+ (let ((obj (transient-suffix-object)))
+ (transient-infix-set obj (transient-infix-read obj)))
+ (transient--show))
+(put 'transient--default-infix-command 'interactive-only t)
+(put 'transient--default-infix-command 'completion-predicate
+ #'transient--suffix-only)
+
+(defun transient--find-function-advised-original (fn func)
+ "Return nil instead of `transient--default-infix-command'.
+When using `find-function' to jump to the definition of a transient
+infix command/argument, then we want to actually jump to that, not to
+the definition of `transient--default-infix-command', which all infix
+commands are aliases for."
+ (let ((val (funcall fn func)))
+ (and val (not (eq val 'transient--default-infix-command)) val)))
+(advice-add 'find-function-advised-original :around
+ #'transient--find-function-advised-original)
+
+(eval-and-compile
+ (defun transient--expand-define-args (args &optional arglist nobody)
+ (unless (listp arglist)
+ (error "Mandatory ARGLIST is missing"))
+ (let (class keys suffixes docstr declare (interactive-only t))
+ (when (stringp (car args))
+ (setq docstr (pop args)))
+ (while (keywordp (car args))
+ (let ((k (pop args))
+ (v (pop args)))
+ (if (eq k :class)
+ (setq class v)
+ (push k keys)
+ (push v keys))))
+ (while (let ((arg (car args)))
+ (or (vectorp arg)
+ (and arg (symbolp arg))))
+ (push (pop args) suffixes))
+ (when (eq (car-safe (car args)) 'declare)
+ (setq declare (car args))
+ (setq args (cdr args))
+ (when-let ((int (assq 'interactive-only declare)))
+ (setq interactive-only (cadr int))
+ (delq int declare))
+ (unless (cdr declare)
+ (setq declare nil)))
+ (cond
+ ((not args))
+ (nobody
+ (error "transient-define-infix: No function body allowed"))
+ ((not (eq (car-safe (nth (if declare 1 0) args)) 'interactive))
+ (error "transient-define-*: Interactive form missing")))
+ (list (if (eq (car-safe class) 'quote)
+ (cadr class)
+ class)
+ (nreverse keys)
+ (nreverse suffixes)
+ docstr
+ (if declare (cons declare args) args)
+ interactive-only))))
+
+(defun transient--parse-child (prefix spec)
+ (cl-typecase spec
+ (null (error "Invalid transient--parse-child spec: %s" spec))
+ (symbol (let ((value (symbol-value spec)))
+ (if (and (listp value)
+ (or (listp (car value))
+ (vectorp (car value))))
+ (cl-mapcan (lambda (s) (transient--parse-child prefix s)) value)
+ (transient--parse-child prefix value))))
+ (vector (and-let* ((c (transient--parse-group prefix spec))) (list c)))
+ (list (and-let* ((c (transient--parse-suffix prefix spec))) (list c)))
+ (string (list spec))
+ (t (error "Invalid transient--parse-child spec: %s" spec))))
+
+(defun transient--parse-group (prefix spec)
+ (setq spec (append spec nil))
+ (cl-symbol-macrolet
+ ((car (car spec))
+ (pop (pop spec)))
+ (let (level class args)
+ (when (integerp car)
+ (setq level pop))
+ (when (stringp car)
+ (setq args (plist-put args :description pop)))
+ (while (keywordp car)
+ (let ((key pop)
+ (val pop))
+ (cond ((eq key :class)
+ (setq class (macroexp-quote val)))
+ ((or (symbolp val)
+ (and (listp val) (not (eq (car val) 'lambda))))
+ (setq args (plist-put args key (macroexp-quote val))))
+ ((setq args (plist-put args key val))))))
+ (unless (or spec class (not (plist-get args :setup-children)))
+ (message "WARNING: %s: When %s is used, %s must also be specified"
+ 'transient-define-prefix :setup-children :class))
+ (list 'vector
+ (or level transient--default-child-level)
+ (cond (class)
+ ((or (vectorp car)
+ (and car (symbolp car)))
+ (quote 'transient-columns))
+ ((quote 'transient-column)))
+ (and args (cons 'list args))
+ (cons 'list
+ (cl-mapcan (lambda (s) (transient--parse-child prefix s))
+ spec))))))
+
+(defun transient--parse-suffix (prefix spec)
+ (let (level class args)
+ (cl-symbol-macrolet
+ ((car (car spec))
+ (pop (pop spec)))
+ (when (integerp car)
+ (setq level pop))
+ (when (or (stringp car)
+ (vectorp car))
+ (setq args (plist-put args :key pop)))
+ (cond
+ ((or (stringp car)
+ (and (eq (car-safe car) 'lambda)
+ (not (commandp car))))
+ (setq args (plist-put args :description pop)))
+ ((and (symbolp car)
+ (not (keywordp car))
+ (not (commandp car))
+ (commandp (cadr spec)))
+ (setq args (plist-put args :description (macroexp-quote pop)))))
+ (cond
+ ((memq car '(:info :info*)))
+ ((keywordp car)
+ (error "Need command, `:info' or `:info*', got `%s'" car))
+ ((symbolp car)
+ (setq args (plist-put args :command (macroexp-quote pop))))
+ ((and (commandp car)
+ (not (stringp car)))
+ (let ((cmd pop)
+ (sym (intern
+ (format "transient:%s:%s"
+ prefix
+ (let ((desc (plist-get args :description)))
+ (if (and (stringp desc)
+ (length< desc 16))
+ desc
+ (plist-get args :key)))))))
+ (setq args (plist-put
+ args :command
+ `(prog1 ',sym
+ (put ',sym 'interactive-only t)
+ (put ',sym 'completion-predicate #'transient--suffix-only)
+ (defalias ',sym
+ ,(if (eq (car-safe cmd) 'lambda)
+ cmd
+ (macroexp-quote cmd))))))))
+ ((or (stringp car)
+ (and car (listp car)))
+ (let ((arg pop)
+ (sym nil))
+ (cl-typecase arg
+ (list
+ (setq args (plist-put args :shortarg (car arg)))
+ (setq args (plist-put args :argument (cadr arg)))
+ (setq arg (cadr arg)))
+ (string
+ (when-let ((shortarg (transient--derive-shortarg arg)))
+ (setq args (plist-put args :shortarg shortarg)))
+ (setq args (plist-put args :argument arg))))
+ (setq sym (intern (format "transient:%s:%s" prefix arg)))
+ (setq args (plist-put
+ args :command
+ `(prog1 ',sym
+ (put ',sym 'interactive-only t)
+ (put ',sym 'completion-predicate #'transient--suffix-only)
+ (defalias ',sym #'transient--default-infix-command))))
+ (cond ((and car (not (keywordp car)))
+ (setq class 'transient-option)
+ (setq args (plist-put args :reader (macroexp-quote pop))))
+ ((not (string-suffix-p "=" arg))
+ (setq class 'transient-switch))
+ (t
+ (setq class 'transient-option)))))
+ (t
+ (error "Needed command or argument, got %S" car)))
+ (while (keywordp car)
+ (let ((key pop)
+ (val pop))
+ (cond ((eq key :class) (setq class val))
+ ((eq key :level) (setq level val))
+ ((eq key :info)
+ (setq class 'transient-information)
+ (setq args (plist-put args :description val)))
+ ((eq key :info*)
+ (setq class 'transient-information*)
+ (setq args (plist-put args :description val)))
+ ((eq (car-safe val) '\,)
+ (setq args (plist-put args key (cadr val))))
+ ((or (symbolp val)
+ (and (listp val) (not (eq (car val) 'lambda))))
+ (setq args (plist-put args key (macroexp-quote val))))
+ ((setq args (plist-put args key val)))))))
+ (unless (plist-get args :key)
+ (when-let ((shortarg (plist-get args :shortarg)))
+ (setq args (plist-put args :key shortarg))))
+ (list 'list
+ (or level transient--default-child-level)
+ (macroexp-quote (or class 'transient-suffix))
+ (cons 'list args))))
+
+(defun transient--derive-shortarg (arg)
+ (save-match-data
+ (and (string-match "\\`\\(-[a-zA-Z]\\)\\(\\'\\|=\\)" arg)
+ (match-string 1 arg))))
+
+(defun transient-command-completion-not-suffix-only-p (symbol _buffer)
+ "Say whether SYMBOL should be offered as a completion.
+If the value of SYMBOL's `completion-predicate' property is
+`transient--suffix-only', then return nil, otherwise return t.
+This is the case when a command should only ever be used as a
+suffix of a transient prefix command (as opposed to bindings
+in regular keymaps or by using `execute-extended-command')."
+ (not (eq (get symbol 'completion-predicate) 'transient--suffix-only)))
+
+(defalias 'transient--suffix-only #'ignore
+ "Ignore ARGUMENTS, do nothing, and return nil.
+Also see `transient-command-completion-not-suffix-only-p'.
+Only use this alias as the value of the `completion-predicate'
+symbol property.")
+
+(when (and (boundp 'read-extended-command-predicate) ; since Emacs 28.1
+ (not read-extended-command-predicate))
+ (setq read-extended-command-predicate
+ 'transient-command-completion-not-suffix-only-p))
+
+(defun transient-parse-suffix (prefix suffix)
+ "Parse SUFFIX, to be added to PREFIX.
+PREFIX is a prefix command, a symbol.
+SUFFIX is a suffix command or a group specification (of
+ the same forms as expected by `transient-define-prefix').
+Intended for use in a group's `:setup-children' function."
+ (cl-assert (and prefix (symbolp prefix)))
+ (eval (car (transient--parse-child prefix suffix))))
+
+(defun transient-parse-suffixes (prefix suffixes)
+ "Parse SUFFIXES, to be added to PREFIX.
+PREFIX is a prefix command, a symbol.
+SUFFIXES is a list of suffix command or a group specification
+ (of the same forms as expected by `transient-define-prefix').
+Intended for use in a group's `:setup-children' function."
+ (cl-assert (and prefix (symbolp prefix)))
+ (mapcar (apply-partially #'transient-parse-suffix prefix) suffixes))
+
+;;; Edit
+
+(defun transient--insert-suffix (prefix loc suffix action &optional keep-other)
+ (let* ((suf (cl-etypecase suffix
+ (vector (transient--parse-group prefix suffix))
+ (list (transient--parse-suffix prefix suffix))
+ (string suffix)))
+ (mem (transient--layout-member loc prefix))
+ (elt (car mem)))
+ (setq suf (eval suf))
+ (cond
+ ((not mem)
+ (message "Cannot insert %S into %s; %s not found"
+ suffix prefix loc))
+ ((or (and (vectorp suffix) (not (vectorp elt)))
+ (and (listp suffix) (vectorp elt))
+ (and (stringp suffix) (vectorp elt)))
+ (message "Cannot place %S into %s at %s; %s"
+ suffix prefix loc
+ "suffixes and groups cannot be siblings"))
+ (t
+ (when-let* ((bindingp (listp suf))
+ (key (transient--spec-key suf))
+ (conflict (car (transient--layout-member key prefix)))
+ (conflictp
+ (and (not (and (eq action 'replace)
+ (eq conflict elt)))
+ (or (not keep-other)
+ (eq (plist-get (nth 2 suf) :command)
+ (plist-get (nth 2 conflict) :command)))
+ (equal (transient--suffix-predicate suf)
+ (transient--suffix-predicate conflict)))))
+ (transient-remove-suffix prefix key))
+ (pcase-exhaustive action
+ ('insert (setcdr mem (cons elt (cdr mem)))
+ (setcar mem suf))
+ ('append (setcdr mem (cons suf (cdr mem))))
+ ('replace (setcar mem suf)))))))
+
+;;;###autoload
+(defun transient-insert-suffix (prefix loc suffix &optional keep-other)
+ "Insert a SUFFIX into PREFIX before LOC.
+PREFIX is a prefix command, a symbol.
+SUFFIX is a suffix command or a group specification (of
+ the same forms as expected by `transient-define-prefix').
+LOC is a command, a key vector, a key description (a string
+ as returned by `key-description'), or a coordination list
+ (whose last element may also be a command or key).
+Remove a conflicting binding unless optional KEEP-OTHER is
+ non-nil.
+See info node `(transient)Modifying Existing Transients'."
+ (declare (indent defun))
+ (transient--insert-suffix prefix loc suffix 'insert keep-other))
+
+;;;###autoload
+(defun transient-append-suffix (prefix loc suffix &optional keep-other)
+ "Insert a SUFFIX into PREFIX after LOC.
+PREFIX is a prefix command, a symbol.
+SUFFIX is a suffix command or a group specification (of
+ the same forms as expected by `transient-define-prefix').
+LOC is a command, a key vector, a key description (a string
+ as returned by `key-description'), or a coordination list
+ (whose last element may also be a command or key).
+Remove a conflicting binding unless optional KEEP-OTHER is
+ non-nil.
+See info node `(transient)Modifying Existing Transients'."
+ (declare (indent defun))
+ (transient--insert-suffix prefix loc suffix 'append keep-other))
+
+;;;###autoload
+(defun transient-replace-suffix (prefix loc suffix)
+ "Replace the suffix at LOC in PREFIX with SUFFIX.
+PREFIX is a prefix command, a symbol.
+SUFFIX is a suffix command or a group specification (of
+ the same forms as expected by `transient-define-prefix').
+LOC is a command, a key vector, a key description (a string
+ as returned by `key-description'), or a coordination list
+ (whose last element may also be a command or key).
+See info node `(transient)Modifying Existing Transients'."
+ (declare (indent defun))
+ (transient--insert-suffix prefix loc suffix 'replace))
+
+;;;###autoload
+(defun transient-remove-suffix (prefix loc)
+ "Remove the suffix or group at LOC in PREFIX.
+PREFIX is a prefix command, a symbol.
+LOC is a command, a key vector, a key description (a string
+ as returned by `key-description'), or a coordination list
+ (whose last element may also be a command or key).
+See info node `(transient)Modifying Existing Transients'."
+ (declare (indent defun))
+ (transient--layout-member loc prefix 'remove))
+
+(defun transient-get-suffix (prefix loc)
+ "Return the suffix or group at LOC in PREFIX.
+PREFIX is a prefix command, a symbol.
+LOC is a command, a key vector, a key description (a string
+ as returned by `key-description'), or a coordination list
+ (whose last element may also be a command or key).
+See info node `(transient)Modifying Existing Transients'."
+ (if-let ((mem (transient--layout-member loc prefix)))
+ (car mem)
+ (error "%s not found in %s" loc prefix)))
+
+(defun transient-suffix-put (prefix loc prop value)
+ "Edit the suffix at LOC in PREFIX, setting PROP to VALUE.
+PREFIX is a prefix command, a symbol.
+SUFFIX is a suffix command or a group specification (of
+ the same forms as expected by `transient-define-prefix').
+LOC is a command, a key vector, a key description (a string
+ as returned by `key-description'), or a coordination list
+ (whose last element may also be a command or key).
+See info node `(transient)Modifying Existing Transients'."
+ (let ((suf (transient-get-suffix prefix loc)))
+ (setf (elt suf 2)
+ (plist-put (elt suf 2) prop value))))
+
+(defun transient--layout-member (loc prefix &optional remove)
+ (let ((val (or (get prefix 'transient--layout)
+ (error "%s is not a transient command" prefix))))
+ (when (listp loc)
+ (while (integerp (car loc))
+ (let* ((children (if (vectorp val) (aref val 3) val))
+ (mem (transient--nthcdr (pop loc) children)))
+ (if (and remove (not loc))
+ (let ((rest (delq (car mem) children)))
+ (if (vectorp val)
+ (aset val 3 rest)
+ (put prefix 'transient--layout rest))
+ (setq val nil))
+ (setq val (if loc (car mem) mem)))))
+ (setq loc (car loc)))
+ (if loc
+ (transient--layout-member-1 (transient--kbd loc) val remove)
+ val)))
+
+(defun transient--layout-member-1 (loc layout remove)
+ (cond ((listp layout)
+ (seq-some (lambda (elt) (transient--layout-member-1 loc elt remove))
+ layout))
+ ((vectorp (car (aref layout 3)))
+ (seq-some (lambda (elt) (transient--layout-member-1 loc elt remove))
+ (aref layout 3)))
+ (remove
+ (aset layout 3
+ (delq (car (transient--group-member loc layout))
+ (aref layout 3)))
+ nil)
+ ((transient--group-member loc layout))))
+
+(defun transient--group-member (loc group)
+ (cl-member-if (lambda (suffix)
+ (and (listp suffix)
+ (let* ((def (nth 2 suffix))
+ (cmd (plist-get def :command)))
+ (if (symbolp loc)
+ (eq cmd loc)
+ (equal (transient--kbd
+ (or (plist-get def :key)
+ (transient--command-key cmd)))
+ loc)))))
+ (aref group 3)))
+
+(defun transient--kbd (keys)
+ (when (vectorp keys)
+ (setq keys (key-description keys)))
+ (when (stringp keys)
+ (setq keys (kbd keys)))
+ keys)
+
+(defun transient--spec-key (spec)
+ (let ((plist (nth 2 spec)))
+ (or (plist-get plist :key)
+ (transient--command-key
+ (plist-get plist :command)))))
+
+(defun transient--command-key (cmd)
+ (and-let* ((obj (transient--suffix-prototype cmd)))
+ (cond ((slot-boundp obj 'key)
+ (oref obj key))
+ ((slot-exists-p obj 'shortarg)
+ (if (slot-boundp obj 'shortarg)
+ (oref obj shortarg)
+ (transient--derive-shortarg (oref obj argument)))))))
+
+(defun transient--nthcdr (n list)
+ (nthcdr (if (< n 0) (- (length list) (abs n)) n) list))
+
+;;; Variables
+
+(defvar transient-current-prefix nil
+ "The transient from which this suffix command was invoked.
+This is an object representing that transient, use
+`transient-current-command' to get the respective command.")
+
+(defvar transient-current-command nil
+ "The transient from which this suffix command was invoked.
+This is a symbol representing that transient, use
+`transient-current-prefix' to get the respective object.")
+
+(defvar transient-current-suffixes nil
+ "The suffixes of the transient from which this suffix command was invoked.
+This is a list of objects. Usually it is sufficient to instead
+use the function `transient-args', which returns a list of
+values. In complex cases it might be necessary to use this
+variable instead.")
+
+(defvar transient-exit-hook nil
+ "Hook run after exiting a transient.")
+
+(defvar transient-setup-buffer-hook nil
+ "Hook run when setting up the transient buffer.
+That buffer is current and empty when this hook runs.")
+
+(defvar transient--prefix nil)
+(defvar transient--layout nil)
+(defvar transient--suffixes nil)
+
+(defconst transient--stay t "Do not exit the transient.")
+(defconst transient--exit nil "Do exit the transient.")
+
+(defvar transient--exitp nil "Whether to exit the transient.")
+(defvar transient--showp nil "Whether to show the transient popup buffer.")
+(defvar transient--helpp nil "Whether help-mode is active.")
+(defvar transient--editp nil "Whether edit-mode is active.")
+
+(defvar transient--refreshp nil
+ "Whether to refresh the transient completely.")
+
+(defvar transient--all-levels-p nil
+ "Whether temporary display of suffixes on all levels is active.")
+
+(defvar transient--timer nil)
+
+(defvar transient--stack nil)
+
+(defvar transient--minibuffer-depth 0)
+
+(defvar transient--buffer-name " *transient*"
+ "Name of the transient buffer.")
+
+(defvar transient--window nil
+ "The window used to display the transient popup buffer.")
+
+(defvar transient--original-window nil
+ "The window that was selected before the transient was invoked.
+Usually it remains selected while the transient is active.")
+
+(defvar transient--original-buffer nil
+ "The buffer that was current before the transient was invoked.
+Usually it remains current while the transient is active.")
+
+(defvar transient--restore-winconf nil
+ "Window configuration to restore after exiting help.")
+
+(defvar transient--shadowed-buffer nil
+ "The buffer that is temporarily shadowed by the transient buffer.
+This is bound while the suffix predicate is being evaluated and while
+drawing in the transient buffer.")
+
+(defvar transient--pending-suffix nil
+ "The suffix that is currently being processed.
+This is bound while the suffix predicate is being evaluated,
+and while functions that return faces are being evaluated.")
+
+(defvar transient--pending-group nil
+ "The group that is currently being processed.
+This is bound while the suffixes are drawn in the transient buffer.")
+
+(defvar transient--debug nil
+ "Whether to put debug information into *Messages*.")
+
+(defvar transient--history nil)
+
+(defvar transient--scroll-commands
+ '(transient-scroll-up
+ transient-scroll-down
+ mwheel-scroll
+ scroll-bar-toolkit-scroll))
+
+;;; Identities
+
+(defun transient-prefix-object ()
+ "Return the current prefix as an object.
+
+While a transient is being setup or refreshed (which involves
+preparing its suffixes) the variable `transient--prefix' can be
+used to access the prefix object. Thus this is what has to be
+used in suffix methods such as `transient-format-description',
+and in object-specific functions that are stored in suffix slots
+such as `description'.
+
+When a suffix command is invoked (i.e., in its `interactive' form
+and function body) then the variable `transient-current-prefix'
+has to be used instead.
+
+Two distinct variables are needed, because any prefix may itself
+be used as a suffix of another prefix, and such sub-prefixes have
+to be able to tell themselves apart from the prefix they were
+invoked from.
+
+Regular suffix commands, which are not prefixes, do not have to
+concern themselves with this distinction, so they can use this
+function instead. In the context of a plain suffix, it always
+returns the value of the appropriate variable."
+ (or transient--prefix transient-current-prefix))
+
+(defun transient-suffix-object (&optional command)
+ "Return the object associated with the current suffix command.
+
+Each suffix commands is associated with an object, which holds
+additional information about the suffix, such as its value (in
+the case of an infix command, which is a kind of suffix command).
+
+This function is intended to be called by infix commands, which
+are usually aliases of `transient--default-infix-command', which
+is defined like this:
+
+ (defun transient--default-infix-command ()
+ (interactive)
+ (let ((obj (transient-suffix-object)))
+ (transient-infix-set obj (transient-infix-read obj)))
+ (transient--show))
+
+\(User input is read outside of `interactive' to prevent the
+command from being added to `command-history'. See #23.)
+
+Such commands need to be able to access their associated object
+to guide how `transient-infix-read' reads the new value and to
+store the read value. Other suffix commands (including non-infix
+commands) may also need the object to guide their behavior.
+
+This function attempts to return the object associated with the
+current suffix command even if the suffix command was not invoked
+from a transient. (For some suffix command that is a valid thing
+to do, for others it is not.) In that case nil may be returned,
+if the command was not defined using one of the macros intended
+to define such commands.
+
+The optional argument COMMAND is intended for internal use. If
+you are contemplating using it in your own code, then you should
+probably use this instead:
+
+ (get COMMAND \\='transient--suffix)"
+ (when command
+ (cl-check-type command command))
+ (cond
+ (transient--pending-suffix)
+ ((or transient--prefix
+ transient-current-prefix)
+ (let ((suffixes
+ (cl-remove-if-not
+ (lambda (obj)
+ (eq (oref obj command)
+ (or command
+ (if (eq this-command 'transient-set-level)
+ ;; This is how it can look up for which
+ ;; command it is setting the level.
+ this-original-command
+ this-command))))
+ (or transient--suffixes
+ transient-current-suffixes))))
+ (or (and (cdr suffixes)
+ (cl-find-if
+ (lambda (obj)
+ (equal (listify-key-sequence (transient--kbd (oref obj key)))
+ (listify-key-sequence (this-command-keys))))
+ suffixes))
+ (car suffixes))))
+ ((and-let* ((obj (transient--suffix-prototype (or command this-command)))
+ (obj (clone obj)))
+ (progn ; work around debbugs#31840
+ (transient-init-scope obj)
+ (transient-init-value obj)
+ obj)))))
+
+(defun transient--suffix-prototype (command)
+ (or (get command 'transient--suffix)
+ (seq-some (lambda (cmd) (get cmd 'transient--suffix))
+ (function-alias-p command))))
+
+;;; Keymaps
+
+(defvar-keymap transient-base-map
+ :doc "Parent of other keymaps used by Transient.
+
+This is the parent keymap of all the keymaps that are used in
+all transients: `transient-map' (which in turn is the parent
+of the transient-specific keymaps), `transient-edit-map' and
+`transient-sticky-map'.
+
+If you change a binding here, then you might also have to edit
+`transient-sticky-map' and `transient-common-commands'. While
+the latter isn't a proper transient prefix command, it can be
+edited using the same functions as used for transients.
+
+If you add a new command here, then you must also add a binding
+to `transient-predicate-map'."
+ "ESC ESC ESC" #'transient-quit-all
+ "C-g" #'transient-quit-one
+ "C-q" #'transient-quit-all
+ "C-z" #'transient-suspend
+ "C-v" #'transient-scroll-up
+ "C-M-v" #'transient-scroll-down
+ "<next>" #'transient-scroll-up
+ "<prior>" #'transient-scroll-down)
+
+(defvar-keymap transient-map
+ :doc "Top-level keymap used by all transients.
+
+If you add a new command here, then you must also add a binding
+to `transient-predicate-map'. Also see `transient-base-map'."
+ :parent transient-base-map
+ "C-u" #'universal-argument
+ "C--" #'negative-argument
+ "C-t" #'transient-show
+ "?" #'transient-help
+ "C-h" #'transient-help
+ ;; Also bound to "C-x p" and "C-x n" in transient-common-commands.
+ "C-M-p" #'transient-history-prev
+ "C-M-n" #'transient-history-next)
+
+(defvar-keymap transient-edit-map
+ :doc "Keymap that is active while a transient in is in \"edit mode\"."
+ :parent transient-base-map
+ "?" #'transient-help
+ "C-h" #'transient-help
+ "C-x l" #'transient-set-level)
+
+(defvar-keymap transient-sticky-map
+ :doc "Keymap that is active while an incomplete key sequence is active."
+ :parent transient-base-map
+ "C-g" #'transient-quit-seq)
+
+(defvar transient--common-command-prefixes '(?\C-x))
+
+(put 'transient-common-commands
+ 'transient--layout
+ (list
+ (eval
+ (car (transient--parse-child
+ 'transient-common-commands
+ (vector
+ :hide
+ (lambda ()
+ (and (not (memq
+ (car (bound-and-true-p transient--redisplay-key))
+ transient--common-command-prefixes))
+ (not transient-show-common-commands)))
+ (vector
+ "Value commands"
+ (list "C-x s " "Set" #'transient-set)
+ (list "C-x C-s" "Save" #'transient-save)
+ (list "C-x C-k" "Reset" #'transient-reset)
+ (list "C-x p " "Previous value" #'transient-history-prev)
+ (list "C-x n " "Next value" #'transient-history-next))
+ (vector
+ "Sticky commands"
+ ;; Like `transient-sticky-map' except that
+ ;; "C-g" has to be bound to a different command.
+ (list "C-g" "Quit prefix or transient" #'transient-quit-one)
+ (list "C-q" "Quit transient stack" #'transient-quit-all)
+ (list "C-z" "Suspend transient stack" #'transient-suspend))
+ (vector
+ "Customize"
+ (list "C-x t" 'transient-toggle-common :description
+ (lambda ()
+ (if transient-show-common-commands
+ "Hide common commands"
+ "Show common permanently")))
+ (list "C-x l" "Show/hide suffixes" #'transient-set-level)
+ (list "C-x a" #'transient-toggle-level-limit))))))))
+
+(defvar-keymap transient-popup-navigation-map
+ :doc "One of the keymaps used when popup navigation is enabled.
+See `transient-enable-popup-navigation'."
+ "<down-mouse-1>" #'transient-noop
+ "<up>" #'transient-backward-button
+ "<down>" #'transient-forward-button
+ "C-r" #'transient-isearch-backward
+ "C-s" #'transient-isearch-forward
+ "M-RET" #'transient-push-button)
+
+(defvar-keymap transient-button-map
+ :doc "One of the keymaps used when popup navigation is enabled.
+See `transient-enable-popup-navigation'."
+ "<mouse-1>" #'transient-push-button
+ "<mouse-2>" #'transient-push-button)
+
+(defvar-keymap transient-resume-mode-map
+ :doc "Keymap for `transient-resume-mode'.
+
+This keymap remaps every command that would usually just quit the
+documentation buffer to `transient-resume', which additionally
+resumes the suspended transient."
+ "<remap> <Man-quit>" #'transient-resume
+ "<remap> <Info-exit>" #'transient-resume
+ "<remap> <quit-window>" #'transient-resume)
+
+(defvar-keymap transient-predicate-map
+ :doc "Base keymap used to map common commands to their transient behavior.
+
+The \"transient behavior\" of a command controls, among other
+things, whether invoking the command causes the transient to be
+exited or not, and whether infix arguments are exported before
+doing so.
+
+Each \"key\" is a command that is common to all transients and
+that is bound in `transient-map', `transient-edit-map',
+`transient-sticky-map' and/or `transient-common-command'.
+
+Each binding is a \"pre-command\", a function that controls the
+transient behavior of the respective command.
+
+For transient commands that are bound in individual transients,
+the transient behavior is specified using the `:transient' slot
+of the corresponding object."
+ "<transient-suspend>" #'transient--do-suspend
+ "<transient-help>" #'transient--do-stay
+ "<transient-set-level>" #'transient--do-stay
+ "<transient-history-prev>" #'transient--do-stay
+ "<transient-history-next>" #'transient--do-stay
+ "<universal-argument>" #'transient--do-stay
+ "<universal-argument-more>" #'transient--do-stay
+ "<negative-argument>" #'transient--do-minus
+ "<digit-argument>" #'transient--do-stay
+ "<top-level>" #'transient--do-quit-all
+ "<transient-quit-all>" #'transient--do-quit-all
+ "<transient-quit-one>" #'transient--do-quit-one
+ "<transient-quit-seq>" #'transient--do-stay
+ "<transient-show>" #'transient--do-stay
+ "<transient-update>" #'transient--do-stay
+ "<transient-toggle-common>" #'transient--do-stay
+ "<transient-set>" #'transient--do-call
+ "<transient-set-and-exit>" #'transient--do-exit
+ "<transient-save>" #'transient--do-call
+ "<transient-save-and-exit>" #'transient--do-exit
+ "<transient-reset>" #'transient--do-call
+ "<describe-key-briefly>" #'transient--do-stay
+ "<describe-key>" #'transient--do-stay
+ "<transient-scroll-up>" #'transient--do-stay
+ "<transient-scroll-down>" #'transient--do-stay
+ "<mwheel-scroll>" #'transient--do-stay
+ "<scroll-bar-toolkit-scroll>" #'transient--do-stay
+ "<transient-noop>" #'transient--do-noop
+ "<transient-mouse-push-button>" #'transient--do-move
+ "<transient-push-button>" #'transient--do-push-button
+ "<transient-backward-button>" #'transient--do-move
+ "<transient-forward-button>" #'transient--do-move
+ "<transient-isearch-backward>" #'transient--do-move
+ "<transient-isearch-forward>" #'transient--do-move
+ ;; If a valid but incomplete prefix sequence is followed by
+ ;; an unbound key, then Emacs calls the `undefined' command
+ ;; but does not set `this-command', `this-original-command'
+ ;; or `real-this-command' accordingly. Instead they are nil.
+ "<nil>" #'transient--do-warn
+ ;; Bound to the `mouse-movement' event, this command is similar
+ ;; to `ignore'.
+ "<ignore-preserving-kill-region>" #'transient--do-noop)
+
+(defvar transient--transient-map nil)
+(defvar transient--predicate-map nil)
+(defvar transient--redisplay-map nil)
+(defvar transient--redisplay-key nil)
+
+(defun transient--push-keymap (var)
+ (let ((map (symbol-value var)))
+ (transient--debug " push %s%s" var (if map "" " VOID"))
+ (when map
+ (with-demoted-errors "transient--push-keymap: %S"
+ (internal-push-keymap map 'overriding-terminal-local-map)))))
+
+(defun transient--pop-keymap (var)
+ (let ((map (symbol-value var)))
+ (when map
+ (transient--debug " pop %s" var)
+ (with-demoted-errors "transient--pop-keymap: %S"
+ (internal-pop-keymap map 'overriding-terminal-local-map)))))
+
+(defun transient--make-transient-map ()
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map (if transient--editp
+ transient-edit-map
+ transient-map))
+ (dolist (obj transient--suffixes)
+ (let ((key (oref obj key)))
+ (when (vectorp key)
+ (setq key (key-description key))
+ (oset obj key key))
+ (when transient-substitute-key-function
+ (setq key (save-match-data
+ (funcall transient-substitute-key-function obj)))
+ (oset obj key key))
+ (let* ((kbd (kbd key))
+ (cmd (oref obj command))
+ (alt (transient--lookup-key map kbd)))
+ (cond ((not alt)
+ (define-key map kbd cmd))
+ ((eq alt cmd))
+ ((transient--inapt-suffix-p obj))
+ ((and-let* ((obj (transient-suffix-object alt)))
+ (transient--inapt-suffix-p obj))
+ (define-key map kbd cmd))
+ (transient-detect-key-conflicts
+ (error "Cannot bind %S to %s and also %s"
+ (string-trim key) cmd alt))
+ ((define-key map kbd cmd))))))
+ (when-let ((b (keymap-lookup map "-"))) (keymap-set map "<kp-subtract>" b))
+ (when-let ((b (keymap-lookup map "="))) (keymap-set map "<kp-equal>" b))
+ (when-let ((b (keymap-lookup map "+"))) (keymap-set map "<kp-add>" b))
+ (when transient-enable-popup-navigation
+ ;; `transient--make-redisplay-map' maps only over bindings that are
+ ;; directly in the base keymap, so that cannot be a composed keymap.
+ (set-keymap-parent
+ map (make-composed-keymap
+ (keymap-parent map)
+ transient-popup-navigation-map)))
+ map))
+
+(defun transient--make-predicate-map ()
+ (let* ((default (transient--resolve-pre-command
+ (oref transient--prefix transient-suffix)))
+ (return (and transient--stack (eq default t)))
+ (map (make-sparse-keymap)))
+ (set-keymap-parent map transient-predicate-map)
+ (when (or (and (slot-boundp transient--prefix 'transient-switch-frame)
+ (transient--resolve-pre-command
+ (not (oref transient--prefix transient-switch-frame))))
+ (memq (transient--resolve-pre-command
+ (oref transient--prefix transient-non-suffix))
+ '(nil transient--do-warn transient--do-noop)))
+ (define-key map [handle-switch-frame] #'transient--do-suspend))
+ (dolist (obj transient--suffixes)
+ (let* ((cmd (oref obj command))
+ (kind (cond ((get cmd 'transient--prefix) 'prefix)
+ ((cl-typep obj 'transient-infix) 'infix)
+ (t 'suffix))))
+ (cond
+ ((oref obj inapt)
+ (define-key map (vector cmd) #'transient--do-warn-inapt))
+ ((slot-boundp obj 'transient)
+ (define-key map (vector cmd)
+ (pcase (list kind
+ (transient--resolve-pre-command (oref obj transient))
+ return)
+ (`(prefix t ,_) #'transient--do-recurse)
+ (`(prefix nil ,_) #'transient--do-stack)
+ (`(infix t ,_) #'transient--do-stay)
+ (`(suffix t ,_) #'transient--do-call)
+ ('(suffix nil t) #'transient--do-return)
+ (`(,_ nil ,_) #'transient--do-exit)
+ (`(,_ ,do ,_) do))))
+ ((not (lookup-key transient-predicate-map (vector cmd)))
+ (define-key map (vector cmd)
+ (pcase (list kind default return)
+ (`(prefix ,(or 'transient--do-stay 'transient--do-call) ,_)
+ #'transient--do-recurse)
+ (`(prefix t ,_) #'transient--do-recurse)
+ (`(prefix ,_ ,_) #'transient--do-stack)
+ (`(infix ,_ ,_) #'transient--do-stay)
+ (`(suffix t ,_) #'transient--do-call)
+ ('(suffix nil t) #'transient--do-return)
+ (`(suffix nil ,_) #'transient--do-exit)
+ (`(suffix ,do ,_) do)))))))
+ map))
+
+(defun transient--make-redisplay-map ()
+ (setq transient--redisplay-key
+ (pcase this-command
+ ('transient-update
+ (setq transient--showp t)
+ (setq unread-command-events
+ (listify-key-sequence (this-single-command-raw-keys))))
+ ('transient-quit-seq
+ (setq unread-command-events
+ (butlast (listify-key-sequence
+ (this-single-command-raw-keys))
+ 2))
+ (butlast transient--redisplay-key))
+ (_ nil)))
+ (let ((topmap (make-sparse-keymap))
+ (submap (make-sparse-keymap)))
+ (when transient--redisplay-key
+ (define-key topmap (vconcat transient--redisplay-key) submap)
+ (set-keymap-parent submap transient-sticky-map))
+ (map-keymap-internal
+ (lambda (key def)
+ (when (and (not (eq key ?\e))
+ (listp def)
+ (keymapp def))
+ (define-key topmap (vconcat transient--redisplay-key (list key))
+ #'transient-update)))
+ (if transient--redisplay-key
+ (let ((key (vconcat transient--redisplay-key)))
+ (or (lookup-key transient--transient-map key)
+ (and-let* ((regular (lookup-key local-function-key-map key)))
+ (lookup-key transient--transient-map (vconcat regular)))))
+ transient--transient-map))
+ topmap))
+
+;;; Setup
+
+(defun transient-setup (&optional name layout edit &rest params)
+ "Setup the transient specified by NAME.
+
+This function is called by transient prefix commands to setup the
+transient. In that case NAME is mandatory, LAYOUT and EDIT must
+be nil and PARAMS may be (but usually is not) used to set, e.g.,
+the \"scope\" of the transient (see `transient-define-prefix').
+
+This function is also called internally in which case LAYOUT and
+EDIT may be non-nil."
+ (transient--debug 'setup)
+ (transient--with-emergency-exit :setup
+ (cond
+ ((not name)
+ ;; Switching between regular and edit mode.
+ (transient--pop-keymap 'transient--transient-map)
+ (transient--pop-keymap 'transient--redisplay-map)
+ (setq name (oref transient--prefix command))
+ (setq params (list :scope (oref transient--prefix scope))))
+ (transient--prefix
+ ;; Invoked as a ":transient-non-suffix 'transient--do-{stay,call}"
+ ;; of an outer prefix. Unlike the usual `transient--do-stack',
+ ;; these predicates fail to clean up after the outer prefix.
+ (transient--pop-keymap 'transient--transient-map)
+ (transient--pop-keymap 'transient--redisplay-map))
+ ((not (or layout ; resuming parent/suspended prefix
+ transient-current-command)) ; entering child prefix
+ (transient--stack-zap)) ; replace suspended prefix, if any
+ (edit
+ ;; Returning from help to edit.
+ (setq transient--editp t)))
+ (transient--init-objects name layout params)
+ (transient--init-keymaps)
+ (transient--history-init transient--prefix)
+ (setq transient--original-window (selected-window))
+ (setq transient--original-buffer (current-buffer))
+ (setq transient--minibuffer-depth (minibuffer-depth))
+ (transient--redisplay)
+ (transient--init-transient)
+ (transient--suspend-which-key-mode)))
+
+(cl-defgeneric transient-setup-children (group children)
+ "Setup the CHILDREN of GROUP.
+If the value of the `setup-children' slot is non-nil, then call
+that function with CHILDREN as the only argument and return the
+value. Otherwise return CHILDREN as is."
+ (if (slot-boundp group 'setup-children)
+ (funcall (oref group setup-children) children)
+ children))
+
+(defun transient--init-keymaps ()
+ (setq transient--predicate-map (transient--make-predicate-map))
+ (setq transient--transient-map (transient--make-transient-map))
+ (setq transient--redisplay-map (transient--make-redisplay-map)))
+
+(defun transient--init-objects (&optional name layout params)
+ (if name
+ (setq transient--prefix (transient--init-prefix name params))
+ (setq name (oref transient--prefix command)))
+ (setq transient--refreshp (oref transient--prefix refresh-suffixes))
+ (setq transient--layout (or layout (transient--init-suffixes name)))
+ (setq transient--suffixes (transient--flatten-suffixes transient--layout)))
+
+(defun transient--init-prefix (name &optional params)
+ (let ((obj (let ((proto (get name 'transient--prefix)))
+ (apply #'clone proto
+ :prototype proto
+ :level (or (alist-get t (alist-get name transient-levels))
+ transient-default-level)
+ params))))
+ (transient--setup-recursion obj)
+ (transient-init-value obj)
+ obj))
+
+(defun transient--init-suffixes (name)
+ (let ((levels (alist-get name transient-levels)))
+ (cl-mapcan (lambda (c) (transient--init-child levels c))
+ (append (get name 'transient--layout)
+ (and (not transient--editp)
+ (get 'transient-common-commands
+ 'transient--layout))))))
+
+(defun transient--flatten-suffixes (layout)
+ (cl-labels ((s (def)
+ (cond
+ ((stringp def) nil)
+ ((cl-typep def 'transient-information) nil)
+ ((listp def) (cl-mapcan #'s def))
+ ((cl-typep def 'transient-group)
+ (cl-mapcan #'s (oref def suffixes)))
+ ((cl-typep def 'transient-suffix)
+ (list def)))))
+ (cl-mapcan #'s layout)))
+
+(defun transient--init-child (levels spec)
+ (cl-etypecase spec
+ (vector (transient--init-group levels spec))
+ (list (transient--init-suffix levels spec))
+ (string (list spec))))
+
+(defun transient--init-group (levels spec)
+ (pcase-let ((`(,level ,class ,args ,children) (append spec nil)))
+ (and-let* (((transient--use-level-p level))
+ (obj (apply class :level level args))
+ ((transient--use-suffix-p obj))
+ (suffixes (cl-mapcan (lambda (c) (transient--init-child levels c))
+ (transient-setup-children obj children))))
+ (progn ; work around debbugs#31840
+ (oset obj suffixes suffixes)
+ (list obj)))))
+
+(defun transient--init-suffix (levels spec)
+ (pcase-let* ((`(,level ,class ,args) spec)
+ (cmd (plist-get args :command))
+ (key (transient--kbd (plist-get args :key)))
+ (level (or (alist-get (cons cmd key) levels nil nil #'equal)
+ (alist-get cmd levels)
+ level)))
+ (let ((fn (and (symbolp cmd)
+ (symbol-function cmd))))
+ (when (autoloadp fn)
+ (transient--debug " autoload %s" cmd)
+ (autoload-do-load fn)))
+ (when (transient--use-level-p level)
+ (let ((obj (if (child-of-class-p class 'transient-information)
+ (apply class :level level args)
+ (unless (and cmd (symbolp cmd))
+ (error "BUG: Non-symbolic suffix command: %s" cmd))
+ (if-let ((proto (and cmd (transient--suffix-prototype cmd))))
+ (apply #'clone proto :level level args)
+ (apply class :command cmd :level level args)))))
+ (cond ((not cmd))
+ ((commandp cmd))
+ ((or (cl-typep obj 'transient-switch)
+ (cl-typep obj 'transient-option))
+ ;; As a temporary special case, if the package was compiled
+ ;; with an older version of Transient, then we must define
+ ;; "anonymous" switch and option commands here.
+ (defalias cmd #'transient--default-infix-command))
+ ((transient--use-suffix-p obj)
+ (error "Suffix command %s is not defined or autoloaded" cmd)))
+ (unless (cl-typep obj 'transient-information)
+ (transient--init-suffix-key obj))
+ (when (transient--use-suffix-p obj)
+ (if (transient--inapt-suffix-p obj)
+ (oset obj inapt t)
+ (transient-init-scope obj)
+ (transient-init-value obj))
+ (list obj))))))
+
+(cl-defmethod transient--init-suffix-key ((obj transient-suffix))
+ (unless (slot-boundp obj 'key)
+ (error "No key for %s" (oref obj command))))
+
+(cl-defmethod transient--init-suffix-key ((obj transient-argument))
+ (if (transient-switches--eieio-childp obj)
+ (cl-call-next-method obj)
+ (unless (slot-boundp obj 'shortarg)
+ (when-let ((shortarg (transient--derive-shortarg (oref obj argument))))
+ (oset obj shortarg shortarg)))
+ (unless (slot-boundp obj 'key)
+ (if (slot-boundp obj 'shortarg)
+ (oset obj key (oref obj shortarg))
+ (error "No key for %s" (oref obj command))))))
+
+(defun transient--use-level-p (level &optional edit)
+ (or transient--all-levels-p
+ (and transient--editp (not edit))
+ (and (>= level 1)
+ (<= level (oref transient--prefix level)))))
+
+(defun transient--use-suffix-p (obj)
+ (let ((transient--shadowed-buffer (current-buffer))
+ (transient--pending-suffix obj))
+ (transient--do-suffix-p
+ (oref obj if)
+ (oref obj if-not)
+ (oref obj if-nil)
+ (oref obj if-non-nil)
+ (oref obj if-mode)
+ (oref obj if-not-mode)
+ (oref obj if-derived)
+ (oref obj if-not-derived)
+ t)))
+
+(defun transient--inapt-suffix-p (obj)
+ (let ((transient--shadowed-buffer (current-buffer))
+ (transient--pending-suffix obj))
+ (transient--do-suffix-p
+ (oref obj inapt-if)
+ (oref obj inapt-if-not)
+ (oref obj inapt-if-nil)
+ (oref obj inapt-if-non-nil)
+ (oref obj inapt-if-mode)
+ (oref obj inapt-if-not-mode)
+ (oref obj inapt-if-derived)
+ (oref obj inapt-if-not-derived)
+ nil)))
+
+(defun transient--do-suffix-p
+ (if if-not if-nil if-non-nil if-mode if-not-mode if-derived if-not-derived
+ default)
+ (cond
+ (if (funcall if))
+ (if-not (not (funcall if-not)))
+ (if-non-nil (symbol-value if-non-nil))
+ (if-nil (not (symbol-value if-nil)))
+ (if-mode (if (atom if-mode)
+ (eq major-mode if-mode)
+ (memq major-mode if-mode)))
+ (if-not-mode (not (if (atom if-not-mode)
+ (eq major-mode if-not-mode)
+ (memq major-mode if-not-mode))))
+ (if-derived (if (or (atom if-derived)
+ (>= emacs-major-version 30))
+ (derived-mode-p if-derived)
+ (apply #'derived-mode-p if-derived)))
+ (if-not-derived (not (if (or (atom if-not-derived)
+ (>= emacs-major-version 30))
+ (derived-mode-p if-not-derived)
+ (apply #'derived-mode-p if-not-derived))))
+ (default)))
+
+(defun transient--suffix-predicate (spec)
+ (let ((plist (nth 2 spec)))
+ (seq-some (lambda (prop)
+ (and-let* ((pred (plist-get plist prop)))
+ (list prop pred)))
+ '( :if :if-not
+ :if-nil :if-non-nil
+ :if-mode :if-not-mode
+ :if-derived :if-not-derived
+ :inapt-if :inapt-if-not
+ :inapt-if-nil :inapt-if-non-nil
+ :inapt-if-mode :inapt-if-not-mode
+ :inapt-if-derived :inapt-if-not-derived))))
+
+;;; Flow-Control
+
+(defun transient--init-transient ()
+ (transient--debug 'init-transient)
+ (transient--push-keymap 'transient--transient-map)
+ (transient--push-keymap 'transient--redisplay-map)
+ (add-hook 'pre-command-hook #'transient--pre-command)
+ (add-hook 'post-command-hook #'transient--post-command)
+ (advice-add 'recursive-edit :around #'transient--recursive-edit)
+ (when transient--exitp
+ ;; This prefix command was invoked as the suffix of another.
+ ;; Prevent `transient--post-command' from removing the hooks
+ ;; that we just added.
+ (setq transient--exitp 'replace)))
+
+(defun transient--refresh-transient ()
+ (transient--debug 'refresh-transient)
+ (transient--pop-keymap 'transient--predicate-map)
+ (transient--pop-keymap 'transient--transient-map)
+ (transient--pop-keymap 'transient--redisplay-map)
+ (transient--init-objects)
+ (transient--init-keymaps)
+ (transient--push-keymap 'transient--transient-map)
+ (transient--push-keymap 'transient--redisplay-map)
+ (transient--redisplay))
+
+(defun transient--pre-command ()
+ (transient--debug 'pre-command)
+ (transient--with-emergency-exit :pre-command
+ ;; The use of `overriding-terminal-local-map' does not prevent the
+ ;; lookup of command remappings in the overridden maps, which can
+ ;; lead to a suffix being remapped to a non-suffix. We have to undo
+ ;; the remapping in that case. However, remapping a non-suffix to
+ ;; another should remain possible.
+ (when (and (transient--get-pre-command this-original-command 'suffix)
+ (not (transient--get-pre-command this-command 'suffix)))
+ (setq this-command this-original-command))
+ (cond
+ ((memq this-command '(transient-update transient-quit-seq))
+ (transient--pop-keymap 'transient--redisplay-map))
+ ((and transient--helpp
+ (not (memq this-command '(transient-quit-one
+ transient-quit-all))))
+ (cond
+ ((transient-help)
+ (transient--do-suspend)
+ (setq this-command 'transient-suspend)
+ (transient--pre-exit))
+ ((not (transient--edebug-command-p))
+ (setq this-command 'transient-undefined))))
+ ((and transient--editp
+ (transient-suffix-object)
+ (not (memq this-command '(transient-quit-one
+ transient-quit-all
+ transient-help))))
+ (setq this-command 'transient-set-level)
+ (transient--wrap-command))
+ (t
+ (setq transient--exitp nil)
+ (let ((exitp (eq (transient--call-pre-command) transient--exit)))
+ (transient--wrap-command)
+ (when exitp
+ (transient--pre-exit)))))))
+
+(defun transient--pre-exit ()
+ (transient--debug 'pre-exit)
+ (transient--delete-window)
+ (transient--timer-cancel)
+ (transient--pop-keymap 'transient--transient-map)
+ (transient--pop-keymap 'transient--redisplay-map)
+ (unless transient--showp
+ (let ((message-log-max nil))
+ (message "")))
+ (setq transient--transient-map nil)
+ (setq transient--predicate-map nil)
+ (setq transient--redisplay-map nil)
+ (setq transient--redisplay-key nil)
+ (setq transient--helpp nil)
+ (setq transient--editp nil)
+ (setq transient--prefix nil)
+ (setq transient--layout nil)
+ (setq transient--suffixes nil)
+ (setq transient--original-window nil)
+ (setq transient--original-buffer nil)
+ (setq transient--window nil))
+
+(defun transient--delete-window ()
+ (when (window-live-p transient--window)
+ (let ((remain-in-minibuffer-window
+ (and (minibuffer-selected-window)
+ (selected-window))))
+ ;; Only delete the window if it has never shown another buffer.
+ (unless (eq (car (window-parameter transient--window 'quit-restore))
+ 'other)
+ (with-demoted-errors "Error while exiting transient: %S"
+ (delete-window transient--window)))
+ (when-let ((buffer (get-buffer transient--buffer-name)))
+ (kill-buffer buffer))
+ (when remain-in-minibuffer-window
+ (select-window remain-in-minibuffer-window)))))
+
+(defun transient--export ()
+ (setq transient-current-prefix transient--prefix)
+ (setq transient-current-command (oref transient--prefix command))
+ (setq transient-current-suffixes transient--suffixes)
+ (transient--history-push transient--prefix))
+
+(defun transient--suspend-override (&optional nohide)
+ (transient--debug 'suspend-override)
+ (transient--timer-cancel)
+ (cond ((and (not nohide) transient-hide-during-minibuffer-read)
+ (transient--delete-window))
+ ((and transient--prefix transient--redisplay-key)
+ (setq transient--redisplay-key nil)
+ (when transient--showp
+ (if-let ((win (minibuffer-selected-window)))
+ (with-selected-window win
+ (transient--show))
+ (transient--show)))))
+ (transient--pop-keymap 'transient--transient-map)
+ (transient--pop-keymap 'transient--redisplay-map)
+ (remove-hook 'pre-command-hook #'transient--pre-command)
+ (remove-hook 'post-command-hook #'transient--post-command))
+
+(defun transient--resume-override (&optional _ignore)
+ (transient--debug 'resume-override)
+ (when (and transient--showp transient-hide-during-minibuffer-read)
+ (transient--show))
+ (transient--push-keymap 'transient--transient-map)
+ (transient--push-keymap 'transient--redisplay-map)
+ (add-hook 'pre-command-hook #'transient--pre-command)
+ (add-hook 'post-command-hook #'transient--post-command))
+
+(defun transient--recursive-edit (fn)
+ (transient--debug 'recursive-edit)
+ (if (not transient--prefix)
+ (funcall fn)
+ (transient--suspend-override (bound-and-true-p edebug-active))
+ (funcall fn) ; Already unwind protected.
+ (cond ((memq this-command '(top-level abort-recursive-edit))
+ (setq transient--exitp t)
+ (transient--post-exit)
+ (transient--delete-window))
+ (transient--prefix
+ (transient--resume-override)))))
+
+(defmacro transient--with-suspended-override (&rest body)
+ (let ((depth (make-symbol "depth"))
+ (setup (make-symbol "setup"))
+ (exit (make-symbol "exit")))
+ `(if (and transient--transient-map
+ (memq transient--transient-map
+ overriding-terminal-local-map))
+ (let ((,depth (1+ (minibuffer-depth))) ,setup ,exit)
+ (setq ,setup
+ (lambda () "@transient--with-suspended-override"
+ (transient--debug 'minibuffer-setup)
+ (remove-hook 'minibuffer-setup-hook ,setup)
+ (transient--suspend-override)))
+ (setq ,exit
+ (lambda () "@transient--with-suspended-override"
+ (transient--debug 'minibuffer-exit)
+ (when (= (minibuffer-depth) ,depth)
+ (transient--resume-override))))
+ (unwind-protect
+ (progn
+ (add-hook 'minibuffer-setup-hook ,setup)
+ (add-hook 'minibuffer-exit-hook ,exit)
+ ,@body)
+ (remove-hook 'minibuffer-setup-hook ,setup)
+ (remove-hook 'minibuffer-exit-hook ,exit)))
+ ,@body)))
+
+(static-if (>= emacs-major-version 30) ;transient--wrap-command
+ (defun transient--wrap-command ()
+ (cl-assert
+ (>= emacs-major-version 30) nil
+ "Emacs was downgraded, making it necessary to recompile Transient")
+ (letrec
+ ((prefix transient--prefix)
+ (suffix this-command)
+ (advice
+ (lambda (fn &rest args)
+ (interactive
+ (lambda (spec)
+ (let ((abort t))
+ (unwind-protect
+ (prog1 (let ((debugger #'transient--exit-and-debug))
+ (advice-eval-interactive-spec spec))
+ (setq abort nil))
+ (when abort
+ (when-let ((unwind (oref prefix unwind-suffix)))
+ (transient--debug 'unwind-interactive)
+ (funcall unwind suffix))
+ (advice-remove suffix advice)
+ (oset prefix unwind-suffix nil))))))
+ (unwind-protect
+ (let ((debugger #'transient--exit-and-debug))
+ (apply fn args))
+ (when-let ((unwind (oref prefix unwind-suffix)))
+ (transient--debug 'unwind-command)
+ (funcall unwind suffix))
+ (advice-remove suffix advice)
+ (oset prefix unwind-suffix nil)))))
+ (when (symbolp this-command)
+ (advice-add suffix :around advice '((depth . -99))))))
+
+ (defun transient--wrap-command ()
+ (let* ((prefix transient--prefix)
+ (suffix this-command)
+ (advice nil)
+ (advice-interactive
+ (lambda (spec)
+ (let ((abort t))
+ (unwind-protect
+ (prog1 (let ((debugger #'transient--exit-and-debug))
+ (advice-eval-interactive-spec spec))
+ (setq abort nil))
+ (when abort
+ (when-let ((unwind (oref prefix unwind-suffix)))
+ (transient--debug 'unwind-interactive)
+ (funcall unwind suffix))
+ (advice-remove suffix advice)
+ (oset prefix unwind-suffix nil))))))
+ (advice-body
+ (lambda (fn &rest args)
+ (unwind-protect
+ (let ((debugger #'transient--exit-and-debug))
+ (apply fn args))
+ (when-let ((unwind (oref prefix unwind-suffix)))
+ (transient--debug 'unwind-command)
+ (funcall unwind suffix))
+ (advice-remove suffix advice)
+ (oset prefix unwind-suffix nil)))))
+ (setq advice `(lambda (fn &rest args)
+ (interactive ,advice-interactive)
+ (apply ',advice-body fn args)))
+ (when (symbolp this-command)
+ (advice-add suffix :around advice '((depth . -99)))))))
+
+(defun transient--premature-post-command ()
+ (and (equal (this-command-keys-vector) [])
+ (= (minibuffer-depth)
+ (1+ transient--minibuffer-depth))
+ (progn
+ (transient--debug 'premature-post-command)
+ (transient--suspend-override)
+ (oset (or transient--prefix transient-current-prefix)
+ unwind-suffix
+ (if transient--exitp
+ #'transient--post-exit
+ #'transient--resume-override))
+ t)))
+
+(defun transient--post-command ()
+ (unless (transient--premature-post-command)
+ (transient--debug 'post-command)
+ (transient--with-emergency-exit :post-command
+ (cond (transient--exitp (transient--post-exit))
+ ;; If `this-command' is the current transient prefix, then we
+ ;; have already taken care of updating the transient buffer...
+ ((and (eq this-command (oref transient--prefix command))
+ ;; ... but if `prefix-arg' is non-nil, then the values
+ ;; of `this-command' and `real-this-command' are untrue
+ ;; because `prefix-command-preserve-state' changes them.
+ ;; We cannot use `current-prefix-arg' because it is set
+ ;; too late (in `command-execute'), and if it were set
+ ;; earlier, then we likely still would not be able to
+ ;; rely on it and `prefix-command-preserve-state-hook'
+ ;; would have to be used to record that a universal
+ ;; argument is in effect.
+ (not prefix-arg)))
+ (transient--refreshp
+ (transient--refresh-transient))
+ ((let ((old transient--redisplay-map)
+ (new (transient--make-redisplay-map)))
+ (unless (equal old new)
+ (transient--pop-keymap 'transient--redisplay-map)
+ (setq transient--redisplay-map new)
+ (transient--push-keymap 'transient--redisplay-map))
+ (transient--redisplay)))))))
+
+(defun transient--post-exit (&optional command)
+ (transient--debug 'post-exit)
+ (unless (and (eq transient--exitp 'replace)
+ (or transient--prefix
+ ;; The current command could act as a prefix,
+ ;; but decided not to call `transient-setup',
+ ;; or it is prevented from doing so because it
+ ;; uses the minibuffer and the user aborted
+ ;; that.
+ (prog1 nil
+ (if (let ((obj (transient-suffix-object command)))
+ (and (slot-boundp obj 'transient)
+ (oref obj transient)))
+ ;; This sub-prefix is a transient suffix;
+ ;; go back to outer prefix, by calling
+ ;; `transient--stack-pop' further down.
+ (setq transient--exitp nil)
+ (transient--stack-zap)))))
+ (remove-hook 'pre-command-hook #'transient--pre-command)
+ (remove-hook 'post-command-hook #'transient--post-command)
+ (advice-remove 'recursive-edit #'transient--recursive-edit))
+ (setq transient-current-prefix nil)
+ (setq transient-current-command nil)
+ (setq transient-current-suffixes nil)
+ (let ((resume (and transient--stack
+ (not (memq transient--exitp '(replace suspend))))))
+ (unless (or resume (eq transient--exitp 'replace))
+ (setq transient--showp nil))
+ (setq transient--exitp nil)
+ (setq transient--helpp nil)
+ (setq transient--editp nil)
+ (setq transient--all-levels-p nil)
+ (setq transient--minibuffer-depth 0)
+ (run-hooks 'transient-exit-hook)
+ (when resume
+ (transient--stack-pop))))
+
+(defun transient--stack-push ()
+ (transient--debug 'stack-push)
+ (push (list (oref transient--prefix command)
+ transient--layout
+ transient--editp
+ :transient-suffix (oref transient--prefix transient-suffix)
+ :scope (oref transient--prefix scope))
+ transient--stack))
+
+(defun transient--stack-pop ()
+ (transient--debug 'stack-pop)
+ (and transient--stack
+ (prog1 t (apply #'transient-setup (pop transient--stack)))))
+
+(defun transient--stack-zap ()
+ (transient--debug 'stack-zap)
+ (setq transient--stack nil))
+
+(defun transient--redisplay ()
+ (if (or (eq transient-show-popup t)
+ transient--showp)
+ (unless
+ (or (memq this-command transient--scroll-commands)
+ (and (or (memq this-command '(mouse-drag-region
+ mouse-set-region))
+ (equal (key-description (this-command-keys-vector))
+ "<mouse-movement>"))
+ (and (eq (current-buffer)
+ (get-buffer transient--buffer-name)))))
+ (transient--show))
+ (when (and (numberp transient-show-popup)
+ (not (zerop transient-show-popup))
+ (not transient--timer))
+ (transient--timer-start))
+ (transient--show-brief)))
+
+(defun transient--timer-start ()
+ (setq transient--timer
+ (run-at-time (abs transient-show-popup) nil
+ (lambda ()
+ (transient--timer-cancel)
+ (transient--show)
+ (let ((message-log-max nil))
+ (message ""))))))
+
+(defun transient--timer-cancel ()
+ (when transient--timer
+ (cancel-timer transient--timer)
+ (setq transient--timer nil)))
+
+(defun transient--debug (arg &rest args)
+ (when transient--debug
+ (let ((inhibit-message (not (eq transient--debug 'message))))
+ (if (symbolp arg)
+ (message "-- %-22s (cmd: %s, event: %S, exit: %s%s)"
+ arg
+ (or (and (symbolp this-command) this-command)
+ (if (byte-code-function-p this-command)
+ "#[...]"
+ this-command))
+ (key-description (this-command-keys-vector))
+ transient--exitp
+ (cond ((keywordp (car args))
+ (format ", from: %s"
+ (substring (symbol-name (car args)) 1)))
+ ((stringp (car args))
+ (concat ", " (apply #'format args)))
+ ((functionp (car args))
+ (concat ", " (apply (car args) (cdr args))))
+ ("")))
+ (apply #'message arg args)))))
+
+(defun transient--emergency-exit (&optional id)
+ "Exit the current transient command after an error occurred.
+When no transient is active (i.e., when `transient--prefix' is
+nil) then do nothing. Optional ID is a keyword identifying the
+exit."
+ (transient--debug 'emergency-exit id)
+ (when transient--prefix
+ (setq transient--stack nil)
+ (setq transient--exitp t)
+ (transient--pre-exit)
+ (transient--post-exit)))
+
+;;; Pre-Commands
+
+(defun transient--call-pre-command ()
+ (if-let ((fn (transient--get-pre-command this-command)))
+ (let ((action (funcall fn)))
+ (when (eq action transient--exit)
+ (setq transient--exitp (or transient--exitp t)))
+ action)
+ (if (let ((keys (this-command-keys-vector)))
+ (eq (aref keys (1- (length keys))) ?\C-g))
+ (setq this-command 'transient-noop)
+ (unless (transient--edebug-command-p)
+ (setq this-command 'transient-undefined)))
+ transient--stay))
+
+(defun transient--get-pre-command (&optional cmd enforce-type)
+ (or (and (not (eq enforce-type 'non-suffix))
+ (symbolp cmd)
+ (lookup-key transient--predicate-map (vector cmd)))
+ (and (not (eq enforce-type 'suffix))
+ (transient--resolve-pre-command
+ (oref transient--prefix transient-non-suffix)
+ t))))
+
+(defun transient--resolve-pre-command (pre &optional resolve-boolean)
+ (cond ((booleanp pre)
+ (if resolve-boolean
+ (if pre #'transient--do-stay #'transient--do-warn)
+ pre))
+ ((string-match-p "--do-" (symbol-name pre)) pre)
+ ((let ((sym (intern (format "transient--do-%s" pre))))
+ (if (functionp sym) sym pre)))))
+
+(defun transient--do-stay ()
+ "Call the command without exporting variables and stay transient."
+ transient--stay)
+
+(defun transient--do-noop ()
+ "Call `transient-noop' and stay transient."
+ (setq this-command 'transient-noop)
+ transient--stay)
+
+(defun transient--do-warn ()
+ "Call `transient-undefined' and stay transient."
+ (setq this-command 'transient-undefined)
+ transient--stay)
+
+(defun transient--do-warn-inapt ()
+ "Call `transient-inapt' and stay transient."
+ (setq this-command 'transient-inapt)
+ transient--stay)
+
+(defun transient--do-call ()
+ "Call the command after exporting variables and stay transient."
+ (transient--export)
+ transient--stay)
+
+(defun transient--do-return ()
+ "Call the command after exporting variables and return to parent prefix.
+If there is no parent prefix, then behave like `transient--do-exit'."
+ (if (not transient--stack)
+ (transient--do-exit)
+ (transient--export)
+ transient--exit))
+
+(defun transient--do-exit ()
+ "Call the command after exporting variables and exit the transient."
+ (transient--export)
+ (transient--stack-zap)
+ transient--exit)
+
+(defun transient--do-leave ()
+ "Call the command without exporting variables and exit the transient."
+ (transient--stack-zap)
+ transient--exit)
+
+(defun transient--do-push-button ()
+ "Call the command represented by the activated button.
+Use that command's pre-command to determine transient behavior."
+ (if (and (mouse-event-p last-command-event)
+ (not (eq (posn-window (event-start last-command-event))
+ transient--window)))
+ transient--stay
+ (setq this-command
+ (with-selected-window transient--window
+ (get-text-property (if (mouse-event-p last-command-event)
+ (posn-point (event-start last-command-event))
+ (point))
+ 'command)))
+ (transient--call-pre-command)))
+
+(defun transient--do-recurse ()
+ "Call the transient prefix command, preparing for return to active transient.
+If there is no parent prefix, then just call the command."
+ (transient--do-stack))
+
+(defun transient--setup-recursion (prefix-obj)
+ (when transient--stack
+ (let ((command (oref prefix-obj command)))
+ (when-let ((suffix-obj (transient-suffix-object command)))
+ (when (memq (if (slot-boundp suffix-obj 'transient)
+ (oref suffix-obj transient)
+ (oref transient-current-prefix transient-suffix))
+ (list t #'transient--do-recurse))
+ (oset prefix-obj transient-suffix t))))))
+
+(defun transient--do-stack ()
+ "Call the transient prefix command, stacking the active transient.
+Push the active transient to the transient stack."
+ (transient--export)
+ (transient--stack-push)
+ (setq transient--exitp 'replace)
+ transient--exit)
+
+(defun transient--do-replace ()
+ "Call the transient prefix command, replacing the active transient.
+Do not push the active transient to the transient stack."
+ (transient--export)
+ (setq transient--exitp 'replace)
+ transient--exit)
+
+(defun transient--do-suspend ()
+ "Suspend the active transient, saving the transient stack."
+ (transient--stack-push)
+ (setq transient--exitp 'suspend)
+ transient--exit)
+
+(defun transient--do-quit-one ()
+ "If active, quit help or edit mode, else exit the active transient."
+ (cond (transient--helpp
+ (setq transient--helpp nil)
+ transient--stay)
+ (transient--editp
+ (setq transient--editp nil)
+ (transient-setup)
+ transient--stay)
+ (prefix-arg
+ transient--stay)
+ (transient--exit)))
+
+(defun transient--do-quit-all ()
+ "Exit all transients without saving the transient stack."
+ (transient--stack-zap)
+ transient--exit)
+
+(defun transient--do-move ()
+ "Call the command if `transient-enable-popup-navigation' is non-nil.
+In that case behave like `transient--do-stay', otherwise similar
+to `transient--do-warn'."
+ (unless transient-enable-popup-navigation
+ (setq this-command 'transient-inhibit-move))
+ transient--stay)
+
+(defun transient--do-minus ()
+ "Call `negative-argument' or pivot to `transient-update'.
+If `negative-argument' is invoked using \"-\" then preserve the
+prefix argument and pivot to `transient-update'."
+ (when (equal (this-command-keys) "-")
+ (setq this-command 'transient-update))
+ transient--stay)
+
+(put 'transient--do-stay 'transient-face 'transient-key-stay)
+(put 'transient--do-noop 'transient-face 'transient-key-noop)
+(put 'transient--do-warn 'transient-face 'transient-key-noop)
+(put 'transient--do-warn-inapt 'transient-face 'transient-key-noop)
+(put 'transient--do-call 'transient-face 'transient-key-stay)
+(put 'transient--do-return 'transient-face 'transient-key-return)
+(put 'transient--do-exit 'transient-face 'transient-key-exit)
+(put 'transient--do-leave 'transient-face 'transient-key-exit)
+
+(put 'transient--do-recurse 'transient-face 'transient-key-stay)
+(put 'transient--do-stack 'transient-face 'transient-key-stay)
+(put 'transient--do-replace 'transient-face 'transient-key-exit)
+(put 'transient--do-suspend 'transient-face 'transient-key-exit)
+
+(put 'transient--do-quit-one 'transient-face 'transient-key-return)
+(put 'transient--do-quit-all 'transient-face 'transient-key-exit)
+(put 'transient--do-move 'transient-face 'transient-key-stay)
+(put 'transient--do-minus 'transient-face 'transient-key-stay)
+
+;;; Commands
+;;;; Noop
+
+(defun transient-noop ()
+ "Do nothing at all."
+ (interactive))
+
+(defun transient-undefined ()
+ "Warn the user that the pressed key is not bound to any suffix."
+ (interactive)
+ (transient--invalid "Unbound suffix"))
+
+(defun transient-inapt ()
+ "Warn the user that the invoked command is inapt."
+ (interactive)
+ (transient--invalid "Inapt command"))
+
+(defun transient--invalid (msg)
+ (ding)
+ (message "%s: `%s' (Use `%s' to abort, `%s' for help)%s"
+ msg
+ (propertize (key-description (this-single-command-keys))
+ 'face 'font-lock-warning-face)
+ (propertize "C-g" 'face 'transient-key)
+ (propertize "?" 'face 'transient-key)
+ ;; `this-command' is `transient-undefined' or `transient-inapt'.
+ ;; Show the command (`this-original-command') the user actually
+ ;; tried to invoke.
+ (if-let ((cmd (or (ignore-errors (symbol-name this-original-command))
+ (ignore-errors (symbol-name this-command)))))
+ (format " [%s]" (propertize cmd 'face 'font-lock-warning-face))
+ ""))
+ (unless (and transient--transient-map
+ (memq transient--transient-map overriding-terminal-local-map))
+ (let ((transient--prefix (or transient--prefix 'sic)))
+ (transient--emergency-exit))
+ (view-lossage)
+ (other-window 1)
+ (display-warning 'transient "Inconsistent transient state detected.
+This should never happen.
+Please open an issue and post the shown command log." :error)))
+
+(defun transient-inhibit-move ()
+ "Warn the user that popup navigation is disabled."
+ (interactive)
+ (message "To enable use of `%s', please customize `%s'"
+ this-original-command
+ 'transient-enable-popup-navigation))
+
+;;;; Core
+
+(defun transient-quit-all ()
+ "Exit all transients without saving the transient stack."
+ (interactive))
+
+(defun transient-quit-one ()
+ "Exit the current transients, returning to outer transient, if any."
+ (interactive))
+
+(defun transient-quit-seq ()
+ "Abort the current incomplete key sequence."
+ (interactive))
+
+(defun transient-update ()
+ "Redraw the transient's state in the popup buffer."
+ (interactive)
+ (setq prefix-arg current-prefix-arg))
+
+(defun transient-show ()
+ "Show the transient's state in the popup buffer."
+ (interactive)
+ (setq transient--showp t))
+
+(defun transient-push-button ()
+ "Invoke the suffix command represented by this button."
+ (interactive))
+
+;;;; Suspend
+
+(defun transient-suspend ()
+ "Suspend the current transient.
+It can later be resumed using `transient-resume', while no other
+transient is active."
+ (interactive))
+
+(define-minor-mode transient-resume-mode
+ "Auxiliary minor-mode used to resume a transient after viewing help.")
+
+(defun transient-resume ()
+ "Resume a previously suspended stack of transients."
+ (interactive)
+ (cond (transient--stack
+ (let ((winconf transient--restore-winconf))
+ (kill-local-variable 'transient--restore-winconf)
+ (when transient-resume-mode
+ (transient-resume-mode -1)
+ (quit-window))
+ (when winconf
+ (set-window-configuration winconf)))
+ (transient--stack-pop))
+ (transient-resume-mode
+ (kill-local-variable 'transient--restore-winconf)
+ (transient-resume-mode -1)
+ (quit-window))
+ (t
+ (message "No suspended transient command"))))
+
+;;;; Help
+
+(defun transient-help (&optional interactive)
+ "Show help for the active transient or one of its suffixes.\n\n(fn)"
+ (interactive (list t))
+ (if interactive
+ (setq transient--helpp t)
+ (with-demoted-errors "transient-help: %S"
+ (when (lookup-key transient--transient-map
+ (this-single-command-raw-keys))
+ (setq transient--helpp nil)
+ (let ((winconf (current-window-configuration)))
+ (transient-show-help
+ (if (eq this-original-command 'transient-help)
+ transient--prefix
+ (or (transient-suffix-object)
+ this-original-command)))
+ (setq-local transient--restore-winconf winconf))
+ (fit-window-to-buffer nil (frame-height) (window-height))
+ (transient-resume-mode)
+ (message (substitute-command-keys
+ "Type \\`q' to resume transient command."))
+ t))))
+
+;;;; Level
+
+(defun transient-set-level (&optional command level)
+ "Set the level of the transient or one of its suffix commands."
+ (interactive
+ (let ((command this-original-command)
+ (prefix (oref transient--prefix command)))
+ (and (or (not (eq command 'transient-set-level))
+ (and transient--editp
+ (setq command prefix)))
+ (list command
+ (let ((keys (this-single-command-raw-keys)))
+ (and (lookup-key transient--transient-map keys)
+ (progn
+ (transient--show)
+ (string-to-number
+ (transient--read-number-N
+ (format "Set level for `%s': " command)
+ nil nil (not (eq command prefix)))))))))))
+ (cond
+ ((not command)
+ (setq transient--editp t)
+ (transient-setup))
+ (level
+ (let* ((prefix (oref transient--prefix command))
+ (alist (alist-get prefix transient-levels))
+ (akey command))
+ (cond ((eq command prefix)
+ (oset transient--prefix level level)
+ (setq akey t))
+ (t
+ (oset (transient-suffix-object command) level level)
+ (when (cdr (cl-remove-if-not (lambda (obj)
+ (eq (oref obj command) command))
+ transient--suffixes))
+ (setq akey (cons command (this-command-keys))))))
+ (setf (alist-get akey alist) level)
+ (setf (alist-get prefix transient-levels) alist))
+ (transient-save-levels)
+ (transient--show))
+ (t
+ (transient-undefined))))
+
+(transient-define-suffix transient-toggle-level-limit ()
+ "Toggle whether to temporarily displayed suffixes on all levels."
+ :description
+ (lambda ()
+ (cond
+ ((= transient-default-level transient--max-level)
+ "Always displaying all levels")
+ (transient--all-levels-p
+ (format "Hide suffix %s"
+ (propertize
+ (format "levels > %s" (oref (transient-prefix-object) level))
+ 'face 'transient-higher-level)))
+ ("Show all suffix levels")))
+ :inapt-if (lambda () (= transient-default-level transient--max-level))
+ :transient t
+ (interactive)
+ (setq transient--all-levels-p (not transient--all-levels-p))
+ (setq transient--refreshp t))
+
+;;;; Value
+
+(defun transient-set ()
+ "Set active transient's value for this Emacs session."
+ (interactive)
+ (transient-set-value (transient-prefix-object)))
+
+(defalias 'transient-set-and-exit 'transient-set
+ "Set active transient's value for this Emacs session and exit.")
+
+(defun transient-save ()
+ "Save active transient's value for this and future Emacs sessions."
+ (interactive)
+ (transient-save-value (transient-prefix-object)))
+
+(defalias 'transient-save-and-exit 'transient-save
+ "Save active transient's value for this and future Emacs sessions and exit.")
+
+(defun transient-reset ()
+ "Clear the set and saved values of the active transient."
+ (interactive)
+ (transient-reset-value (transient-prefix-object)))
+
+(defun transient-history-next ()
+ "Switch to the next value used for the active transient."
+ (interactive)
+ (let* ((obj transient--prefix)
+ (pos (1- (oref obj history-pos)))
+ (hst (oref obj history)))
+ (if (< pos 0)
+ (user-error "End of history")
+ (oset obj history-pos pos)
+ (oset obj value (nth pos hst))
+ (mapc #'transient-init-value transient--suffixes))))
+
+(defun transient-history-prev ()
+ "Switch to the previous value used for the active transient."
+ (interactive)
+ (let* ((obj transient--prefix)
+ (pos (1+ (oref obj history-pos)))
+ (hst (oref obj history))
+ (len (length hst)))
+ (if (> pos (1- len))
+ (user-error "End of history")
+ (oset obj history-pos pos)
+ (oset obj value (nth pos hst))
+ (mapc #'transient-init-value transient--suffixes))))
+
+;;;; Auxiliary
+
+(defun transient-toggle-common ()
+ "Toggle whether common commands are permanently shown."
+ (interactive)
+ (setq transient-show-common-commands (not transient-show-common-commands)))
+
+(defun transient-toggle-debug ()
+ "Toggle debugging statements for transient commands."
+ (interactive)
+ (setq transient--debug (not transient--debug))
+ (message "Debugging transient %s"
+ (if transient--debug "enabled" "disabled")))
+
+(transient-define-suffix transient-echo-arguments (arguments)
+ "Show the transient's active ARGUMENTS in the echo area.
+Intended for use in prefixes used for demonstration purposes,
+such as when suggesting a new feature or reporting an issue."
+ :transient t
+ :description "Echo arguments"
+ :key "x"
+ (interactive (list (transient-args transient-current-command)))
+ (message "%s: %s"
+ (key-description (this-command-keys))
+ (mapconcat (lambda (arg)
+ (propertize (if (string-match-p " " arg)
+ (format "%S" arg)
+ arg)
+ 'face 'transient-argument))
+ arguments " ")))
+
+;;; Value
+;;;; Init
+
+(cl-defgeneric transient-init-scope (obj)
+ "Set the scope of the suffix object OBJ.
+
+The scope is actually a property of the transient prefix, not of
+individual suffixes. However it is possible to invoke a suffix
+command directly instead of from a transient. In that case, if
+the suffix expects a scope, then it has to determine that itself
+and store it in its `scope' slot.
+
+This function is called for all suffix commands, but unless a
+concrete method is implemented this falls through to the default
+implementation, which is a noop.")
+
+(cl-defmethod transient-init-scope ((_ transient-suffix))
+ "Noop." nil)
+
+(cl-defgeneric transient-init-value (_)
+ "Set the initial value of the object OBJ.
+
+This function is called for all prefix and suffix commands.
+
+For suffix commands (including infix argument commands) the
+default implementation is a noop. Classes derived from the
+abstract `transient-infix' class must implement this function.
+Non-infix suffix commands usually don't have a value."
+ nil)
+
+(cl-defmethod transient-init-value :around ((obj transient-prefix))
+ "If bound, then call OBJ's `init-value' function.
+Otherwise call the primary method according to object's class."
+ (if (slot-boundp obj 'init-value)
+ (funcall (oref obj init-value) obj)
+ (cl-call-next-method obj)))
+
+(cl-defmethod transient-init-value :around ((obj transient-infix))
+ "If bound, then call OBJ's `init-value' function.
+Otherwise call the primary method according to object's class."
+ (if (slot-boundp obj 'init-value)
+ (funcall (oref obj init-value) obj)
+ (cl-call-next-method obj)))
+
+(cl-defmethod transient-init-value ((obj transient-prefix))
+ (if (slot-boundp obj 'value)
+ (oref obj value)
+ (oset obj value
+ (if-let ((saved (assq (oref obj command) transient-values)))
+ (cdr saved)
+ (transient-default-value obj)))))
+
+(cl-defmethod transient-init-value ((obj transient-argument))
+ (oset obj value
+ (let ((value (oref transient--prefix value))
+ (argument (and (slot-boundp obj 'argument)
+ (oref obj argument)))
+ (multi-value (oref obj multi-value))
+ (case-fold-search nil)
+ (regexp (if (slot-exists-p obj 'argument-regexp)
+ (oref obj argument-regexp)
+ (format "\\`%s\\(.*\\)" (oref obj argument)))))
+ (if (memq multi-value '(t rest))
+ (cdr (assoc argument value))
+ (let ((match (lambda (v)
+ (and (stringp v)
+ (string-match regexp v)
+ (match-string 1 v)))))
+ (if multi-value
+ (delq nil (mapcar match value))
+ (cl-some match value)))))))
+
+(cl-defmethod transient-init-value ((obj transient-switch))
+ (oset obj value
+ (car (member (oref obj argument)
+ (oref transient--prefix value)))))
+
+;;;; Default
+
+(cl-defgeneric transient-default-value (_)
+ "Return the default value."
+ nil)
+
+(cl-defmethod transient-default-value ((obj transient-prefix))
+ (if-let ((default (and (slot-boundp obj 'default-value)
+ (oref obj default-value))))
+ (if (functionp default)
+ (funcall default)
+ default)
+ nil))
+
+;;;; Read
+
+(cl-defgeneric transient-infix-read (obj)
+ "Determine the new value of the infix object OBJ.
+
+This function merely determines the value; `transient-infix-set'
+is used to actually store the new value in the object.
+
+For most infix classes this is done by reading a value from the
+user using the reader specified by the `reader' slot (using the
+`transient-infix' method described below).
+
+For some infix classes the value is changed without reading
+anything in the minibuffer, i.e., the mere act of invoking the
+infix command determines what the new value should be, based
+on the previous value.")
+
+(cl-defmethod transient-infix-read :around ((obj transient-infix))
+ "Refresh the transient buffer and call the next method.
+
+Also wrap `cl-call-next-method' with two macros:
+- `transient--with-suspended-override' allows use of minibuffer.
+- `transient--with-emergency-exit' arranges for the transient to
+ be exited in case of an error."
+ (transient--show)
+ (transient--with-emergency-exit :infix-read
+ (transient--with-suspended-override
+ (cl-call-next-method obj))))
+
+(cl-defmethod transient-infix-read ((obj transient-infix))
+ "Read a value while taking care of history.
+
+This method is suitable for a wide variety of infix commands,
+including but not limited to inline arguments and variables.
+
+If you do not use this method for your own infix class, then
+you should likely replicate a lot of the behavior of this
+method. If you fail to do so, then users might not appreciate
+the lack of history, for example.
+
+Only for very simple classes that toggle or cycle through a very
+limited number of possible values should you replace this with a
+simple method that does not handle history. (E.g., for a command
+line switch the only possible values are \"use it\" and \"don't use
+it\", in which case it is pointless to preserve history.)"
+ (with-slots (value multi-value always-read allow-empty choices) obj
+ (if (and value
+ (not multi-value)
+ (not always-read)
+ transient--prefix)
+ (oset obj value nil)
+ (let* ((enable-recursive-minibuffers t)
+ (reader (oref obj reader))
+ (choices (if (functionp choices) (funcall choices) choices))
+ (prompt (transient-prompt obj))
+ (value (if multi-value (mapconcat #'identity value ",") value))
+ (history-key (or (oref obj history-key)
+ (oref obj command)))
+ (transient--history (alist-get history-key transient-history))
+ (transient--history (if (or (null value)
+ (eq value (car transient--history)))
+ transient--history
+ (cons value transient--history)))
+ (initial-input (and transient-read-with-initial-input
+ (car transient--history)))
+ (history (if initial-input
+ (cons 'transient--history 1)
+ 'transient--history))
+ (value
+ (cond
+ (reader (funcall reader prompt initial-input history))
+ (multi-value
+ (completing-read-multiple prompt choices nil nil
+ initial-input history))
+ (choices
+ (completing-read prompt choices nil t initial-input history))
+ ((read-string prompt initial-input history)))))
+ (cond ((and (equal value "") (not allow-empty))
+ (setq value nil))
+ ((and (equal value "\"\"") allow-empty)
+ (setq value "")))
+ (when value
+ (when (and (bound-and-true-p ivy-mode)
+ (stringp (car transient--history)))
+ (set-text-properties 0 (length (car transient--history)) nil
+ (car transient--history)))
+ (setf (alist-get history-key transient-history)
+ (delete-dups transient--history)))
+ value))))
+
+(cl-defmethod transient-infix-read ((obj transient-switch))
+ "Toggle the switch on or off."
+ (if (oref obj value) nil (oref obj argument)))
+
+(cl-defmethod transient-infix-read ((obj transient-switches))
+ "Cycle through the mutually exclusive switches.
+The last value is \"don't use any of these switches\"."
+ (let ((choices (mapcar (apply-partially #'format (oref obj argument-format))
+ (oref obj choices))))
+ (if-let ((value (oref obj value)))
+ (cadr (member value choices))
+ (car choices))))
+
+(cl-defmethod transient-infix-read ((command symbol))
+ "Elsewhere use the reader of the infix command COMMAND.
+Use this if you want to share an infix's history with a regular
+stand-alone command."
+ (if-let ((obj (transient--suffix-prototype command)))
+ (cl-letf (((symbol-function #'transient--show) #'ignore))
+ (transient-infix-read obj))
+ (error "Not a suffix command: `%s'" command)))
+
+;;;; Readers
+
+(defun transient-read-file (prompt _initial-input _history)
+ "Read a file."
+ (file-local-name (expand-file-name (read-file-name prompt))))
+
+(defun transient-read-existing-file (prompt _initial-input _history)
+ "Read an existing file."
+ (file-local-name (expand-file-name (read-file-name prompt nil nil t))))
+
+(defun transient-read-directory (prompt _initial-input _history)
+ "Read a directory."
+ (file-local-name (expand-file-name (read-directory-name prompt))))
+
+(defun transient-read-existing-directory (prompt _initial-input _history)
+ "Read an existing directory."
+ (file-local-name (expand-file-name (read-directory-name prompt nil nil t))))
+
+(defun transient-read-number-N0 (prompt initial-input history)
+ "Read a natural number (including zero) and return it as a string."
+ (transient--read-number-N prompt initial-input history t))
+
+(defun transient-read-number-N+ (prompt initial-input history)
+ "Read a natural number (excluding zero) and return it as a string."
+ (transient--read-number-N prompt initial-input history nil))
+
+(defun transient--read-number-N (prompt initial-input history include-zero)
+ (save-match-data
+ (cl-block nil
+ (while t
+ (let ((str (read-from-minibuffer prompt initial-input nil nil history)))
+ (when (or (string-equal str "")
+ (string-match-p (if include-zero
+ "\\`\\(0\\|[1-9][0-9]*\\)\\'"
+ "\\`[1-9][0-9]*\\'")
+ str))
+ (cl-return str)))
+ (message "Please enter a natural number (%s zero)."
+ (if include-zero "including" "excluding"))
+ (sit-for 1)))))
+
+(defun transient-read-date (prompt default-time _history)
+ "Read a date using `org-read-date' (which see)."
+ (require 'org)
+ (when (fboundp 'org-read-date)
+ (org-read-date 'with-time nil nil prompt default-time)))
+
+;;;; Prompt
+
+(cl-defgeneric transient-prompt (obj)
+ "Return the prompt to be used to read infix object OBJ's value.")
+
+(cl-defmethod transient-prompt ((obj transient-infix))
+ "Return the prompt to be used to read infix object OBJ's value.
+
+This implementation should be suitable for almost all infix
+commands.
+
+If the value of OBJ's `prompt' slot is non-nil, then it must be
+a string or a function. If it is a string, then use that. If
+it is a function, then call that with OBJ as the only argument.
+That function must return a string, which is then used as the
+prompt.
+
+Otherwise, if the value of either the `argument' or `variable'
+slot of OBJ is a string, then base the prompt on that (preferring
+the former), appending either \"=\" (if it appears to be a
+command-line option) or \": \".
+
+Finally fall through to using \"(BUG: no prompt): \" as the
+prompt."
+ (if-let ((prompt (oref obj prompt)))
+ (let ((prompt (if (functionp prompt)
+ (funcall prompt obj)
+ prompt)))
+ (if (stringp prompt)
+ prompt
+ "(BUG: no prompt): "))
+ (or (and-let* ((arg (and (slot-boundp obj 'argument) (oref obj argument))))
+ (if (and (stringp arg) (string-suffix-p "=" arg))
+ arg
+ (concat arg ": ")))
+ (and-let* ((var (and (slot-boundp obj 'variable) (oref obj variable))))
+ (and (stringp var)
+ (concat var ": ")))
+ "(BUG: no prompt): ")))
+
+;;;; Set
+
+(cl-defgeneric transient-infix-set (obj value)
+ "Set the value of infix object OBJ to value.")
+
+(cl-defmethod transient-infix-set ((obj transient-infix) value)
+ "Set the value of infix object OBJ to value."
+ (oset obj value value))
+
+(cl-defmethod transient-infix-set :after ((obj transient-argument) value)
+ "Unset incompatible infix arguments."
+ (when-let* ((value)
+ (val (transient-infix-value obj))
+ (arg (if (slot-boundp obj 'argument)
+ (oref obj argument)
+ (oref obj argument-format)))
+ (spec (oref transient--prefix incompatible))
+ (filter (lambda (x rule)
+ (and (member x rule)
+ (remove x rule))))
+ (incomp (nconc
+ (cl-mapcan (apply-partially filter arg) spec)
+ (and (not (equal val arg))
+ (cl-mapcan (apply-partially filter val) spec)))))
+ (dolist (obj transient--suffixes)
+ (when-let* (((cl-typep obj 'transient-argument))
+ (val (transient-infix-value obj))
+ (arg (if (slot-boundp obj 'argument)
+ (oref obj argument)
+ (oref obj argument-format)))
+ ((if (equal val arg)
+ (member arg incomp)
+ (or (member val incomp)
+ (member arg incomp)))))
+ (transient-infix-set obj nil)))))
+
+(cl-defgeneric transient-set-value (obj)
+ "Set the value of the transient prefix OBJ.")
+
+(cl-defmethod transient-set-value ((obj transient-prefix))
+ (oset (oref obj prototype) value (transient-get-value))
+ (transient--history-push obj))
+
+;;;; Save
+
+(cl-defgeneric transient-save-value (obj)
+ "Save the value of the transient prefix OBJ.")
+
+(cl-defmethod transient-save-value ((obj transient-prefix))
+ (let ((value (transient-get-value)))
+ (oset (oref obj prototype) value value)
+ (setf (alist-get (oref obj command) transient-values) value)
+ (transient-save-values))
+ (transient--history-push obj))
+
+;;;; Reset
+
+(cl-defgeneric transient-reset-value (obj)
+ "Clear the set and saved values of the transient prefix OBJ.")
+
+(cl-defmethod transient-reset-value ((obj transient-prefix))
+ (let ((value (transient-default-value obj)))
+ (oset obj value value)
+ (oset (oref obj prototype) value value)
+ (setf (alist-get (oref obj command) transient-values nil 'remove) nil)
+ (transient-save-values))
+ (transient--history-push obj)
+ (mapc #'transient-init-value transient--suffixes))
+
+;;;; Get
+
+(defun transient-args (prefix)
+ "Return the value of the transient prefix command PREFIX.
+If the current command was invoked from the transient prefix
+command PREFIX, then return the active infix arguments. If
+the current command was not invoked from PREFIX, then return
+the set, saved or default value for PREFIX."
+ (cl-mapcan #'transient--get-wrapped-value (transient-suffixes prefix)))
+
+(defun transient-suffixes (prefix)
+ "Return the suffix objects of the transient prefix command PREFIX."
+ (if (eq transient-current-command prefix)
+ transient-current-suffixes
+ (let ((transient--prefix (transient--init-prefix prefix)))
+ (transient--flatten-suffixes
+ (transient--init-suffixes prefix)))))
+
+(defun transient-get-value ()
+ (transient--with-emergency-exit :get-value
+ (cl-mapcan (lambda (obj)
+ (and (or (not (slot-exists-p obj 'unsavable))
+ (not (oref obj unsavable)))
+ (transient--get-wrapped-value obj)))
+ transient-current-suffixes)))
+
+(defun transient--get-wrapped-value (obj)
+ (and-let* ((value (transient-infix-value obj)))
+ (pcase-exhaustive (and (slot-exists-p obj 'multi-value)
+ (oref obj multi-value))
+ ('nil (list value))
+ ((or 't 'rest) (list value))
+ ('repeat value))))
+
+(cl-defgeneric transient-infix-value (obj)
+ "Return the value of the suffix object OBJ.
+
+This function is called by `transient-args' (which see), meaning
+this function is how the value of a transient is determined so
+that the invoked suffix command can use it.
+
+Currently most values are strings, but that is not set in stone.
+Nil is not a value, it means \"no value\".
+
+Usually only infixes have a value, but see the method for
+`transient-suffix'.")
+
+(cl-defmethod transient-infix-value ((_ transient-suffix))
+ "Return nil, which means \"no value\".
+
+Infix arguments contribute the transient's value while suffix
+commands consume it. This function is called for suffixes anyway
+because a command that both contributes to the transient's value
+and also consumes it is not completely unconceivable.
+
+If you define such a command, then you must define a derived
+class and implement this function because this default method
+does nothing." nil)
+
+(cl-defmethod transient-infix-value ((obj transient-infix))
+ "Return the value of OBJ's `value' slot."
+ (oref obj value))
+
+(cl-defmethod transient-infix-value ((obj transient-option))
+ "Return ARGUMENT and VALUE as a unit or nil if the latter is nil."
+ (and-let* ((value (oref obj value)))
+ (let ((arg (oref obj argument)))
+ (pcase-exhaustive (oref obj multi-value)
+ ('nil (concat arg value))
+ ((or 't 'rest) (cons arg value))
+ ('repeat (mapcar (lambda (v) (concat arg v)) value))))))
+
+(cl-defmethod transient-infix-value ((_ transient-variable))
+ "Return nil, which means \"no value\".
+
+Setting the value of a variable is done by, well, setting the
+value of the variable. I.e., this is a side-effect and does
+not contribute to the value of the transient."
+ nil)
+
+;;;; Utilities
+
+(defun transient-arg-value (arg args)
+ "Return the value of ARG as it appears in ARGS.
+
+For a switch return a boolean. For an option return the value as
+a string, using the empty string for the empty value, or nil if
+the option does not appear in ARGS."
+ (if (string-suffix-p "=" arg)
+ (save-match-data
+ (and-let* ((match (let ((case-fold-search nil)
+ (re (format "\\`%s\\(?:=\\(.+\\)\\)?\\'"
+ (substring arg 0 -1))))
+ (cl-find-if (lambda (a)
+ (and (stringp a)
+ (string-match re a)))
+ args))))
+ (or (match-string 1 match) "")))
+ (and (member arg args) t)))
+
+(defun transient-scope ()
+ "Return the value of the `scope' slot of the current prefix."
+ (oref (transient-prefix-object) scope))
+
+;;; History
+
+(cl-defgeneric transient--history-key (obj)
+ "Return OBJ's history key.
+If the value of the `history-key' slot is non-nil, then return
+that. Otherwise return the value of the `command' slot."
+ (or (oref obj history-key)
+ (oref obj command)))
+
+(cl-defgeneric transient--history-push (obj)
+ "Push the current value of OBJ to its entry in `transient-history'."
+ (let ((key (transient--history-key obj)))
+ (setf (alist-get key transient-history)
+ (let ((args (transient-get-value)))
+ (cons args (delete args (alist-get key transient-history)))))))
+
+(cl-defgeneric transient--history-init (obj)
+ "Initialize OBJ's `history' slot.
+This is the transient-wide history; many individual infixes also
+have a history of their own.")
+
+(cl-defmethod transient--history-init ((obj transient-prefix))
+ "Initialize OBJ's `history' slot from the variable `transient-history'."
+ (let ((val (oref obj value)))
+ (oset obj history
+ (cons val (delete val (alist-get (transient--history-key obj)
+ transient-history))))))
+
+;;; Draw
+
+(defun transient--show-brief ()
+ (let ((message-log-max nil))
+ (if (and transient-show-popup (<= transient-show-popup 0))
+ (message "%s-" (key-description (this-command-keys)))
+ (message
+ "%s- [%s] %s"
+ (key-description (this-command-keys))
+ (oref transient--prefix command)
+ (mapconcat
+ #'identity
+ (sort
+ (cl-mapcan
+ (lambda (suffix)
+ (let ((key (kbd (oref suffix key))))
+ ;; Don't list any common commands.
+ (and (not (memq (oref suffix command)
+ `(,(lookup-key transient-map key)
+ ,(lookup-key transient-sticky-map key)
+ ;; From transient-common-commands:
+ transient-set
+ transient-save
+ transient-history-prev
+ transient-history-next
+ transient-quit-one
+ transient-toggle-common
+ transient-set-level)))
+ (list (propertize (oref suffix key) 'face 'transient-key)))))
+ transient--suffixes)
+ #'string<)
+ (propertize "|" 'face 'transient-delimiter))))))
+
+(defun transient--show ()
+ (transient--timer-cancel)
+ (setq transient--showp t)
+ (let ((transient--shadowed-buffer (current-buffer))
+ (buf (get-buffer-create transient--buffer-name))
+ (focus nil))
+ (with-current-buffer buf
+ (when transient-enable-popup-navigation
+ (setq focus (or (button-get (point) 'command)
+ (and (not (bobp))
+ (button-get (1- (point)) 'command))
+ (transient--heading-at-point))))
+ (erase-buffer)
+ (run-hooks 'transient-setup-buffer-hook)
+ (when transient-force-fixed-pitch
+ (transient--force-fixed-pitch))
+ (setq window-size-fixed t)
+ (when (bound-and-true-p tab-line-format)
+ (setq tab-line-format nil))
+ (setq header-line-format nil)
+ (setq mode-line-format
+ (if (or (natnump transient-mode-line-format)
+ (eq transient-mode-line-format 'line))
+ nil
+ transient-mode-line-format))
+ (setq mode-line-buffer-identification
+ (symbol-name (oref transient--prefix command)))
+ (if transient-enable-popup-navigation
+ (setq-local cursor-in-non-selected-windows 'box)
+ (setq cursor-type nil))
+ (setq display-line-numbers nil)
+ (setq show-trailing-whitespace nil)
+ (transient--insert-groups)
+ (when (or transient--helpp transient--editp)
+ (transient--insert-help))
+ (when-let ((line (transient--separator-line)))
+ (insert line)))
+ (unless (window-live-p transient--window)
+ (setq transient--window
+ (display-buffer buf transient-display-buffer-action)))
+ (when (window-live-p transient--window)
+ (with-selected-window transient--window
+ (goto-char (point-min))
+ (when transient-enable-popup-navigation
+ (transient--goto-button focus))
+ (transient--fit-window-to-buffer transient--window)))))
+
+(defun transient--fit-window-to-buffer (window)
+ (let ((window-resize-pixelwise t)
+ (window-size-fixed nil))
+ (if (eq (car (window-parameter window 'quit-restore)) 'other)
+ ;; Grow but never shrink window that previously displayed
+ ;; another buffer and is going to display that again.
+ (fit-window-to-buffer window nil (window-height window))
+ (fit-window-to-buffer window nil 1))))
+
+(defun transient--separator-line ()
+ (and-let* ((height (cond ((not window-system) nil)
+ ((natnump transient-mode-line-format)
+ transient-mode-line-format)
+ ((eq transient-mode-line-format 'line) 1)))
+ (face `(,@(and (>= emacs-major-version 27) '(:extend t))
+ :background
+ ,(or (face-foreground (transient--key-face nil 'non-suffix)
+ nil t)
+ "#gray60"))))
+ (concat (propertize "__" 'face face 'display `(space :height (,height)))
+ (propertize "\n" 'face face 'line-height t))))
+
+(defmacro transient-with-shadowed-buffer (&rest body)
+ "While in the transient buffer, temporarly make the shadowed buffer current."
+ (declare (indent 0) (debug t))
+ `(with-current-buffer (or transient--shadowed-buffer (current-buffer))
+ ,@body))
+
+(defun transient--insert-groups ()
+ (let ((groups (cl-mapcan (lambda (group)
+ (let ((hide (oref group hide)))
+ (and (not (and (functionp hide)
+ (transient-with-shadowed-buffer
+ (funcall hide))))
+ (list group))))
+ transient--layout))
+ group)
+ (while (setq group (pop groups))
+ (transient--insert-group group)
+ (when groups
+ (insert ?\n)))))
+
+(defvar transient--max-group-level 1)
+
+(cl-defgeneric transient--insert-group (group)
+ "Format GROUP and its elements and insert the result.")
+
+(cl-defmethod transient--insert-group :around ((group transient-group))
+ "Insert GROUP's description, if any."
+ (when-let ((desc (transient-with-shadowed-buffer
+ (transient-format-description group))))
+ (insert desc ?\n))
+ (let ((transient--max-group-level
+ (max (oref group level) transient--max-group-level))
+ (transient--pending-group group))
+ (cl-call-next-method group)))
+
+(cl-defmethod transient--insert-group ((group transient-row))
+ (transient--maybe-pad-keys group)
+ (dolist (suffix (oref group suffixes))
+ (insert (transient-with-shadowed-buffer (transient-format suffix)))
+ (insert " "))
+ (insert ?\n))
+
+(cl-defmethod transient--insert-group ((group transient-column))
+ (transient--maybe-pad-keys group)
+ (dolist (suffix (oref group suffixes))
+ (let ((str (transient-with-shadowed-buffer (transient-format suffix))))
+ (insert str)
+ (unless (string-match-p ".\n\\'" str)
+ (insert ?\n)))))
+
+(cl-defmethod transient--insert-group ((group transient-columns))
+ (let* ((columns
+ (mapcar
+ (lambda (column)
+ (transient--maybe-pad-keys column group)
+ (transient-with-shadowed-buffer
+ (let* ((transient--pending-group column)
+ (rows (mapcar #'transient-format (oref column suffixes))))
+ (when-let ((desc (transient-format-description column)))
+ (push desc rows))
+ (flatten-tree rows))))
+ (oref group suffixes)))
+ (vp (or (oref transient--prefix variable-pitch)
+ transient-align-variable-pitch))
+ (rs (apply #'max (mapcar #'length columns)))
+ (cs (length columns))
+ (cw (mapcar (let ((widths (oref transient--prefix column-widths)))
+ (lambda (col)
+ (apply
+ #'max
+ (if-let ((min (pop widths)))
+ (if vp (* min (transient--pixel-width " ")) min)
+ 0)
+ (mapcar (if vp #'transient--pixel-width #'length)
+ col))))
+ columns))
+ (cc (transient--seq-reductions-from
+ (apply-partially #'+ (* 3 (if vp (transient--pixel-width " ") 1)))
+ cw 0)))
+ (if transient-force-single-column
+ (dotimes (c cs)
+ (dotimes (r rs)
+ (when-let ((cell (nth r (nth c columns))))
+ (unless (equal cell "")
+ (insert cell ?\n))))
+ (unless (= c (1- cs))
+ (insert ?\n)))
+ (dotimes (r rs)
+ (dotimes (c cs)
+ (if vp
+ (progn
+ (when-let ((cell (nth r (nth c columns))))
+ (insert cell))
+ (if (= c (1- cs))
+ (insert ?\n)
+ (insert (propertize " " 'display
+ `(space :align-to (,(nth (1+ c) cc)))))))
+ (when (> c 0)
+ (insert (make-string (max 1 (- (nth c cc) (current-column)))
+ ?\s)))
+ (when-let ((cell (nth r (nth c columns))))
+ (insert cell))
+ (when (= c (1- cs))
+ (insert ?\n))))))))
+
+(cl-defmethod transient--insert-group ((group transient-subgroups))
+ (let* ((subgroups (oref group suffixes))
+ (n (length subgroups)))
+ (dotimes (s n)
+ (let ((subgroup (nth s subgroups)))
+ (transient--maybe-pad-keys subgroup group)
+ (transient--insert-group subgroup)
+ (when (< s (1- n))
+ (insert ?\n))))))
+
+(cl-defgeneric transient-format (obj)
+ "Format and return OBJ for display.
+
+When this function is called, then the current buffer is some
+temporary buffer. If you need the buffer from which the prefix
+command was invoked to be current, then do so by temporarily
+making `transient--original-buffer' current.")
+
+(cl-defmethod transient-format ((arg string))
+ "Return the string ARG after applying the `transient-heading' face."
+ (propertize arg 'face 'transient-heading))
+
+(cl-defmethod transient-format ((_ null))
+ "Return a string containing just the newline character."
+ "\n")
+
+(cl-defmethod transient-format ((arg integer))
+ "Return a string containing just the ARG character."
+ (char-to-string arg))
+
+(cl-defmethod transient-format :around ((obj transient-suffix))
+ "Add additional formatting if appropriate.
+When reading user input for this infix, then highlight it.
+When edit-mode is enabled, then prepend the level information.
+When `transient-enable-popup-navigation' is non-nil then format
+as a button."
+ (let ((str (cl-call-next-method obj)))
+ (when (and (cl-typep obj 'transient-infix)
+ (eq (oref obj command) this-original-command)
+ (active-minibuffer-window))
+ (setq str (transient--add-face str 'transient-active-infix)))
+ (when transient--editp
+ (setq str (concat (let ((level (oref obj level)))
+ (propertize (format " %s " level)
+ 'face (if (transient--use-level-p level t)
+ 'transient-enabled-suffix
+ 'transient-disabled-suffix)))
+ str)))
+ (when (and transient-enable-popup-navigation
+ (slot-boundp obj 'command))
+ (setq str (make-text-button str nil
+ 'type 'transient
+ 'command (oref obj command))))
+ str))
+
+(cl-defmethod transient-format ((obj transient-infix))
+ "Return a string generated using OBJ's `format'.
+%k is formatted using `transient-format-key'.
+%d is formatted using `transient-format-description'.
+%v is formatted using `transient-format-value'."
+ (format-spec (oref obj format)
+ `((?k . ,(transient-format-key obj))
+ (?d . ,(transient-format-description obj))
+ (?v . ,(transient-format-value obj)))))
+
+(cl-defmethod transient-format ((obj transient-suffix))
+ "Return a string generated using OBJ's `format'.
+%k is formatted using `transient-format-key'.
+%d is formatted using `transient-format-description'."
+ (format-spec (oref obj format)
+ `((?k . ,(transient-format-key obj))
+ (?d . ,(transient-format-description obj)))))
+
+(cl-defgeneric transient-format-key (obj)
+ "Format OBJ's `key' for display and return the result.")
+
+(cl-defmethod transient-format-key :around ((obj transient-suffix))
+ "Add `transient-inapt-suffix' face if suffix is inapt."
+ (let ((str (cl-call-next-method)))
+ (if (oref obj inapt)
+ (transient--add-face str 'transient-inapt-suffix)
+ str)))
+
+(cl-defmethod transient-format-key ((obj transient-suffix))
+ "Format OBJ's `key' for display and return the result."
+ (let ((key (if (slot-boundp obj 'key) (oref obj key) ""))
+ (cmd (and (slot-boundp obj 'command) (oref obj command))))
+ (when-let ((width (oref transient--pending-group pad-keys)))
+ (setq key (truncate-string-to-width key width nil ?\s)))
+ (if transient--redisplay-key
+ (let ((len (length transient--redisplay-key))
+ (seq (cl-coerce (edmacro-parse-keys key t) 'list)))
+ (cond
+ ((member (seq-take seq len)
+ (list transient--redisplay-key
+ (thread-last transient--redisplay-key
+ (cl-substitute ?- 'kp-subtract)
+ (cl-substitute ?= 'kp-equal)
+ (cl-substitute ?+ 'kp-add))))
+ (let ((pre (key-description (vconcat (seq-take seq len))))
+ (suf (key-description (vconcat (seq-drop seq len)))))
+ (setq pre (string-replace "RET" "C-m" pre))
+ (setq pre (string-replace "TAB" "C-i" pre))
+ (setq suf (string-replace "RET" "C-m" suf))
+ (setq suf (string-replace "TAB" "C-i" suf))
+ ;; We use e.g., "-k" instead of the more correct "- k",
+ ;; because the former is prettier. If we did that in
+ ;; the definition, then we want to drop the space that
+ ;; is reinserted above. False-positives are possible
+ ;; for silly bindings like "-C-c C-c".
+ (unless (string-search " " key)
+ (setq pre (string-replace " " "" pre))
+ (setq suf (string-replace " " "" suf)))
+ (concat (propertize pre 'face 'transient-unreachable-key)
+ (and (string-prefix-p (concat pre " ") key) " ")
+ (propertize suf 'face (transient--key-face cmd))
+ (save-excursion
+ (and (string-match " +\\'" key)
+ (propertize (match-string 0 key)
+ 'face 'fixed-pitch))))))
+ ((transient--lookup-key transient-sticky-map (kbd key))
+ (propertize key 'face (transient--key-face cmd)))
+ (t
+ (propertize key 'face 'transient-unreachable-key))))
+ (propertize key 'face (transient--key-face cmd)))))
+
+(cl-defmethod transient-format-key :around ((obj transient-argument))
+ "Handle `transient-highlight-mismatched-keys'."
+ (let ((key (cl-call-next-method obj)))
+ (cond
+ ((not transient-highlight-mismatched-keys) key)
+ ((not (slot-boundp obj 'shortarg))
+ (transient--add-face key 'transient-nonstandard-key))
+ ((not (string-equal key (oref obj shortarg)))
+ (transient--add-face key 'transient-mismatched-key))
+ (key))))
+
+(cl-defgeneric transient-format-description (obj)
+ "Format OBJ's `description' for display and return the result.")
+
+(cl-defmethod transient-format-description ((obj transient-child))
+ "The `description' slot may be a function, in which case that is
+called inside the correct buffer (see `transient--insert-group')
+and its value is returned to the caller."
+ (and-let* ((desc (oref obj description))
+ (desc (if (functionp desc)
+ (if (= (car (transient--func-arity desc)) 1)
+ (funcall desc obj)
+ (funcall desc))
+ desc)))
+ (if-let* ((face (transient--get-face obj 'face)))
+ (transient--add-face desc face t)
+ desc)))
+
+(cl-defmethod transient-format-description ((obj transient-group))
+ "Format the description by calling the next method. If the result
+doesn't use the `face' property at all, then apply the face
+`transient-heading' to the complete string."
+ (and-let* ((desc (cl-call-next-method obj)))
+ (if (text-property-not-all 0 (length desc) 'face nil desc)
+ desc
+ (propertize desc 'face 'transient-heading))))
+
+(cl-defmethod transient-format-description :around ((obj transient-suffix))
+ "Format the description by calling the next method. If the result
+is nil, then use \"(BUG: no description)\" as the description.
+If the OBJ's `key' is currently unreachable, then apply the face
+`transient-unreachable' to the complete string."
+ (let ((desc (or (cl-call-next-method obj)
+ (and (slot-boundp transient--prefix 'suffix-description)
+ (funcall (oref transient--prefix suffix-description)
+ obj))
+ (propertize "(BUG: no description)" 'face 'error))))
+ (when (if transient--all-levels-p
+ (> (oref obj level) transient--default-prefix-level)
+ (and transient-highlight-higher-levels
+ (> (max (oref obj level) transient--max-group-level)
+ transient--default-prefix-level)))
+ (setq desc (transient--add-face desc 'transient-higher-level)))
+ (when-let ((inapt-face (and (oref obj inapt)
+ (transient--get-face obj 'inapt-face))))
+ (setq desc (transient--add-face desc inapt-face)))
+ (when (and (slot-boundp obj 'key)
+ (transient--key-unreachable-p obj))
+ (setq desc (transient--add-face desc 'transient-unreachable)))
+ desc))
+
+(cl-defgeneric transient-format-value (obj)
+ "Format OBJ's value for display and return the result.")
+
+(cl-defmethod transient-format-value ((obj transient-suffix))
+ (propertize (oref obj argument)
+ 'face (if (oref obj value)
+ 'transient-argument
+ 'transient-inactive-argument)))
+
+(cl-defmethod transient-format-value ((obj transient-option))
+ (let ((argument (oref obj argument)))
+ (if-let ((value (oref obj value)))
+ (pcase-exhaustive (oref obj multi-value)
+ ('nil
+ (concat (propertize argument 'face 'transient-argument)
+ (propertize value 'face 'transient-value)))
+ ((or 't 'rest)
+ (concat (propertize (if (string-suffix-p " " argument)
+ argument
+ (concat argument " "))
+ 'face 'transient-argument)
+ (propertize (mapconcat #'prin1-to-string value " ")
+ 'face 'transient-value)))
+ ('repeat
+ (mapconcat (lambda (value)
+ (concat (propertize argument 'face 'transient-argument)
+ (propertize value 'face 'transient-value)))
+ value " ")))
+ (propertize argument 'face 'transient-inactive-argument))))
+
+(cl-defmethod transient-format-value ((obj transient-switches))
+ (with-slots (value argument-format choices) obj
+ (format (propertize argument-format
+ 'face (if value
+ 'transient-argument
+ 'transient-inactive-argument))
+ (format
+ (propertize "[%s]" 'face 'transient-delimiter)
+ (mapconcat
+ (lambda (choice)
+ (propertize choice 'face
+ (if (equal (format argument-format choice) value)
+ 'transient-value
+ 'transient-inactive-value)))
+ choices
+ (propertize "|" 'face 'transient-delimiter))))))
+
+(defun transient--add-face (string face &optional append beg end)
+ (let ((str (copy-sequence string)))
+ (add-face-text-property (or beg 0) (or end (length str)) face append str)
+ str))
+
+(defun transient--get-face (obj slot)
+ (and-let* (((slot-exists-p obj slot))
+ ((slot-boundp obj slot))
+ (face (slot-value obj slot)))
+ (if (and (not (facep face))
+ (functionp face))
+ (let ((transient--pending-suffix obj))
+ (if (= (car (transient--func-arity face)) 1)
+ (funcall face obj)
+ (funcall face)))
+ face)))
+
+(defun transient--key-face (&optional cmd enforce-type)
+ (or (and transient-semantic-coloring
+ (not transient--helpp)
+ (not transient--editp)
+ (or (and cmd (get cmd 'transient-face))
+ (get (transient--get-pre-command cmd enforce-type)
+ 'transient-face)))
+ (if cmd 'transient-key 'transient-key-noop)))
+
+(defun transient--key-unreachable-p (obj)
+ (and transient--redisplay-key
+ (let ((key (oref obj key)))
+ (not (or (equal (seq-take (cl-coerce (edmacro-parse-keys key t) 'list)
+ (length transient--redisplay-key))
+ transient--redisplay-key)
+ (transient--lookup-key transient-sticky-map (kbd key)))))))
+
+(defun transient--lookup-key (keymap key)
+ (let ((val (lookup-key keymap key)))
+ (and val (not (integerp val)) val)))
+
+(defun transient--maybe-pad-keys (group &optional parent)
+ (when-let ((pad (or (oref group pad-keys)
+ (and parent (oref parent pad-keys)))))
+ (oset group pad-keys
+ (apply #'max (cons (if (integerp pad) pad 0)
+ (seq-keep (lambda (suffix)
+ (and (eieio-object-p suffix)
+ (slot-boundp suffix 'key)
+ (length (oref suffix key))))
+ (oref group suffixes)))))))
+
+(defun transient--pixel-width (string)
+ (save-window-excursion
+ (with-temp-buffer
+ (insert string)
+ (set-window-dedicated-p nil nil)
+ (set-window-buffer nil (current-buffer))
+ (car (window-text-pixel-size
+ nil (line-beginning-position) (point))))))
+
+(defun transient-command-summary-or-name (obj)
+ "Return the summary or name of the command represented by OBJ.
+
+If the command has a doc-string, then return the first line of
+that, else its name.
+
+Intended to be temporarily used as the `:suffix-description' of
+a prefix command, while porting a regular keymap to a transient."
+ (let ((command (oref obj command)))
+ (if-let ((doc (documentation command)))
+ (propertize (car (split-string doc "\n")) 'face 'font-lock-doc-face)
+ (propertize (symbol-name command) 'face 'font-lock-function-name-face))))
+
+;;; Help
+
+(cl-defgeneric transient-show-help (obj)
+ "Show documentation for the command represented by OBJ.")
+
+(cl-defmethod transient-show-help ((obj transient-prefix))
+ "Call `show-help' if non-nil, else show `info-manual',
+if non-nil, else show the `man-page' if non-nil, else use
+`describe-function'."
+ (with-slots (show-help info-manual man-page command) obj
+ (cond (show-help (funcall show-help obj))
+ (info-manual (transient--show-manual info-manual))
+ (man-page (transient--show-manpage man-page))
+ ((transient--describe-function command)))))
+
+(cl-defmethod transient-show-help ((obj transient-suffix))
+ "Call `show-help' if non-nil, else use `describe-function'.
+Also used to dispatch showing documentation for the current
+prefix. If the suffix is a sub-prefix, then also call the
+prefix method."
+ (cond
+ ((eq this-command 'transient-help)
+ (transient-show-help transient--prefix))
+ ((let ((prefix (get (oref obj command)
+ 'transient--prefix)))
+ (and prefix (not (eq (oref transient--prefix command) this-command))
+ (prog1 t (transient-show-help prefix)))))
+ ((if-let ((show-help (oref obj show-help)))
+ (funcall show-help obj)
+ (transient--describe-function this-command)))))
+
+(cl-defmethod transient-show-help ((obj transient-infix))
+ "Call `show-help' if non-nil, else show the `man-page'
+if non-nil, else use `describe-function'. When showing the
+manpage, then try to jump to the correct location."
+ (if-let ((show-help (oref obj show-help)))
+ (funcall show-help obj)
+ (if-let ((man-page (oref transient--prefix man-page))
+ (argument (and (slot-boundp obj 'argument)
+ (oref obj argument))))
+ (transient--show-manpage man-page argument)
+ (transient--describe-function this-command))))
+
+;; `cl-generic-generalizers' doesn't support `command' et al.
+(cl-defmethod transient-show-help (cmd)
+ "Show the command doc-string."
+ (transient--describe-function cmd))
+
+(defun transient--describe-function (fn)
+ (describe-function fn)
+ (unless (derived-mode-p 'help-mode)
+ (when-let* ((buf (get-buffer "*Help*"))
+ (win (or (and buf (get-buffer-window buf))
+ (cl-find-if (lambda (win)
+ (with-current-buffer (window-buffer win)
+ (derived-mode-p 'help-mode)))
+ (window-list)))))
+ (select-window win))))
+
+(defun transient--show-manual (manual)
+ (info manual))
+
+(defun transient--show-manpage (manpage &optional argument)
+ (require 'man)
+ (let* ((Man-notify-method 'meek)
+ (buf (Man-getpage-in-background manpage))
+ (proc (get-buffer-process buf)))
+ (while (and proc (eq (process-status proc) 'run))
+ (accept-process-output proc))
+ (switch-to-buffer buf)
+ (when argument
+ (transient--goto-argument-description argument))))
+
+(defun transient--goto-argument-description (arg)
+ (goto-char (point-min))
+ (let ((case-fold-search nil)
+ ;; This matches preceding/proceeding options. Options
+ ;; such as "-a", "-S[<keyid>]", and "--grep=<pattern>"
+ ;; are matched by this regex without the shy group.
+ ;; The ". " in the shy group is for options such as
+ ;; "-m parent-number", and the "-[^[:space:]]+ " is
+ ;; for options such as "--mainline parent-number"
+ (others "-\\(?:. \\|-[^[:space:]]+ \\)?[^[:space:]]+"))
+ (when (re-search-forward
+ (if (equal arg "--")
+ ;; Special case.
+ "^[\t\s]+\\(--\\(?: \\|$\\)\\|\\[--\\]\\)"
+ ;; Should start with whitespace and may have
+ ;; any number of options before and/or after.
+ (format
+ "^[\t\s]+\\(?:%s, \\)*?\\(?1:%s\\)%s\\(?:, %s\\)*$"
+ others
+ ;; Options don't necessarily end in an "="
+ ;; (e.g., "--gpg-sign[=<keyid>]")
+ (string-remove-suffix "=" arg)
+ ;; Simple options don't end in an "=". Splitting this
+ ;; into 2 cases should make getting false positives
+ ;; less likely.
+ (if (string-suffix-p "=" arg)
+ ;; "[^[:space:]]*[^.[:space:]]" matches the option
+ ;; value, which is usually after the option name
+ ;; and either '=' or '[='. The value can't end in
+ ;; a period, as that means it's being used at the
+ ;; end of a sentence. The space is for options
+ ;; such as '--mainline parent-number'.
+ "\\(?: \\|\\[?=\\)[^[:space:]]*[^.[:space:]]"
+ ;; Either this doesn't match anything (e.g., "-a"),
+ ;; or the option is followed by a value delimited
+ ;; by a "[", "<", or ":". A space might appear
+ ;; before this value, as in "-f <file>". The
+ ;; space alternative is for options such as
+ ;; "-m parent-number".
+ "\\(?:\\(?: \\| ?[\\[<:]\\)[^[:space:]]*[^.[:space:]]\\)?")
+ others))
+ nil t)
+ (goto-char (match-beginning 1)))))
+
+(defun transient--insert-help ()
+ (unless (looking-back "\n\n" 2)
+ (insert "\n"))
+ (when transient--helpp
+ (insert
+ (format (propertize "\
+Type a %s to show help for that suffix command, or %s to show manual.
+Type %s to exit help.\n"
+ 'face 'transient-heading)
+ (propertize "<KEY>" 'face 'transient-key)
+ (propertize "?" 'face 'transient-key)
+ (propertize "C-g" 'face 'transient-key))))
+ (when transient--editp
+ (unless transient--helpp
+ (insert
+ (format (propertize "\
+Type a %s to set level for that suffix command.
+Type %s to set what levels are available for this prefix command.\n"
+ 'face 'transient-heading)
+ (propertize "<KEY>" 'face 'transient-key)
+ (propertize "C-x l" 'face 'transient-key))))
+ (with-slots (level) transient--prefix
+ (insert
+ (format (propertize "
+Suffixes on levels %s are available.
+Suffixes on levels %s and %s are unavailable.\n"
+ 'face 'transient-heading)
+ (propertize (format "1-%s" level)
+ 'face 'transient-enabled-suffix)
+ (propertize " 0 "
+ 'face 'transient-disabled-suffix)
+ (propertize (format ">=%s" (1+ level))
+ 'face 'transient-disabled-suffix))))))
+
+;;; Popup Navigation
+
+(defun transient-scroll-up (&optional arg)
+ "Scroll text of transient popup window upward ARG lines.
+If ARG is nil scroll near full screen. This is a wrapper
+around `scroll-up-command' (which see)."
+ (interactive "^P")
+ (with-selected-window transient--window
+ (scroll-up-command arg)))
+
+(defun transient-scroll-down (&optional arg)
+ "Scroll text of transient popup window down ARG lines.
+If ARG is nil scroll near full screen. This is a wrapper
+around `scroll-down-command' (which see)."
+ (interactive "^P")
+ (with-selected-window transient--window
+ (scroll-down-command arg)))
+
+(defun transient-backward-button (n)
+ "Move to the previous button in the transient popup buffer.
+See `backward-button' for information about N."
+ (interactive "p")
+ (with-selected-window transient--window
+ (backward-button n t)))
+
+(defun transient-forward-button (n)
+ "Move to the next button in the transient popup buffer.
+See `forward-button' for information about N."
+ (interactive "p")
+ (with-selected-window transient--window
+ (forward-button n t)))
+
+(define-button-type 'transient
+ 'face nil
+ 'keymap transient-button-map)
+
+(defun transient--goto-button (command)
+ (cond
+ ((stringp command)
+ (when (re-search-forward (concat "^" (regexp-quote command)) nil t)
+ (goto-char (match-beginning 0))))
+ (command
+ (while (and (ignore-errors (forward-button 1))
+ (not (eq (button-get (button-at (point)) 'command) command))))
+ (unless (eq (button-get (button-at (point)) 'command) command)
+ (goto-char (point-min))
+ (forward-button 1)))))
+
+(defun transient--heading-at-point ()
+ (and (eq (get-text-property (point) 'face) 'transient-heading)
+ (let ((beg (line-beginning-position)))
+ (buffer-substring-no-properties
+ beg (next-single-property-change
+ beg 'face nil (line-end-position))))))
+
+;;; Compatibility
+;;;; Popup Isearch
+
+(defvar-keymap transient--isearch-mode-map
+ :parent isearch-mode-map
+ "<remap> <isearch-exit>" #'transient-isearch-exit
+ "<remap> <isearch-cancel>" #'transient-isearch-cancel
+ "<remap> <isearch-abort>" #'transient-isearch-abort)
+
+(defun transient-isearch-backward (&optional regexp-p)
+ "Do incremental search backward.
+With a prefix argument, do an incremental regular expression
+search instead."
+ (interactive "P")
+ (transient--isearch-setup)
+ (let ((isearch-mode-map transient--isearch-mode-map))
+ (isearch-mode nil regexp-p)))
+
+(defun transient-isearch-forward (&optional regexp-p)
+ "Do incremental search forward.
+With a prefix argument, do an incremental regular expression
+search instead."
+ (interactive "P")
+ (transient--isearch-setup)
+ (let ((isearch-mode-map transient--isearch-mode-map))
+ (isearch-mode t regexp-p)))
+
+(defun transient-isearch-exit ()
+ "Like `isearch-exit' but adapted for `transient'."
+ (interactive)
+ (isearch-exit)
+ (transient--isearch-exit))
+
+(defun transient-isearch-cancel ()
+ "Like `isearch-cancel' but adapted for `transient'."
+ (interactive)
+ (condition-case nil (isearch-cancel) (quit))
+ (transient--isearch-exit))
+
+(defun transient-isearch-abort ()
+ "Like `isearch-abort' but adapted for `transient'."
+ (interactive)
+ (let ((around (lambda (fn)
+ (condition-case nil (funcall fn) (quit))
+ (transient--isearch-exit))))
+ (advice-add 'isearch-cancel :around around)
+ (unwind-protect
+ (isearch-abort)
+ (advice-remove 'isearch-cancel around))))
+
+(defun transient--isearch-setup ()
+ (select-window transient--window)
+ (transient--suspend-override t))
+
+(defun transient--isearch-exit ()
+ (select-window transient--original-window)
+ (transient--resume-override))
+
+;;;; Edebug
+
+(defun transient--edebug-command-p ()
+ (and (bound-and-true-p edebug-active)
+ (or (memq this-command '(top-level abort-recursive-edit))
+ (string-prefix-p "edebug" (symbol-name this-command)))))
+
+;;;; Miscellaneous
+
+(cl-pushnew (list nil (concat "^\\s-*("
+ (eval-when-compile
+ (regexp-opt
+ '("transient-define-prefix"
+ "transient-define-suffix"
+ "transient-define-infix"
+ "transient-define-argument")
+ t))
+ "\\s-+\\(" lisp-mode-symbol-regexp "\\)")
+ 2)
+ lisp-imenu-generic-expression :test #'equal)
+
+(declare-function which-key-mode "which-key" (&optional arg))
+
+(defun transient--suspend-which-key-mode ()
+ (when (bound-and-true-p which-key-mode)
+ (which-key-mode -1)
+ (add-hook 'transient-exit-hook #'transient--resume-which-key-mode)))
+
+(defun transient--resume-which-key-mode ()
+ (unless transient--prefix
+ (which-key-mode 1)
+ (remove-hook 'transient-exit-hook #'transient--resume-which-key-mode)))
+
+(defun transient-bind-q-to-quit ()
+ "Modify some keymaps to bind \"q\" to the appropriate quit command.
+
+\"C-g\" is the default binding for such commands now, but Transient's
+predecessor Magit-Popup used \"q\" instead. If you would like to get
+that binding back, then call this function in your init file like so:
+
+ (with-eval-after-load \\='transient
+ (transient-bind-q-to-quit))
+
+Individual transients may already bind \"q\" to something else
+and such a binding would shadow the quit binding. If that is the
+case then \"Q\" is bound to whatever \"q\" would have been bound
+to by setting `transient-substitute-key-function' to a function
+that does that. Of course \"Q\" may already be bound to something
+else, so that function binds \"M-q\" to that command instead.
+Of course \"M-q\" may already be bound to something else, but
+we stop there."
+ (keymap-set transient-base-map "q" #'transient-quit-one)
+ (keymap-set transient-sticky-map "q" #'transient-quit-seq)
+ (setq transient-substitute-key-function
+ #'transient-rebind-quit-commands))
+
+(defun transient-rebind-quit-commands (obj)
+ "See `transient-bind-q-to-quit'."
+ (let ((key (oref obj key)))
+ (cond ((string-equal key "q") "Q")
+ ((string-equal key "Q") "M-q")
+ (key))))
+
+(defun transient--force-fixed-pitch ()
+ (require 'face-remap)
+ (face-remap-reset-base 'default)
+ (face-remap-add-relative 'default 'fixed-pitch))
+
+(defun transient--func-arity (fn)
+ (func-arity (advice--cd*r (if (symbolp fn) (symbol-function fn) fn))))
+
+(defun transient--seq-reductions-from (function sequence initial-value)
+ (let ((acc (list initial-value)))
+ (seq-doseq (elt sequence)
+ (push (funcall function (car acc) elt) acc))
+ (nreverse acc)))
+
+;;; Font-Lock
+
+(defconst transient-font-lock-keywords
+ (eval-when-compile
+ `((,(concat "("
+ (regexp-opt (list "transient-define-prefix"
+ "transient-define-infix"
+ "transient-define-argument"
+ "transient-define-suffix")
+ t)
+ "\\_>[ \t'(]*"
+ "\\(\\(?:\\sw\\|\\s_\\)+\\)?")
+ (1 'font-lock-keyword-face)
+ (2 'font-lock-function-name-face nil t)))))
+
+(font-lock-add-keywords 'emacs-lisp-mode transient-font-lock-keywords)
+
+;;; Auxiliary Classes
+;;;; `transient-lisp-variable'
+
+(defclass transient-lisp-variable (transient-variable)
+ ((reader :initform #'transient-lisp-variable--reader)
+ (always-read :initform t)
+ (set-value :initarg :set-value :initform #'set))
+ "[Experimental] Class used for Lisp variables.")
+
+(cl-defmethod transient-init-value ((obj transient-lisp-variable))
+ (oset obj value (symbol-value (oref obj variable))))
+
+(cl-defmethod transient-infix-set ((obj transient-lisp-variable) value)
+ (funcall (oref obj set-value)
+ (oref obj variable)
+ (oset obj value value)))
+
+(cl-defmethod transient-format-description ((obj transient-lisp-variable))
+ (or (cl-call-next-method obj)
+ (symbol-name (oref obj variable))))
+
+(cl-defmethod transient-format-value ((obj transient-lisp-variable))
+ (propertize (prin1-to-string (oref obj value))
+ 'face 'transient-value))
+
+(cl-defmethod transient-prompt ((obj transient-lisp-variable))
+ (if (and (slot-boundp obj 'prompt)
+ (oref obj prompt))
+ (cl-call-next-method obj)
+ (format "Set %s: " (oref obj variable))))
+
+(defun transient-lisp-variable--reader (prompt initial-input _history)
+ (read--expression prompt initial-input))
+
+;;; _
+(provide 'transient)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; checkdoc-symbol-words: ("command-line" "edit-mode" "help-mode")
+;; End:
+;;; transient.el ends here
--- /dev/null
+This is transient.info, produced by makeinfo version 6.7 from
+transient.texi.
+
+ Copyright (C) 2018–2024 Free Software Foundation, Inc.
+
+ You can redistribute this document 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 document 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.
+
+INFO-DIR-SECTION Emacs misc features
+START-INFO-DIR-ENTRY
+* Transient: (transient). Transient Commands.
+END-INFO-DIR-ENTRY
+
+\1f
+File: transient.info, Node: Top, Next: Introduction, Up: (dir)
+
+Transient User and Developer Manual
+***********************************
+
+Transient is the library used to implement the keyboard-driven “menus”
+in Magit. It is distributed as a separate package, so that it can be
+used to implement similar menus in other packages.
+
+ This manual can be bit hard to digest when getting started. A useful
+resource to get over that hurdle is Psionic K’s interactive tutorial,
+available at <https://github.com/positron-solutions/transient-showcase>.
+
+This manual is for Transient version 0.6.0.
+
+ Copyright (C) 2018–2024 Free Software Foundation, Inc.
+
+ You can redistribute this document 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 document 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.
+
+* Menu:
+
+* Introduction::
+* Usage::
+* Modifying Existing Transients::
+* Defining New Commands::
+* Classes and Methods::
+* FAQ::
+* Keystroke Index::
+* Command and Function Index::
+* Variable Index::
+* Concept Index::
+* GNU General Public License::
+
+— The Detailed Node Listing —
+
+Usage
+
+* Invoking Transients::
+* Aborting and Resuming Transients::
+* Common Suffix Commands::
+* Saving Values::
+* Using History::
+* Getting Help for Suffix Commands::
+* Enabling and Disabling Suffixes::
+* Other Commands::
+* Configuration::
+
+Defining New Commands
+
+* Technical Introduction::
+* Defining Transients::
+* Binding Suffix and Infix Commands::
+* Defining Suffix and Infix Commands::
+* Using Infix Arguments::
+* Transient State::
+
+Binding Suffix and Infix Commands
+
+* Group Specifications::
+* Suffix Specifications::
+
+
+Classes and Methods
+
+* Group Classes::
+* Group Methods::
+* Prefix Classes::
+* Suffix Classes::
+* Suffix Methods::
+* Prefix Slots::
+* Suffix Slots::
+* Predicate Slots::
+
+Suffix Methods
+
+* Suffix Value Methods::
+* Suffix Format Methods::
+
+
+
+\1f
+File: transient.info, Node: Introduction, Next: Usage, Prev: Top, Up: Top
+
+1 Introduction
+**************
+
+Transient is the library used to implement the keyboard-driven “menus”
+in Magit. It is distributed as a separate package, so that it can be
+used to implement similar menus in other packages.
+
+ This manual can be bit hard to digest when getting started. A useful
+resource to get over that hurdle is Psionic K’s interactive tutorial,
+available at <https://github.com/positron-solutions/transient-showcase>.
+
+Some things that Transient can do
+=================================
+
+ • Display current state of arguments
+ • Display and manage lifecycle of modal bindings
+ • Contextual user interface
+ • Flow control for wizard-like composition of interactive forms
+ • History & persistence
+ • Rendering arguments for controlling CLI programs
+
+Complexity in CLI programs
+==========================
+
+Complexity tends to grow with time. How do you manage the complexity of
+commands? Consider the humble shell command ‘ls’. It now has over
+_fifty_ command line options. Some of these are boolean flags (‘ls
+-l’). Some take arguments (‘ls --sort=s’). Some have no effect unless
+paired with other flags (‘ls -lh’). Some are mutually exclusive. Some
+shell commands even have so many options that they introduce
+_subcommands_ (‘git branch’, ‘git commit’), each with their own rich set
+of options (‘git branch -f’).
+
+Using Transient for composing interactive commands
+==================================================
+
+What about Emacs commands used interactively? How do these handle
+options? One solution is to make many versions of the same command, so
+you don’t need to! Consider: ‘delete-other-windows’ vs.
+‘delete-other-windows-vertically’ (among many similar examples).
+
+ Some Emacs commands will simply prompt you for the next "argument"
+(‘M-x switch-to-buffer’). Another common solution is to use prefix
+arguments which usually start with ‘C-u’. Sometimes these are sensibly
+numerical in nature (‘C-u 4 M-x forward-paragraph’ to move forward 4
+paragraphs). But sometimes they function instead as boolean "switches"
+(‘C-u C-SPACE’ to jump to the last mark instead of just setting it, ‘C-u
+C-u C-SPACE’ to unconditionally set the mark). Since there aren’t many
+standards for the use of prefix options, you have to read the command’s
+documentation to find out what the possibilities are.
+
+ But when an Emacs command grows to have a truly large set of options
+and arguments, with dependencies between them, lots of option values,
+etc., these simple approaches just don’t scale. Transient is designed
+to solve this issue. Think of it as the humble prefix argument ‘C-u’,
+_raised to the power of 10_. Like ‘C-u’, it is key driven. Like the
+shell, it supports boolean "flag" options, options that take arguments,
+and even "sub-commands", with their own options. But instead of
+searching through a man page or command documentation, well-designed
+transients _guide_ their users to the relevant set of options (and even
+their possible values!) directly, taking into account any important
+pre-existing Emacs settings. And while for shell commands like ‘ls’,
+there is only one way to "execute" (hit ‘Return’!), transients can
+"execute" using multiple different keys tied to one of many
+self-documenting _actions_ (imagine having 5 different colored return
+keys on your keyboard!). Transients make navigating and setting large,
+complex groups of command options and arguments easy. Fun even. Once
+you’ve tried it, it’s hard to go back to the ‘C-u what can I do here
+again?’ way.
+
+\1f
+File: transient.info, Node: Usage, Next: Modifying Existing Transients, Prev: Introduction, Up: Top
+
+2 Usage
+*******
+
+* Menu:
+
+* Invoking Transients::
+* Aborting and Resuming Transients::
+* Common Suffix Commands::
+* Saving Values::
+* Using History::
+* Getting Help for Suffix Commands::
+* Enabling and Disabling Suffixes::
+* Other Commands::
+* Configuration::
+
+\1f
+File: transient.info, Node: Invoking Transients, Next: Aborting and Resuming Transients, Up: Usage
+
+2.1 Invoking Transients
+=======================
+
+A transient prefix command is invoked like any other command by pressing
+the key that is bound to that command. The main difference to other
+commands is that a transient prefix command activates a transient
+keymap, which temporarily binds the transient’s infix and suffix
+commands. Bindings from other keymaps may, or may not, be disabled
+while the transient state is in effect.
+
+ There are two kinds of commands that are available after invoking a
+transient prefix command; infix and suffix commands. Infix commands set
+some value (which is then shown in a popup buffer), without leaving the
+transient. Suffix commands, on the other hand, usually quit the
+transient and they may use the values set by the infix commands, i.e.,
+the infix *arguments*.
+
+ Instead of setting arguments to be used by a suffix command, infix
+commands may also set some value by side-effect, e.g., by setting the
+value of some variable.
+
+\1f
+File: transient.info, Node: Aborting and Resuming Transients, Next: Common Suffix Commands, Prev: Invoking Transients, Up: Usage
+
+2.2 Aborting and Resuming Transients
+====================================
+
+To quit the transient without invoking a suffix command press ‘C-g’.
+
+ Key bindings in transient keymaps may be longer than a single event.
+After pressing a valid prefix key, all commands whose bindings do not
+begin with that prefix key are temporarily unavailable and grayed out.
+To abort the prefix key press ‘C-g’ (which in this case only quits the
+prefix key, but not the complete transient).
+
+ A transient prefix command can be bound as a suffix of another
+transient. Invoking such a suffix replaces the current transient state
+with a new transient state, i.e., the available bindings change and the
+information displayed in the popup buffer is updated accordingly.
+Pressing ‘C-g’ while a nested transient is active only quits the
+innermost transient, causing a return to the previous transient.
+
+ ‘C-q’ or ‘C-z’ on the other hand always exits all transients. If you
+use the latter, then you can later resume the stack of transients using
+‘M-x transient-resume’.
+
+‘C-g’ (‘transient-quit-seq’)
+‘C-g’ (‘transient-quit-one’)
+ This key quits the currently active incomplete key sequence, if
+ any, or else the current transient. When quitting the current
+ transient, it returns to the previous transient, if any.
+
+ Transient’s predecessor bound ‘q’ instead of ‘C-g’ to the quit
+command. To learn how to get that binding back see
+‘transient-bind-q-to-quit’’s documentation string.
+
+‘C-q’ (‘transient-quit-all’)
+ This command quits the currently active incomplete key sequence, if
+ any, and all transients, including the active transient and all
+ suspended transients, if any.
+
+‘C-z’ (‘transient-suspend’)
+ Like ‘transient-quit-all’, this command quits an incomplete key
+ sequence, if any, and all transients. Additionally, it saves the
+ stack of transients so that it can easily be resumed (which is
+ particularly useful if you quickly need to do “something else” and
+ the stack is deeper than a single transient, and/or you have
+ already changed the values of some infix arguments).
+
+ Note that only a single stack of transients can be saved at a time.
+ If another stack is already saved, then saving a new stack discards
+ the previous stack.
+
+‘M-x transient-resume’
+ This command resumes the previously suspended stack of transients,
+ if any.
+
+\1f
+File: transient.info, Node: Common Suffix Commands, Next: Saving Values, Prev: Aborting and Resuming Transients, Up: Usage
+
+2.3 Common Suffix Commands
+==========================
+
+A few shared suffix commands are available in all transients. These
+suffix commands are not shown in the popup buffer by default.
+
+ This includes the aborting commands mentioned in the previous
+section, as well as some other commands that are all bound to ‘C-x KEY’.
+After ‘C-x’ is pressed, a section featuring all these common commands is
+temporarily shown in the popup buffer. After invoking one of them, the
+section disappears again. Note, however, that one of these commands is
+described as “Show common permanently”; invoke that if you want the
+common commands to always be shown for all transients.
+
+‘C-x t’ (‘transient-toggle-common’)
+ This command toggles whether the generic commands that are common
+ to all transients are always displayed or only after typing the
+ incomplete prefix key sequence ‘C-x’. This only affects the
+ current Emacs session.
+
+ -- User Option: transient-show-common-commands
+ This option controls whether shared suffix commands are shown
+ alongside the transient-specific infix and suffix commands. By
+ default, the shared commands are not shown to avoid overwhelming
+ the user with too many options.
+
+ While a transient is active, pressing ‘C-x’ always shows the common
+ commands. The value of this option can be changed for the current
+ Emacs session by typing ‘C-x t’ while a transient is active.
+
+ The other common commands are described in either the previous or in
+one of the following sections.
+
+ Some of Transient’s key bindings differ from the respective bindings
+of Magit-Popup; see *note FAQ:: for more information.
+
+\1f
+File: transient.info, Node: Saving Values, Next: Using History, Prev: Common Suffix Commands, Up: Usage
+
+2.4 Saving Values
+=================
+
+After setting the infix arguments in a transient, the user can save
+those arguments for future invocations.
+
+ Most transients will start out with the saved arguments when they are
+invoked. There are a few exceptions, though. Some transients are
+designed so that the value that they use is stored externally as the
+buffer-local value of some variable. Invoking such a transient again
+uses the buffer-local value. (1)
+
+ If the user does not save the value and just exits using a regular
+suffix command, then the value is merely saved to the transient’s
+history. That value won’t be used when the transient is next invoked,
+but it is easily accessible (see *note Using History::).
+
+‘C-x s’ (‘transient-set’)
+ This command saves the value of the active transient for this Emacs
+ session.
+
+‘C-x C-s’ (‘transient-save’)
+ Save the value of the active transient persistently across Emacs
+ sessions.
+
+‘C-x C-k’ (‘transient-reset’)
+ Clear the set and saved values of the active transient.
+
+ -- User Option: transient-values-file
+ This option names the file that is used to persist the values of
+ transients between Emacs sessions.
+
+ ---------- Footnotes ----------
+
+ (1) ‘magit-diff’ and ‘magit-log’ are two prominent examples, and
+their handling of buffer-local values is actually a bit more complicated
+than outlined above and even customizable.
+
+\1f
+File: transient.info, Node: Using History, Next: Getting Help for Suffix Commands, Prev: Saving Values, Up: Usage
+
+2.5 Using History
+=================
+
+Every time the user invokes a suffix command the transient’s current
+value is saved to its history. These values can be cycled through the
+same way one can cycle through the history of commands that read
+user-input in the minibuffer.
+
+‘C-M-p’ (‘transient-history-prev’)
+‘C-x p’
+ This command switches to the previous value used for the active
+ transient.
+
+‘C-M-n’ (‘transient-history-next’)
+‘C-x n’
+ This command switches to the next value used for the active
+ transient.
+
+ In addition to the transient-wide history, Transient of course
+supports per-infix history. When an infix reads user-input using the
+minibuffer, the user can use the regular minibuffer history commands to
+cycle through previously used values. Usually the same keys as those
+mentioned above are bound to those commands.
+
+ Authors of transients should arrange for different infix commands
+that read the same kind of value to also use the same history key (see
+*note Suffix Slots::).
+
+ Both kinds of history are saved to a file when Emacs is exited.
+
+ -- User Option: transient-history-file
+ This option names the file that is used to persist the history of
+ transients and their infixes between Emacs sessions.
+
+ -- User Option: transient-history-limit
+ This option controls how many history elements are kept at the time
+ the history is saved in ‘transient-history-file’.
+
+\1f
+File: transient.info, Node: Getting Help for Suffix Commands, Next: Enabling and Disabling Suffixes, Prev: Using History, Up: Usage
+
+2.6 Getting Help for Suffix Commands
+====================================
+
+Transients can have many suffixes and infixes that the user might not be
+familiar with. To make it trivial to get help for these, Transient
+provides access to the documentation directly from the active transient.
+
+‘C-h’ (‘transient-help’)
+ This command enters help mode. When help mode is active, typing a
+ key shows information about the suffix command that the key
+ normally is bound to (instead of invoking it). Pressing ‘C-h’ a
+ second time shows information about the _prefix_ command.
+
+ After typing a key, the stack of transient states is suspended and
+ information about the suffix command is shown instead. Typing ‘q’
+ in the help buffer buries that buffer and resumes the transient
+ state.
+
+ What sort of documentation is shown depends on how the transient was
+defined. For infix commands that represent command-line arguments this
+ideally shows the appropriate manpage. ‘transient-help’ then tries to
+jump to the correct location within that. Info manuals are also
+supported. The fallback is to show the command’s documentation string,
+for non-infix suffixes this is usually appropriate.
+
+\1f
+File: transient.info, Node: Enabling and Disabling Suffixes, Next: Other Commands, Prev: Getting Help for Suffix Commands, Up: Usage
+
+2.7 Enabling and Disabling Suffixes
+===================================
+
+The user base of a package that uses transients can be very diverse.
+This is certainly the case for Magit; some users have been using it and
+Git for a decade, while others are just getting started now.
+
+ For that reason a mechanism is needed that authors can use to
+classify a transient’s infixes and suffixes along the
+essentials...everything spectrum. We use the term “levels” to describe
+that mechanism.
+
+ Each suffix command is placed on a level and each transient has a
+level (called “transient-level”), which controls which suffix commands
+are available. Integers between 1 and 7 (inclusive) are valid levels.
+For suffixes, 0 is also valid; it means that the suffix is not displayed
+at any level.
+
+ The levels of individual transients and/or their individual suffixes
+can be changed interactively, by invoking the transient and then
+pressing ‘C-x l’ to enter the “edit” mode, see below.
+
+ The default level for both transients and their suffixes is 4. The
+‘transient-default-level’ option only controls the default for
+transients. The default suffix level is always 4. The authors of
+transients should place certain suffixes on a higher level, if they
+expect that it won’t be of use to most users, and they should place very
+important suffixes on a lower level, so that they remain available even
+if the user lowers the transient level.
+
+ -- User Option: transient-default-level
+ This option controls which suffix levels are made available by
+ default. It sets the transient-level for transients for which the
+ user has not set that individually.
+
+ -- User Option: transient-levels-file
+ This option names the file that is used to persist the levels of
+ transients and their suffixes between Emacs sessions.
+
+‘C-x l’ (‘transient-set-level’)
+ This command enters edit mode. When edit mode is active, then all
+ infixes and suffixes that are currently usable are displayed along
+ with their levels. The colors of the levels indicate whether they
+ are enabled or not. The level of the transient is also displayed
+ along with some usage information.
+
+ In edit mode, pressing the key that would usually invoke a certain
+ suffix instead prompts the user for the level that suffix should be
+ placed on.
+
+ Help mode is available in edit mode.
+
+ To change the transient level press ‘C-x l’ again.
+
+ To exit edit mode press ‘C-g’.
+
+ Note that edit mode does not display any suffixes that are not
+ currently usable. ‘magit-rebase’, for example, shows different
+ suffixes depending on whether a rebase is already in progress or
+ not. The predicates also apply in edit mode.
+
+ Therefore, to control which suffixes are available given a certain
+ state, you have to make sure that that state is currently active.
+
+‘C-x a’ (‘transient-toggle-level-limit’)
+ This command toggle whether suffixes that are on levels higher than
+ the level specified by ‘transient-default-level’ are temporarily
+ available anyway.
+
+\1f
+File: transient.info, Node: Other Commands, Next: Configuration, Prev: Enabling and Disabling Suffixes, Up: Usage
+
+2.8 Other Commands
+==================
+
+When invoking a transient in a small frame, the transient window may not
+show the complete buffer, making it necessary to scroll, using the
+following commands. These commands are never shown in the transient
+window, and the key bindings are the same as for ‘scroll-up-command’ and
+‘scroll-down-command’ in other buffers.
+
+ -- Command: transient-scroll-up arg
+ This command scrolls text of transient popup window upward ARG
+ lines. If ARG is ‘nil’, then it scrolls near full screen. This is
+ a wrapper around ‘scroll-up-command’ (which see).
+
+ -- Command: transient-scroll-down arg
+ This command scrolls text of transient popup window down ARG lines.
+ If ARG is ‘nil’, then it scrolls near full screen. This is a
+ wrapper around ‘scroll-down-command’ (which see).
+
+\1f
+File: transient.info, Node: Configuration, Prev: Other Commands, Up: Usage
+
+2.9 Configuration
+=================
+
+More options are described in *note Common Suffix Commands::, in *note
+Saving Values::, in *note Using History:: and in *note Enabling and
+Disabling Suffixes::.
+
+Essential Options
+-----------------
+
+Also see *note Common Suffix Commands::.
+
+ -- User Option: transient-show-popup
+ This option controls whether the current transient’s infix and
+ suffix commands are shown in the popup buffer.
+
+ • If ‘t’ (the default) then the popup buffer is shown as soon as
+ a transient prefix command is invoked.
+
+ • If ‘nil’, then the popup buffer is not shown unless the user
+ explicitly requests it, by pressing an incomplete prefix key
+ sequence.
+
+ • If a number, then the a brief one-line summary is shown
+ instead of the popup buffer. If zero or negative, then not
+ even that summary is shown; only the pressed key itself is
+ shown.
+
+ The popup is shown when the user explicitly requests it by
+ pressing an incomplete prefix key sequence. Unless this is
+ zero, the popup is shown after that many seconds of inactivity
+ (using the absolute value).
+
+ -- User Option: transient-enable-popup-navigation
+ This option controls whether navigation commands are enabled in the
+ transient popup buffer.
+
+ While a transient is active the transient popup buffer is not the
+ current buffer, making it necessary to use dedicated commands to
+ act on that buffer itself. This is disabled by default. If this
+ option is non-‘nil’, then the following features are available:
+
+ • ‘<UP>’ moves the cursor to the previous suffix.
+ • ‘<DOWN>’ moves the cursor to the next suffix.
+ • ‘<RET>’ invokes the suffix the cursor is on.
+ • ‘mouse-1’ invokes the clicked on suffix.
+ • ‘C-s’ and ‘C-r’ start isearch in the popup buffer.
+
+ -- User Option: transient-display-buffer-action
+ This option specifies the action used to display the transient
+ popup buffer. The transient popup buffer is displayed in a window
+ using ‘(display-buffer BUFFER transient-display-buffer-action)’.
+
+ The value of this option has the form ‘(FUNCTION . ALIST)’, where
+ FUNCTION is a function or a list of functions. Each such function
+ should accept two arguments: a buffer to display and an alist of
+ the same form as ALIST. See *note (elisp)Choosing Window::, for
+ details.
+
+ The default is:
+
+ (display-buffer-in-side-window
+ (side . bottom)
+ (inhibit-same-window . t)
+ (window-parameters (no-other-window . t)))
+
+ This displays the window at the bottom of the selected frame.
+ Another useful FUNCTION is ‘display-buffer-below-selected’, which
+ is what ‘magit-popup’ used by default. For more alternatives see
+ *note (elisp)Buffer Display Action Functions::, and *note
+ (elisp)Buffer Display Action Alists::.
+
+ Note that the buffer that was current before the transient buffer
+ is shown should remain the current buffer. Many suffix commands
+ act on the thing at point, if appropriate, and if the transient
+ buffer became the current buffer, then that would change what is at
+ point. To that effect ‘inhibit-same-window’ ensures that the
+ selected window is not used to show the transient buffer.
+
+ It may be possible to display the window in another frame, but
+ whether that works in practice depends on the window-manager. If
+ the window manager selects the new window (Emacs frame), then that
+ unfortunately changes which buffer is current.
+
+ If you change the value of this option, then you might also want to
+ change the value of ‘transient-mode-line-format’.
+
+Accessibility Options
+---------------------
+
+ -- User Option: transient-force-single-column
+ This option controls whether the use of a single column to display
+ suffixes is enforced. This might be useful for users with low
+ vision who use large text and might otherwise have to scroll in two
+ dimensions.
+
+Auxiliary Options
+-----------------
+
+ -- User Option: transient-mode-line-format
+ This option controls whether the transient popup buffer has a
+ mode-line, separator line, or neither.
+
+ If ‘nil’, then the buffer has no mode-line. If the buffer is not
+ displayed right above the echo area, then this probably is not a
+ good value.
+
+ If ‘line’ (the default) or a natural number, then the buffer has no
+ mode-line, but a line is drawn is drawn in its place. If a number
+ is used, that specifies the thickness of the line. On termcap
+ frames we cannot draw lines, so there ‘line’ and numbers are
+ synonyms for ‘nil’.
+
+ The color of the line is used to indicate if non-suffixes are
+ allowed and whether they exit the transient. The foreground color
+ of ‘transient-key-noop’ (if non-suffix are disallowed),
+ ‘transient-key-stay’ (if allowed and transient stays active), or
+ ‘transient-key-exit’ (if allowed and they exit the transient) is
+ used to draw the line.
+
+ Otherwise this can be any mode-line format. See *note (elisp)Mode
+ Line Format::, for details.
+
+ -- User Option: transient-semantic-coloring
+ This option controls whether colors are used to indicate the
+ transient behavior of commands.
+
+ If non-‘nil’, then the key binding of each suffix is colorized to
+ indicate whether it exits the transient state or not. The color of
+ the prefix is indicated using the line that is drawn when the value
+ of ‘transient-mode-line-format’ is ‘line’.
+
+ -- User Option: transient-highlight-mismatched-keys
+ This option controls whether key bindings of infix commands that do
+ not match the respective command-line argument should be
+ highlighted. For other infix commands this option has no effect.
+
+ When this option is non-‘nil’, the key binding for an infix
+ argument is highlighted when only a long argument (e.g.,
+ ‘--verbose’) is specified but no shorthand (e.g., ‘-v’). In the
+ rare case that a shorthand is specified but the key binding does
+ not match, then it is highlighted differently.
+
+ Highlighting mismatched key bindings is useful when learning the
+ arguments of the underlying command-line tool; you wouldn’t want to
+ learn any short-hands that do not actually exist.
+
+ The highlighting is done using one of the faces
+ ‘transient-mismatched-key’ and ‘transient-nonstandard-key’.
+
+ -- User Option: transient-substitute-key-function
+ This function is used to modify key bindings. If the value of this
+ option is ‘nil’ (the default), then no substitution is performed.
+
+ This function is called with one argument, the prefix object, and
+ must return a key binding description, either the existing key
+ description it finds in the ‘key’ slot, or the key description that
+ replaces the prefix key. It could be used to make other
+ substitutions, but that is discouraged.
+
+ For example, ‘=’ is hard to reach using my custom keyboard layout,
+ so I substitute ‘(’ for that, which is easy to reach using a layout
+ optimized for lisp.
+
+ (setq transient-substitute-key-function
+ (lambda (obj)
+ (let ((key (oref obj key)))
+ (if (string-match "\\`\\(=\\)[a-zA-Z]" key)
+ (replace-match "(" t t key 1)
+ key))))
+
+ -- User Option: transient-read-with-initial-input
+ This option controls whether the last history element is used as
+ the initial minibuffer input when reading the value of an infix
+ argument from the user. If ‘nil’, there is no initial input and
+ the first element has to be accessed the same way as the older
+ elements.
+
+ -- User Option: transient-hide-during-minibuffer-read
+ This option controls whether the transient buffer is hidden while
+ user input is being read in the minibuffer.
+
+ -- User Option: transient-align-variable-pitch
+ This option controls whether columns are aligned pixel-wise in the
+ popup buffer.
+
+ If this is non-‘nil’, then columns are aligned pixel-wise to
+ support variable-pitch fonts. Keys are not aligned, so you should
+ use a fixed-pitch font for the ‘transient-key’ face. Other key
+ faces inherit from that face unless a theme is used that breaks
+ that relationship.
+
+ This option is intended for users who use a variable-pitch font for
+ the ‘default’ face.
+
+ -- User Option: transient-force-fixed-pitch
+ This option controls whether to force the use of a monospaced font
+ in popup buffer. Even if you use a proportional font for the
+ ‘default’ face, you might still want to use a monospaced font in
+ transient’s popup buffer. Setting this option to ‘t’ causes
+ ‘default’ to be remapped to ‘fixed-pitch’ in that buffer.
+
+Developer Options
+-----------------
+
+These options are mainly intended for developers.
+
+ -- User Option: transient-detect-key-conflicts
+ This option controls whether key binding conflicts should be
+ detected at the time the transient is invoked. If so, this results
+ in an error, which prevents the transient from being used. Because
+ of that, conflicts are ignored by default.
+
+ Conflicts cannot be determined earlier, i.e., when the transient is
+ being defined and when new suffixes are being added, because at
+ that time there can be false-positives. It is actually valid for
+ multiple suffixes to share a common key binding, provided the
+ predicates of those suffixes prevent that more than one of them is
+ enabled at a time.
+
+ -- User Option: transient-highlight-higher-levels
+ This option controls whether suffixes that would not be available
+ by default are highlighted.
+
+ When non-‘nil’ then the descriptions of suffixes are highlighted if
+ their level is above 4, the default of ‘transient-default-level’.
+ Assuming you have set that variable to 7, this highlights all
+ suffixes that won’t be available to users without them making the
+ same customization.
+
+\1f
+File: transient.info, Node: Modifying Existing Transients, Next: Defining New Commands, Prev: Usage, Up: Top
+
+3 Modifying Existing Transients
+*******************************
+
+To an extent, transients can be customized interactively, see *note
+Enabling and Disabling Suffixes::. This section explains how existing
+transients can be further modified non-interactively. Let’s begin with
+an example:
+
+ (transient-append-suffix 'magit-patch-apply "-3"
+ '("-R" "Apply in reverse" "--reverse"))
+
+ This inserts a new infix argument to toggle the ‘--reverse’ argument
+after the infix argument that toggles ‘-3’ in ‘magit-patch-apply’.
+
+ The following functions share a few arguments:
+
+ • PREFIX is a transient prefix command, a symbol.
+
+ • SUFFIX is a transient infix or suffix specification in the same
+ form as expected by ‘transient-define-prefix’. Note that an infix
+ is a special kind of suffix. Depending on context “suffixes” means
+ “suffixes (including infixes)” or “non-infix suffixes”. Here it
+ means the former. See *note Suffix Specifications::.
+
+ SUFFIX may also be a group in the same form as expected by
+ ‘transient-define-prefix’. See *note Group Specifications::.
+
+ • LOC is a command, a key vector, a key description (a string as
+ returned by ‘key-description’), or a list specifying coordinates
+ (the last element may also be a command or key). For example ‘(1 0
+ -1)’ identifies the last suffix (‘-1’) of the first subgroup (‘0’)
+ of the second group (‘1’).
+
+ If LOC is a list of coordinates, then it can be used to identify a
+ group, not just an individual suffix command.
+
+ The function ‘transient-get-suffix’ can be useful to determine
+ whether a certain coordination list identifies the suffix or group
+ that you expect it to identify. In hairy cases it may be necessary
+ to look at the definition of the transient prefix command.
+
+ These functions operate on the information stored in the
+‘transient--layout’ property of the PREFIX symbol. Suffix entries in
+that tree are not objects but have the form ‘(LEVEL CLASS PLIST)’, where
+PLIST should set at least ‘:key’, ‘:description’ and ‘:command’.
+
+ -- Function: transient-insert-suffix prefix loc suffix &optional
+ keep-other
+ -- Function: transient-append-suffix prefix loc suffix &optional
+ keep-other
+ These functions insert the suffix or group SUFFIX into PREFIX
+ before or after LOC.
+
+ Conceptually adding a binding to a transient prefix is similar to
+ adding a binding to a keymap, but this is complicated by the fact
+ that multiple suffix commands can be bound to the same key,
+ provided they are never active at the same time, see *note
+ Predicate Slots::.
+
+ Unfortunately both false-positives and false-negatives are
+ possible. To deal with the former use non-‘nil’ KEEP-OTHER. To
+ deal with the latter remove the conflicting binding explicitly.
+
+ -- Function: transient-replace-suffix prefix loc suffix
+ This function replaces the suffix or group at LOC in PREFIX with
+ suffix or group SUFFIX.
+
+ -- Function: transient-remove-suffix prefix loc
+ This function removes the suffix or group at LOC in PREFIX.
+
+ -- Function: transient-get-suffix prefix loc
+ This function returns the suffix or group at LOC in PREFIX. The
+ returned value has the form mentioned above.
+
+ -- Function: transient-suffix-put prefix loc prop value
+ This function edits the suffix or group at LOC in PREFIX, by
+ setting the PROP of its plist to VALUE.
+
+ Most of these functions do not signal an error if they cannot perform
+the requested modification. The functions that insert new suffixes show
+a warning if LOC cannot be found in PREFIX without signaling an error.
+The reason for doing it like this is that establishing a key binding
+(and that is what we essentially are trying to do here) should not
+prevent the rest of the configuration from loading. Among these
+functions only ‘transient-get-suffix’ and ‘transient-suffix-put’ may
+signal an error.
+
+\1f
+File: transient.info, Node: Defining New Commands, Next: Classes and Methods, Prev: Modifying Existing Transients, Up: Top
+
+4 Defining New Commands
+***********************
+
+* Menu:
+
+* Technical Introduction::
+* Defining Transients::
+* Binding Suffix and Infix Commands::
+* Defining Suffix and Infix Commands::
+* Using Infix Arguments::
+* Transient State::
+
+\1f
+File: transient.info, Node: Technical Introduction, Next: Defining Transients, Up: Defining New Commands
+
+4.1 Technical Introduction
+==========================
+
+Taking inspiration from prefix keys and prefix arguments, Transient
+implements a similar abstraction involving a prefix command, infix
+arguments and suffix commands.
+
+ When the user calls a transient prefix command, a transient
+(temporary) keymap is activated, which binds the transient’s infix and
+suffix commands, and functions that control the transient state are
+added to ‘pre-command-hook’ and ‘post-command-hook’. The available
+suffix and infix commands and their state are shown in a popup buffer
+until the transient state is exited by invoking a suffix command.
+
+ Calling an infix command causes its value to be changed. How that is
+done depends on the type of the infix command. The simplest case is an
+infix command that represents a command-line argument that does not take
+a value. Invoking such an infix command causes the switch to be toggled
+on or off. More complex infix commands may read a value from the user,
+using the minibuffer.
+
+ Calling a suffix command usually causes the transient to be exited;
+the transient keymaps and hook functions are removed, the popup buffer
+no longer shows information about the (no longer bound) suffix commands,
+the values of some public global variables are set, while some internal
+global variables are unset, and finally the command is actually called.
+Suffix commands can also be configured to not exit the transient.
+
+ A suffix command can, but does not have to, use the infix arguments
+in much the same way any command can choose to use or ignore the prefix
+arguments. For a suffix command that was invoked from a transient, the
+variable ‘transient-current-suffixes’ and the function ‘transient-args’
+serve about the same purpose as the variables ‘prefix-arg’ and
+‘current-prefix-arg’ do for any command that was called after the prefix
+arguments have been set using a command such as ‘universal-argument’.
+
+ Transient can be used to implement simple “command dispatchers”. The
+main benefit then is that the user can see all the available commands in
+a popup buffer, which can be thought of as a “menus”. That is useful by
+itself because it frees the user from having to remember all the keys
+that are valid after a certain prefix key or command. Magit’s
+‘magit-dispatch’ (on ‘C-x M-g’) command is an example of using Transient
+to merely implement a command dispatcher.
+
+ In addition to that, Transient also allows users to interactively
+pass arguments to commands. These arguments can be much more complex
+than what is reasonable when using prefix arguments. There is a limit
+to how many aspects of a command can be controlled using prefix
+arguments. Furthermore, what a certain prefix argument means for
+different commands can be completely different, and users have to read
+documentation to learn and then commit to memory what a certain prefix
+argument means to a certain command.
+
+ Transient suffix commands, on the other hand, can accept dozens of
+different arguments without the user having to remember anything. When
+using Transient, one can call a command with arguments that are just as
+complex as when calling the same function non-interactively from Lisp.
+
+ Invoking a transient suffix command with arguments is similar to
+invoking a command in a shell with command-line completion and history
+enabled. One benefit of the Transient interface is that it remembers
+history not only on a global level (“this command was invoked using
+these arguments, and previously it was invoked using those other
+arguments”), but also remembers the values of individual arguments
+independently. See *note Using History::.
+
+ After a transient prefix command is invoked, ‘C-h KEY’ can be used to
+show the documentation for the infix or suffix command that ‘KEY’ is
+bound to (see *note Getting Help for Suffix Commands::), and infixes and
+suffixes can be removed from the transient using ‘C-x l KEY’. Infixes
+and suffixes that are disabled by default can be enabled the same way.
+See *note Enabling and Disabling Suffixes::.
+
+ Transient ships with support for a few different types of specialized
+infix commands. A command that sets a command line option, for example,
+has different needs than a command that merely toggles a boolean flag.
+Additionally, Transient provides abstractions for defining new types,
+which the author of Transient did not anticipate (or didn’t get around
+to implementing yet).
+
+ Note that suffix commands also support regular prefix arguments. A
+suffix command may even be called with both infix and prefix arguments
+at the same time. If you invoke a command as a suffix of a transient
+prefix command, but also want to pass prefix arguments to it, then first
+invoke the prefix command, and only after doing that invoke the prefix
+arguments, before finally invoking the suffix command. If you instead
+began by providing the prefix arguments, then those would apply to the
+prefix command, not the suffix command. Likewise, if you want to change
+infix arguments before invoking a suffix command with prefix arguments,
+then change the infix arguments before invoking the prefix arguments.
+In other words, regular prefix arguments always apply to the next
+command, and since transient prefix, infix and suffix commands are just
+regular commands, the same applies to them. (Regular prefix keys behave
+differently because they are not commands at all, instead they are just
+incomplete key sequences, and those cannot be interrupted with prefix
+commands.)
+
+\1f
+File: transient.info, Node: Defining Transients, Next: Binding Suffix and Infix Commands, Prev: Technical Introduction, Up: Defining New Commands
+
+4.2 Defining Transients
+=======================
+
+A transient consists of a prefix command and at least one suffix
+command, though usually a transient has several infix and suffix
+commands. The below macro defines the transient prefix command *and*
+binds the transient’s infix and suffix commands. In other words, it
+defines the complete transient, not just the transient prefix command
+that is used to invoke that transient.
+
+ -- Macro: transient-define-prefix name arglist [docstring] [keyword
+ value]... group... [body...]
+ This macro defines NAME as a transient prefix command and binds the
+ transient’s infix and suffix commands.
+
+ ARGLIST are the arguments that the prefix command takes. DOCSTRING
+ is the documentation string and is optional.
+
+ These arguments can optionally be followed by keyword-value pairs.
+ Each key has to be a keyword symbol, either ‘:class’ or a keyword
+ argument supported by the constructor of that class. The
+ ‘transient-prefix’ class is used if the class is not specified
+ explicitly.
+
+ GROUPs add key bindings for infix and suffix commands and specify
+ how these bindings are presented in the popup buffer. At least one
+ GROUP has to be specified. See *note Binding Suffix and Infix
+ Commands::.
+
+ The BODY is optional. If it is omitted, then ARGLIST is ignored
+ and the function definition becomes:
+
+ (lambda ()
+ (interactive)
+ (transient-setup 'NAME))
+
+ If BODY is specified, then it must begin with an ‘interactive’ form
+ that matches ARGLIST, and it must call ‘transient-setup’. It may,
+ however, call that function only when some condition is satisfied.
+
+ All transients have a (possibly ‘nil’) value, which is exported
+ when suffix commands are called, so that they can consume that
+ value. For some transients it might be necessary to have a sort of
+ secondary value, called a “scope”. Such a scope would usually be
+ set in the command’s ‘interactive’ form and has to be passed to the
+ setup function:
+
+ (transient-setup 'NAME nil nil :scope SCOPE)
+
+ For example, the scope of the ‘magit-branch-configure’ transient is
+ the branch whose variables are being configured.
+
+\1f
+File: transient.info, Node: Binding Suffix and Infix Commands, Next: Defining Suffix and Infix Commands, Prev: Defining Transients, Up: Defining New Commands
+
+4.3 Binding Suffix and Infix Commands
+=====================================
+
+The macro ‘transient-define-prefix’ is used to define a transient. This
+defines the actual transient prefix command (see *note Defining
+Transients::) and adds the transient’s infix and suffix bindings, as
+described below.
+
+ Users and third-party packages can add additional bindings using
+functions such as ‘transient-insert-suffix’ (see *note Modifying
+Existing Transients::). These functions take a “suffix specification”
+as one of their arguments, which has the same form as the specifications
+used in ‘transient-define-prefix’.
+
+* Menu:
+
+* Group Specifications::
+* Suffix Specifications::
+
+\1f
+File: transient.info, Node: Group Specifications, Next: Suffix Specifications, Up: Binding Suffix and Infix Commands
+
+4.3.1 Group Specifications
+--------------------------
+
+The suffix and infix commands of a transient are organized in groups.
+The grouping controls how the descriptions of the suffixes are outlined
+visually but also makes it possible to set certain properties for a set
+of suffixes.
+
+ Several group classes exist, some of which organize suffixes in
+subgroups. In most cases the class does not have to be specified
+explicitly, but see *note Group Classes::.
+
+ Groups are specified in the call to ‘transient-define-prefix’, using
+vectors. Because groups are represented using vectors, we cannot use
+square brackets to indicate an optional element and instead use curly
+brackets to do the latter.
+
+ Group specifications then have this form:
+
+ [{LEVEL} {DESCRIPTION} {KEYWORD VALUE}... ELEMENT...]
+
+ The LEVEL is optional and defaults to 4. See *note Enabling and
+Disabling Suffixes::.
+
+ The DESCRIPTION is optional. If present, it is used as the heading
+of the group.
+
+ The KEYWORD-VALUE pairs are optional. Each keyword has to be a
+keyword symbol, either ‘:class’ or a keyword argument supported by the
+constructor of that class.
+
+ • One of these keywords, ‘:description’, is equivalent to specifying
+ DESCRIPTION at the very beginning of the vector. The
+ recommendation is to use ‘:description’ if some other keyword is
+ also used, for consistency, or DESCRIPTION otherwise, because it
+ looks better.
+
+ • Likewise ‘:level’ is equivalent to LEVEL.
+
+ • Other important keywords include the ‘:if...’ keywords. These
+ keywords control whether the group is available in a certain
+ situation.
+
+ For example, one group of the ‘magit-rebase’ transient uses ‘:if
+ magit-rebase-in-progress-p’, which contains the suffixes that are
+ useful while rebase is already in progress; and another that uses
+ ‘:if-not magit-rebase-in-progress-p’, which contains the suffixes
+ that initiate a rebase.
+
+ These predicates can also be used on individual suffixes and are
+ only documented once, see *note Predicate Slots::.
+
+ • The value of ‘:hide’, if non-‘nil’, is a predicate that controls
+ whether the group is hidden by default. The key bindings for
+ suffixes of a hidden group should all use the same prefix key.
+ Pressing that prefix key should temporarily show the group and its
+ suffixes, which assumes that a predicate like this is used:
+
+ (lambda ()
+ (eq (car transient--redisplay-key)
+ ?\C-c)) ; the prefix key shared by all bindings
+
+ • The value of ‘:setup-children’, if non-‘nil’, is a function that
+ takes one argument, a potentially list of children, and must return
+ a list of children or an empty list. This can either be used to
+ somehow transform the group’s children that were defined the normal
+ way, or to dynamically create the children from scratch.
+
+ The returned children must have the same form as stored in the
+ prefix’s ‘transient--layout’ property, but it is often more
+ convenient to use the same form as understood by
+ ‘transient-define-prefix’, described below. If you use the latter
+ approach, you can use the ‘transient-parse-suffixes’ and
+ ‘transient-parse-suffix’ functions to transform them from the
+ convenient to the expected form.
+
+ If you explicitly specify children and then transform them using
+ ‘:setup-chilren’, then the class of the group is determined as
+ usual, based on explicitly specified children.
+
+ If you do not explicitly specify children and thus rely solely on
+ ‘:setup-children’, then you must specify the class using ‘:class’.
+ For backward compatibility, if you fail to do so,
+ ‘transient-column’ is used and a warning is displayed. This
+ warning will eventually be replaced with an error.
+
+ • The boolean ‘:pad-keys’ argument controls whether keys of all
+ suffixes contained in a group are right padded, effectively
+ aligning the descriptions.
+
+ The ELEMENTs are either all subgroups, or all suffixes and strings.
+(At least currently no group type exists that would allow mixing
+subgroups with commands at the same level, though in principle there is
+nothing that prevents that.)
+
+ If the ELEMENTs are not subgroups, then they can be a mixture of
+lists, which specify commands, and strings. Strings are inserted
+verbatim into the buffer. The empty string can be used to insert gaps
+between suffixes, which is particularly useful if the suffixes are
+outlined as a table.
+
+ Inside group specifications, including inside contained suffix
+specifications, nothing has to be quoted and quoting anyway is invalid.
+The value following a keyword, can be explicitly unquoted using ‘,’.
+This feature is experimental and should be avoided.
+
+ The form of suffix specifications is documented in the next node.
+
+\1f
+File: transient.info, Node: Suffix Specifications, Prev: Group Specifications, Up: Binding Suffix and Infix Commands
+
+4.3.2 Suffix Specifications
+---------------------------
+
+A transient’s suffix and infix commands are bound when the transient
+prefix command is defined using ‘transient-define-prefix’, see *note
+Defining Transients::. The commands are organized into groups, see
+*note Group Specifications::. Here we describe the form used to bind an
+individual suffix command.
+
+ The same form is also used when later binding additional commands
+using functions such as ‘transient-insert-suffix’, see *note Modifying
+Existing Transients::.
+
+ Note that an infix is a special kind of suffix. Depending on context
+“suffixes” means “suffixes (including infixes)” or “non-infix suffixes”.
+Here it means the former.
+
+ Suffix specifications have this form:
+
+ ([LEVEL] [KEY [DESCRIPTION]] COMMAND|ARGUMENT [KEYWORD VALUE]...)
+
+ LEVEL, KEY and DESCRIPTION can also be specified using the KEYWORDs
+‘:level’, ‘:key’ and ‘:description’. If the object that is associated
+with COMMAND sets these properties, then they do not have to be
+specified here. You can however specify them here anyway, possibly
+overriding the object’s values just for the binding inside this
+transient.
+
+ • LEVEL is the suffix level, an integer between 1 and 7. See *note
+ Enabling and Disabling Suffixes::.
+
+ • KEY is the key binding, either a vector or key description string.
+
+ • DESCRIPTION is the description, either a string or a function that
+ takes zero or one arguments (the suffix object) and returns a
+ string. The function should be a lambda expression to avoid
+ ambiguity. In some cases a symbol that is bound as a function
+ would also work but to be safe you should use ‘:description’ in
+ that case.
+
+ The next element is either a command or an argument. This is the
+only argument that is mandatory in all cases.
+
+ • COMMAND should be a symbol that is bound as a function, which has
+ to be defined or at least autoloaded as a command by the time the
+ containing prefix command is invoked.
+
+ Any command will do; it does not need to have an object associated
+ with it (as would be the case if ‘transient-define-suffix’ or
+ ‘transient-define-infix’ were used to define it).
+
+ COMMAND can also be a ‘lambda’ expression.
+
+ As mentioned above, the object that is associated with a command
+ can be used to set the default for certain values that otherwise
+ have to be set in the suffix specification. Therefore if there is
+ no object, then you have to make sure to specify the KEY and the
+ DESCRIPTION.
+
+ As a special case, if you want to add a command that might be
+ neither defined nor autoloaded, you can use a workaround like:
+
+ (transient-insert-suffix 'some-prefix "k"
+ '("!" "Ceci n'est pas une commande" no-command
+ :if (lambda () (featurep 'no-library))))
+
+ Instead of ‘featurep’ you could also use ‘require’ with a non-‘nil’
+ value for NOERROR.
+
+ • The mandatory argument can also be a command-line argument, a
+ string. In that case an anonymous command is defined and bound.
+
+ Instead of a string, this can also be a list of two strings, in
+ which case the first string is used as the short argument (which
+ can also be specified using ‘:shortarg’) and the second as the long
+ argument (which can also be specified using ‘:argument’).
+
+ Only the long argument is displayed in the popup buffer. See
+ ‘transient-detect-key-conflicts’ for how the short argument may be
+ used.
+
+ Unless the class is specified explicitly, the appropriate class is
+ guessed based on the long argument. If the argument ends with ‘=’
+ (e.g., ‘--format=’) then ‘transient-option’ is used, otherwise
+ ‘transient-switch’.
+
+ Finally, details can be specified using optional KEYWORD-VALUE pairs.
+Each keyword has to be a keyword symbol, either ‘:class’ or a keyword
+argument supported by the constructor of that class. See *note Suffix
+Slots::.
+
+\1f
+File: transient.info, Node: Defining Suffix and Infix Commands, Next: Using Infix Arguments, Prev: Binding Suffix and Infix Commands, Up: Defining New Commands
+
+4.4 Defining Suffix and Infix Commands
+======================================
+
+Note that an infix is a special kind of suffix. Depending on context
+“suffixes” means “suffixes (including infixes)” or “non-infix suffixes”.
+
+ -- Macro: transient-define-suffix name arglist [docstring] [keyword
+ value]... body...
+ This macro defines NAME as a transient suffix command.
+
+ ARGLIST are the arguments that the command takes. DOCSTRING is the
+ documentation string and is optional.
+
+ These arguments can optionally be followed by keyword-value pairs.
+ Each keyword has to be a keyword symbol, either ‘:class’ or a
+ keyword argument supported by the constructor of that class. The
+ ‘transient-suffix’ class is used if the class is not specified
+ explicitly.
+
+ The BODY must begin with an ‘interactive’ form that matches
+ ARGLIST. The infix arguments are usually accessed by using
+ ‘transient-args’ inside ‘interactive’.
+
+ -- Macro: transient-define-infix name arglist [docstring] [keyword
+ value]...
+ This macro defines NAME as a transient infix command.
+
+ ARGLIST is always ignored (but mandatory never-the-less) and
+ reserved for future use. DOCSTRING is the documentation string and
+ is optional.
+
+ At least one key-value pair is required. All transient infix
+ commands are ‘equal’ to each other (but not ‘eq’). It is
+ meaningless to define an infix command, without providing at least
+ one keyword argument (usually ‘:argument’ or ‘:variable’, depending
+ on the class). The suffix class defaults to ‘transient-switch’ and
+ can be set using the ‘:class’ keyword.
+
+ The function definition is always:
+
+ (lambda ()
+ (interactive)
+ (let ((obj (transient-suffix-object)))
+ (transient-infix-set obj (transient-infix-read obj)))
+ (transient--show))
+
+ ‘transient-infix-read’ and ‘transient-infix-set’ are generic
+ functions. Different infix commands behave differently because the
+ concrete methods are different for different infix command classes.
+ In rare cases the above command function might not be suitable,
+ even if you define your own infix command class. In that case you
+ have to use ‘transient-define-suffix’ to define the infix command
+ and use ‘t’ as the value of the ‘:transient’ keyword.
+
+ -- Macro: transient-define-argument name arglist [docstring] [keyword
+ value]...
+ This macro defines NAME as a transient infix command.
+
+ This is an alias for ‘transient-define-infix’. Only use this alias
+ to define an infix command that actually sets an infix argument.
+ To define an infix command that, for example, sets a variable, use
+ ‘transient-define-infix’ instead.
+
+\1f
+File: transient.info, Node: Using Infix Arguments, Next: Transient State, Prev: Defining Suffix and Infix Commands, Up: Defining New Commands
+
+4.5 Using Infix Arguments
+=========================
+
+The functions and the variables described below allow suffix commands to
+access the value of the transient from which they were invoked; which is
+the value of its infix arguments. These variables are set when the user
+invokes a suffix command that exits the transient, but before actually
+calling the command.
+
+ When returning to the command-loop after calling the suffix command,
+the arguments are reset to ‘nil’ (which causes the function to return
+‘nil’ too).
+
+ Like for Emacs’ prefix arguments, it is advisable, but not mandatory,
+to access the infix arguments inside the command’s ‘interactive’ form.
+The preferred way of doing that is to call the ‘transient-args’
+function, which for infix arguments serves about the same purpose as
+‘prefix-arg’ serves for prefix arguments.
+
+ -- Function: transient-args prefix
+ This function returns the value of the transient prefix command
+ PREFIX.
+
+ If the current command was invoked from the transient prefix
+ command PREFIX, then it returns the active infix arguments. If the
+ current command was not invoked from PREFIX, then it returns the
+ set, saved or default value for PREFIX.
+
+ -- Function: transient-arg-value arg args
+ This function return the value of ARG as it appears in ARGS.
+
+ For a switch a boolean is returned. For an option the value is
+ returned as a string, using the empty string for the empty value,
+ or ‘nil’ if the option does not appear in ARGS.
+
+ -- Function: transient-suffixes prefix
+ This function returns the suffixes of the transient prefix command
+ PREFIX. This is a list of objects. This function should only be
+ used if you need the objects (as opposed to just their values) and
+ if the current command is not being invoked from PREFIX.
+
+ -- Variable: transient-current-suffixes
+ The suffixes of the transient from which this suffix command was
+ invoked. This is a list of objects. Usually it is sufficient to
+ instead use the function ‘transient-args’, which returns a list of
+ values. In complex cases it might be necessary to use this
+ variable instead, i.e., if you need access to information beside
+ the value.
+
+ -- Variable: transient-current-prefix
+ The transient from which this suffix command was invoked. The
+ returned value is a ‘transient-prefix’ object, which holds
+ information associated with the transient prefix command.
+
+ -- Variable: transient-current-command
+ The transient from which this suffix command was invoked. The
+ returned value is a symbol, the transient prefix command.
+
+\1f
+File: transient.info, Node: Transient State, Prev: Using Infix Arguments, Up: Defining New Commands
+
+4.6 Transient State
+===================
+
+Invoking a transient prefix command “activates” the respective
+transient, i.e., it puts a transient keymap into effect, which binds the
+transient’s infix and suffix commands.
+
+ The default behavior while a transient is active is as follows:
+
+ • Invoking an infix command does not affect the transient state; the
+ transient remains active.
+
+ • Invoking a (non-infix) suffix command “deactivates” the transient
+ state by removing the transient keymap and performing some
+ additional cleanup.
+
+ • Invoking a command that is bound in a keymap other than the
+ transient keymap is disallowed and trying to do so results in a
+ warning. This does not “deactivate” the transient.
+
+ The behavior can be changed for all suffixes of a particular prefix
+and/or for individual suffixes. The values should nearly always be
+booleans, but certain functions, called “pre-commands”, can also be
+used. These functions are named ‘transient--do-VERB’, and the symbol
+‘VERB’ can be used as a shorthand.
+
+ A boolean is interpreted as answering the question "does the
+transient stay active, when this command is invoked?" ‘t’ means that
+the transient stays active, while ‘nil’ means that invoking the command
+exits the transient.
+
+ Note that when the suffix is a “sub-prefix”, invoking that command
+always activates that sub-prefix, causing the outer prefix to no longer
+be active and displayed. Here ‘t’ means that when you exit the inner
+prefix, then the outer prefix becomes active again, while ‘nil’ means
+that all outer prefixes are exited at once.
+
+ • The behavior for non-suffixes can be set for a particular prefix,
+ by the prefix’s ‘transient-non-suffix’ slot to a boolean, a
+ suitable pre-command function, or a shorthand for such a function.
+ See *note Pre-commands for Non-Suffixes::.
+
+ • The common behavior for the suffixes of a particular prefix can be
+ set using the prefix’s ‘transient-suffixes’ slot.
+
+ The value specified in this slot does *not* affect infixes.
+ Because it affects both regular suffixes as well as sub-prefixes,
+ which have different needs, it is best to avoid explicitly
+ specifying a function.
+
+ • The behavior of an individual suffix can be changed using its
+ ‘transient’ slot. While it is usually best to use a boolean, for
+ this slot it can occasionally make sense to specify a function
+ explicitly.
+
+ Note that this slot can be set when defining a suffix command using
+ ‘transient-define-suffix’ and/or in the definition of the prefix.
+ If set in both places, then the latter takes precedence, as usual.
+
+ The available pre-command functions are documented in the following
+sub-sections. They are called by ‘transient--pre-command’, a function
+on ‘pre-command-hook’, and the value that they return determines whether
+the transient is exited. To do so the value of one of the constants
+‘transient--exit’ or ‘transient--stay’ is used (that way we don’t have
+to remember if ‘t’ means “exit” or “stay”).
+
+ Additionally, these functions may change the value of ‘this-command’
+(which explains why they have to be called using ‘pre-command-hook’),
+call ‘transient-export’, ‘transient--stack-zap’ or
+‘transient--stack-push’; and set the values of ‘transient--exitp’,
+‘transient--helpp’ or ‘transient--editp’.
+
+ For completeness sake, some notes about complications:
+
+ • The transient-ness of certain built-in suffix commands is specified
+ using ‘transient-predicate-map’. This is a special keymap, which
+ binds commands to pre-commands (as opposed to keys to commands) and
+ takes precedence over the prefix’s ‘transient-suffix’ slot, but not
+ the suffix’s ‘transient’ slot.
+
+ • While a sub-prefix is active we nearly always want ‘C-g’ to take
+ the user back to the “super-prefix”, even when the other suffixes
+ don’t do that. However, in rare cases this may not be desirable,
+ and that makes the following complication necessary:
+
+ For ‘transient-suffix’ objects the ‘transient’ slot is unbound. We
+ can ignore that for the most part because ‘nil’ and the slot being
+ unbound are treated as equivalent, and mean “do exit”. That isn’t
+ actually true for suffixes that are sub-prefixes though. For such
+ suffixes unbound means “do exit but allow going back”, which is the
+ default, while ‘nil’ means “do exit permanently”, which requires
+ that slot to be explicitly set to that value.
+
+Pre-commands for Infixes
+------------------------
+
+The default for infixes is ‘transient--do-stay’. This is also the only
+function that makes sense for infixes, which is why this predicate is
+used even if the value of the prefix’s ‘transient-suffix’ slot is ‘t’.
+In extremely rare cases, one might want to use something else, which can
+be done by setting the infix’s ‘transient’ slot directly.
+
+ -- Function: transient--do-stay
+ Call the command without exporting variables and stay transient.
+
+Pre-commands for Suffixes
+-------------------------
+
+By default, invoking a suffix causes the transient to be exited.
+
+ The behavior for an individual suffix command can be changed by
+setting its ‘transient’ slot to a boolean (which is highly recommended),
+or to one of the following pre-commands.
+
+ -- Function: transient--do-exit
+ Call the command after exporting variables and exit the transient.
+
+ -- Function: transient--do-return
+ Call the command after exporting variables and return to the parent
+ prefix. If there is no parent prefix, then call
+ ‘transient--do-exit’.
+
+ -- Function: transient--do-call
+ Call the command after exporting variables and stay transient.
+
+ The following pre-commands are only suitable for sub-prefixes. It is
+not necessary to explicitly use these predicates because the correct
+predicate is automatically picked based on the value of the ‘transient’
+slot for the sub-prefix itself.
+
+ -- Function: transient--do-recurse
+ Call the transient prefix command, preparing for return to active
+ transient.
+
+ Whether we actually return to the parent transient is ultimately
+ under the control of each invoked suffix. The difference between
+ this pre-command and ‘transient--do-stack’ is that it changes the
+ value of the ‘transient-suffix’ slot to ‘t’.
+
+ If there is no parent transient, then only call this command and
+ skip the second step.
+
+ -- Function: transient--do-stack
+ Call the transient prefix command, stacking the active transient.
+ Push the active transient to the transient stack.
+
+ Unless ‘transient--do-recurse’ is explicitly used, this pre-command
+ is automatically used for suffixes that are prefixes themselves,
+ i.e., for sub-prefixes.
+
+ -- Function: transient--do-replace
+ Call the transient prefix command, replacing the active transient.
+ Do not push the active transient to the transient stack.
+
+ Unless ‘transient--do-recurse’ is explicitly used, this pre-command
+ is automatically used for suffixes that are prefixes themselves,
+ i.e., for sub-prefixes.
+
+ -- Function: transient--do-suspend
+ Suspend the active transient, saving the transient stack.
+
+ This is used by the command ‘transient-suspend’ and optionally also
+ by “external events” such as ‘handle-switch-frame’. Such bindings
+ should be added to ‘transient-predicate-map’.
+
+Pre-commands for Non-Suffixes
+-----------------------------
+
+By default, non-suffixes (commands that are bound in other keymaps
+beside the transient keymap) cannot be invoked. Trying to invoke such a
+command results in a warning and the transient stays active.
+
+ If you want a different behavior, then set the ‘transient-non-suffix’
+slot of the transient prefix command. The value should be a boolean,
+answering the question, "is it allowed to invoke non-suffix commands?, a
+pre-command function, or a shorthand for such a function.
+
+ If the value is ‘t’, then non-suffixes can be invoked, when it is
+‘nil’ (the default) then they cannot be invoked.
+
+ The only other recommended value is ‘leave’. If that is used, then
+non-suffixes can be invoked, but if one is invoked, then that exits the
+transient.
+
+ -- Function: transient--do-warn
+ Call ‘transient-undefined’ and stay transient.
+
+ -- Function: transient--do-stay
+ Call the command without exporting variables and stay transient.
+
+ -- Function: transient--do-leave
+ Call the command without exporting variables and exit the
+ transient.
+
+Special Pre-Commands
+--------------------
+
+ -- Function: transient--do-quit-one
+ If active, quit help or edit mode, else exit the active transient.
+
+ This is used when the user pressed ‘C-g’.
+
+ -- Function: transient--do-quit-all
+ Exit all transients without saving the transient stack.
+
+ This is used when the user pressed ‘C-q’.
+
+ -- Function: transient--do-suspend
+ Suspend the active transient, saving the transient stack.
+
+ This is used when the user pressed ‘C-z’.
+
+\1f
+File: transient.info, Node: Classes and Methods, Next: FAQ, Prev: Defining New Commands, Up: Top
+
+5 Classes and Methods
+*********************
+
+Transient uses classes and generic functions to make it possible to
+define new types of suffix commands that are similar to existing types,
+but behave differently in some aspects. It does the same for groups and
+prefix commands, though at least for prefix commands that *currently*
+appears to be less important.
+
+ Every prefix, infix and suffix command is associated with an object,
+which holds information that controls certain aspects of its behavior.
+This happens in two ways.
+
+ • Associating a command with a certain class gives the command a
+ type. This makes it possible to use generic functions to do
+ certain things that have to be done differently depending on what
+ type of command it acts on.
+
+ That in turn makes it possible for third-parties to add new types
+ without having to convince the maintainer of Transient that that
+ new type is important enough to justify adding a special case to a
+ dozen or so functions.
+
+ • Associating a command with an object makes it possible to easily
+ store information that is specific to that particular command.
+
+ Two commands may have the same type, but obviously their key
+ bindings and descriptions still have to be different, for example.
+
+ The values of some slots are functions. The ‘reader’ slot for
+ example holds a function that is used to read a new value for an
+ infix command. The values of such slots are regular functions.
+
+ Generic functions are used when a function should do something
+ different based on the type of the command, i.e., when all commands
+ of a certain type should behave the same way but different from the
+ behavior for other types. Object slots that hold a regular
+ function as value are used when the task that they perform is
+ likely to differ even between different commands of the same type.
+
+* Menu:
+
+* Group Classes::
+* Group Methods::
+* Prefix Classes::
+* Suffix Classes::
+* Suffix Methods::
+* Prefix Slots::
+* Suffix Slots::
+* Predicate Slots::
+
+\1f
+File: transient.info, Node: Group Classes, Next: Group Methods, Up: Classes and Methods
+
+5.1 Group Classes
+=================
+
+The type of a group can be specified using the ‘:class’ property at the
+beginning of the class specification, e.g., ‘[:class transient-columns
+...]’ in a call to ‘transient-define-prefix’.
+
+ • The abstract ‘transient-child’ class is the base class of both
+ ‘transient-group’ (and therefore all groups) as well as of
+ ‘transient-suffix’ (and therefore all suffix and infix commands).
+
+ This class exists because the elements (or “children”) of certain
+ groups can be other groups instead of suffix and infix commands.
+
+ • The abstract ‘transient-group’ class is the superclass of all other
+ group classes.
+
+ • The ‘transient-column’ class is the simplest group.
+
+ This is the default “flat” group. If the class is not specified
+ explicitly and the first element is not a vector (i.e., not a
+ group), then this class is used.
+
+ This class displays each element on a separate line.
+
+ • The ‘transient-row’ class displays all elements on a single line.
+
+ • The ‘transient-columns’ class displays commands organized in
+ columns.
+
+ Direct elements have to be groups whose elements have to be
+ commands or strings. Each subgroup represents a column. This
+ class takes care of inserting the subgroups’ elements.
+
+ This is the default “nested” group. If the class is not specified
+ explicitly and the first element is a vector (i.e., a group), then
+ this class is used.
+
+ • The ‘transient-subgroups’ class wraps other groups.
+
+ Direct elements have to be groups whose elements have to be
+ commands or strings. This group inserts an empty line between
+ subgroups. The subgroups themselves are responsible for displaying
+ their elements.
+
+\1f
+File: transient.info, Node: Group Methods, Next: Prefix Classes, Prev: Group Classes, Up: Classes and Methods
+
+5.2 Group Methods
+=================
+
+ -- Function: transient-setup-children group children
+ This generic function can be used to setup the children or a group.
+
+ The default implementation usually just returns the children
+ unchanged, but if the ‘setup-children’ slot of GROUP is non-‘nil’,
+ then it calls that function with CHILDREN as the only argument and
+ returns the value.
+
+ The children are given as a (potentially empty) list consisting of
+ either group or suffix specifications. These functions can make
+ arbitrary changes to the children including constructing new
+ children from scratch.
+
+ -- Function: transient--insert-group group
+ This generic function formats the group and its elements and
+ inserts the result into the current buffer, which is a temporary
+ buffer. The contents of that buffer are later inserted into the
+ popup buffer.
+
+ Functions that are called by this function may need to operate in
+ the buffer from which the transient was called. To do so they can
+ temporarily make the ‘transient--source-buffer’ the current buffer.
+
+\1f
+File: transient.info, Node: Prefix Classes, Next: Suffix Classes, Prev: Group Methods, Up: Classes and Methods
+
+5.3 Prefix Classes
+==================
+
+Currently the ‘transient-prefix’ class is being used for all prefix
+commands and there is only a single generic function that can be
+specialized based on the class of a prefix command.
+
+ -- Function: transient--history-init obj
+ This generic function is called while setting up the transient and
+ is responsible for initializing the ‘history’ slot. This is the
+ transient-wide history; many individual infixes also have a history
+ of their own.
+
+ The default (and currently only) method extracts the value from the
+ global variable ‘transient-history’.
+
+ A transient prefix command’s object is stored in the
+‘transient--prefix’ property of the command symbol. While a transient
+is active, a clone of that object is stored in the variable
+‘transient--prefix’. A clone is used because some changes that are made
+to the active transient’s object should not affect later invocations.
+
+\1f
+File: transient.info, Node: Suffix Classes, Next: Suffix Methods, Prev: Prefix Classes, Up: Classes and Methods
+
+5.4 Suffix Classes
+==================
+
+ • All suffix and infix classes derive from ‘transient-suffix’, which
+ in turn derives from ‘transient-child’, from which
+ ‘transient-group’ also derives (see *note Group Classes::).
+
+ • All infix classes derive from the abstract ‘transient-infix’ class,
+ which in turn derives from the ‘transient-suffix’ class.
+
+ Infixes are a special type of suffixes. The primary difference is
+ that infixes always use the ‘transient--do-stay’ pre-command, while
+ non-infix suffixes use a variety of pre-commands (see *note
+ Transient State::). Doing that is most easily achieved by using
+ this class, though theoretically it would be possible to define an
+ infix class that does not do so. If you do that then you get to
+ implement many methods.
+
+ Also, infixes and non-infix suffixes are usually defined using
+ different macros (see *note Defining Suffix and Infix Commands::).
+
+ • Classes used for infix commands that represent arguments should be
+ derived from the abstract ‘transient-argument’ class.
+
+ • The ‘transient-switch’ class (or a derived class) is used for infix
+ arguments that represent command-line switches (arguments that do
+ not take a value).
+
+ • The ‘transient-option’ class (or a derived class) is used for infix
+ arguments that represent command-line options (arguments that do
+ take a value).
+
+ • The ‘transient-switches’ class can be used for a set of mutually
+ exclusive command-line switches.
+
+ • The ‘transient-files’ class can be used for a ‘--’ argument that
+ indicates that all remaining arguments are files.
+
+ • Classes used for infix commands that represent variables should
+ derived from the abstract ‘transient-variable’ class.
+
+ • The ‘transient-information’ class is special in that suffixes that
+ use this class are not associated with a command and thus also not
+ with any key binding. Such suffixes are only used to display
+ arbitrary information, and that anywhere a suffix can appear.
+ Display-only suffix specifications take this form:
+
+ ([LEVEL] :info DESCRIPTION [KEYWORD VALUE]...)
+
+ The ‘:info’ keyword argument replaces the ‘:description’ keyword
+ used for other suffix classes. Other keyword arguments that you
+ might want to set, include ‘:face’, predicate keywords (such as
+ ‘:if’), and ‘:format’. By default the value of ‘:format’ includes
+ ‘%k’, which for this class is replaced with the empty string or
+ spaces, if keys are being padded in the containing group.
+
+ Magit defines additional classes, which can serve as examples for the
+fancy things you can do without modifying Transient. Some of these
+classes will likely get generalized and added to Transient. For now
+they are very much subject to change and not documented.
+
+\1f
+File: transient.info, Node: Suffix Methods, Next: Prefix Slots, Prev: Suffix Classes, Up: Classes and Methods
+
+5.5 Suffix Methods
+==================
+
+To get information about the methods implementing these generic
+functions use ‘describe-function’.
+
+* Menu:
+
+* Suffix Value Methods::
+* Suffix Format Methods::
+
+\1f
+File: transient.info, Node: Suffix Value Methods, Next: Suffix Format Methods, Up: Suffix Methods
+
+5.5.1 Suffix Value Methods
+--------------------------
+
+ -- Function: transient-init-value obj
+ This generic function sets the initial value of the object OBJ.
+
+ This function is called for all suffix commands, but unless a
+ concrete method is implemented this falls through to the default
+ implementation, which is a noop. In other words this usually only
+ does something for infix commands, but note that this is not
+ implemented for the abstract class ‘transient-infix’, so if your
+ class derives from that directly, then you must implement a method.
+
+ -- Function: transient-infix-read obj
+ This generic function determines the new value of the infix object
+ OBJ.
+
+ This function merely determines the value; ‘transient-infix-set’ is
+ used to actually store the new value in the object.
+
+ For most infix classes this is done by reading a value from the
+ user using the reader specified by the ‘reader’ slot (using the
+ ‘transient-infix-value’ method described below).
+
+ For some infix classes the value is changed without reading
+ anything in the minibuffer, i.e., the mere act of invoking the
+ infix command determines what the new value should be, based on the
+ previous value.
+
+ -- Function: transient-prompt obj
+ This generic function returns the prompt to be used to read infix
+ object OBJ’s value.
+
+ -- Function: transient-infix-set obj value
+ This generic function sets the value of infix object OBJ to VALUE.
+
+ -- Function: transient-infix-value obj
+ This generic function returns the value of the suffix object OBJ.
+
+ This function is called by ‘transient-args’ (which see), meaning
+ this function is how the value of a transient is determined so that
+ the invoked suffix command can use it.
+
+ Currently most values are strings, but that is not set in stone.
+ ‘nil’ is not a value, it means “no value”.
+
+ Usually only infixes have a value, but see the method for
+ ‘transient-suffix’.
+
+ -- Function: transient-init-scope obj
+ This generic function sets the scope of the suffix object OBJ.
+
+ The scope is actually a property of the transient prefix, not of
+ individual suffixes. However it is possible to invoke a suffix
+ command directly instead of from a transient. In that case, if the
+ suffix expects a scope, then it has to determine that itself and
+ store it in its ‘scope’ slot.
+
+ This function is called for all suffix commands, but unless a
+ concrete method is implemented this falls through to the default
+ implementation, which is a noop.
+
+\1f
+File: transient.info, Node: Suffix Format Methods, Prev: Suffix Value Methods, Up: Suffix Methods
+
+5.5.2 Suffix Format Methods
+---------------------------
+
+ -- Function: transient-format obj
+ This generic function formats and returns OBJ for display.
+
+ When this function is called, then the current buffer is some
+ temporary buffer. If you need the buffer from which the prefix
+ command was invoked to be current, then do so by temporarily making
+ ‘transient--source-buffer’ current.
+
+ -- Function: transient-format-key obj
+ This generic function formats OBJ’s ‘key’ for display and returns
+ the result.
+
+ -- Function: transient-format-description obj
+ This generic function formats OBJ’s ‘description’ for display and
+ returns the result.
+
+ -- Function: transient-format-value obj
+ This generic function formats OBJ’s value for display and returns
+ the result.
+
+ -- Function: transient-show-help obj
+ Show help for the prefix, infix or suffix command represented by
+ OBJ.
+
+ For prefixes, show the info manual, if that is specified using the
+ ‘info-manual’ slot. Otherwise, show the manpage if that is
+ specified using the ‘man-page’ slot. Otherwise, show the command’s
+ documentation string.
+
+ For suffixes, show the command’s documentation string.
+
+ For infixes, show the manpage if that is specified. Otherwise show
+ the command’s documentation string.
+
+\1f
+File: transient.info, Node: Prefix Slots, Next: Suffix Slots, Prev: Suffix Methods, Up: Classes and Methods
+
+5.6 Prefix Slots
+================
+
+ • ‘show-help’, ‘man-page’ or ‘info-manual’ can be used to specify the
+ documentation for the prefix and its suffixes. The command
+ ‘transient-help’ uses the method ‘transient-show-help’ (which see)
+ to lookup and use these values.
+
+ • ‘history-key’ If multiple prefix commands should share a single
+ value, then this slot has to be set to the same value for all of
+ them. You probably don’t want that.
+
+ • ‘transient-suffix’ and ‘transient-non-suffix’ play a part when
+ determining whether the currently active transient prefix command
+ remains active/transient when a suffix or arbitrary non-suffix
+ command is invoked. See *note Transient State::.
+
+ • ‘refresh-suffixes’ Normally suffix objects and keymaps are only
+ setup once, when the prefix is invoked. Setting this to ‘t’,
+ causes them to be recreated after every command. This is useful
+ when using ‘:if...’ predicates, and those need to be rerun for some
+ reason. Doing this is somewhat costly, and there is a risk of
+ losing state, so this is disabled by default and still considered
+ experimental.
+
+ • ‘incompatible’ A list of lists. Each sub-list specifies a set of
+ mutually exclusive arguments. Enabling one of these arguments
+ causes the others to be disabled. An argument may appear in
+ multiple sub-lists. Arguments must me given in the same form as
+ used in the ‘argument’ or ‘argument-format’ slot of the respective
+ suffix objects, usually something like ‘--switch’ or ‘--option=%s’.
+ For options and ‘transient-switches’ suffixes it is also possible
+ to match against a specific value, as returned by
+ ‘transient-infix-value’, for example, ‘--option=one’.
+
+ • ‘scope’ For some transients it might be necessary to have a sort of
+ secondary value, called a “scope”. See ‘transient-define-prefix’.
+
+Internal Prefix Slots
+---------------------
+
+These slots are mostly intended for internal use. They should not be
+set in calls to ‘transient-define-prefix’.
+
+ • ‘prototype’ When a transient prefix command is invoked, then a
+ clone of that object is stored in the global variable
+ ‘transient--prefix’ and the prototype is stored in the clone’s
+ ‘prototype’ slot.
+
+ • ‘command’ The command, a symbol. Each transient prefix command
+ consists of a command, which is stored in a symbol’s function slot
+ and an object, which is stored in the ‘transient--prefix’ property
+ of the same symbol.
+
+ • ‘level’ The level of the prefix commands. The suffix commands
+ whose layer is equal or lower are displayed. See *note Enabling
+ and Disabling Suffixes::.
+
+ • ‘value’ The likely outdated value of the prefix. Instead of
+ accessing this slot directly you should use the function
+ ‘transient-get-value’, which is guaranteed to return the up-to-date
+ value.
+
+ • ‘history’ and ‘history-pos’ are used to keep track of historic
+ values. Unless you implement your own ‘transient-infix-read’
+ method you should not have to deal with these slots.
+
+\1f
+File: transient.info, Node: Suffix Slots, Next: Predicate Slots, Prev: Prefix Slots, Up: Classes and Methods
+
+5.7 Suffix Slots
+================
+
+Here we document most of the slots that are only available for suffix
+objects. Some slots are shared by suffix and group objects, they are
+documented in *note Predicate Slots::.
+
+ Also see *note Suffix Classes::.
+
+Slots of ‘transient-suffix’
+---------------------------
+
+ • ‘key’ The key, a key vector or a key description string.
+
+ • ‘command’ The command, a symbol.
+
+ • ‘transient’ Whether to stay transient. See *note Transient
+ State::.
+
+ • ‘format’ The format used to display the suffix in the popup buffer.
+ It must contain the following %-placeholders:
+
+ • ‘%k’ For the key.
+ • ‘%d’ For the description.
+ • ‘%v’ For the infix value. Non-infix suffixes don’t have a
+ value.
+
+ • ‘description’ The description, either a string or a function, which
+ is called with zero or one argument (the suffix object), and
+ returns a string.
+
+ • ‘face’ Face used for the description. In simple cases it is easier
+ to use this instead of using a function as ‘description’ and adding
+ the styling there. ‘face’ is appended using
+ ‘add-face-text-property’.
+
+ • ‘show-help’ A function used to display help for the suffix. If
+ unspecified, the prefix controls how help is displayed for its
+ suffixes.
+
+Slots of ‘transient-infix’
+--------------------------
+
+Some of these slots are only meaningful for some of the subclasses.
+They are defined here anyway to allow sharing certain methods.
+
+ • ‘argument’ The long argument, e.g., ‘--verbose’.
+
+ • ‘shortarg’ The short argument, e.g., ‘-v’.
+
+ • ‘value’ The value. Should not be accessed directly.
+
+ • ‘init-value’ Function that is responsible for setting the object’s
+ value. If bound, then this is called with the object as the only
+ argument. Usually this is not bound, in which case the object’s
+ primary ‘transient-init-value’ method is called instead.
+
+ • ‘unsavable’ Whether the value of the suffix is not saved as part of
+ the prefixes.
+
+ • ‘multi-value’ For options, whether the option can have multiple
+ values. If this is non-‘nil’, then the values are read using
+ ‘completing-read-multiple’ by default and if you specify your own
+ reader, then it should read the values using that function or
+ similar.
+
+ Supported non-‘nil’ values are:
+
+ • Use ‘rest’ for an option that can have multiple values. This
+ is useful e.g., for an ‘--’ argument that indicates that all
+ remaining arguments are files (such as ‘git log -- file1
+ file2’).
+
+ In the list returned by ‘transient-args’ such an option and
+ its values are represented by a single list of the form
+ ‘(ARGUMENT . VALUES)’.
+
+ • Use ‘repeat’ for an option that can be specified multiple
+ times.
+
+ In the list returned by ‘transient-args’ each instance of the
+ option and its value appears separately in the usual from, for
+ example: ‘("--another-argument" "--option=first"
+ "--option=second")’.
+
+ In both cases the option’s values have to be specified in the
+ default value of a prefix using the same format as returned by
+ ‘transient-args’, e.g., ‘("--other" "--o=1" "--o=2" ("--" "f1"
+ "f2"))’.
+
+ • ‘always-read’ For options, whether to read a value on every
+ invocation. If this is ‘nil’, then options that have a value are
+ simply unset and have to be invoked a second time to set a new
+ value.
+
+ • ‘allow-empty’ For options, whether the empty string is a valid
+ value.
+
+ • ‘history-key’ The key used to store the history. This defaults to
+ the command name. This is useful when multiple infixes should
+ share the same history because their values are of the same kind.
+
+ • ‘reader’ The function used to read the value of an infix. Not used
+ for switches. The function takes three arguments, PROMPT,
+ INITIAL-INPUT and HISTORY, and must return a string.
+
+ • ‘prompt’ The prompt used when reading the value, either a string or
+ a function that takes the object as the only argument and which
+ returns a prompt string.
+
+ • ‘choices’ A list of valid values, or a function that returns such a
+ list. The latter is not implemented for ‘transient-switches’,
+ because I couldn’t think of a use-case. How exactly the choices
+ are used varies depending on the class of the suffix.
+
+Slots of ‘transient-variable’
+-----------------------------
+
+ • ‘variable’ The variable.
+
+Slots of ‘transient-switches’
+-----------------------------
+
+ • ‘argument-format’ The display format. Must contain ‘%s’, one of
+ the ‘choices’ is substituted for that. E.g., ‘--%s-order’.
+
+ • ‘argument-regexp’ The regexp used to match any one of the switches.
+ E.g., ‘\\(--\\(topo\\|author-date\\|date\\)-order\\)’.
+
+\1f
+File: transient.info, Node: Predicate Slots, Prev: Suffix Slots, Up: Classes and Methods
+
+5.8 Predicate Slots
+===================
+
+Suffix and group objects share some predicate slots that control whether
+a group or suffix should be available depending on some state. Only one
+of these slots can be used at the same time. It is undefined what
+happens if you use more than one.
+
+ • ‘if’ Enable if predicate returns non-‘nil’.
+ • ‘if-not’ Enable if predicate returns ‘nil’.
+ • ‘if-non-nil’ Enable if variable’s value is non-‘nil’.
+ • ‘if-nil’ Enable if variable’s value is ‘nil’.
+ • ‘if-mode’ Enable if major-mode matches value.
+ • ‘if-not-mode’ Enable if major-mode does not match value.
+ • ‘if-derived’ Enable if major-mode derives from value.
+ • ‘if-not-derived’ Enable if major-mode does not derive from value.
+
+ By default these predicates run when the prefix command is invoked,
+but this can be changes, using the ‘refresh-suffixes’ prefix slot. See
+*note Prefix Slots::.
+
+ One more slot is shared between group and suffix classes, ‘level’.
+Like the slots documented above, it is a predicate, but it is used for a
+different purpose. The value has to be an integer between 1 and 7.
+‘level’ controls whether a suffix or a group should be available
+depending on user preference. See *note Enabling and Disabling
+Suffixes::.
+
+\1f
+File: transient.info, Node: FAQ, Next: Keystroke Index, Prev: Classes and Methods, Up: Top
+
+Appendix A FAQ
+**************
+
+A.1 Can I control how the popup buffer is displayed?
+====================================================
+
+Yes, see ‘transient-display-buffer-action’ in *note Configuration::.
+
+A.2 How can I copy text from the popup buffer?
+==============================================
+
+To be able to mark text in Transient’s popup buffer using the mouse, you
+have to add the below binding. Note that for technical reasons, the
+region won’t be visualized, while doing so. After you have quit the
+transient popup, you will be able to yank it in another buffer.
+
+ (keymap-set transient-predicate-map
+ "<mouse-set-region>"
+ #'transient--do-stay)
+
+A.3 How does Transient compare to prefix keys and universal arguments?
+======================================================================
+
+See
+<https://github.com/magit/transient/wiki/Comparison-with-prefix-keys-and-universal-arguments>.
+
+A.4 How does Transient compare to Magit-Popup and Hydra?
+========================================================
+
+See
+<https://github.com/magit/transient/wiki/Comparison-with-other-packages>.
+
+A.5 Why did some of the key bindings change?
+============================================
+
+You may have noticed that the bindings for some of the common commands
+do *not* have the prefix ‘C-x’ and that furthermore some of these
+commands are grayed out while others are not. That unfortunately is a
+bit confusing if the section of common commands is not shown
+permanently, making the following explanation necessary.
+
+ The purpose of usually hiding that section but showing it after the
+user pressed the respective prefix key is to conserve space and not
+overwhelm users with too much noise, while allowing the user to quickly
+list common bindings on demand.
+
+ That however should not keep us from using the best possible key
+bindings. The bindings that do use a prefix do so to avoid wasting too
+many non-prefix bindings, keeping them available for use in individual
+transients. The bindings that do not use a prefix and that are *not*
+grayed out are very important bindings that are *always* available, even
+when invoking the “common command key prefix” or *any other*
+transient-specific prefix. The non-prefix keys that *are* grayed out
+however, are not available when any incomplete prefix key sequence is
+active. They do not use the “common command key prefix” because it is
+likely that users want to invoke them several times in a row and e.g.,
+‘M-p M-p M-p’ is much more convenient than ‘C-x M-p C-x M-p C-x M-p’.
+
+ You may also have noticed that the “Set” command is bound to ‘C-x s’,
+while Magit-Popup used to bind ‘C-c C-c’ instead. I have seen several
+users praise the latter binding (sic), so I did not change it
+willy-nilly. The reason that I changed it is that using different
+prefix keys for different common commands, would have made the temporary
+display of the common commands even more confusing, i.e., after pressing
+‘C-c’ all the bindings that begin with the ‘C-x’ prefix would be grayed
+out.
+
+ Using a single prefix for common commands key means that all other
+potential prefix keys can be used for transient-specific commands
+*without* the section of common commands also popping up. ‘C-c’ in
+particular is a prefix that I want to (and already do) use for Magit,
+and also using that for a common command would prevent me from doing so.
+
+ (Also see the next question.)
+
+A.6 Why does ‘q’ not quit popups anymore?
+=========================================
+
+I agree that ‘q’ is a good binding for commands that quit something.
+This includes quitting whatever transient is currently active, but it
+also includes quitting whatever it is that some specific transient is
+controlling. The transient ‘magit-blame’ for example binds ‘q’ to the
+command that turns ‘magit-blame-mode’ off.
+
+ So I had to decide if ‘q’ should quit the active transient (like
+Magit-Popup used to) or whether ‘C-g’ should do that instead, so that
+‘q’ could be bound in individual transient to whatever commands make
+sense for them. Because all other letters are already reserved for use
+by individual transients, I have decided to no longer make an exception
+for ‘q’.
+
+ If you want to get ‘q’’s old binding back then you can do so. Doing
+that is a bit more complicated than changing a single key binding, so I
+have implemented a function, ‘transient-bind-q-to-quit’ that makes the
+necessary changes. See its documentation string for more information.
+
+\1f
+File: transient.info, Node: Keystroke Index, Next: Command and Function Index, Prev: FAQ, Up: Top
+
+Appendix B Keystroke Index
+**************************
+
+\0\b[index\0\b]
+* Menu:
+
+* C-g: Aborting and Resuming Transients.
+ (line 27)
+* C-g <1>: Aborting and Resuming Transients.
+ (line 27)
+* C-h: Getting Help for Suffix Commands.
+ (line 11)
+* C-M-n: Using History. (line 18)
+* C-M-p: Using History. (line 13)
+* C-q: Aborting and Resuming Transients.
+ (line 36)
+* C-x a: Enabling and Disabling Suffixes.
+ (line 68)
+* C-x C-k: Saving Values. (line 29)
+* C-x C-s: Saving Values. (line 25)
+* C-x l: Enabling and Disabling Suffixes.
+ (line 43)
+* C-x n: Using History. (line 18)
+* C-x p: Using History. (line 13)
+* C-x s: Saving Values. (line 21)
+* C-x t: Common Suffix Commands.
+ (line 18)
+* C-z: Aborting and Resuming Transients.
+ (line 41)
+
+\1f
+File: transient.info, Node: Command and Function Index, Next: Variable Index, Prev: Keystroke Index, Up: Top
+
+Appendix C Command and Function Index
+*************************************
+
+\0\b[index\0\b]
+* Menu:
+
+* transient--do-call: Transient State. (line 125)
+* transient--do-exit: Transient State. (line 117)
+* transient--do-leave: Transient State. (line 193)
+* transient--do-quit-all: Transient State. (line 205)
+* transient--do-quit-one: Transient State. (line 200)
+* transient--do-recurse: Transient State. (line 133)
+* transient--do-replace: Transient State. (line 153)
+* transient--do-return: Transient State. (line 120)
+* transient--do-stack: Transient State. (line 145)
+* transient--do-stay: Transient State. (line 105)
+* transient--do-stay <1>: Transient State. (line 190)
+* transient--do-suspend: Transient State. (line 161)
+* transient--do-suspend <1>: Transient State. (line 210)
+* transient--do-warn: Transient State. (line 187)
+* transient--history-init: Prefix Classes. (line 10)
+* transient--insert-group: Group Methods. (line 19)
+* transient-append-suffix: Modifying Existing Transients.
+ (line 51)
+* transient-arg-value: Using Infix Arguments.
+ (line 31)
+* transient-args: Using Infix Arguments.
+ (line 22)
+* transient-define-argument: Defining Suffix and Infix Commands.
+ (line 57)
+* transient-define-infix: Defining Suffix and Infix Commands.
+ (line 26)
+* transient-define-prefix: Defining Transients. (line 13)
+* transient-define-suffix: Defining Suffix and Infix Commands.
+ (line 9)
+* transient-format: Suffix Format Methods.
+ (line 6)
+* transient-format-description: Suffix Format Methods.
+ (line 18)
+* transient-format-key: Suffix Format Methods.
+ (line 14)
+* transient-format-value: Suffix Format Methods.
+ (line 22)
+* transient-get-suffix: Modifying Existing Transients.
+ (line 73)
+* transient-help: Getting Help for Suffix Commands.
+ (line 11)
+* transient-history-next: Using History. (line 18)
+* transient-history-prev: Using History. (line 13)
+* transient-infix-read: Suffix Value Methods.
+ (line 16)
+* transient-infix-set: Suffix Value Methods.
+ (line 36)
+* transient-infix-value: Suffix Value Methods.
+ (line 39)
+* transient-init-scope: Suffix Value Methods.
+ (line 52)
+* transient-init-value: Suffix Value Methods.
+ (line 6)
+* transient-insert-suffix: Modifying Existing Transients.
+ (line 49)
+* transient-prompt: Suffix Value Methods.
+ (line 32)
+* transient-quit-all: Aborting and Resuming Transients.
+ (line 36)
+* transient-quit-one: Aborting and Resuming Transients.
+ (line 27)
+* transient-quit-seq: Aborting and Resuming Transients.
+ (line 27)
+* transient-remove-suffix: Modifying Existing Transients.
+ (line 70)
+* transient-replace-suffix: Modifying Existing Transients.
+ (line 66)
+* transient-reset: Saving Values. (line 29)
+* transient-resume: Aborting and Resuming Transients.
+ (line 53)
+* transient-save: Saving Values. (line 25)
+* transient-scroll-down: Other Commands. (line 17)
+* transient-scroll-up: Other Commands. (line 12)
+* transient-set: Saving Values. (line 21)
+* transient-set-level: Enabling and Disabling Suffixes.
+ (line 43)
+* transient-setup-children: Group Methods. (line 6)
+* transient-show-help: Suffix Format Methods.
+ (line 26)
+* transient-suffix-put: Modifying Existing Transients.
+ (line 77)
+* transient-suffixes: Using Infix Arguments.
+ (line 38)
+* transient-suspend: Aborting and Resuming Transients.
+ (line 41)
+* transient-toggle-common: Common Suffix Commands.
+ (line 18)
+* transient-toggle-level-limit: Enabling and Disabling Suffixes.
+ (line 68)
+
+\1f
+File: transient.info, Node: Variable Index, Next: Concept Index, Prev: Command and Function Index, Up: Top
+
+Appendix D Variable Index
+*************************
+
+\0\b[index\0\b]
+* Menu:
+
+* transient-align-variable-pitch: Configuration. (line 185)
+* transient-current-command: Using Infix Arguments.
+ (line 57)
+* transient-current-prefix: Using Infix Arguments.
+ (line 52)
+* transient-current-suffixes: Using Infix Arguments.
+ (line 44)
+* transient-default-level: Enabling and Disabling Suffixes.
+ (line 33)
+* transient-detect-key-conflicts: Configuration. (line 210)
+* transient-display-buffer-action: Configuration. (line 51)
+* transient-enable-popup-navigation: Configuration. (line 36)
+* transient-force-fixed-pitch: Configuration. (line 198)
+* transient-force-single-column: Configuration. (line 93)
+* transient-hide-during-minibuffer-read: Configuration. (line 181)
+* transient-highlight-higher-levels: Configuration. (line 223)
+* transient-highlight-mismatched-keys: Configuration. (line 135)
+* transient-history-file: Using History. (line 33)
+* transient-history-limit: Using History. (line 37)
+* transient-levels-file: Enabling and Disabling Suffixes.
+ (line 38)
+* transient-mode-line-format: Configuration. (line 102)
+* transient-read-with-initial-input: Configuration. (line 174)
+* transient-semantic-coloring: Configuration. (line 126)
+* transient-show-common-commands: Common Suffix Commands.
+ (line 23)
+* transient-show-popup: Configuration. (line 15)
+* transient-substitute-key-function: Configuration. (line 153)
+* transient-values-file: Saving Values. (line 31)
+
+\1f
+File: transient.info, Node: Concept Index, Next: GNU General Public License, Prev: Variable Index, Up: Top
+
+Appendix E Concept Index
+************************
+
+\0\b[index\0\b]
+* Menu:
+
+* aborting transients: Aborting and Resuming Transients.
+ (line 6)
+* classes and methods: Classes and Methods. (line 6)
+* command dispatchers: Technical Introduction.
+ (line 39)
+* common suffix commands: Common Suffix Commands.
+ (line 6)
+* defining infix commands: Defining Suffix and Infix Commands.
+ (line 6)
+* defining suffix commands: Defining Suffix and Infix Commands.
+ (line 6)
+* disabling suffixes: Enabling and Disabling Suffixes.
+ (line 6)
+* enabling suffixes: Enabling and Disabling Suffixes.
+ (line 6)
+* getting help: Getting Help for Suffix Commands.
+ (line 6)
+* group specifications: Group Specifications. (line 6)
+* invoking transients: Invoking Transients. (line 6)
+* levels: Enabling and Disabling Suffixes.
+ (line 10)
+* modifying existing transients: Modifying Existing Transients.
+ (line 6)
+* quit transient: Aborting and Resuming Transients.
+ (line 6)
+* resuming transients: Aborting and Resuming Transients.
+ (line 6)
+* saving values of arguments: Saving Values. (line 6)
+* scope of a transient: Defining Transients. (line 43)
+* suffix specifications: Suffix Specifications.
+ (line 6)
+* transient state: Transient State. (line 6)
+* transient-level: Enabling and Disabling Suffixes.
+ (line 15)
+* value history: Using History. (line 6)
+
+\1f
+File: transient.info, Node: GNU General Public License, Prev: Concept Index, Up: Top
+
+Appendix F GNU General Public License
+*************************************
+
+ Version 3, 29 June 2007
+
+ Copyright © 2007 Free Software Foundation, Inc. <https://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 <https://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 <https://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 <https://www.gnu.org/licenses/why-not-lgpl.html>.
+
+
+\1f
+Tag Table:
+Node: Top\7f763
+Node: Introduction\7f2976
+Ref: Some things that Transient can do\7f3504
+Ref: Complexity in CLI programs\7f3857
+Ref: Using Transient for composing interactive commands\7f4458
+Node: Usage\7f6700
+Node: Invoking Transients\7f7068
+Node: Aborting and Resuming Transients\7f8147
+Node: Common Suffix Commands\7f10768
+Node: Saving Values\7f12604
+Ref: Saving Values-Footnote-1\7f13975
+Node: Using History\7f14168
+Node: Getting Help for Suffix Commands\7f15742
+Node: Enabling and Disabling Suffixes\7f17120
+Node: Other Commands\7f20408
+Node: Configuration\7f21384
+Ref: Essential Options\7f21664
+Ref: Accessibility Options\7f25325
+Ref: Auxiliary Options\7f25648
+Ref: Developer Options\7f30611
+Node: Modifying Existing Transients\7f31859
+Node: Defining New Commands\7f36051
+Node: Technical Introduction\7f36414
+Node: Defining Transients\7f42115
+Node: Binding Suffix and Infix Commands\7f44582
+Node: Group Specifications\7f45440
+Node: Suffix Specifications\7f50541
+Node: Defining Suffix and Infix Commands\7f54754
+Node: Using Infix Arguments\7f57802
+Node: Transient State\7f60636
+Ref: Pre-commands for Infixes\7f65451
+Ref: Pre-commands for Suffixes\7f65971
+Ref: Pre-commands for Non-Suffixes\7f68425
+Ref: Special Pre-Commands\7f69561
+Node: Classes and Methods\7f70069
+Node: Group Classes\7f72253
+Node: Group Methods\7f74180
+Node: Prefix Classes\7f75433
+Node: Suffix Classes\7f76524
+Node: Suffix Methods\7f79611
+Node: Suffix Value Methods\7f79932
+Node: Suffix Format Methods\7f82690
+Node: Prefix Slots\7f84169
+Ref: Internal Prefix Slots\7f86304
+Node: Suffix Slots\7f87561
+Ref: Slots of transient-suffix\7f87929
+Ref: Slots of transient-infix\7f89066
+Ref: Slots of transient-variable\7f92362
+Ref: Slots of transient-switches\7f92464
+Node: Predicate Slots\7f92827
+Node: FAQ\7f94262
+Ref: Can I control how the popup buffer is displayed?\7f94391
+Ref: How can I copy text from the popup buffer?\7f94572
+Ref: How does Transient compare to prefix keys and universal arguments?\7f95066
+Ref: How does Transient compare to Magit-Popup and Hydra?\7f95309
+Ref: Why did some of the key bindings change?\7f95503
+Ref: Why does q not quit popups anymore?\7f97856
+Node: Keystroke Index\7f98959
+Node: Command and Function Index\7f100824
+Node: Variable Index\7f107416
+Node: Concept Index\7f109689
+Node: GNU General Public License\7f112425
+\1f
+End Tag Table
+
+\1f
+Local Variables:
+coding: utf-8
+End: