dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

commit ce33ac2b119ec3a8ef13471a5a295d9ec575a920
parent 5c4878d4d5cd40d20f8a7d2be4da452ad5bb1be8
Author: Lukas Henkel <lh@entf.net>
Date:   Fri, 17 Nov 2023 22:24:48 +0100

Add diff-hl

Diffstat:
Aelpa/diff-hl-1.9.2.signed | 3+++
Aelpa/diff-hl-1.9.2/.dir-locals.el | 5+++++
Aelpa/diff-hl-1.9.2/.elpaignore | 2++
Aelpa/diff-hl-1.9.2/LICENSE | 674+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/diff-hl-1.9.2/Makefile | 26++++++++++++++++++++++++++
Aelpa/diff-hl-1.9.2/diff-hl-amend.el | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/diff-hl-1.9.2/diff-hl-autoloads.el | 348+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/diff-hl-1.9.2/diff-hl-dired.el | 185+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/diff-hl-1.9.2/diff-hl-flydiff.el | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/diff-hl-1.9.2/diff-hl-inline-popup.el | 284+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/diff-hl-1.9.2/diff-hl-margin.el | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/diff-hl-1.9.2/diff-hl-pkg.el | 2++
Aelpa/diff-hl-1.9.2/diff-hl-show-hunk-posframe.el | 238+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/diff-hl-1.9.2/diff-hl-show-hunk.el | 419+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/diff-hl-1.9.2/diff-hl.el | 1128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/diff-hl-1.9.2/test/diff-hl-test.el | 173+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/diff-hl-1.9.2/test/empty | 10++++++++++
Minit.el | 3++-
18 files changed, 3808 insertions(+), 1 deletion(-)

diff --git a/elpa/diff-hl-1.9.2.signed b/elpa/diff-hl-1.9.2.signed @@ -0,0 +1,2 @@ +Good signature from 066DAFCB81E42C40 GNU ELPA Signing Agent (2019) <elpasign@elpa.gnu.org> (trust undefined) created at 2023-02-19T11:05:02+0100 using RSA +Good signature from 645357D2883A0966 GNU ELPA Signing Agent (2023) <elpasign@elpa.gnu.org> (trust undefined) created at 2023-02-19T11:05:02+0100 using EDDSA +\ No newline at end of file diff --git a/elpa/diff-hl-1.9.2/.dir-locals.el b/elpa/diff-hl-1.9.2/.dir-locals.el @@ -0,0 +1,5 @@ +((nil . ((indent-tabs-mode . nil) + (fill-column . 80) + (sentence-end-double-space . t) + (emacs-lisp-docstring-fill-column . 75))) + (makefile-mode . ((indent-tabs-mode . t)))) diff --git a/elpa/diff-hl-1.9.2/.elpaignore b/elpa/diff-hl-1.9.2/.elpaignore @@ -0,0 +1,2 @@ +README.md +screenshot* diff --git a/elpa/diff-hl-1.9.2/LICENSE b/elpa/diff-hl-1.9.2/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/elpa/diff-hl-1.9.2/Makefile b/elpa/diff-hl-1.9.2/Makefile @@ -0,0 +1,26 @@ +EMACS ?= emacs +SOURCES=diff-hl.el +SOURCES+=diff-hl-amend.el +SOURCES+=diff-hl-dired.el +SOURCES+=diff-hl-flydiff.el +SOURCES+=diff-hl-inline-popup.el +SOURCES+=diff-hl-margin.el +SOURCES+=diff-hl-show-hunk-posframe.el +SOURCES+=diff-hl-show-hunk.el + +ARTIFACTS=$(patsubst %.el, %.elc, $(SOURCES)) + +RM ?= rm -f + +all: compile test + +test: + $(EMACS) -batch -L . -l test/diff-hl-test.el -f diff-hl-run-tests + +compile: + $(EMACS) -batch -L . -f batch-byte-compile $(SOURCES) + +clean: + $(RM) $(ARTIFACTS) + +.PHONY: all test compile plain clean diff --git a/elpa/diff-hl-1.9.2/diff-hl-amend.el b/elpa/diff-hl-1.9.2/diff-hl-amend.el @@ -0,0 +1,69 @@ +;; Copyright (C) 2012-2013, 2020 Free Software Foundation, Inc. -*- lexical-binding: t -*- + +;; Author: Dmitry Gutov <dgutov@yandex.ru> +;; URL: https://github.com/dgutov/diff-hl + +;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Toggle in the current buffer with `M-x diff-hl-amend-mode'. +;; Toggle in all buffers with `M-x global-diff-hl-amend-mode'. + +;;; Code: + +(require 'diff-hl) + +;;;###autoload +(define-minor-mode diff-hl-amend-mode + "Show changes against the second-last revision in `diff-hl-mode'. +Most useful with backends that support rewriting local commits, +and most importantly, \"amending\" the most recent one. +Currently only supports Git, Mercurial and Bazaar." + :lighter " Amend" + (if diff-hl-amend-mode + (progn + (diff-hl-amend-setup) + (add-hook 'after-revert-hook 'diff-hl-amend-setup nil t)) + (remove-hook 'after-revert-hook 'diff-hl-amend-setup t) + (kill-local-variable 'diff-hl-reference-revision)) + (when diff-hl-mode + (diff-hl-update))) + +(defun diff-hl-amend-setup () + (let ((backend (vc-backend buffer-file-name))) + (when backend + (setq-local diff-hl-reference-revision + (cl-case backend + (Git + "HEAD^") + (Hg + "-2") + (Bzr + "revno:-2")))))) + +;;;###autoload +(define-globalized-minor-mode global-diff-hl-amend-mode diff-hl-amend-mode + turn-on-diff-hl-amend-mode + :group 'diff-hl) + +(defun turn-on-diff-hl-amend-mode () + "Turn on `diff-hl-amend-mode' in a buffer if appropriate." + (and buffer-file-name (diff-hl-amend-mode 1))) + +(provide 'diff-hl-amend) + +;;; diff-hl-amend.el ends here diff --git a/elpa/diff-hl-1.9.2/diff-hl-autoloads.el b/elpa/diff-hl-1.9.2/diff-hl-autoloads.el @@ -0,0 +1,348 @@ +;;; diff-hl-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))) + + + +;;; Generated autoloads from diff-hl.el + +(autoload 'diff-hl-mode "diff-hl" "\ +Toggle VC diff highlighting. + +This is a minor mode. If called interactively, toggle the +`Diff-Hl mode' mode. If the prefix argument is positive, enable +the mode, and if it is zero or negative, disable the mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate `diff-hl-mode'. + +The mode's hook is called both when the mode is enabled and when +it is disabled. + +(fn &optional ARG)" t) +(autoload 'turn-on-diff-hl-mode "diff-hl" "\ +Turn on `diff-hl-mode' or `diff-hl-dir-mode' in a buffer if appropriate.") +(autoload 'diff-hl--global-turn-on "diff-hl" "\ +Call `turn-on-diff-hl-mode' if the current major mode is applicable.") +(autoload 'diff-hl-set-reference-rev "diff-hl" "\ +Set the reference revision globally to REV. +When called interactively, REV read with completion. + +The default value chosen using one of methods below: + +- In a log view buffer, it uses the revision of current entry. +Call `vc-print-log' or `vc-print-root-log' first to open a log +view buffer. +- In a VC annotate buffer, it uses the revision of current line. +- In other situations, it uses the symbol at point. + +Notice that this sets the reference revision globally, so in +files from other repositories, `diff-hl-mode' will not highlight +changes correctly, until you run `diff-hl-reset-reference-rev'. + +Also notice that this will disable `diff-hl-amend-mode' in +buffers that enables it, since `diff-hl-amend-mode' overrides its +effect. + +(fn REV)" t) +(autoload 'diff-hl-reset-reference-rev "diff-hl" "\ +Reset the reference revision globally to the most recent one." t) +(put 'global-diff-hl-mode 'globalized-minor-mode t) +(defvar global-diff-hl-mode nil "\ +Non-nil if Global Diff-Hl mode is enabled. +See the `global-diff-hl-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `global-diff-hl-mode'.") +(custom-autoload 'global-diff-hl-mode "diff-hl" nil) +(autoload 'global-diff-hl-mode "diff-hl" "\ +Toggle Diff-Hl mode in all buffers. +With prefix ARG, enable Global Diff-Hl mode if ARG is positive; +otherwise, disable it. + +If called from Lisp, toggle the mode if ARG is `toggle'. +Enable the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +Diff-Hl mode is enabled in all buffers where `diff-hl--global-turn-on' +would do it. + +See `diff-hl-mode' for more information on Diff-Hl mode. + +(fn &optional ARG)" t) +(register-definition-prefixes "diff-hl" '("diff-hl-")) + + +;;; Generated autoloads from diff-hl-amend.el + +(autoload 'diff-hl-amend-mode "diff-hl-amend" "\ +Show changes against the second-last revision in `diff-hl-mode'. + +Most useful with backends that support rewriting local commits, +and most importantly, \"amending\" the most recent one. +Currently only supports Git, Mercurial and Bazaar. + +This is a minor mode. If called interactively, toggle the +`Diff-Hl-Amend mode' mode. If the prefix argument is positive, +enable the mode, and if it is zero or negative, disable the mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate `diff-hl-amend-mode'. + +The mode's hook is called both when the mode is enabled and when +it is disabled. + +(fn &optional ARG)" t) +(put 'global-diff-hl-amend-mode 'globalized-minor-mode t) +(defvar global-diff-hl-amend-mode nil "\ +Non-nil if Global Diff-Hl-Amend mode is enabled. +See the `global-diff-hl-amend-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `global-diff-hl-amend-mode'.") +(custom-autoload 'global-diff-hl-amend-mode "diff-hl-amend" nil) +(autoload 'global-diff-hl-amend-mode "diff-hl-amend" "\ +Toggle Diff-Hl-Amend mode in all buffers. +With prefix ARG, enable Global Diff-Hl-Amend mode if ARG is positive; +otherwise, disable it. + +If called from Lisp, toggle the mode if ARG is `toggle'. +Enable the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +Diff-Hl-Amend mode is enabled in all buffers where +`turn-on-diff-hl-amend-mode' would do it. + +See `diff-hl-amend-mode' for more information on Diff-Hl-Amend mode. + +(fn &optional ARG)" t) +(register-definition-prefixes "diff-hl-amend" '("diff-hl-amend-setup" "turn-on-diff-hl-amend-mode")) + + +;;; Generated autoloads from diff-hl-dired.el + +(autoload 'diff-hl-dired-mode "diff-hl-dired" "\ +Toggle VC diff highlighting on the side of a Dired window. + +This is a minor mode. If called interactively, toggle the +`Diff-Hl-Dired mode' mode. If the prefix argument is positive, +enable the mode, and if it is zero or negative, disable the mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate `diff-hl-dired-mode'. + +The mode's hook is called both when the mode is enabled and when +it is disabled. + +(fn &optional ARG)" t) +(autoload 'diff-hl-dired-mode-unless-remote "diff-hl-dired") +(register-definition-prefixes "diff-hl-dired" '("diff-hl-dired-")) + + +;;; Generated autoloads from diff-hl-flydiff.el + +(defvar diff-hl-flydiff-mode nil "\ +Non-nil if Diff-Hl-Flydiff mode is enabled. +See the `diff-hl-flydiff-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `diff-hl-flydiff-mode'.") +(custom-autoload 'diff-hl-flydiff-mode "diff-hl-flydiff" nil) +(autoload 'diff-hl-flydiff-mode "diff-hl-flydiff" "\ +Perform highlighting on-the-fly. + +This is a global minor mode. It alters how `diff-hl-mode' works. + +This is a global minor mode. If called interactively, toggle the +`Diff-Hl-Flydiff mode' mode. If the prefix argument is positive, +enable the mode, and if it is zero or negative, disable the mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate `(default-value \\='diff-hl-flydiff-mode)'. + +The mode's hook is called both when the mode is enabled and when +it is disabled. + +(fn &optional ARG)" t) +(register-definition-prefixes "diff-hl-flydiff" '("diff-hl-flydiff")) + + +;;; Generated autoloads from diff-hl-inline-popup.el + +(autoload 'diff-hl-inline-popup-hide "diff-hl-inline-popup" "\ +Hide the current inline popup." t) +(autoload 'diff-hl-inline-popup-show "diff-hl-inline-popup" "\ +Create a phantom overlay to show the inline popup, with some +content LINES, and a HEADER and a FOOTER, at POINT. KEYMAP is +added to the current keymaps. CLOSE-HOOK is called when the popup +is closed. + +(fn LINES &optional HEADER FOOTER KEYMAP CLOSE-HOOK POINT HEIGHT)") +(register-definition-prefixes "diff-hl-inline-popup" '("diff-hl-inline-popup-")) + + +;;; Generated autoloads from diff-hl-margin.el + +(defvar diff-hl-margin-mode nil "\ +Non-nil if Diff-Hl-Margin mode is enabled. +See the `diff-hl-margin-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `diff-hl-margin-mode'.") +(custom-autoload 'diff-hl-margin-mode "diff-hl-margin" nil) +(autoload 'diff-hl-margin-mode "diff-hl-margin" "\ +Toggle displaying `diff-hl-mode' highlights on the margin. + +This is a global minor mode. If called interactively, toggle the +`Diff-Hl-Margin mode' mode. If the prefix argument is positive, +enable the mode, and if it is zero or negative, disable the mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate `(default-value \\='diff-hl-margin-mode)'. + +The mode's hook is called both when the mode is enabled and when +it is disabled. + +(fn &optional ARG)" t) +(autoload 'diff-hl-margin-local-mode "diff-hl-margin" "\ +Toggle displaying `diff-hl-mode' highlights on the margin locally. + +You probably shouldn't use this function directly. + +This is a minor mode. If called interactively, toggle the +`Diff-Hl-Margin-Local mode' mode. If the prefix argument is +positive, enable the mode, and if it is zero or negative, disable +the mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate `diff-hl-margin-local-mode'. + +The mode's hook is called both when the mode is enabled and when +it is disabled. + +(fn &optional ARG)" t) +(register-definition-prefixes "diff-hl-margin" '("diff-hl-")) + + +;;; Generated autoloads from diff-hl-show-hunk.el + +(autoload 'diff-hl-show-hunk-inline-popup "diff-hl-show-hunk" "\ +Implementation to show the hunk in a inline popup. +BUFFER is a buffer with the hunk. + +(fn BUFFER &optional IGNORED-LINE)") +(autoload 'diff-hl-show-hunk-previous "diff-hl-show-hunk" "\ +Go to previous hunk/change and show it." t) +(autoload 'diff-hl-show-hunk-next "diff-hl-show-hunk" "\ +Go to next hunk/change and show it." t) +(autoload 'diff-hl-show-hunk "diff-hl-show-hunk" "\ +Show the VC diff hunk at point. +The backend is determined by `diff-hl-show-hunk-function'." t) +(autoload 'diff-hl-show-hunk-mouse-mode "diff-hl-show-hunk" "\ +Enables the margin and fringe to show a posframe/popup with vc diffs when clicked. + +By default, the popup shows only the current hunk, and +the line of the hunk that matches the current position is +highlighted. The face, border and other visual preferences are +customizable. It can be also invoked with the command +`diff-hl-show-hunk' +\\{diff-hl-show-hunk-mouse-mode-map} + +This is a minor mode. If called interactively, toggle the +`Diff-Hl-Show-Hunk-Mouse mode' mode. If the prefix argument is +positive, enable the mode, and if it is zero or negative, disable +the mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate `diff-hl-show-hunk-mouse-mode'. + +The mode's hook is called both when the mode is enabled and when +it is disabled. + +(fn &optional ARG)" t) +(put 'global-diff-hl-show-hunk-mouse-mode 'globalized-minor-mode t) +(defvar global-diff-hl-show-hunk-mouse-mode nil "\ +Non-nil if Global Diff-Hl-Show-Hunk-Mouse mode is enabled. +See the `global-diff-hl-show-hunk-mouse-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `global-diff-hl-show-hunk-mouse-mode'.") +(custom-autoload 'global-diff-hl-show-hunk-mouse-mode "diff-hl-show-hunk" nil) +(autoload 'global-diff-hl-show-hunk-mouse-mode "diff-hl-show-hunk" "\ +Toggle Diff-Hl-Show-Hunk-Mouse mode in all buffers. +With prefix ARG, enable Global Diff-Hl-Show-Hunk-Mouse mode if ARG is +positive; otherwise, disable it. + +If called from Lisp, toggle the mode if ARG is `toggle'. +Enable the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +Diff-Hl-Show-Hunk-Mouse mode is enabled in all buffers where +`diff-hl-show-hunk-mouse-mode' would do it. + +See `diff-hl-show-hunk-mouse-mode' for more information on +Diff-Hl-Show-Hunk-Mouse mode. + +(fn &optional ARG)" t) +(register-definition-prefixes "diff-hl-show-hunk" '("diff-hl-show-hunk-")) + + +;;; Generated autoloads from diff-hl-show-hunk-posframe.el + +(autoload 'diff-hl-show-hunk-posframe "diff-hl-show-hunk-posframe" "\ +Implementation to show the hunk in a posframe. + +(fn BUFFER &optional LINE)") +(register-definition-prefixes "diff-hl-show-hunk-posframe" '("diff-hl-show-hunk-")) + +;;; End of scraped data + +(provide 'diff-hl-autoloads) + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; no-native-compile: t +;; coding: utf-8-emacs-unix +;; End: + +;;; diff-hl-autoloads.el ends here diff --git a/elpa/diff-hl-1.9.2/diff-hl-dired.el b/elpa/diff-hl-1.9.2/diff-hl-dired.el @@ -0,0 +1,185 @@ +;;; diff-hl-dired.el --- Highlight changed files in Dired -*- lexical-binding: t -*- + +;; Copyright (C) 2012-2017, 2023 Free Software Foundation, Inc. + +;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; To enable in all Dired buffers, add this to your init file: +;; +;; (add-hook 'dired-mode-hook 'diff-hl-dired-mode) +;; +;; or +;; +;; (add-hook 'dired-mode-hook 'diff-hl-dired-mode-unless-remote) +;; +;; to do it only in local Dired buffers. + +;;; Code: + +(require 'diff-hl) +(require 'dired) +(require 'vc-hooks) + +(defvar diff-hl-dired-process-buffer nil) + +(defgroup diff-hl-dired nil + "VC diff highlighting on the side of a Dired window." + :group 'diff-hl) + +(defface diff-hl-dired-insert + '((default :inherit diff-hl-insert)) + "Face used to highlight added files.") + +(defface diff-hl-dired-delete + '((default :inherit diff-hl-delete)) + "Face used to highlight directories with deleted files.") + +(defface diff-hl-dired-change + '((default :inherit diff-hl-change)) + "Face used to highlight changed files.") + +(defface diff-hl-dired-unknown + '((default :inherit dired-ignored)) + "Face used to highlight unregistered files.") + +(defface diff-hl-dired-ignored + '((default :inherit dired-ignored)) + "Face used to highlight unregistered files.") + +(defcustom diff-hl-dired-extra-indicators t + "Non-nil to indicate ignored files." + :type 'boolean) + +(defcustom diff-hl-dired-ignored-backends '(RCS) + "VC backends to ignore. +The directories registered to one of these backends won't have +status indicators." + :type `(repeat (choice ,@(mapcar + (lambda (name) + `(const :tag ,(symbol-name name) ,name)) + vc-handled-backends)))) + +;;;###autoload +(define-minor-mode diff-hl-dired-mode + "Toggle VC diff highlighting on the side of a Dired window." + :lighter "" + (if diff-hl-dired-mode + (progn + (diff-hl-maybe-define-bitmaps) + (set (make-local-variable 'diff-hl-dired-process-buffer) nil) + (add-hook 'dired-after-readin-hook 'diff-hl-dired-update nil t)) + (remove-hook 'dired-after-readin-hook 'diff-hl-dired-update t) + (diff-hl-dired-clear))) + +(defun diff-hl-dired-update () + "Highlight the Dired buffer." + (let ((backend (ignore-errors (vc-responsible-backend default-directory))) + (def-dir default-directory) + (buffer (current-buffer)) + dirs-alist files-alist) + (when (and backend (not (memq backend diff-hl-dired-ignored-backends))) + (diff-hl-dired-clear) + (if (buffer-live-p diff-hl-dired-process-buffer) + (let ((proc (get-buffer-process diff-hl-dired-process-buffer))) + (when proc (kill-process proc))) + (setq diff-hl-dired-process-buffer + (generate-new-buffer " *diff-hl-dired* tmp status"))) + (with-current-buffer diff-hl-dired-process-buffer + (setq default-directory (expand-file-name def-dir)) + (erase-buffer) + (diff-hl-dired-status-files + backend def-dir + (when diff-hl-dired-extra-indicators + (cl-loop for file in (directory-files def-dir) + unless (member file '("." ".." ".hg")) + collect file)) + (lambda (entries &optional more-to-come) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (dolist (entry entries) + (cl-destructuring-bind (file state &rest r) entry + ;; Work around http://debbugs.gnu.org/18605 + (setq file (replace-regexp-in-string "\\` " "" file)) + (let ((type (plist-get + '( edited change added insert removed delete + unregistered unknown ignored ignored) + state))) + (if (string-match "\\`\\([^/]+\\)/" file) + (let* ((dir (match-string 1 file)) + (value (cdr (assoc dir dirs-alist)))) + (unless (eq value type) + (cond + ((eq state 'up-to-date)) + ((null value) + (push (cons dir type) dirs-alist)) + ((not (eq type 'ignored)) + (setcdr (assoc dir dirs-alist) 'change))))) + (push (cons file type) files-alist))))) + (unless more-to-come + (diff-hl-dired-highlight-items + (append dirs-alist files-alist)))) + (unless more-to-come + (kill-buffer diff-hl-dired-process-buffer)))) + ))))) + +(defun diff-hl-dired-status-files (backend dir files update-function) + "Using version control BACKEND, return list of (FILE STATE EXTRA) entries +for DIR containing FILES. Call UPDATE-FUNCTION as entries are added." + (if (version< "25" emacs-version) + (vc-call-backend backend 'dir-status-files dir files update-function) + (vc-call-backend backend 'dir-status-files dir files nil update-function))) + +(when (version< emacs-version "24.4.51.5") + ;; Work around http://debbugs.gnu.org/19386 + (defadvice vc-git-dir-status-goto-stage (around + diff-hl-dired-skip-up-to-date + (stage files update-function) + activate) + (when (eq stage 'ls-files-up-to-date) + (setq stage 'diff-index)) + ad-do-it)) + +(defun diff-hl-dired-highlight-items (alist) + "Highlight ALIST containing (FILE . TYPE) elements." + (dolist (pair alist) + (let ((file (car pair)) + (type (cdr pair))) + (save-excursion + (goto-char (point-min)) + (when (and type (dired-goto-file-1 + file (expand-file-name file) nil)) + (let* ((diff-hl-fringe-bmp-function 'diff-hl-fringe-bmp-from-type) + (diff-hl-fringe-face-function 'diff-hl-dired-face-from-type) + (o (diff-hl-add-highlighting type 'single))) + (overlay-put o 'modification-hooks '(diff-hl-overlay-modified)) + (overlay-put o 'diff-hl-dired-type type) + )))))) + +(defun diff-hl-dired-face-from-type (type _pos) + (intern (format "diff-hl-dired-%s" type))) + +(defalias 'diff-hl-dired-clear 'diff-hl-remove-overlays) + +;;;###autoload +(defun diff-hl-dired-mode-unless-remote () + (unless (file-remote-p default-directory) + (diff-hl-dired-mode))) + +(provide 'diff-hl-dired) + +;;; diff-hl-dired.el ends here diff --git a/elpa/diff-hl-1.9.2/diff-hl-flydiff.el b/elpa/diff-hl-1.9.2/diff-hl-flydiff.el @@ -0,0 +1,83 @@ +;; Copyright (C) 2015-2021 Free Software Foundation, Inc. -*- lexical-binding: t -*- + +;; Author: Jonathan Hayase <PythonNut@gmail.com> +;; URL: https://github.com/dgutov/diff-hl + +;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This mode enables diffing on-the-fly (i.e. without saving the buffer first) +;; Toggle in all buffers with M-x diff-hl-flydiff-mode + +;;; Code: + +(require 'diff-hl) +(require 'diff) + +(defgroup diff-hl-flydiff nil + "Highlight changes on the fly" + :group 'diff-hl) + +(defcustom diff-hl-flydiff-delay 0.3 + "The idle delay in seconds before highlighting is updated." + :type 'number) + +(defvar diff-hl-flydiff-modified-tick nil) +(defvar diff-hl-flydiff-timer nil) +(make-variable-buffer-local 'diff-hl-flydiff-modified-tick) + +(defun diff-hl-flydiff-changes-buffer (file &optional backend) + (setq diff-hl-flydiff-modified-tick (buffer-chars-modified-tick)) + (diff-hl-diff-buffer-with-reference file " *diff-hl-diff*" backend)) + +(defun diff-hl-flydiff-update () + (unless (or + (not diff-hl-mode) + (eq diff-hl-flydiff-modified-tick (buffer-chars-modified-tick)) + (not buffer-file-name) + (file-remote-p default-directory) + (not (file-exists-p buffer-file-name))) + (diff-hl-update))) + +(defun diff-hl-flydiff/modified-p (_state) + (buffer-modified-p)) + +;;;###autoload +(define-minor-mode diff-hl-flydiff-mode + "Perform highlighting on-the-fly. +This is a global minor mode. It alters how `diff-hl-mode' works." + :lighter "" :global t + (if diff-hl-flydiff-mode + (progn + (advice-add 'diff-hl-overlay-modified :override #'ignore) + + (advice-add 'diff-hl-modified-p :before-until + #'diff-hl-flydiff/modified-p) + (advice-add 'diff-hl-changes-buffer :override + #'diff-hl-flydiff-changes-buffer) + (setq diff-hl-flydiff-timer + (run-with-idle-timer diff-hl-flydiff-delay t #'diff-hl-flydiff-update))) + + (advice-remove 'diff-hl-overlay-modified #'ignore) + + (advice-remove 'diff-hl-modified-p #'diff-hl-flydiff/modified-p) + (advice-remove 'diff-hl-changes-buffer #'diff-hl-flydiff-changes-buffer) + + (and diff-hl-flydiff-timer + (cancel-timer diff-hl-flydiff-timer)))) + +(provide 'diff-hl-flydiff) diff --git a/elpa/diff-hl-1.9.2/diff-hl-inline-popup.el b/elpa/diff-hl-1.9.2/diff-hl-inline-popup.el @@ -0,0 +1,284 @@ +;;; diff-hl-inline-popup.el --- inline popup using phantom overlays -*- lexical-binding: t -*- + +;; Copyright (C) 2020-2021 Free Software Foundation, Inc. + +;; Author: Álvaro González <alvarogonzalezsotillo@gmail.com> + +;; 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: +;; Shows inline popups using phantom overlays. The lines of the popup +;; can be scrolled. +;;; Code: + +(require 'subr-x) + +(defvar diff-hl-inline-popup--current-popup nil "The overlay of the current inline popup.") +(defvar diff-hl-inline-popup--current-lines nil "A list of the lines to show in the popup.") +(defvar diff-hl-inline-popup--current-index nil "First line showed in popup.") +(defvar diff-hl-inline-popup--invokinkg-command nil "Command that invoked the popup.") +(defvar diff-hl-inline-popup--current-footer nil "String to be displayed in the footer.") +(defvar diff-hl-inline-popup--current-header nil "String to be displayed in the header.") +(defvar diff-hl-inline-popup--height nil "Height of the popup.") +(defvar diff-hl-inline-popup--current-custom-keymap nil "Keymap to be added to the keymap of the inline popup.") +(defvar diff-hl-inline-popup--close-hook nil "Function to be called when the popup closes.") + +(make-variable-buffer-local 'diff-hl-inline-popup--current-popup) +(make-variable-buffer-local 'diff-hl-inline-popup--current-lines) +(make-variable-buffer-local 'diff-hl-inline-popup--current-index) +(make-variable-buffer-local 'diff-hl-inline-popup--current-header) +(make-variable-buffer-local 'diff-hl-inline-popup--current-footer) +(make-variable-buffer-local 'diff-hl-inline-popup--invokinkg-command) +(make-variable-buffer-local 'diff-hl-inline-popup--current-custom-keymap) +(make-variable-buffer-local 'diff-hl-inline-popup--height) +(make-variable-buffer-local 'diff-hl-inline-popup--close-hook) + +(defun diff-hl-inline-popup--splice (list offset length) + "Compute a sublist of LIST starting at OFFSET, of LENGTH." + (butlast + (nthcdr offset list) + (- (length list) length offset))) + +(defun diff-hl-inline-popup--ensure-enough-lines (pos content-height) + "Ensure there is enough lines below POS to show the inline popup with CONTENT-HEIGHT height." + (let* ((line (line-number-at-pos pos)) + (end (line-number-at-pos (window-end nil t))) + (height (+ 6 content-height)) + (overflow (- (+ line height) end))) + (when (< 0 overflow) + (run-with-timer 0.1 nil #'scroll-up overflow)))) + +(defun diff-hl-inline-popup--compute-content-height (&optional content-size) + "Compute the height of the inline popup. +Default for CONTENT-SIZE is the size of the current lines" + (let ((content-size (or content-size (length diff-hl-inline-popup--current-lines))) + (max-size (- (/(window-height) 2) 3))) + (min content-size max-size))) + +(defun diff-hl-inline-popup--compute-content-lines (lines index window-size) + "Compute the lines to show in the popup, from LINES starting at INDEX with a WINDOW-SIZE." + (let* ((len (length lines)) + (window-size (min window-size len)) + (index (min index (- len window-size)))) + (diff-hl-inline-popup--splice lines index window-size))) + +(defun diff-hl-inline-popup--compute-header (width &optional header) + "Compute the header of the popup, with some WIDTH, and some optional HEADER text." + (let* ((scroll-indicator (if (eq diff-hl-inline-popup--current-index 0) " " " ⬆ ")) + (header (or header "")) + (new-width (- width (length header) (length scroll-indicator))) + (header (if (< new-width 0) "" header)) + (new-width (- width (length header) (length scroll-indicator))) + (line (propertize (concat (diff-hl-inline-popup--separator new-width) + header scroll-indicator ) + 'face '(:underline t)))) + (concat line "\n") )) + +(defun diff-hl-inline-popup--compute-footer (width &optional footer) + "Compute the header of the popup, with some WIDTH, and some optional FOOTER text." + (let* ((scroll-indicator (if (>= diff-hl-inline-popup--current-index + (- (length diff-hl-inline-popup--current-lines) + diff-hl-inline-popup--height)) + " " + " ⬇ ")) + (footer (or footer "")) + (new-width (- width (length footer) (length scroll-indicator))) + (footer (if (< new-width 0) "" footer)) + (new-width (- width (length footer) (length scroll-indicator))) + (blank-line (if (display-graphic-p) + "" + (concat "\n" (propertize (diff-hl-inline-popup--separator width) + 'face '(:underline t))))) + (line (propertize (concat (diff-hl-inline-popup--separator new-width) + footer scroll-indicator) + 'face '(:overline t)))) + (concat blank-line "\n" line))) + +(defun diff-hl-inline-popup--separator (width &optional sep) + "Return the horizontal separator with character SEP and a WIDTH." + (let ((sep (or sep ?\s))) + (make-string width sep))) + +(defun diff-hl-inline-popup--available-width () + "Compute the available width in chars." + (let ((magic-adjust 3)) + (if (not (display-graphic-p)) + (let* ((linumber-width (line-number-display-width nil)) + (width (- (window-body-width) linumber-width magic-adjust))) + width) + (let* ((font-width (window-font-width)) + (window-width (window-body-width nil t)) + (linenumber-width (line-number-display-width t)) + (available-pixels (- window-width linenumber-width)) + (width (- (/ available-pixels font-width) magic-adjust))) + + ;; https://emacs.stackexchange.com/questions/5495/how-can-i-determine-the-width-of-characters-on-the-screen + width)))) + +(defun diff-hl-inline-popup--compute-popup-str (lines index window-size header footer) + "Compute the string that represents the popup. +There are some content LINES starting at INDEX, with a WINDOW-SIZE. HEADER and +FOOTER are showed at start and end." + (let* ((width (diff-hl-inline-popup--available-width)) + (content-lines (diff-hl-inline-popup--compute-content-lines lines index window-size)) + (header (diff-hl-inline-popup--compute-header width header)) + (footer (diff-hl-inline-popup--compute-footer width footer))) + (concat header (string-join content-lines "\n") footer "\n"))) + +(defun diff-hl-inline-popup-scroll-to (index) + "Scroll the inline popup to make visible the line at position INDEX." + (when diff-hl-inline-popup--current-popup + (setq diff-hl-inline-popup--current-index (max 0 (min index (- (length diff-hl-inline-popup--current-lines) diff-hl-inline-popup--height)))) + (let* ((str (diff-hl-inline-popup--compute-popup-str + diff-hl-inline-popup--current-lines + diff-hl-inline-popup--current-index + diff-hl-inline-popup--height + diff-hl-inline-popup--current-header + diff-hl-inline-popup--current-footer))) + ;; https://debbugs.gnu.org/38563, `company--replacement-string'. + (add-face-text-property 0 (length str) 'default t str) + (overlay-put diff-hl-inline-popup--current-popup 'after-string str)))) + +(defun diff-hl-inline-popup--popup-down() + "Scrolls one line down." + (interactive) + (diff-hl-inline-popup-scroll-to (1+ diff-hl-inline-popup--current-index) )) + +(defun diff-hl-inline-popup--popup-up() + "Scrolls one line up." + (interactive) + (diff-hl-inline-popup-scroll-to (1- diff-hl-inline-popup--current-index) )) + +(defun diff-hl-inline-popup--popup-pagedown() + "Scrolls one page down." + (interactive) + (diff-hl-inline-popup-scroll-to (+ diff-hl-inline-popup--current-index diff-hl-inline-popup--height) )) + +(defun diff-hl-inline-popup--popup-pageup() + "Scrolls one page up." + (interactive) + (diff-hl-inline-popup-scroll-to (- diff-hl-inline-popup--current-index diff-hl-inline-popup--height) )) + +(defvar diff-hl-inline-popup-transient-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "<prior>") #'diff-hl-inline-popup--popup-pageup) + (define-key map (kbd "M-v") #'diff-hl-inline-popup--popup-pageup) + (define-key map (kbd "<next>") #'diff-hl-inline-popup--popup-pagedown) + (define-key map (kbd "C-v") #'diff-hl-inline-popup--popup-pagedown) + (define-key map (kbd "<up>") #'diff-hl-inline-popup--popup-up) + (define-key map (kbd "C-p") #'diff-hl-inline-popup--popup-up) + (define-key map (kbd "<down>") #'diff-hl-inline-popup--popup-down) + (define-key map (kbd "C-n") #'diff-hl-inline-popup--popup-down) + (define-key map (kbd "C-g") #'diff-hl-inline-popup-hide) + (define-key map [escape] #'diff-hl-inline-popup-hide) + (define-key map (kbd "q") #'diff-hl-inline-popup-hide) + ;;http://ergoemacs.org/emacs/emacs_mouse_wheel_config.html + (define-key map (kbd "<mouse-4>") #'diff-hl-inline-popup--popup-up) + (define-key map (kbd "<wheel-up>") #'diff-hl-inline-popup--popup-up) + (define-key map (kbd "<mouse-5>") #'diff-hl-inline-popup--popup-down) + (define-key map (kbd "<wheel-down>") #'diff-hl-inline-popup--popup-down) + map) + "Keymap for command `diff-hl-inline-popup-transient-mode'. +Capture all the vertical movement of the point, and converts it +to scroll in the popup") + +(defun diff-hl-inline-popup--ignorable-command-p (command) + "Decide if COMMAND is a command allowed while showing an inline popup." + ;; https://emacs.stackexchange.com/questions/653/how-can-i-find-out-in-which-keymap-a-key-is-bound + (let ((keys (where-is-internal command (list diff-hl-inline-popup--current-custom-keymap + diff-hl-inline-popup-transient-mode-map ) t)) + (invoking (eq command diff-hl-inline-popup--invokinkg-command))) + (or keys invoking))) + +(defun diff-hl-inline-popup--post-command-hook () + "Called each time a command is executed." + (let ((allowed-command (or + (string-match-p "diff-hl-inline-popup-" (symbol-name this-command)) + (diff-hl-inline-popup--ignorable-command-p this-command)))) + (unless allowed-command + (diff-hl-inline-popup-hide)))) + +(define-minor-mode diff-hl-inline-popup-transient-mode + "Temporal minor mode to control an inline popup" + :global nil + (remove-hook 'post-command-hook #'diff-hl-inline-popup--post-command-hook t) + (set-keymap-parent diff-hl-inline-popup-transient-mode-map nil) + + (when diff-hl-inline-popup-transient-mode + (set-keymap-parent diff-hl-inline-popup-transient-mode-map + diff-hl-inline-popup--current-custom-keymap) + (add-hook 'post-command-hook #'diff-hl-inline-popup--post-command-hook 0 t))) + +;;;###autoload +(defun diff-hl-inline-popup-hide() + "Hide the current inline popup." + (interactive) + (when diff-hl-inline-popup-transient-mode + (diff-hl-inline-popup-transient-mode -1)) + (when diff-hl-inline-popup--close-hook + (funcall diff-hl-inline-popup--close-hook) + (setq diff-hl-inline-popup--close-hook nil)) + (when diff-hl-inline-popup--current-popup + (delete-overlay diff-hl-inline-popup--current-popup) + (setq diff-hl-inline-popup--current-popup nil))) + +;;;###autoload +(defun diff-hl-inline-popup-show (lines &optional header footer keymap close-hook point height) + "Create a phantom overlay to show the inline popup, with some +content LINES, and a HEADER and a FOOTER, at POINT. KEYMAP is +added to the current keymaps. CLOSE-HOOK is called when the popup +is closed." + (when diff-hl-inline-popup--current-popup + (delete-overlay diff-hl-inline-popup--current-popup) + (setq diff-hl-inline-popup--current-popup nil)) + + (when (< (diff-hl-inline-popup--compute-content-height 99) 2) + (user-error "There is no enough vertical space to show the inline popup")) + (let* ((the-point (or point (line-end-position))) + (the-buffer (current-buffer)) + (overlay (make-overlay the-point the-point the-buffer))) + (overlay-put overlay 'phantom t) + (overlay-put overlay 'diff-hl-inline-popup t) + (setq diff-hl-inline-popup--current-popup overlay) + + (setq diff-hl-inline-popup--current-lines + (mapcar (lambda (s) (replace-regexp-in-string "\n" " " s)) lines)) + (setq diff-hl-inline-popup--current-header header) + (setq diff-hl-inline-popup--current-footer footer) + (setq diff-hl-inline-popup--invokinkg-command this-command) + (setq diff-hl-inline-popup--current-custom-keymap keymap) + (setq diff-hl-inline-popup--close-hook close-hook) + (setq diff-hl-inline-popup--height (diff-hl-inline-popup--compute-content-height height)) + (setq diff-hl-inline-popup--height (min diff-hl-inline-popup--height + (length diff-hl-inline-popup--current-lines))) + ;; (diff-hl-inline-popup--ensure-enough-lines point diff-hl-inline-popup--height) + (diff-hl-inline-popup-transient-mode 1) + (diff-hl-inline-popup-scroll-to 0) + overlay)) + +(defun diff-hl-inline-popup--hide-all () + "Testing purposes, use in case some inline popups get stuck in a buffer." + (interactive) + (when diff-hl-inline-popup-transient-mode + (diff-hl-inline-popup-transient-mode -1)) + (setq diff-hl-inline-popup--current-popup nil) + (let* ((all-overlays (overlays-in (point-min) (point-max))) + (overlays (cl-remove-if-not (lambda (o)(overlay-get o 'diff-hl-inline-popup)) all-overlays))) + (dolist (o overlays) + (delete-overlay o)))) + +(provide 'diff-hl-inline-popup) +;;; diff-hl-inline-popup ends here diff --git a/elpa/diff-hl-1.9.2/diff-hl-margin.el b/elpa/diff-hl-1.9.2/diff-hl-margin.el @@ -0,0 +1,157 @@ +;;; diff-hl-margin.el --- Highlight buffer changes on margins -*- lexical-binding: t -*- + +;; Copyright (C) 2012-2017 Free Software Foundation, Inc. + +;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This is a global mode, it modifies `diff-hl-mode' to use the margin +;; instead of the fringe. To toggle, type `M-x diff-hl-margin-mode'. +;; +;; Compared to the default behavior, this makes `diff-hl-mode' +;; indicators show up even when Emacs is running in a terminal. +;; +;; On the flip side, the indicators look simpler, and they are +;; incompatible with `linum-mode' or any other mode that uses the +;; margin. +;; +;; You might want to enable it conditionally in your init file +;; depending on whether Emacs is running in graphical mode: +;; +;; (unless (window-system) (diff-hl-margin-mode)) + +(require 'cl-lib) +(require 'diff-hl) +(require 'diff-hl-dired) + +(defvar diff-hl-margin-old-highlight-function nil) + +(defvar diff-hl-margin-old-width nil) + +(defgroup diff-hl-margin nil + "Highlight buffer changes on margin" + :group 'diff-hl) + +(defface diff-hl-margin-insert + '((default :inherit diff-hl-insert)) + "Face used to highlight inserted lines on the margin.") + +(defface diff-hl-margin-delete + '((default :inherit diff-hl-delete)) + "Face used to highlight deleted lines on the margin.") + +(defface diff-hl-margin-change + '((default :inherit diff-hl-change)) + "Face used to highlight changed lines on the margin.") + +(defface diff-hl-margin-ignored + '((default :inherit dired-ignored)) + "Face used to highlight changed lines on the margin.") + +(defface diff-hl-margin-unknown + '((default :inherit dired-ignored)) + "Face used to highlight changed lines on the margin.") + +(defcustom diff-hl-margin-symbols-alist + '((insert . "+") (delete . "-") (change . "!") + (unknown . "?") (ignored . "i")) + "Associative list from symbols to strings." + :type '(alist :key-type symbol + :value-type string + :options (insert delete change unknown ignored)) + :set (lambda (symbol value) + (defvar diff-hl-margin-spec-cache) + (set-default symbol value) + (setq diff-hl-margin-spec-cache nil))) + +;;;###autoload +(define-minor-mode diff-hl-margin-mode + "Toggle displaying `diff-hl-mode' highlights on the margin." + :lighter "" :global t + (if diff-hl-margin-mode + (progn + (add-hook 'diff-hl-mode-on-hook 'diff-hl-margin-local-mode) + (add-hook 'diff-hl-mode-off-hook 'diff-hl-margin-local-mode-off) + (add-hook 'diff-hl-dired-mode-on-hook 'diff-hl-margin-local-mode) + (add-hook 'diff-hl-dired-mode-off-hook 'diff-hl-margin-local-mode-off)) + (remove-hook 'diff-hl-mode-on-hook 'diff-hl-margin-local-mode) + (remove-hook 'diff-hl-mode-off-hook 'diff-hl-margin-local-mode-off) + (remove-hook 'diff-hl-dired-mode-on-hook 'diff-hl-margin-local-mode) + (remove-hook 'diff-hl-dired-mode-off-hook 'diff-hl-margin-local-mode-off)) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (cond + (diff-hl-mode + (diff-hl-margin-local-mode (if diff-hl-margin-mode 1 -1)) + (diff-hl-update)) + (diff-hl-dired-mode + (diff-hl-margin-local-mode (if diff-hl-margin-mode 1 -1)) + (diff-hl-dired-update)))))) + +;;;###autoload +(define-minor-mode diff-hl-margin-local-mode + "Toggle displaying `diff-hl-mode' highlights on the margin locally. +You probably shouldn't use this function directly." + :lighter "" + (let ((width-var (intern (format "%s-margin-width" diff-hl-side)))) + (if diff-hl-margin-local-mode + (progn + (setq-local diff-hl-margin-old-highlight-function + diff-hl-highlight-function) + (setq-local diff-hl-highlight-function + #'diff-hl-highlight-on-margin) + (setq-local diff-hl-margin-old-width (symbol-value width-var)) + (set width-var 1)) + (when diff-hl-margin-old-highlight-function + (setq diff-hl-highlight-function diff-hl-margin-old-highlight-function + diff-hl-margin-old-highlight-function nil)) + (set width-var diff-hl-margin-old-width) + (kill-local-variable 'diff-hl-margin-old-width))) + (dolist (win (get-buffer-window-list)) + (set-window-buffer win (current-buffer)))) + +(defun diff-hl-margin-local-mode-off () + (diff-hl-margin-local-mode -1)) + +(defvar diff-hl-margin-spec-cache nil) + +(defun diff-hl-margin-spec-cache () + (or diff-hl-margin-spec-cache + (setq diff-hl-margin-spec-cache + (diff-hl-margin-build-spec-cache)))) + +(defun diff-hl-margin-build-spec-cache () + (cl-loop for (type . char) in diff-hl-margin-symbols-alist + nconc + (cl-loop for side in '(left right) + collect + (cons + (cons type side) + (propertize + " " 'display + `((margin ,(intern (format "%s-margin" side))) + ,(propertize char 'face + (intern (format "diff-hl-margin-%s" type))))))))) + +(defun diff-hl-highlight-on-margin (ovl type _shape) + (let ((spec (cdr (assoc (cons type diff-hl-side) + (diff-hl-margin-spec-cache))))) + (overlay-put ovl 'before-string spec))) + +(provide 'diff-hl-margin) + +;;; diff-hl-margin.el ends here diff --git a/elpa/diff-hl-1.9.2/diff-hl-pkg.el b/elpa/diff-hl-1.9.2/diff-hl-pkg.el @@ -0,0 +1,2 @@ +;; Generated package description from diff-hl.el -*- no-byte-compile: t -*- +(define-package "diff-hl" "1.9.2" "Highlight uncommitted changes using VC" '((cl-lib "0.2") (emacs "25.1")) :commit "d20f16bf5eadd66e775f215e800f25caddae8cb5" :authors '(("Dmitry Gutov" . "dgutov@yandex.ru")) :maintainer '("Dmitry Gutov" . "dgutov@yandex.ru") :keywords '("vc" "diff") :url "https://github.com/dgutov/diff-hl") diff --git a/elpa/diff-hl-1.9.2/diff-hl-show-hunk-posframe.el b/elpa/diff-hl-1.9.2/diff-hl-show-hunk-posframe.el @@ -0,0 +1,238 @@ +;;; diff-hl-show-hunk-posframe.el --- posframe backend for diff-hl-show-hunk -*- lexical-binding: t -*- + +;; Copyright (C) 2020-2021 Free Software Foundation, Inc. + +;; Author: Álvaro González <alvarogonzalezsotillo@gmail.com> + +;; 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: +;; +;; This provides `diff-hl-show-hunk-posframe' than can be used as +;; `diff-hl-show-hunk-function'. `posframe' is a runtime dependency, +;; it is not required by this package, but it should be installed. +;; +;;; Code: + +(require 'diff-hl-show-hunk) + +;; This package uses some runtime dependencies, so we need to declare +;; the external functions and variables +(declare-function posframe-workable-p "posframe") +(declare-function posframe-show "posframe") +(defvar posframe-mouse-banish) + +(defgroup diff-hl-show-hunk-posframe nil + "Show vc diffs in a posframe." + :group 'diff-hl-show-hunk) + +(defcustom diff-hl-show-hunk-posframe-show-header-line t + "Show some useful buttons at the top of the diff-hl posframe." + :type 'boolean) + +(defcustom diff-hl-show-hunk-posframe-internal-border-width 2 + "Internal border width of the posframe." + :type 'integer) + +(defcustom diff-hl-show-hunk-posframe-internal-border-color "#00ffff" + "Internal border color of the posframe." + :type 'color) + +(defcustom diff-hl-show-hunk-posframe-poshandler nil + "Poshandler of the posframe (see `posframe-show`)." + :type '(choice function + (const :tag "None" nil))) + +(defcustom diff-hl-show-hunk-posframe-parameters nil + "The frame parameters used by helm-posframe." + :type '(choice string + (const :tag "None" nil))) + +(defface diff-hl-show-hunk-posframe '((t nil)) + "Face for the posframe buffer. +Customize it to change the base properties of the text.") + +(defface diff-hl-show-hunk-posframe-button-face '((t . (:height 0.9))) + "Face for the posframe buttons" ) + +(defvar diff-hl-show-hunk--frame nil "The postframe frame used in function `diff-hl-show-hunk-posframe'.") +(defvar diff-hl-show-hunk--original-frame nil "The frame from which the hunk is shown.") + +(defun diff-hl-show-hunk--posframe-hide () + "Hide the posframe and clean up buffer." + (interactive) + (diff-hl-show-hunk-posframe--transient-mode -1) + (when (frame-live-p diff-hl-show-hunk--frame) + (make-frame-invisible diff-hl-show-hunk--frame)) + (when diff-hl-show-hunk--original-frame + (when (frame-live-p diff-hl-show-hunk--original-frame) + (let ((frame diff-hl-show-hunk--original-frame)) + (select-frame-set-input-focus frame) + ;; In Gnome, sometimes the input focus is not restored to the + ;; original frame, so we try harder in a while + (run-with-timer 0.1 nil (lambda () (select-frame-set-input-focus frame))))) + (setq diff-hl-show-hunk--original-frame nil))) + +(defvar diff-hl-show-hunk-posframe--transient-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [escape] #'diff-hl-show-hunk-hide) + (define-key map (kbd "q") #'diff-hl-show-hunk-hide) + (define-key map (kbd "C-g") #'diff-hl-show-hunk-hide) + (set-keymap-parent map diff-hl-show-hunk-map) + map) + "Keymap for command `diff-hl-show-hunk-posframe--transient-mode'.") + +(define-minor-mode diff-hl-show-hunk-posframe--transient-mode + "Temporal minor mode to control diff-hl posframe." + :lighter "" + :global t + (if diff-hl-show-hunk-posframe--transient-mode + (add-hook 'post-command-hook #'diff-hl-show-hunk--posframe-post-command-hook nil) + (remove-hook 'post-command-hook #'diff-hl-show-hunk--posframe-post-command-hook nil))) + +(defun diff-hl-show-hunk--posframe-post-command-hook () + "Called for each command while in `diff-hl-show-hunk-posframe--transient-mode." + (let* ((allowed-command (or + (diff-hl-show-hunk-ignorable-command-p this-command) + (and (symbolp this-command) + (string-match-p "diff-hl-" (symbol-name this-command))))) + (event-in-frame (eq last-event-frame diff-hl-show-hunk--frame)) + (has-focus (and (frame-live-p diff-hl-show-hunk--frame) + (functionp 'frame-focus-state) + (eq (frame-focus-state diff-hl-show-hunk--frame) t))) + (still-visible (or event-in-frame allowed-command has-focus))) + (unless still-visible + (diff-hl-show-hunk--posframe-hide)))) + +(defun diff-hl-show-hunk--posframe-button (text help-echo action) + "Make a string implementing a button with TEXT and a HELP-ECHO. +The button calls an ACTION." + (concat + (propertize (concat " " text " ") + 'help-echo (if action help-echo "Not available") + 'face 'diff-hl-show-hunk-posframe-button-face + 'mouse-face (when action '(:box (:style released-button))) + 'keymap (when action + (let ((map (make-sparse-keymap))) + (define-key map (kbd "<header-line> <mouse-1>") action) + map))) + " ")) + +(defun diff-hl-show-hunk-posframe--header-line () + "Make the header line of the posframe." + (concat + (diff-hl-show-hunk--posframe-button + "⨯ Close" + "Close (\\[diff-hl-show-hunk-hide])" + #'diff-hl-show-hunk-hide) + (diff-hl-show-hunk--posframe-button + "⬆ Previous change" + "Previous change in hunk (\\[diff-hl-show-hunk-previous])" + #'diff-hl-show-hunk-previous) + + (diff-hl-show-hunk--posframe-button + "⬇ Next change" + "Next change in hunk (\\[diff-hl-show-hunk-next])" + #'diff-hl-show-hunk-next) + + (diff-hl-show-hunk--posframe-button + "⊚ Copy original" + "Copy original (\\[diff-hl-show-hunk-copy-original-text])" + #'diff-hl-show-hunk-copy-original-text) + + (diff-hl-show-hunk--posframe-button + "♻ Revert hunk" + "Revert hunk (\\[diff-hl-show-hunk-revert-hunk])" + #'diff-hl-show-hunk-revert-hunk) + + (unless diff-hl-show-staged-changes + (diff-hl-show-hunk--posframe-button + "⊕ Stage hunk" + "Stage hunk (\\[diff-hl-show-hunk-stage-hunk])" + #'diff-hl-show-hunk-stage-hunk)) + )) + +;;;###autoload +(defun diff-hl-show-hunk-posframe (buffer &optional _line) + "Implementation to show the hunk in a posframe." + + (unless (require 'posframe nil t) + (user-error + (concat + "`diff-hl-show-hunk-posframe' requires the `posframe' package." + " Please install it or customize `diff-hl-show-hunk-function'."))) + + (unless (posframe-workable-p) + (user-error + "Package `posframe' is not workable. Please customize diff-hl-show-hunk-function")) + + (diff-hl-show-hunk--posframe-hide) + (setq diff-hl-show-hunk--hide-function #'diff-hl-show-hunk--posframe-hide) + + ;; put an overlay to override read-only-mode keymap + (with-current-buffer buffer + ;; Change face size + (buffer-face-set 'diff-hl-show-hunk-posframe) + + (let ((full-overlay (make-overlay 1 (1+ (buffer-size))))) + (overlay-put full-overlay + 'keymap diff-hl-show-hunk-posframe--transient-mode-map))) + + (setq posframe-mouse-banish nil) + (setq diff-hl-show-hunk--original-frame last-event-frame) + + (let* ((hunk-overlay diff-hl-show-hunk--original-overlay) + (position (overlay-end hunk-overlay))) + (setq + diff-hl-show-hunk--frame + (posframe-show buffer + :position position + :poshandler diff-hl-show-hunk-posframe-poshandler + :internal-border-width diff-hl-show-hunk-posframe-internal-border-width + :accept-focus t + ;; internal-border-color Doesn't always work, if not customize internal-border face + :internal-border-color diff-hl-show-hunk-posframe-internal-border-color + :hidehandler nil + ;; Sometimes, header-line is not taken into account, so put a min height and a min width + :min-height (when diff-hl-show-hunk-posframe-show-header-line 10) + :min-width (when diff-hl-show-hunk-posframe-show-header-line + (length (diff-hl-show-hunk-posframe--header-line))) + :respect-header-line diff-hl-show-hunk-posframe-show-header-line + :respect-tab-line nil + :respect-mode-line nil + :override-parameters diff-hl-show-hunk-posframe-parameters))) + + (set-frame-parameter diff-hl-show-hunk--frame 'drag-internal-border t) + (set-frame-parameter diff-hl-show-hunk--frame 'drag-with-header-line t) + + (with-selected-frame diff-hl-show-hunk--frame + (with-current-buffer buffer + (diff-hl-show-hunk-posframe--transient-mode 1) + (when diff-hl-show-hunk-posframe-show-header-line + (setq header-line-format (diff-hl-show-hunk-posframe--header-line))) + (goto-char (point-min)) + (setq buffer-quit-function #'diff-hl-show-hunk--posframe-hide) + (select-window (window-main-window diff-hl-show-hunk--frame)) + + ;; Make cursor visible (mainly for selecting text in posframe) + (setq cursor-type 'box) + + ;; Recenter arround point + (recenter))) + (select-frame-set-input-focus diff-hl-show-hunk--frame)) + +(provide 'diff-hl-show-hunk-posframe) +;;; diff-hl-show-hunk-posframe.el ends here diff --git a/elpa/diff-hl-1.9.2/diff-hl-show-hunk.el b/elpa/diff-hl-1.9.2/diff-hl-show-hunk.el @@ -0,0 +1,419 @@ +;;; diff-hl-show-hunk.el --- Integrate popup/posframe and diff-hl-diff-goto-hunk -*- lexical-binding: t -*- + +;; Copyright (C) 2020-2021 Free Software Foundation, Inc. + +;; Author: Álvaro González <alvarogonzalezsotillo@gmail.com> + +;; 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; `diff-hl-show-hunk' shows a popup with the modification hunk at point. +;; `diff-hl-show-hunk-function' points to the backend used to show the +;; hunk. Its default value is `diff-hl-show-hunk-inline-popup', that +;; shows diffs inline using overlay. There is another built-in backend: +;; `diff-hl-show-hunk-posframe' (based on posframe). +;; +;; `diff-hl-show-hunk-mouse-mode' adds interaction on clicking in the +;; margin or the fringe (shows the current hunk as well). +;; +;; To use it in all buffers: +;; +;; (global-diff-hl-show-hunk-mouse-mode) + +;;; Code: + +(require 'diff-hl-inline-popup) +(require 'diff-hl) + +(defvar diff-hl-show-hunk-mouse-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "<left-margin> <mouse-1>") 'diff-hl-show-hunk--click) + (define-key map (kbd "<right-margin> <mouse-1>") 'diff-hl-show-hunk--click) + (define-key map (kbd "<left-fringe> <mouse-1>") 'diff-hl-show-hunk--click) + (define-key map (kbd "<right-fringe> <mouse-1>") 'diff-hl-show-hunk--click) + map) + "Keymap for command `diff-hl-show-hunk-mouse-mode'.") + +(defvar diff-hl-show-hunk-buffer-name "*diff-hl-show-hunk-buffer*" + "Name of the buffer used by diff-hl-show-hunk.") + +(defvar diff-hl-show-hunk-diff-buffer-name "*diff-hl-show-hunk-diff-buffer*" + "Name of the buffer used by diff-hl-show-hunk to show the diff.") + +(defvar diff-hl-show-hunk--original-window nil + "The vc window of which the hunk is shown.") + +(defvar diff-hl-show-hunk--original-buffer nil + "The vc buffer of which the hunk is shown.") + +(defvar diff-hl-show-hunk--original-content nil + "The original content of the hunk.") + +(defvar diff-hl-show-hunk--original-overlay nil + "Copy of the diff-hl hunk overlay.") + +(defgroup diff-hl-show-hunk nil + "Show vc diffs in a posframe or popup." + :group 'diff-hl) + +(defconst diff-hl-show-hunk-boundary "^@@.*@@") +(defconst diff-hl-show-hunk--no-lines-removed-message (list "<<no lines removed>>")) + +(defcustom diff-hl-show-hunk-inline-popup-hide-hunk nil + "If t, inline-popup is shown over the hunk, hiding it." + :type 'boolean) + +(defcustom diff-hl-show-hunk-inline-popup-smart-lines t + "If t, inline-popup tries to show only the deleted lines of the +hunk. The added lines are shown when scrolling the popup. If +the hunk consist only on added lines, then +`diff-hl-show-hunk--no-lines-removed-message' it is shown." + :type 'boolean) + +(defcustom diff-hl-show-hunk-function 'diff-hl-show-hunk-inline-popup + "The function used to render the hunk. +The function receives as first parameter a buffer with the +contents of the hunk, and as second parameter the line number +corresponding to the clicked line in the original buffer." + :type '(choice + (const :tag "Show inline" diff-hl-show-hunk-inline-popup) + (const :tag "Show using posframe" diff-hl-show-hunk-posframe))) + +(defvar diff-hl-show-hunk--hide-function nil + "Function to call to close the shown hunk.") + +(defun diff-hl-show-hunk-hide () + "Hide the current shown hunk." + (interactive) + (if (and diff-hl-show-hunk--original-window (window-live-p diff-hl-show-hunk--original-window)) + (select-window diff-hl-show-hunk--original-window)) + (setq diff-hl-show-hunk--original-window nil) + (if (buffer-live-p diff-hl-show-hunk--original-buffer) + (switch-to-buffer diff-hl-show-hunk--original-buffer)) + (setq diff-hl-show-hunk--original-buffer nil) + (with-current-buffer (get-buffer-create diff-hl-show-hunk-buffer-name) + (read-only-mode -1) + (erase-buffer)) + (bury-buffer diff-hl-show-hunk-buffer-name) + (when (get-buffer diff-hl-show-hunk-diff-buffer-name) + (bury-buffer diff-hl-show-hunk-diff-buffer-name)) + (when diff-hl-show-hunk--hide-function + (let ((hidefunc diff-hl-show-hunk--hide-function)) + (setq diff-hl-show-hunk--hide-function nil) + (funcall hidefunc))) + (when diff-hl-show-hunk--original-overlay + (diff-hl-show-hunk--goto-hunk-overlay diff-hl-show-hunk--original-overlay)) + (when diff-hl-show-hunk--original-overlay + (delete-overlay diff-hl-show-hunk--original-overlay)) + (setq diff-hl-show-hunk--original-overlay nil)) + +(defun diff-hl-show-hunk-ignorable-command-p (command) + "Decide if COMMAND is a command allowed while showing the current hunk." + (member command '(ignore diff-hl-show-hunk handle-switch-frame diff-hl-show-hunk--click))) + +(defun diff-hl-show-hunk--compute-diffs () + "Compute diffs using functions of diff-hl. +Then put the differences inside a special buffer and set the +point in that buffer to the corresponding line of the original +buffer." + (defvar vc-sentinel-movepoint) + (let* ((buffer (or (buffer-base-buffer) (current-buffer))) + (line (line-number-at-pos)) + (dest-buffer diff-hl-show-hunk-diff-buffer-name)) + (with-current-buffer buffer + (diff-hl-diff-buffer-with-reference (buffer-file-name buffer) dest-buffer) + (switch-to-buffer dest-buffer) + (diff-hl-diff-skip-to line) + (setq vc-sentinel-movepoint (point))) + dest-buffer)) + +(defun diff-hl-show-hunk--get-original-lines (content) + "Extracts the lines starting with '-' from CONTENT and save them." + (let* ((lines (split-string content "[\n\r]+" ))) + (cl-remove-if-not (lambda (l) (string-match-p "^-.*" l)) lines))) + +(defun diff-hl-show-hunk--fill-original-content (content) + "Extracts the lines starting with '-' from CONTENT and save them." + (let* ((original-lines (diff-hl-show-hunk--get-original-lines content)) + (original-lines (mapcar (lambda (l) (substring l 1)) original-lines)) + (content (string-join original-lines "\n"))) + (setq diff-hl-show-hunk--original-content content))) + +(defun diff-hl-show-hunk-buffer () + "Create the buffer with the contents of the hunk at point. +The buffer has the point in the corresponding line of the hunk. +Returns a list with the buffer and the line number of the clicked line." + (let ((content) + (point-in-buffer) + (line) + (line-overlay) + ;; https://emacs.stackexchange.com/questions/35680/stop-emacs-from-updating-display + (inhibit-redisplay t) + (buffer (get-buffer-create diff-hl-show-hunk-buffer-name))) + + ;; Get differences + (save-window-excursion + (save-excursion + (with-current-buffer (diff-hl-show-hunk--compute-diffs) + (setq content (buffer-substring-no-properties (point-min) (point-max))) + (setq point-in-buffer (point))))) + + (with-current-buffer buffer + (read-only-mode -1) + (erase-buffer) + (insert content) + + ;; Highlight the clicked line + (goto-char point-in-buffer) + (setq line-overlay (make-overlay (line-beginning-position) + (min (point-max) + (1+ (line-end-position))))) + + ;; diff-mode + (diff-mode) + (read-only-mode 1) + + ;; Find the hunk and narrow to it + (re-search-backward diff-hl-show-hunk-boundary nil 1) + (forward-line 1) + (let* ((start (point))) + (re-search-forward diff-hl-show-hunk-boundary nil 1) + (move-beginning-of-line nil) + (narrow-to-region start (point))) + + ;; Store original content + (let ((content (buffer-string))) + (diff-hl-show-hunk--fill-original-content content)) + + ;; Come back to the clicked line + (goto-char (overlay-start line-overlay)) + (setq line (line-number-at-pos))) + + (list buffer line))) + +(defun diff-hl-show-hunk--click (event) + "Called when user clicks on margins. EVENT is click information." + (interactive "e") + ;; Go the click's position. + (posn-set-point (event-start event)) + (diff-hl-show-hunk)) + +(defvar diff-hl-show-hunk-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "p") #'diff-hl-show-hunk-previous) + (define-key map (kbd "n") #'diff-hl-show-hunk-next) + (define-key map (kbd "c") #'diff-hl-show-hunk-copy-original-text) + (define-key map (kbd "r") #'diff-hl-show-hunk-revert-hunk) + (define-key map (kbd "[") #'diff-hl-show-hunk-previous) + (define-key map (kbd "]") #'diff-hl-show-hunk-next) + (define-key map (kbd "{") #'diff-hl-show-hunk-previous) + (define-key map (kbd "}") #'diff-hl-show-hunk-next) + (define-key map (kbd "S") #'diff-hl-show-hunk-stage-hunk) + map)) + +(defvar diff-hl-show-hunk--hide-function) + +;;;###autoload +(defun diff-hl-show-hunk-inline-popup (buffer &optional _ignored-line) + "Implementation to show the hunk in a inline popup. +BUFFER is a buffer with the hunk." + (diff-hl-inline-popup-hide) + (setq diff-hl-show-hunk--hide-function #'diff-hl-inline-popup-hide) + (let* ((lines (split-string (with-current-buffer buffer (buffer-string)) "[\n\r]+" )) + (smart-lines diff-hl-show-hunk-inline-popup-smart-lines) + (original-lines-number (cl-count-if (lambda (s) (string-prefix-p "-" s)) lines)) + (lines (if (string= (car (last lines)) "" ) (butlast lines) lines)) + (lines (if (and (eq original-lines-number 0) smart-lines) + diff-hl-show-hunk--no-lines-removed-message + lines)) + (overlay diff-hl-show-hunk--original-overlay) + (type (overlay-get overlay 'diff-hl-hunk-type)) + (point (if (eq type 'delete) (overlay-start overlay) (overlay-end overlay))) + (propertize-line (lambda (l) + (propertize l 'face + (cond ((string-prefix-p "+" l) + 'diff-added) + ((string-prefix-p "-" l) + 'diff-removed))))) + (propertized-lines (mapcar propertize-line lines))) + + (save-excursion + ;; Save point in case the hunk is hidden, so next/previous works as expected + ;; If the hunk is delete type, then don't hide the hunk + ;; (because the hunk is located in a non deleted line) + (when (and diff-hl-show-hunk-inline-popup-hide-hunk + (not (eq type 'delete))) + (let* ((invisible-overlay (make-overlay (overlay-start overlay) + (overlay-end overlay)))) + ;; Make new overlay, since the diff-hl overlay can be changed by diff-hl-flydiff + (overlay-put invisible-overlay 'invisible t) + ;; Change default hide popup function, to make the overlay visible + (setq diff-hl-show-hunk--hide-function + (lambda () + (overlay-put invisible-overlay 'invisible nil) + (delete-overlay invisible-overlay) + (diff-hl-inline-popup-hide))))) + (diff-hl-show-hunk--goto-hunk-overlay overlay) + (let ((height + (when smart-lines + (when (not (eq 0 original-lines-number)) + original-lines-number))) + (footer "(q)Quit (p)Previous (n)Next (r)Revert (c)Copy original")) + (unless diff-hl-show-staged-changes + (setq footer (concat footer " (S)Stage"))) + (diff-hl-inline-popup-show + propertized-lines + (if (and (boundp 'diff-hl-reference-revision) diff-hl-reference-revision) + (concat "Diff with " diff-hl-reference-revision) + "Diff with HEAD") + footer + diff-hl-show-hunk-map + #'diff-hl-show-hunk-hide + point + height)) + ))) + +(defun diff-hl-show-hunk-copy-original-text () + "Extracts all the lines from BUFFER starting with '-' to the kill ring." + (interactive) + (kill-new diff-hl-show-hunk--original-content) + (message "Original hunk content added to kill-ring")) + +(defun diff-hl-show-hunk-revert-hunk () + "Dismiss the popup and revert the current diff hunk." + (interactive) + (diff-hl-show-hunk-hide) + (let (diff-hl-ask-before-revert-hunk) + (diff-hl-revert-hunk))) + +(defun diff-hl-show-hunk-stage-hunk () + "Dismiss the popup and stage the current hunk." + (interactive) + (diff-hl-show-hunk-hide) + (diff-hl-stage-current-hunk)) + +;;;###autoload +(defun diff-hl-show-hunk-previous () + "Go to previous hunk/change and show it." + (interactive) + (let* ((point (if diff-hl-show-hunk--original-overlay + (overlay-start diff-hl-show-hunk--original-overlay) + nil)) + (previous-overlay (diff-hl-show-hunk--next-hunk t point))) + (if (not previous-overlay) + (message "There is no previous change") + (diff-hl-show-hunk-hide) + (diff-hl-show-hunk--goto-hunk-overlay previous-overlay) + (recenter) + (diff-hl-show-hunk)))) + +(defun diff-hl-show-hunk--next-hunk (backward point) + "Same as `diff-hl-search-next-hunk', but in the current buffer +of `diff-hl-show-hunk'." + (with-current-buffer (or diff-hl-show-hunk--original-buffer (current-buffer)) + (diff-hl-search-next-hunk backward point))) + +(defun diff-hl-show-hunk--goto-hunk-overlay (overlay) + "Tries to display the whole overlay, and place the point at the +end of the OVERLAY, so posframe/inline is placed below the hunk." + (when (and (overlayp overlay) (overlay-buffer overlay)) + (let ((pt (point))) + (goto-char (overlay-start overlay)) + (cond + ((< (point) (window-start)) + (set-window-start nil (point))) + ((> (point) pt) + (redisplay)))) + (goto-char (1- (overlay-end overlay))))) + +;;;###autoload +(defun diff-hl-show-hunk-next () + "Go to next hunk/change and show it." + (interactive) + (let* ((point (if diff-hl-show-hunk--original-overlay + (overlay-start diff-hl-show-hunk--original-overlay) + nil)) + (next-overlay (diff-hl-show-hunk--next-hunk nil point))) + (if (not next-overlay) + (message "There is no next change") + (diff-hl-show-hunk-hide) + (diff-hl-show-hunk--goto-hunk-overlay next-overlay) + (recenter) + (diff-hl-show-hunk)))) + +;;;###autoload +(defun diff-hl-show-hunk () + "Show the VC diff hunk at point. +The backend is determined by `diff-hl-show-hunk-function'." + (interactive) + + ;; Close any previous hunk + (save-excursion + (diff-hl-show-hunk-hide)) + + (unless (vc-backend buffer-file-name) + (user-error "The buffer is not under version control")) + + (diff-hl-find-current-hunk) + + (setq diff-hl-show-hunk--original-overlay nil) + + ;; Store begining and end of hunk overlay + (let ((overlay (diff-hl-hunk-overlay-at (point)))) + (when overlay + (let ((start (overlay-start overlay)) + (end (overlay-end overlay)) + (type (overlay-get overlay 'diff-hl-hunk-type))) + (setq diff-hl-show-hunk--original-overlay (make-overlay start end)) + (overlay-put diff-hl-show-hunk--original-overlay 'diff-hl-hunk-type type))) + + (unless overlay + (user-error "Not in a hunk"))) + + (cond + ((not diff-hl-show-hunk-function) + (message "Please configure `diff-hl-show-hunk-function'") + (diff-hl-diff-goto-hunk)) + ((let ((buffer-and-line (diff-hl-show-hunk-buffer))) + (setq diff-hl-show-hunk--original-buffer (current-buffer)) + (setq diff-hl-show-hunk--original-window (selected-window)) + (apply diff-hl-show-hunk-function buffer-and-line)) + ;; We could fall back to `diff-hl-diff-goto-hunk', but the + ;; current default should work in all environments (both GUI + ;; and terminal), and if something goes wrong we better show + ;; the error to the user. + ))) + +;;;###autoload +(define-minor-mode diff-hl-show-hunk-mouse-mode + "Enables the margin and fringe to show a posframe/popup with vc diffs when clicked. +By default, the popup shows only the current hunk, and +the line of the hunk that matches the current position is +highlighted. The face, border and other visual preferences are +customizable. It can be also invoked with the command +`diff-hl-show-hunk' +\\{diff-hl-show-hunk-mouse-mode-map}" + :group 'diff-hl-show-hunk + :lighter "") + +;;;###autoload +(define-globalized-minor-mode global-diff-hl-show-hunk-mouse-mode + diff-hl-show-hunk-mouse-mode + diff-hl-show-hunk-mouse-mode) + +(provide 'diff-hl-show-hunk) +;;; diff-hl-show-hunk.el ends here diff --git a/elpa/diff-hl-1.9.2/diff-hl.el b/elpa/diff-hl-1.9.2/diff-hl.el @@ -0,0 +1,1128 @@ +;;; diff-hl.el --- Highlight uncommitted changes using VC -*- lexical-binding: t -*- + +;; Copyright (C) 2012-2023 Free Software Foundation, Inc. + +;; Author: Dmitry Gutov <dgutov@yandex.ru> +;; URL: https://github.com/dgutov/diff-hl +;; Keywords: vc, diff +;; Version: 1.9.2 +;; Package-Requires: ((cl-lib "0.2") (emacs "25.1")) + +;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; `diff-hl-mode' highlights uncommitted changes on the side of the +;; window (using the fringe, by default), allows you to jump between +;; the hunks and revert them selectively. + +;; Provided commands: +;; +;; `diff-hl-diff-goto-hunk' C-x v = +;; `diff-hl-revert-hunk' C-x v n +;; `diff-hl-previous-hunk' C-x v [ +;; `diff-hl-next-hunk' C-x v ] +;; `diff-hl-show-hunk' C-x v * +;; `diff-hl-stage-current-hunk' C-x v S +;; `diff-hl-set-reference-rev' +;; `diff-hl-reset-reference-rev' +;; `diff-hl-unstage-file' +;; +;; The mode takes advantage of `smartrep' if it is installed. +;; +;; Alternatively, it integrates with `repeat-mode' (Emacs 28+). + +;; Add either of the following to your init file. +;; +;; To use it in all buffers: +;; +;; (global-diff-hl-mode) +;; +;; Only in `prog-mode' buffers, with `vc-dir' integration: +;; +;; (add-hook 'prog-mode-hook 'turn-on-diff-hl-mode) +;; (add-hook 'vc-dir-mode-hook 'turn-on-diff-hl-mode) + +;;; Code: + +(require 'fringe) +(require 'diff-mode) +(require 'vc) +(require 'vc-dir) +(require 'log-view) + +(eval-when-compile + (require 'cl-lib) + (require 'vc-git) + (require 'vc-hg) + (require 'face-remap) + (declare-function smartrep-define-key 'smartrep)) + +(defgroup diff-hl nil + "VC diff highlighting on the side of a window" + :group 'vc) + +(defface diff-hl-insert + '((default :inherit diff-added) + (((class color)) :foreground "green4")) + "Face used to highlight inserted lines." + :group 'diff-hl) + +(defface diff-hl-delete + '((default :inherit diff-removed) + (((class color)) :foreground "red3")) + "Face used to highlight deleted lines." + :group 'diff-hl) + +(defface diff-hl-change + '((default :foreground "blue3") + (((class color) (min-colors 88) (background light)) + :background "#ddddff") + (((class color) (min-colors 88) (background dark)) + :background "#333355")) + "Face used to highlight changed lines." + :group 'diff-hl) + +(defcustom diff-hl-command-prefix (kbd "C-x v") + "The prefix for all `diff-hl' commands." + :group 'diff-hl + :type 'string) + +(defcustom diff-hl-draw-borders t + "Non-nil to draw borders around fringe indicators." + :group 'diff-hl + :type 'boolean) + +(defcustom diff-hl-disable-on-remote nil + "Non-nil will disable `diff-hl' in remote buffers." + :group 'diff-hl + :type 'boolean) + +(defcustom diff-hl-ask-before-revert-hunk t + "Non-nil to ask for confirmation before revert a hunk." + :group 'diff-hl + :type 'boolean) + +(defcustom diff-hl-highlight-function 'diff-hl-highlight-on-fringe + "Function to highlight the current line. Its arguments are + overlay, change type and position within a hunk." + :group 'diff-hl + :type 'function) + +(defcustom diff-hl-fringe-bmp-function 'diff-hl-fringe-bmp-from-pos + "Function to choose the fringe bitmap for a given change type + and position within a hunk. Should accept two arguments." + :group 'diff-hl + :type '(choice (const diff-hl-fringe-bmp-from-pos) + (const diff-hl-fringe-bmp-from-type) + function)) + +(defcustom diff-hl-fringe-face-function 'diff-hl-fringe-face-from-type + "Function to choose the fringe face for a given change type + and position within a hunk. Should accept two arguments." + :group 'diff-hl + :type 'function) + +(defcustom diff-hl-side 'left + "Which side to use for indicators." + :type '(choice (const left) + (const right)) + :initialize 'custom-initialize-default + :set (lambda (var value) + (let ((on (bound-and-true-p global-diff-hl-mode))) + (when on (global-diff-hl-mode -1)) + (set-default var value) + (when on (global-diff-hl-mode 1))))) + +(defcustom diff-hl-highlight-revert-hunk-function + #'diff-hl-revert-narrow-to-hunk + "Function to emphasize the current hunk in `diff-hl-revert-hunk'. +The function is called at the beginning of the hunk and is passed +the end position as its only argument." + :type '(choice (const :tag "Do nothing" ignore) + (const :tag "Highlight the first column" + diff-hl-revert-highlight-first-column) + (const :tag "Narrow to the hunk" + diff-hl-revert-narrow-to-hunk))) + +(defcustom diff-hl-global-modes '(not image-mode) + "Modes for which `diff-hl-mode' is automagically turned on. +This affects the behavior of `global-diff-hl-mode'. +If nil, no modes have `diff-hl-mode' automatically turned on. +If t, all modes have `diff-hl-mode' enabled. +If a list, it should be a list of `major-mode' symbol names for +which it should be automatically turned on. The sense of the list +is negated if it begins with `not'. As such, the default value + (not image-mode) +means that `diff-hl-mode' is turned on in all modes except for +`image-mode' buffers. Previously, `diff-hl-mode' caused worse +performance when viewing such files in certain conditions." + :type '(choice (const :tag "none" nil) + (const :tag "all" t) + (set :menu-tag "mode specific" :tag "modes" + :value (not) + (const :tag "Except" not) + (repeat :inline t (symbol :tag "mode")))) + :group 'diff-hl) + +(defcustom diff-hl-show-staged-changes t + "Whether to include staged changes in the indicators. +Only affects Git, it's the only backend that has staging area." + :type 'boolean) + +(defcustom diff-hl-goto-hunk-old-revisions nil + "When non-nil, `diff-hl-diff-goto-hunk' will always try to +navigate to the line in the diff that corresponds to the current +line in the file buffer (or as close as it can get to it). + +When this variable is nil (default), `diff-hl-diff-goto-hunk' +only does that when called without the prefix argument, or when +the NEW revision is not specified (meaning, the diff is against +the current version of the file)." + :type 'boolean) + +(defvar diff-hl-reference-revision nil + "Revision to diff against. nil means the most recent one.") + +(defun diff-hl-define-bitmaps () + (let* ((scale (if (and (boundp 'text-scale-mode-amount) + (numberp text-scale-mode-amount)) + (expt text-scale-mode-step text-scale-mode-amount) + 1)) + (spacing (or (and (display-graphic-p) (default-value 'line-spacing)) 0)) + (h (+ (ceiling (* (frame-char-height) scale)) + (if (floatp spacing) + (truncate (* (frame-char-height) spacing)) + spacing))) + (w (min (frame-parameter nil (intern (format "%s-fringe" diff-hl-side))) + 16)) + (_ (when (zerop w) (setq w 16))) + (middle (make-vector h (expt 2 (1- w)))) + (ones (1- (expt 2 w))) + (top (copy-sequence middle)) + (bottom (copy-sequence middle)) + (single (copy-sequence middle))) + (aset top 0 ones) + (aset bottom (1- h) ones) + (aset single 0 ones) + (aset single (1- h) ones) + (define-fringe-bitmap 'diff-hl-bmp-top top h w 'top) + (define-fringe-bitmap 'diff-hl-bmp-middle middle h w 'center) + (define-fringe-bitmap 'diff-hl-bmp-bottom bottom h w 'bottom) + (define-fringe-bitmap 'diff-hl-bmp-single single h w 'top) + (define-fringe-bitmap 'diff-hl-bmp-i [3 3 0 3 3 3 3 3 3 3] nil 2 'center) + (let* ((w2 (* (/ w 2) 2)) + ;; When fringes are disabled, it's easier to fix up the width, + ;; instead of doing nothing (#20). + (w2 (if (zerop w2) 2 w2)) + (delete-row (- (expt 2 (1- w2)) 2)) + (middle-pos (1- (/ w2 2))) + (middle-bit (expt 2 middle-pos)) + (insert-bmp (make-vector w2 (* 3 middle-bit)))) + (define-fringe-bitmap 'diff-hl-bmp-delete (make-vector 2 delete-row) w2 w2) + (aset insert-bmp 0 0) + (aset insert-bmp middle-pos delete-row) + (aset insert-bmp (1+ middle-pos) delete-row) + (aset insert-bmp (1- w2) 0) + (define-fringe-bitmap 'diff-hl-bmp-insert insert-bmp w2 w2) + ))) + +(defun diff-hl-maybe-define-bitmaps () + (when (window-system) ;; No fringes in the console. + (unless (fringe-bitmap-p 'diff-hl-bmp-empty) + (diff-hl-define-bitmaps) + (define-fringe-bitmap 'diff-hl-bmp-empty [0] 1 1 'center)))) + +(defun diff-hl-maybe-redefine-bitmaps () + (when (window-system) + (diff-hl-define-bitmaps))) + +(defvar diff-hl-spec-cache (make-hash-table :test 'equal)) + +(defun diff-hl-fringe-spec (type pos side) + (let* ((key (list type pos side + diff-hl-fringe-face-function + diff-hl-fringe-bmp-function)) + (val (gethash key diff-hl-spec-cache))) + (unless val + (let* ((face-sym (funcall diff-hl-fringe-face-function type pos)) + (bmp-sym (funcall diff-hl-fringe-bmp-function type pos))) + (setq val (propertize " " 'display `((,(intern (format "%s-fringe" side)) + ,bmp-sym ,face-sym)))) + (puthash key val diff-hl-spec-cache))) + val)) + +(defun diff-hl-fringe-face-from-type (type _pos) + (intern (format "diff-hl-%s" type))) + +(defun diff-hl-fringe-bmp-from-pos (_type pos) + (intern (format "diff-hl-bmp-%s" pos))) + +(defun diff-hl-fringe-bmp-from-type (type _pos) + (cl-case type + (unknown 'question-mark) + (change 'exclamation-mark) + (ignored 'diff-hl-bmp-i) + (t (intern (format "diff-hl-bmp-%s" type))))) + +(defvar vc-svn-diff-switches) +(defvar vc-fossil-diff-switches) + +(defmacro diff-hl-with-diff-switches (body) + `(let ((vc-git-diff-switches + ;; https://github.com/dgutov/diff-hl/issues/67 + (cons "-U0" + ;; https://github.com/dgutov/diff-hl/issues/9 + (and (boundp 'vc-git-diff-switches) + (listp vc-git-diff-switches) + (cl-remove-if-not + (lambda (arg) + (member arg '("--histogram" "--patience" "--minimal"))) + vc-git-diff-switches)))) + (vc-hg-diff-switches nil) + (vc-svn-diff-switches nil) + (vc-fossil-diff-switches '("-c" "0")) + (vc-diff-switches '("-U0")) + ,@(when (boundp 'vc-disable-async-diff) + '((vc-disable-async-diff t)))) + ,body)) + +(defun diff-hl-modified-p (state) + (or (memq state '(edited conflict)) + (and (eq state 'up-to-date) + ;; VC state is stale in after-revert-hook. + (or revert-buffer-in-progress-p + ;; Diffing against an older revision. + diff-hl-reference-revision)))) + +(declare-function vc-git-command "vc-git") + +(defun diff-hl-changes-buffer (file backend) + (diff-hl-with-diff-switches + (diff-hl-diff-against-reference file backend " *diff-hl* "))) + +(defun diff-hl-diff-against-reference (file backend buffer) + (if (and (eq backend 'Git) + (not diff-hl-reference-revision) + (not diff-hl-show-staged-changes)) + (apply #'vc-git-command buffer 1 + (list file) + "diff-files" + (cons "-p" (vc-switches 'git 'diff))) + (condition-case err + (vc-call-backend backend 'diff (list file) + diff-hl-reference-revision nil + buffer) + (error + ;; https://github.com/dgutov/diff-hl/issues/117 + (when (string-match-p "\\`Failed (status 128)" (error-message-string err)) + (vc-call-backend backend 'diff (list file) + "4b825dc642cb6eb9a060e54bf8d69288fbee4904" + nil + buffer))))) + buffer) + +(defun diff-hl-changes () + (let* ((file buffer-file-name) + (backend (vc-backend file))) + (when backend + (let ((state (vc-state file backend))) + (cond + ((diff-hl-modified-p state) + (diff-hl-changes-from-buffer + (diff-hl-changes-buffer file backend))) + ((eq state 'added) + `((1 ,(line-number-at-pos (point-max)) insert))) + ((eq state 'removed) + `((1 ,(line-number-at-pos (point-max)) delete)))))))) + +(defun diff-hl-changes-from-buffer (buf) + (with-current-buffer buf + (let (res) + (goto-char (point-min)) + (unless (eobp) + ;; TODO: When 27.1 is the minimum requirement, we can drop + ;; these bindings: that version, in addition to switching over + ;; to the diff-refine var, also added the + ;; called-interactively-p check, so refinement can't be + ;; triggered by code calling the navigation functions, only by + ;; direct interactive invocations. + (ignore-errors + (with-no-warnings + (let (diff-auto-refine-mode) + (diff-beginning-of-hunk t)))) + (while (looking-at diff-hunk-header-re-unified) + (let ((line (string-to-number (match-string 3))) + (len (let ((m (match-string 4))) + (if m (string-to-number m) 1))) + (beg (point))) + (with-no-warnings + (let (diff-auto-refine-mode) + (diff-end-of-hunk))) + (let* ((inserts (diff-count-matches "^\\+" beg (point))) + (deletes (diff-count-matches "^-" beg (point))) + (type (cond ((zerop deletes) 'insert) + ((zerop inserts) 'delete) + (t 'change)))) + (when (eq type 'delete) + (setq len 1) + (cl-incf line)) + (push (list line len type) res))))) + (nreverse res)))) + +(defun diff-hl-update () + (let ((changes (diff-hl-changes)) + (current-line 1)) + (diff-hl-remove-overlays) + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (dolist (c changes) + (cl-destructuring-bind (line len type) c + (forward-line (- line current-line)) + (setq current-line line) + (let ((hunk-beg (point))) + (while (cl-plusp len) + (diff-hl-add-highlighting + type + (cond + ((not diff-hl-draw-borders) 'empty) + ((and (= len 1) (= line current-line)) 'single) + ((= len 1) 'bottom) + ((= line current-line) 'top) + (t 'middle))) + (forward-line 1) + (cl-incf current-line) + (cl-decf len)) + (let ((h (make-overlay hunk-beg (point))) + (hook '(diff-hl-overlay-modified))) + (overlay-put h 'diff-hl t) + (overlay-put h 'diff-hl-hunk t) + (overlay-put h 'diff-hl-hunk-type type) + (overlay-put h 'modification-hooks hook) + (overlay-put h 'insert-in-front-hooks hook) + (overlay-put h 'insert-behind-hooks hook))))))))) + +(defvar-local diff-hl--modified-tick nil) + +(put 'diff-hl--modified-tick 'permanent-local t) + +(defun diff-hl-update-once () + (unless (equal diff-hl--modified-tick (buffer-chars-modified-tick)) + (diff-hl-update) + (setq diff-hl--modified-tick (buffer-chars-modified-tick)))) + +(defun diff-hl-add-highlighting (type shape) + (let ((o (make-overlay (point) (point)))) + (overlay-put o 'diff-hl t) + (funcall diff-hl-highlight-function o type shape) + o)) + +(defun diff-hl-highlight-on-fringe (ovl type shape) + (overlay-put ovl 'before-string (diff-hl-fringe-spec type shape + diff-hl-side))) + +(defun diff-hl-remove-overlays (&optional beg end) + (save-restriction + (widen) + (dolist (o (overlays-in (or beg (point-min)) (or end (point-max)))) + (when (overlay-get o 'diff-hl) (delete-overlay o))))) + +(defun diff-hl-overlay-modified (ov after-p _beg _end &optional _length) + "Delete the hunk overlay and all our line overlays inside it." + (unless after-p + (when (overlay-buffer ov) + (diff-hl-remove-overlays (overlay-start ov) (overlay-end ov)) + (delete-overlay ov)))) + +(defvar diff-hl-timer nil) + +(defun diff-hl-edit (_beg _end _len) + "DTRT when we've `undo'-ne the buffer into unmodified state." + (when undo-in-progress + (when diff-hl-timer + (cancel-timer diff-hl-timer)) + (setq diff-hl-timer + (run-with-idle-timer 0.01 nil #'diff-hl-after-undo (current-buffer))))) + +(defun diff-hl-after-undo (buffer) + (with-current-buffer buffer + (unless (buffer-modified-p) + (diff-hl-update)))) + +(defun diff-hl-after-revert () + (defvar revert-buffer-preserve-modes) + (when revert-buffer-preserve-modes + (diff-hl-update))) + +(defun diff-hl-diff-goto-hunk-1 (historic) + (defvar vc-sentinel-movepoint) + (vc-buffer-sync) + (let* ((line (line-number-at-pos)) + (buffer (current-buffer)) + (rev1 diff-hl-reference-revision) + rev2) + (when historic + (let ((revs (diff-hl-diff-read-revisions rev1))) + (setq rev1 (car revs) + rev2 (cdr revs)))) + (vc-diff-internal t (vc-deduce-fileset) rev1 rev2 t) + (vc-run-delayed (if (< (line-number-at-pos (point-max)) 3) + (with-current-buffer buffer (diff-hl-remove-overlays)) + (when (or (not rev2) diff-hl-goto-hunk-old-revisions) + (diff-hl-diff-skip-to line)) + (setq vc-sentinel-movepoint (point)))))) + +(defun diff-hl-diff-goto-hunk (&optional historic) + "Run VC diff command and go to the line corresponding to the current." + (interactive (list current-prefix-arg)) + (with-current-buffer (or (buffer-base-buffer) (current-buffer)) + (diff-hl-diff-goto-hunk-1 historic))) + +(defun diff-hl-diff-read-revisions (rev1-default) + (let* ((file buffer-file-name) + (files (list file)) + (backend (vc-backend file)) + (rev2-default nil)) + (cond + ;; if the file is not up-to-date, use working revision as older revision + ((not (vc-up-to-date-p file)) + (setq rev1-default + (or rev1-default + (vc-working-revision file)))) + ((not rev1-default) + (setq rev1-default (ignore-errors ;If `previous-revision' doesn't work. + (vc-call-backend backend 'previous-revision file + (vc-working-revision file)))) + (when (string= rev1-default "") (setq rev1-default nil)))) + ;; finally read the revisions + (let* ((rev1-prompt (if rev1-default + (concat "Older revision (default " + rev1-default "): ") + "Older revision: ")) + (rev2-prompt (concat "Newer revision (default " + (or rev2-default "current source") "): ")) + (rev1 (vc-read-revision rev1-prompt files backend rev1-default)) + (rev2 (vc-read-revision rev2-prompt files backend rev2-default))) + (when (string= rev1 "") (setq rev1 nil)) + (when (string= rev2 "") (setq rev2 nil)) + (cons rev1 rev2)))) + +(defun diff-hl-diff-skip-to (line) + "In `diff-mode', skip to the hunk and line corresponding to LINE +in the source file, or the last line of the hunk above it." + (goto-char (point-min)) ; Counteract any similar behavior in diff-mode. + (diff-hunk-next) + (let (found) + (while (and (looking-at diff-hunk-header-re-unified) (not found)) + (let ((hunk-line (string-to-number (match-string 3))) + (len (let ((m (match-string 4))) + (if m (string-to-number m) 1)))) + (if (> line (+ hunk-line len)) + (diff-hunk-next) + (setq found t) + (if (< line hunk-line) + ;; Retreat to the previous hunk. + (forward-line -1) + (let ((to-go (1+ (- line hunk-line)))) + (while (cl-plusp to-go) + (forward-line 1) + (unless (looking-at "^-") + (cl-decf to-go)))))))))) + +(defface diff-hl-reverted-hunk-highlight + '((default :inverse-video t)) + "Face used to highlight the first column of the hunk to be reverted.") + +(defun diff-hl-revert-highlight-first-column (end) + (re-search-forward "^[+-]") + (forward-line 0) + (setq end (diff-hl-split-away-changes 0)) + (let ((inhibit-read-only t)) + (save-excursion + (while (< (point) end) + (font-lock-prepend-text-property (point) (1+ (point)) 'font-lock-face + 'diff-hl-reverted-hunk-highlight) + (forward-line 1))))) + +(defun diff-hl-revert-narrow-to-hunk (end) + (narrow-to-region (point) end)) + +(defun diff-hl-revert-hunk-1 () + (save-restriction + (widen) + (vc-buffer-sync) + (let* ((diff-buffer (get-buffer-create + (generate-new-buffer-name "*diff-hl*"))) + (buffer (current-buffer)) + (line (save-excursion + (diff-hl-find-current-hunk) + (line-number-at-pos))) + (file buffer-file-name) + (backend (vc-backend file))) + (unwind-protect + (progn + (vc-setup-buffer diff-buffer) + (diff-hl-diff-against-reference file backend diff-buffer) + (set-buffer diff-buffer) + (diff-mode) + (setq-local diff-vc-backend backend) + (setq-local diff-vc-revisions (list diff-hl-reference-revision nil)) + (setq buffer-read-only t) + (pop-to-buffer diff-buffer) + (vc-run-delayed + (vc-diff-finish diff-buffer nil) + (let (beg-line end-line m-beg m-end) + (when (eobp) + (with-current-buffer buffer (diff-hl-remove-overlays)) + (user-error "Buffer is up-to-date")) + (with-no-warnings + (let (diff-auto-refine-mode) + (diff-hl-diff-skip-to line))) + (setq m-end (diff-hl-split-away-changes 3)) + (setq m-beg (point-marker)) + (funcall diff-hl-highlight-revert-hunk-function m-end) + (setq beg-line (line-number-at-pos m-beg) + end-line (line-number-at-pos m-end)) + (let ((wbh (window-body-height))) + (if (>= wbh (- end-line beg-line)) + (recenter (/ (+ wbh (- beg-line end-line) 2) 2)) + (recenter 1))) + (with-no-warnings + (when diff-auto-refine-mode + (diff-refine-hunk))) + (if diff-hl-ask-before-revert-hunk + (unless (yes-or-no-p (format "Revert current hunk in %s? " + file)) + (user-error "Revert canceled"))) + (let ((diff-advance-after-apply-hunk nil)) + (save-window-excursion + (diff-apply-hunk t))) + (with-current-buffer buffer + (save-buffer)) + (message "Hunk reverted")))) + (quit-windows-on diff-buffer t))))) + +(defun diff-hl-split-away-changes (max-context) + "Split away the minimal hunk at point from the rest of the hunk. + +The minimal hunk is the hunk a diff program would produce if +asked for 0 lines of context. Add MAX-CONTEXT lines of context at +most (stop when encounter another minimal hunk). + +Move point to the beginning of the delineated hunk and return +its end position." + (let (end-marker) + (save-excursion + (while (looking-at "[-+]") (forward-line 1)) + (dotimes (_i max-context) + (unless (looking-at "@\\|[-+]") + (forward-line 1))) + (setq end-marker (point-marker)) + (unless (or (eobp) + (looking-at "@")) + (diff-split-hunk))) + (unless (looking-at "[-+]") (forward-line -1)) + (while (looking-at "[-+]") (forward-line -1)) + (dotimes (_i max-context) + (unless (looking-at "@\\|[-+]") + (forward-line -1))) + (unless (looking-at "@") + (forward-line 1) + (diff-split-hunk)) + end-marker)) + +(defun diff-hl-revert-hunk () + "Revert the diff hunk with changes at or above the point." + (interactive) + (with-current-buffer (or (buffer-base-buffer) (current-buffer)) + (diff-hl-revert-hunk-1))) + +(defun diff-hl-hunk-overlay-at (pos) + (cl-loop for o in (overlays-in pos (1+ pos)) + when (overlay-get o 'diff-hl-hunk) + return o)) + +(defun diff-hl-search-next-hunk (&optional backward point) + "Search the next hunk in the current buffer, or previous if BACKWARD." + (save-excursion + (when point + (goto-char point)) + (catch 'found + (while (not (if backward (bobp) (eobp))) + (goto-char (if backward + (previous-overlay-change (point)) + (next-overlay-change (point)))) + (let ((o (diff-hl-hunk-overlay-at (point)))) + (when (and o (= (overlay-start o) (point))) + (throw 'found o))))))) + +(defun diff-hl-next-hunk (&optional backward) + "Go to the beginning of the next hunk in the current buffer." + (interactive) + (let ((overlay (diff-hl-search-next-hunk backward))) + (if overlay + (goto-char (overlay-start overlay)) + (user-error "No further hunks found")))) + +(defun diff-hl-previous-hunk () + "Go to the beginning of the previous hunk in the current buffer." + (interactive) + (diff-hl-next-hunk t)) + +(defun diff-hl-find-current-hunk () + (let (o) + (cond + ((diff-hl-hunk-overlay-at (point))) + ((setq o (diff-hl-search-next-hunk t)) + (goto-char (overlay-start o))) + (t + (diff-hl-next-hunk))))) + +(defun diff-hl-mark-hunk () + (interactive) + (let ((hunk (diff-hl-hunk-overlay-at (point)))) + (unless hunk + (user-error "No hunk at point")) + (goto-char (overlay-start hunk)) + (push-mark (overlay-end hunk) nil t))) + +(defun diff-hl--ensure-staging-supported () + (let ((backend (vc-backend buffer-file-name))) + (unless (eq backend 'Git) + (user-error "Only Git supports staging; this file is controlled by %s" backend)))) + +(defun diff-hl-stage-current-hunk () + "Stage the hunk at or near point. + +Only supported with Git." + (interactive) + (diff-hl--ensure-staging-supported) + (diff-hl-find-current-hunk) + (let* ((line (line-number-at-pos)) + (file buffer-file-name) + (dest-buffer (get-buffer-create " *diff-hl-stage*")) + (orig-buffer (current-buffer)) + (file-base (shell-quote-argument (file-name-nondirectory file))) + success) + (with-current-buffer dest-buffer + (let ((inhibit-read-only t)) + (erase-buffer))) + (diff-hl-diff-buffer-with-reference file dest-buffer nil 3) + (with-current-buffer dest-buffer + (with-no-warnings + (let (diff-auto-refine-mode) + (diff-hl-diff-skip-to line))) + (let ((inhibit-read-only t)) + (diff-hl-split-away-changes 3) + (save-excursion + (diff-end-of-hunk) + (delete-region (point) (point-max))) + (diff-beginning-of-hunk) + (delete-region (point-min) (point)) + ;; diff-no-select creates a very ugly header; Git rejects it + (insert (format "diff a/%s b/%s\n" file-base file-base)) + (insert (format "--- a/%s\n" file-base)) + (insert (format "+++ b/%s\n" file-base))) + (let ((patchfile (make-temp-file "diff-hl-stage-patch"))) + (write-region (point-min) (point-max) patchfile + nil 'silent) + (unwind-protect + (with-current-buffer orig-buffer + (with-output-to-string + (vc-git-command standard-output 0 + patchfile + "apply" "--cached" )) + (setq success t)) + (delete-file patchfile)))) + (when success + (if diff-hl-show-staged-changes + (message (concat "Hunk staged; customize `diff-hl-show-staged-changes'" + " to highlight only unstages changes")) + (message "Hunk staged")) + (unless diff-hl-show-staged-changes + (diff-hl-update))))) + +(defun diff-hl-unstage-file () + "Unstage all changes in the current file. + +Only supported with Git." + (interactive) + (unless buffer-file-name + (user-error "No current file")) + (diff-hl--ensure-staging-supported) + (vc-git-command nil 0 buffer-file-name "reset") + (message "Unstaged all") + (unless diff-hl-show-staged-changes + (diff-hl-update))) + +(defvar diff-hl-command-map + (let ((map (make-sparse-keymap))) + (define-key map "n" 'diff-hl-revert-hunk) + (define-key map "[" 'diff-hl-previous-hunk) + (define-key map "]" 'diff-hl-next-hunk) + (define-key map "*" 'diff-hl-show-hunk) + (define-key map "{" 'diff-hl-show-hunk-previous) + (define-key map "}" 'diff-hl-show-hunk-next) + (define-key map "S" 'diff-hl-stage-current-hunk) + map)) +(fset 'diff-hl-command-map diff-hl-command-map) + +(defvar diff-hl-lighter "" + "Mode line lighter for Diff Hl. + +The value of this variable is a mode line template as in +`mode-line-format'.") + +;;;###autoload +(define-minor-mode diff-hl-mode + "Toggle VC diff highlighting." + :lighter diff-hl-lighter + :keymap `(([remap vc-diff] . diff-hl-diff-goto-hunk) + (,diff-hl-command-prefix . diff-hl-command-map)) + (if diff-hl-mode + (progn + (diff-hl-maybe-define-bitmaps) + (add-hook 'after-save-hook 'diff-hl-update nil t) + (add-hook 'after-change-functions 'diff-hl-edit nil t) + (add-hook (if vc-mode + ;; Defer until the end of this hook, so that its + ;; elements can modify the update behavior. + 'diff-hl-mode-on-hook + ;; If we're only opening the file now, + ;; `vc-find-file-hook' likely hasn't run yet, so + ;; let's wait until the state information is + ;; saved, in order not to fetch it twice. + 'find-file-hook) + 'diff-hl-update-once t t) + ;; Never removed because it acts globally. + (add-hook 'vc-checkin-hook 'diff-hl-after-checkin) + (add-hook 'after-revert-hook 'diff-hl-after-revert nil t) + ;; Magit does call `auto-revert-handler', but it usually + ;; doesn't do much, because `buffer-stale--default-function' + ;; doesn't care about changed VC state. + ;; https://github.com/magit/magit/issues/603 + (add-hook 'magit-revert-buffer-hook 'diff-hl-update nil t) + ;; Magit versions 2.0-2.3 don't do the above and call this + ;; instead, but only when they don't call `revert-buffer': + (add-hook 'magit-not-reverted-hook 'diff-hl-update nil t) + (add-hook 'text-scale-mode-hook 'diff-hl-maybe-redefine-bitmaps nil t)) + (remove-hook 'after-save-hook 'diff-hl-update t) + (remove-hook 'after-change-functions 'diff-hl-edit t) + (remove-hook 'find-file-hook 'diff-hl-update t) + (remove-hook 'after-revert-hook 'diff-hl-update t) + (remove-hook 'magit-revert-buffer-hook 'diff-hl-update t) + (remove-hook 'magit-not-reverted-hook 'diff-hl-update t) + (remove-hook 'text-scale-mode-hook 'diff-hl-maybe-redefine-bitmaps t) + (diff-hl-remove-overlays))) + +(defun diff-hl-after-checkin () + (let ((fileset (vc-deduce-fileset t))) + (dolist (file (nth 1 fileset)) + (let ((buf (find-buffer-visiting file))) + (when buf + (with-current-buffer buf + (when diff-hl-mode + (diff-hl-update)))))))) + +(defvar diff-hl-repeat-exceptions '(diff-hl-show-hunk + diff-hl-show-hunk-previous + diff-hl-show-hunk-next)) + +(when (require 'smartrep nil t) + (let (smart-keys) + (cl-labels ((scan (map) + (map-keymap + (lambda (event binding) + (if (consp binding) + (scan binding) + (when (and (characterp event) + (not (memq binding diff-hl-repeat-exceptions))) + (push (cons (string event) binding) smart-keys)))) + map))) + (scan diff-hl-command-map) + (smartrep-define-key diff-hl-mode-map diff-hl-command-prefix smart-keys)))) + +;; Integrate with `repeat-mode' in Emacs 28 (https://debbugs.gnu.org/47566) +;; +;; While smartrep feels solid, it looks kinda abandoned. And the +;; chances of it being put into GNU ELPA are slim too. +(map-keymap + (lambda (_key cmd) + (unless (memq cmd diff-hl-repeat-exceptions) + (put cmd 'repeat-map 'diff-hl-command-map))) + diff-hl-command-map) + +(declare-function magit-toplevel "magit-git") +(declare-function magit-unstaged-files "magit-git") + +(defvar diff-hl--magit-unstaged-files nil) + +(defun diff-hl-magit-pre-refresh () + (unless (and diff-hl-disable-on-remote + (file-remote-p default-directory)) + (setq diff-hl--magit-unstaged-files (magit-unstaged-files t)))) + +(defun diff-hl-magit-post-refresh () + (unless (and diff-hl-disable-on-remote + (file-remote-p default-directory)) + (let* ((topdir (magit-toplevel)) + (modified-files + (mapcar (lambda (file) (expand-file-name file topdir)) + (delete-consecutive-dups + (sort + (nconc (magit-unstaged-files t) + diff-hl--magit-unstaged-files) + #'string<)))) + (unmodified-states '(up-to-date ignored unregistered))) + (setq diff-hl--magit-unstaged-files nil) + (dolist (buf (buffer-list)) + (when (and (buffer-local-value 'diff-hl-mode buf) + (not (buffer-modified-p buf)) + ;; Solve the "cloned indirect buffer" problem + ;; (diff-hl-mode could be non-nil there, even if + ;; buffer-file-name is nil): + (buffer-file-name buf) + (file-in-directory-p (buffer-file-name buf) topdir) + (file-exists-p (buffer-file-name buf))) + (with-current-buffer buf + (let* ((file buffer-file-name) + (backend (vc-backend file))) + (when backend + (cond + ((member file modified-files) + (when (memq (vc-state file) unmodified-states) + (vc-state-refresh file backend)) + (diff-hl-update)) + ((not (memq (vc-state file backend) unmodified-states)) + (vc-state-refresh file backend) + (diff-hl-update))))))))))) + +(defun diff-hl-dir-update () + (dolist (pair (if (vc-dir-marked-files) + (vc-dir-marked-only-files-and-states) + (vc-dir-child-files-and-states))) + (when (eq 'up-to-date (cdr pair)) + (let ((buffer (find-buffer-visiting (car pair)))) + (when buffer + (with-current-buffer buffer + (diff-hl-remove-overlays))))))) + +(define-minor-mode diff-hl-dir-mode + "Toggle `diff-hl-mode' integration in a `vc-dir-mode' buffer." + :lighter "" + (if diff-hl-dir-mode + (add-hook 'vc-checkin-hook 'diff-hl-dir-update t t) + (remove-hook 'vc-checkin-hook 'diff-hl-dir-update t))) + +(defun diff-hl-make-temp-file-name (file rev &optional manual) + "Return a backup file name for REV or the current version of FILE. +If MANUAL is non-nil it means that a name for backups created by +the user should be returned." + (let* ((auto-save-file-name-transforms + `((".*" ,temporary-file-directory t))) + (buffer-file-name file)) + (expand-file-name + (concat (make-auto-save-file-name) + ".~" (subst-char-in-string + ?/ ?_ rev) + (unless manual ".") "~") + temporary-file-directory))) + +(defun diff-hl-create-revision (file revision) + "Read REVISION of FILE into a buffer and return the buffer." + (let ((automatic-backup (diff-hl-make-temp-file-name file revision)) + (filebuf (get-file-buffer file)) + (filename (diff-hl-make-temp-file-name file revision 'manual))) + (unless (file-exists-p filename) + (if (file-exists-p automatic-backup) + (rename-file automatic-backup filename nil) + (with-current-buffer filebuf + (let ((coding-system-for-read 'no-conversion) + (coding-system-for-write 'no-conversion)) + (condition-case nil + (with-temp-file filename + (let ((outbuf (current-buffer))) + ;; Change buffer to get local value of + ;; vc-checkout-switches. + (with-current-buffer filebuf + (vc-call find-revision file revision outbuf)))) + (error + (when (file-exists-p filename) + (delete-file filename)))))))) + filename)) + +(defun diff-hl-working-revision (file &optional backend) + "Like vc-working-revision, but always up-to-date" + (vc-file-setprop file 'vc-working-revision + (vc-call-backend (or backend (vc-backend file)) + 'working-revision file))) + +(declare-function diff-no-select "diff") + +(defun diff-hl-diff-buffer-with-reference (file &optional dest-buffer backend context-lines) + "Compute the diff between the current buffer contents and reference in BACKEND. +The diffs are computed in the buffer DEST-BUFFER. This requires +the `diff-program' to be in your `exec-path'. +CONTEXT-LINES is the size of the unified diff context, defaults to 0." + (require 'diff) + (vc-ensure-vc-buffer) + (save-current-buffer + (let* ((dest-buffer (or dest-buffer "*diff-hl-diff-buffer-with-reference*")) + (backend (or backend (vc-backend file))) + (temporary-file-directory + (if (file-directory-p "/dev/shm/") + "/dev/shm/" + temporary-file-directory)) + (rev + (if (and (eq backend 'Git) + (not diff-hl-reference-revision) + (not diff-hl-show-staged-changes)) + (diff-hl-git-index-revision + file + (diff-hl-git-index-object-name file)) + (diff-hl-create-revision + file + (or diff-hl-reference-revision + (diff-hl-working-revision file backend))))) + (switches (format "-U %d --strip-trailing-cr" (or context-lines 0)))) + (diff-no-select rev (current-buffer) switches 'noasync + (get-buffer-create dest-buffer)) + (with-current-buffer dest-buffer + (let ((inhibit-read-only t)) + ;; Function `diff-sentinel' adds a final line, so remove it + (delete-matching-lines "^Diff finished.*"))) + (get-buffer-create dest-buffer)))) + +;; TODO: Cache based on .git/index's mtime, maybe. +(defun diff-hl-git-index-object-name (file) + (with-temp-buffer + (vc-git-command (current-buffer) 0 file "ls-files" "-s") + (and + (goto-char (point-min)) + (re-search-forward "^[0-9]+ \\([0-9a-f]+\\)") + (match-string-no-properties 1)))) + +(defun diff-hl-git-index-revision (file object-name) + (let ((filename (diff-hl-make-temp-file-name file + (concat ":" object-name) + 'manual)) + (filebuf (get-file-buffer file))) + (unless (file-exists-p filename) + (with-current-buffer filebuf + (let ((coding-system-for-read 'no-conversion) + (coding-system-for-write 'no-conversion)) + (condition-case nil + (with-temp-file filename + (let ((outbuf (current-buffer))) + ;; Change buffer to be inside the repo. + (with-current-buffer filebuf + (vc-git-command outbuf 0 nil + "cat-file" "blob" object-name)))) + (error + (when (file-exists-p filename) + (delete-file filename))))))) + filename)) + +;;;###autoload +(defun turn-on-diff-hl-mode () + "Turn on `diff-hl-mode' or `diff-hl-dir-mode' in a buffer if appropriate." + (cond + (buffer-file-name + (unless (and diff-hl-disable-on-remote + (file-remote-p buffer-file-name)) + (diff-hl-mode 1))) + ((eq major-mode 'vc-dir-mode) + (diff-hl-dir-mode 1)))) + +;;;###autoload +(defun diff-hl--global-turn-on () + "Call `turn-on-diff-hl-mode' if the current major mode is applicable." + (when (cond ((eq diff-hl-global-modes t) + t) + ((eq (car-safe diff-hl-global-modes) 'not) + (not (memq major-mode (cdr diff-hl-global-modes)))) + (t (memq major-mode diff-hl-global-modes))) + (turn-on-diff-hl-mode))) + +(declare-function vc-annotate-extract-revision-at-line "vc-annotate") +(declare-function diff-hl-amend-mode "diff-hl-amend") + +;;;###autoload +(defun diff-hl-set-reference-rev (rev) + "Set the reference revision globally to REV. +When called interactively, REV read with completion. + +The default value chosen using one of methods below: + +- In a log view buffer, it uses the revision of current entry. +Call `vc-print-log' or `vc-print-root-log' first to open a log +view buffer. +- In a VC annotate buffer, it uses the revision of current line. +- In other situations, it uses the symbol at point. + +Notice that this sets the reference revision globally, so in +files from other repositories, `diff-hl-mode' will not highlight +changes correctly, until you run `diff-hl-reset-reference-rev'. + +Also notice that this will disable `diff-hl-amend-mode' in +buffers that enables it, since `diff-hl-amend-mode' overrides its +effect." + (interactive + (let* ((def (or (and (equal major-mode 'vc-annotate-mode) + (car (vc-annotate-extract-revision-at-line))) + (log-view-current-tag) + (thing-at-point 'symbol t))) + (prompt (if def + (format "Reference revision (default %s): " def) + "Reference revision: "))) + (list (vc-read-revision prompt nil nil def)))) + (if rev + (message "Set reference revision to %s" rev) + (user-error "No reference revision specified")) + (setq diff-hl-reference-revision rev) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when diff-hl-mode + (when (bound-and-true-p diff-hl-amend-mode) + (diff-hl-amend-mode -1)) + (diff-hl-update))))) + +;;;###autoload +(defun diff-hl-reset-reference-rev () + "Reset the reference revision globally to the most recent one." + (interactive) + (setq diff-hl-reference-revision nil) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when diff-hl-mode + (diff-hl-update))))) + +;;;###autoload +(define-globalized-minor-mode global-diff-hl-mode diff-hl-mode + diff-hl--global-turn-on :after-hook (diff-hl-global-mode-change)) + +(defun diff-hl-global-mode-change () + (unless global-diff-hl-mode + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when diff-hl-dir-mode + (diff-hl-dir-mode -1)))))) + +(provide 'diff-hl) + +;;; diff-hl.el ends here diff --git a/elpa/diff-hl-1.9.2/test/diff-hl-test.el b/elpa/diff-hl-1.9.2/test/diff-hl-test.el @@ -0,0 +1,173 @@ +;;; diff-hl-test.el --- tests for diff-hl -*- lexical-binding: t -*- + +;; Copyright (C) 2020, 2021 Free Software Foundation, Inc. + +;; Author: Nathan Moreau <nathan.moreau@m4x.org> + +;; 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Code: + +(require 'diff-hl) +(require 'subr-x) ;; string-trim +(require 'ert) +(require 'vc-git) + +(defvar diff-hl-test-source-file + (expand-file-name (concat (file-name-directory (locate-library "diff-hl")) + "test/empty"))) + +(defvar diff-hl-test-initial-content nil) + +(defmacro diff-hl-test-in-source (&rest body) + `(save-window-excursion + (find-file diff-hl-test-source-file) + ,@body)) +(put 'diff-hl-test-in-source 'lisp-indent-function 0) + +(defun diff-hl-test-init () + (diff-hl-test-in-source + (setq diff-hl-test-initial-content (buffer-string))) + t) + +(defun diff-hl-test-teardown () + (diff-hl-test-in-source + (erase-buffer) + (insert diff-hl-test-initial-content) + (save-buffer) + (pcase (vc-backend buffer-file-name) + (`Git + (vc-git-command nil 0 buffer-file-name "reset")) + (`Hg + (vc-hg-command nil 0 buffer-file-name "revert"))))) + +(defun diff-hl-test-compute-diff-lines () + (diff-hl-test-in-source + (save-buffer) + (let ((vc-diff-switches "-w")) + (diff-hl-diff-goto-hunk)) + (switch-to-buffer "*vc-diff*") + (let ((lines nil) + (previous-line (point-min))) + (goto-char (point-min)) + (while (< (point) (point-max)) + (forward-line 1) + (push (string-trim (buffer-substring-no-properties previous-line (point))) lines) + (setq previous-line (point))) + (delq nil (nreverse lines))))) + +(defmacro diff-hl-deftest (name &rest body) + `(ert-deftest ,name () + (diff-hl-test-init) + (unwind-protect + (progn ,@body) + (diff-hl-test-teardown)))) +(put 'diff-hl-deftest 'lisp-indent-function 'defun) + +(diff-hl-deftest diff-hl-insert () + (diff-hl-test-in-source + (goto-char (point-max)) + (insert "added\n") + (should (equal "+added" + (car (last (diff-hl-test-compute-diff-lines))))))) + +(diff-hl-deftest diff-hl-remove () + (diff-hl-test-in-source + (delete-region (point-min) (point-max)) + (should (equal "-last line" + (car (last (diff-hl-test-compute-diff-lines))))))) + +(diff-hl-deftest diff-hl-indirect-buffer-insert () + (diff-hl-test-in-source + (narrow-to-region (point-min) (point-max)) + (goto-char (point-max)) + (insert "added\n") + (should (equal "+added" + (car (last (diff-hl-test-compute-diff-lines))))))) + +(diff-hl-deftest diff-hl-indirect-buffer-remove () + (diff-hl-test-in-source + (narrow-to-region (point-min) (point-max)) + (goto-char (point-min)) + (delete-region (point) (point-max)) + (should (equal "-last line" + (car (last (diff-hl-test-compute-diff-lines))))))) + +(diff-hl-deftest diff-hl-indirect-buffer-move () + (diff-hl-test-in-source + (narrow-to-region (point-min) (point-max)) + (goto-char (point-min)) + (kill-whole-line 3) + (goto-char (point-max)) + (insert "added\n") + (save-buffer) + (diff-hl-mode 1) + (diff-hl-previous-hunk) + (should (looking-at "added")) + (diff-hl-previous-hunk) + (should (looking-at "function2")) + (should-error (diff-hl-previous-hunk) :type 'user-error) + (diff-hl-next-hunk) + (should (looking-at "added")) + (should-error (diff-hl-next-hunk) :type 'user-error))) + +(diff-hl-deftest diff-hl-can-ignore-staged-changes () + (diff-hl-test-in-source + (goto-char (point-min)) + (insert "new line 1\n") + (save-buffer) + (vc-git-command nil 0 buffer-file-name "add") + (goto-char (point-max)) + (insert "new line 2\n") + (save-buffer) + (let ((diff-hl-show-staged-changes t)) + (should + (equal (diff-hl-changes) + '((1 1 insert) + (12 1 insert))))) + (let ((diff-hl-show-staged-changes nil)) + (should + (equal (diff-hl-changes) + '((12 1 insert))))))) + +(diff-hl-deftest diff-hl-flydiff-can-ignore-staged-changes () + (diff-hl-test-in-source + (goto-char (point-min)) + (insert "new line 1\n") + (save-buffer) + (vc-git-command nil 0 buffer-file-name "add") + (goto-char (point-max)) + (insert "new line 2\n") + (let ((diff-hl-show-staged-changes t)) + (should + (equal (diff-hl-changes-from-buffer + (diff-hl-diff-buffer-with-reference buffer-file-name)) + '((1 1 insert) + (12 1 insert))))) + (let ((diff-hl-show-staged-changes nil)) + (should + (equal (diff-hl-changes-from-buffer + (diff-hl-diff-buffer-with-reference buffer-file-name)) + '((12 1 insert))))))) + +(defun diff-hl-run-tests () + (ert-run-tests-batch)) + +(provide 'diff-hl-test) + +;;; diff-hl-test.el ends here diff --git a/elpa/diff-hl-1.9.2/test/empty b/elpa/diff-hl-1.9.2/test/empty @@ -0,0 +1,10 @@ +function1 () { +} + +function2 () { +} + +function3 () { +} + +last line diff --git a/init.el b/init.el @@ -330,6 +330,7 @@ '(global-auto-revert-mode t) '(global-company-mode t) '(global-corfu-mode t) + '(global-diff-hl-mode t) '(help-window-select t) '(ibuffer-mode-hook '(all-the-icons-ibuffer-mode)) '(ignored-local-variable-values '((sly-load-failed-fasl . ask))) @@ -382,7 +383,7 @@ ("melpa-stable" . "https://stable.melpa.org/packages/") ("melpa" . "https://melpa.org/packages/"))) '(package-selected-packages - '(embark-consult embark all-the-icons-completion all-the-icons-ibuffer all-the-icons-dired sly-named-readtables sly-macrostep denote-refs denote-menu denote ox-epub ob-powershell powershell web-mode lexic editorconfig elfeed-tube-mpv elfeed-tube cider restclient-jq graphviz-dot-mode consult-eglot jq-mode ob-restclient restclient vterm deadgrep helpful pdf-tools paredit-menu paredit corfu sly eglot aggressive-indent project nov nhexl-mode elfeed magit yaml-mode json-mode lua-mode go-mode geiser-guile geiser org-contrib org ace-window expand-region consult marginalia uuidgen request diminish which-key)) + '(diff-hl embark-consult embark all-the-icons-completion all-the-icons-ibuffer all-the-icons-dired sly-named-readtables sly-macrostep denote-refs denote-menu denote ox-epub ob-powershell powershell web-mode lexic editorconfig elfeed-tube-mpv elfeed-tube cider restclient-jq graphviz-dot-mode consult-eglot jq-mode ob-restclient restclient vterm deadgrep helpful pdf-tools paredit-menu paredit corfu sly eglot aggressive-indent project nov nhexl-mode elfeed magit yaml-mode json-mode lua-mode go-mode geiser-guile geiser org-contrib org ace-window expand-region consult marginalia uuidgen request diminish which-key)) '(pcomplete-ignore-case t t) '(pixel-scroll-precision-mode t) '(read-buffer-completion-ignore-case t)