diff --git a/.gitignore b/.gitignore index ef9c902..a737e16 100644 --- a/.gitignore +++ b/.gitignore @@ -1,60 +1,65 @@ -#------------------------------------------------------------------------------- -# NppExec -NppExec_Manual.chm -*.zip - -#------------------------------------------------------------------------------- -# VisualStudio - -#-- User-specific files -*.suo -*.user -*.sln.docstates - -#-- Build results -[Dd]ebug/ -[Rr]elease/ -x64/ -x86/ -#[Bb]in/ -[Oo]bj/ -*.pdb - -#-- Visual C++ cache files -.vs/ -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.vc.db - -#-- Backup & report files from converting an old project file to a newer -# Visual Studio version. Backup files are not needed, because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -#-- Others -*_i.c -*_p.c -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -.builds -*.pidb +#------------------------------------------------------------------------------- +# NppExec +NppExec_Manual.chm +*.zip + +#------------------------------------------------------------------------------- +# VisualStudio + +#-- User-specific files +*.suo +*.user +*.sln.docstates + +#-- Build results +[Dd]ebug/ +/NppExec/[Rr]elease/* +!/NppExec/[Rr]elease/NppExec/* +NppExecPluginMsgTester/[Rr]elease*/* +UnitTests/[Rr]elease*/* +x64/ +x86/ +#[Bb]in/ +[Oo]bj/ +*.pdb +*.lib + +#-- Visual C++ cache files +.vs/ +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.vc.db + +#-- Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +#-- Others +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.tlog +.builds +*.pidb diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/NppExec/NppExec_DevCpp.dev b/NppExec/NppExec_DevCpp.dev index 771c0d8..2898857 100644 --- a/NppExec/NppExec_DevCpp.dev +++ b/NppExec/NppExec_DevCpp.dev @@ -1,7 +1,7 @@ [Project] FileName=NppExec_DevCpp.dev Name=NppExec -UnitCount=84 +UnitCount=86 Type=3 Ver=2 IsCpp=1 @@ -19,7 +19,7 @@ PrivateResource=NppExec_DevCpp_private.rc ResourceIncludes= MakeIncludes= Compiler=-DUNICODE_@@_-D_UNICODE_@@_ -CppCompiler=-DUNICODE_@@_-D_UNICODE_@@_-std=gnu++11_@@_ +CppCompiler=-DUNICODE_@@_-D_UNICODE_@@_-std=gnu++17_@@_ Linker=-lcomctl32_@@_-lcomdlg32_@@_-lgdi32_@@_-lshlwapi_@@_ Icon= ExeOutput= @@ -922,3 +922,23 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= +[Unit85] +FileName=src\PickColorBtn.cpp +CompileCpp=1 +Folder=NppExec +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit86] +FileName=src\ChildProcess.cpp +CompileCpp=1 +Folder=NppExec +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/NppExec/NppExec_VC2015.vcxproj b/NppExec/NppExec_VC2015.vcxproj index 2fcbd08..4df8527 100644 --- a/NppExec/NppExec_VC2015.vcxproj +++ b/NppExec/NppExec_VC2015.vcxproj @@ -276,6 +276,8 @@ + + @@ -323,16 +325,19 @@ + + + diff --git a/NppExec/NppExec_VC2017.vcxproj b/NppExec/NppExec_VC2017.vcxproj index 5fdbfbc..9c5701a 100644 --- a/NppExec/NppExec_VC2017.vcxproj +++ b/NppExec/NppExec_VC2017.vcxproj @@ -125,7 +125,6 @@ Disabled WIN32;_DEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) - false EnableFastChecks MultiThreadedDebug @@ -148,7 +147,6 @@ Disabled WIN32;_DEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) - false EnableFastChecks MultiThreadedDebug @@ -258,6 +256,7 @@ + @@ -279,6 +278,7 @@ + @@ -296,6 +296,7 @@ + @@ -326,6 +327,7 @@ + @@ -337,6 +339,7 @@ + diff --git a/NppExec/NppExec_VC2017.vcxproj.filters b/NppExec/NppExec_VC2017.vcxproj.filters index 84c855e..646712e 100644 --- a/NppExec/NppExec_VC2017.vcxproj.filters +++ b/NppExec/NppExec_VC2017.vcxproj.filters @@ -141,6 +141,12 @@ Source Files\c_base + + Source Files + + + Source Files + @@ -242,6 +248,9 @@ Header Files + + Header Files\npp_files + Header Files\npp_files @@ -299,6 +308,12 @@ Header Files\c_base + + Header Files + + + Header Files + diff --git a/NppExec/NppExec_VC2019.sln b/NppExec/NppExec_VC2019.sln new file mode 100644 index 0000000..a7a6d55 --- /dev/null +++ b/NppExec/NppExec_VC2019.sln @@ -0,0 +1,33 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.32413.511 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{65281C0D-EEA5-49A9-BF22-ABF2FCAF6A49}") = "NppExec", "NppExec_VC2019.vcxproj", "{70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Debug (ANSI)|Win32 = Debug (ANSI)|Win32 + Debug (ANSI)|x64 = Debug (ANSI)|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93}.Debug|Win32.ActiveCfg = Debug|Win32 + {70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93}.Debug|Win32.Build.0 = Debug|Win32 + {70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93}.Debug|x64.ActiveCfg = Debug|x64 + {70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93}.Debug|x64.Build.0 = Debug|x64 + {70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93}.Debug (ANSI)|Win32.ActiveCfg = Debug (ANSI)|Win32 + {70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93}.Debug (ANSI)|Win32.Build.0 = Debug (ANSI)|Win32 + {70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93}.Debug (ANSI)|x64.ActiveCfg = Debug (ANSI)|x64 + {70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93}.Debug (ANSI)|x64.Build.0 = Debug (ANSI)|x64 + {70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93}.Release|Win32.ActiveCfg = Release|Win32 + {70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93}.Release|Win32.Build.0 = Release|Win32 + {70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93}.Release|x64.ActiveCfg = Release|x64 + {70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/NppExec/NppExec_VC2019.vcxproj b/NppExec/NppExec_VC2019.vcxproj new file mode 100644 index 0000000..f31e16e --- /dev/null +++ b/NppExec/NppExec_VC2019.vcxproj @@ -0,0 +1,354 @@ + + + + + Debug (ANSI) + Win32 + + + Debug (ANSI) + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + NppExec + {70DF0FCD-0D4D-4C2A-B56D-A7DF0296CD93} + NppExec + Win32Proj + + + + DynamicLibrary + v142 + false + Unicode + + + DynamicLibrary + v142 + false + Unicode + + + DynamicLibrary + v142 + false + Unicode + + + DynamicLibrary + v142 + false + MultiByte + + + DynamicLibrary + v142 + false + Unicode + + + DynamicLibrary + v142 + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + false + + + <_ProjectFileVersion>12.0.30501.0 + + + Debug\ + Debug\ + true + + + Debug\ + Debug\ + true + + + true + + + true + + + Release\ + Release\ + false + + + false + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + Level3 + EditAndContinue + /Zc:threadSafeInit- %(AdditionalOptions) + + + comctl32.lib htmlhelp.lib %(AdditionalOptions) + $(OutDir)NppExec.dll + true + $(OutDir)NppExec.pdb + Windows + $(OutDir)NppExec.lib + MachineX86 + shlwapi.lib;%(AdditionalDependencies) + + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + /Zc:threadSafeInit- %(AdditionalOptions) + + + comctl32.lib htmlhelp.lib %(AdditionalOptions) + $(OutDir)NppExec.dll + true + $(OutDir)NppExec.pdb + Windows + $(OutDir)NppExec.lib + MachineX86 + shlwapi.lib;%(AdditionalDependencies) + + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + comctl32.lib htmlhelp.lib %(AdditionalOptions) + $(OutDir)NppExec.dll + true + $(OutDir)NppExec.pdb + Windows + $(OutDir)NppExec.lib + shlwapi.lib;%(AdditionalDependencies) + + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + comctl32.lib htmlhelp.lib %(AdditionalOptions) + $(OutDir)NppExec.dll + true + $(OutDir)NppExec.pdb + Windows + $(OutDir)NppExec.lib + shlwapi.lib;%(AdditionalDependencies) + + + + + WIN32;NDEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + MultiThreaded + + Level3 + ProgramDatabase + /Zc:threadSafeInit- %(AdditionalOptions) + + + comctl32.lib htmlhelp.lib %(AdditionalOptions) + $(OutDir)NppExec.dll + true + Windows + true + true + $(OutDir)NppExec.lib + MachineX86 + shlwapi.lib;%(AdditionalDependencies) + + + + + WIN32;NDEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + comctl32.lib htmlhelp.lib %(AdditionalOptions) + $(OutDir)NppExec.dll + false + Windows + true + true + $(OutDir)NppExec.lib + shlwapi.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NppExec/NppExec_VC2019.vcxproj.filters b/NppExec/NppExec_VC2019.vcxproj.filters new file mode 100644 index 0000000..646712e --- /dev/null +++ b/NppExec/NppExec_VC2019.vcxproj.filters @@ -0,0 +1,323 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + {3dd2d2c6-05d4-41b8-a602-2731eddfc239} + + + {2e542de7-1a8f-4b53-97a0-736ae0c257c3} + + + {d6bb39d9-dfd2-4771-a80d-2617c7f0ec31} + + + {e6dadeeb-d381-419e-8c25-f921e51b9235} + + + {7f553aa3-1d98-4f1c-b924-024428bfff6d} + + + {975a6d58-a2e8-4a99-9cf8-78f4754bf1dc} + + + {17860ebd-8035-4dd1-aa6b-3db759dcd616} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\fparser + + + Source Files + + + Source Files\cpp + + + Source Files\c_base + + + Source Files\c_base + + + Source Files\c_base + + + Source Files\c_base + + + Source Files\c_base + + + Source Files\c_base + + + Source Files\c_base + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\fparser + + + Header Files\fparser + + + Header Files\fparser + + + Header Files\fparser + + + Header Files + + + Header Files\npp_files + + + Header Files\npp_files + + + Header Files\npp_files + + + Header Files\npp_files + + + Header Files\npp_files + + + Header Files\npp_files + + + Header Files\npp_files + + + Header Files\cpp + + + Header Files\cpp + + + Header Files\cpp + + + Header Files\cpp + + + Header Files\cpp + + + Header Files\c_base + + + Header Files\c_base + + + Header Files\c_base + + + Header Files\c_base + + + Header Files\c_base + + + Header Files\c_base + + + Header Files\c_base + + + Header Files\c_base + + + Header Files + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/NppExec/NppExec_VC2022.sln b/NppExec/NppExec_VC2022.sln new file mode 100644 index 0000000..ae70541 --- /dev/null +++ b/NppExec/NppExec_VC2022.sln @@ -0,0 +1,33 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33627.172 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{E562BEB5-0D1F-4E10-AB35-CE4DD4620D6D}") = "NppExec", "NppExec_VC2022.vcxproj", "{653F5B73-87D2-48E3-BF19-309274028BF7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Debug (ANSI)|Win32 = Debug (ANSI)|Win32 + Debug (ANSI)|x64 = Debug (ANSI)|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {653F5B73-87D2-48E3-BF19-309274028BF7}.Debug|Win32.ActiveCfg = Debug|Win32 + {653F5B73-87D2-48E3-BF19-309274028BF7}.Debug|Win32.Build.0 = Debug|Win32 + {653F5B73-87D2-48E3-BF19-309274028BF7}.Debug|x64.ActiveCfg = Debug|x64 + {653F5B73-87D2-48E3-BF19-309274028BF7}.Debug|x64.Build.0 = Debug|x64 + {653F5B73-87D2-48E3-BF19-309274028BF7}.Debug (ANSI)|Win32.ActiveCfg = Debug (ANSI)|Win32 + {653F5B73-87D2-48E3-BF19-309274028BF7}.Debug (ANSI)|Win32.Build.0 = Debug (ANSI)|Win32 + {653F5B73-87D2-48E3-BF19-309274028BF7}.Debug (ANSI)|x64.ActiveCfg = Debug (ANSI)|x64 + {653F5B73-87D2-48E3-BF19-309274028BF7}.Debug (ANSI)|x64.Build.0 = Debug (ANSI)|x64 + {653F5B73-87D2-48E3-BF19-309274028BF7}.Release|Win32.ActiveCfg = Release|Win32 + {653F5B73-87D2-48E3-BF19-309274028BF7}.Release|Win32.Build.0 = Release|Win32 + {653F5B73-87D2-48E3-BF19-309274028BF7}.Release|x64.ActiveCfg = Release|x64 + {653F5B73-87D2-48E3-BF19-309274028BF7}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/NppExec/NppExec_VC2022.vcxproj b/NppExec/NppExec_VC2022.vcxproj new file mode 100644 index 0000000..1d82b95 --- /dev/null +++ b/NppExec/NppExec_VC2022.vcxproj @@ -0,0 +1,354 @@ + + + + + Debug (ANSI) + Win32 + + + Debug (ANSI) + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + NppExec + {653F5B73-87D2-48E3-BF19-309274028BF7} + NppExec + Win32Proj + + + + DynamicLibrary + v143 + false + Unicode + + + DynamicLibrary + v143 + false + Unicode + + + DynamicLibrary + v143 + false + Unicode + + + DynamicLibrary + v143 + false + MultiByte + + + DynamicLibrary + v143 + false + Unicode + + + DynamicLibrary + v143 + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + false + + + <_ProjectFileVersion>12.0.30501.0 + + + Debug\ + Debug\ + true + + + Debug\ + Debug\ + true + + + true + + + true + + + Release\ + Release\ + false + + + false + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + Level3 + EditAndContinue + /Zc:threadSafeInit- %(AdditionalOptions) + + + comctl32.lib htmlhelp.lib %(AdditionalOptions) + $(OutDir)NppExec.dll + true + $(OutDir)NppExec.pdb + Windows + $(OutDir)NppExec.lib + MachineX86 + shlwapi.lib;%(AdditionalDependencies) + + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + /Zc:threadSafeInit- %(AdditionalOptions) + + + comctl32.lib htmlhelp.lib %(AdditionalOptions) + $(OutDir)NppExec.dll + true + $(OutDir)NppExec.pdb + Windows + $(OutDir)NppExec.lib + MachineX86 + shlwapi.lib;%(AdditionalDependencies) + + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + comctl32.lib htmlhelp.lib %(AdditionalOptions) + $(OutDir)NppExec.dll + true + $(OutDir)NppExec.pdb + Windows + $(OutDir)NppExec.lib + shlwapi.lib;%(AdditionalDependencies) + + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + comctl32.lib htmlhelp.lib %(AdditionalOptions) + $(OutDir)NppExec.dll + true + $(OutDir)NppExec.pdb + Windows + $(OutDir)NppExec.lib + shlwapi.lib;%(AdditionalDependencies) + + + + + WIN32;NDEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + MultiThreaded + + Level3 + ProgramDatabase + /Zc:threadSafeInit- %(AdditionalOptions) + + + comctl32.lib htmlhelp.lib %(AdditionalOptions) + $(OutDir)NppExec.dll + true + Windows + true + true + $(OutDir)NppExec.lib + MachineX86 + shlwapi.lib;%(AdditionalDependencies) + + + + + WIN32;NDEBUG;_WINDOWS;_USRDLL;NPPEXEC_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + comctl32.lib htmlhelp.lib %(AdditionalOptions) + $(OutDir)NppExec.dll + false + Windows + true + true + $(OutDir)NppExec.lib + shlwapi.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NppExec/NppExec_VC2022.vcxproj.filters b/NppExec/NppExec_VC2022.vcxproj.filters new file mode 100644 index 0000000..646712e --- /dev/null +++ b/NppExec/NppExec_VC2022.vcxproj.filters @@ -0,0 +1,323 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + {3dd2d2c6-05d4-41b8-a602-2731eddfc239} + + + {2e542de7-1a8f-4b53-97a0-736ae0c257c3} + + + {d6bb39d9-dfd2-4771-a80d-2617c7f0ec31} + + + {e6dadeeb-d381-419e-8c25-f921e51b9235} + + + {7f553aa3-1d98-4f1c-b924-024428bfff6d} + + + {975a6d58-a2e8-4a99-9cf8-78f4754bf1dc} + + + {17860ebd-8035-4dd1-aa6b-3db759dcd616} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\fparser + + + Source Files + + + Source Files\cpp + + + Source Files\c_base + + + Source Files\c_base + + + Source Files\c_base + + + Source Files\c_base + + + Source Files\c_base + + + Source Files\c_base + + + Source Files\c_base + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\fparser + + + Header Files\fparser + + + Header Files\fparser + + + Header Files\fparser + + + Header Files + + + Header Files\npp_files + + + Header Files\npp_files + + + Header Files\npp_files + + + Header Files\npp_files + + + Header Files\npp_files + + + Header Files\npp_files + + + Header Files\npp_files + + + Header Files\cpp + + + Header Files\cpp + + + Header Files\cpp + + + Header Files\cpp + + + Header Files\cpp + + + Header Files\c_base + + + Header Files\c_base + + + Header Files\c_base + + + Header Files\c_base + + + Header Files\c_base + + + Header Files\c_base + + + Header Files\c_base + + + Header Files\c_base + + + Header Files + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/NppExec/Release/NppExec/BaseDef.h b/NppExec/Release/NppExec/BaseDef.h index 6cd4436..c5d28c2 100644 --- a/NppExec/Release/NppExec/BaseDef.h +++ b/NppExec/Release/NppExec/BaseDef.h @@ -10,10 +10,14 @@ #define NPE_SF_REGEXP 0x00000100 // search using a regular expression #define NPE_SF_POSIX 0x00000200 // search using a POSIX-compatible regular expression #define NPE_SF_CXX11REGEX 0x00000400 // search using a C++11 regular expression +#define NPE_SF_REGEXP_EMPTYMATCH_NOTAFTERMATCH 0x00002000 +#define NPE_SF_REGEXP_EMPTYMATCH_ALL 0x00004000 +#define NPE_SF_REGEXP_EMPTYMATCH_ALLOWATSTART 0x00008000 #define NPE_SF_BACKWARD 0x00010000 // search backward (from the bottom to the top) #define NPE_SF_NEXT 0x00020000 // search from current_position + 1 #define NPE_SF_INSELECTION 0x00100000 // search only in the selected text -#define NPE_SF_INWHOLETEXT 0x00200000 // search in the whole text, not only from the current position +#define NPE_SF_INENTIRETEXT 0x00200000 // search in the entire text, not only from the current position +#define NPE_SF_INWHOLETEXT 0x00200000 // search in the entire text, not only from the current position #define NPE_SF_SETPOS 0x01000000 // move the caret to the position of the occurrence found #define NPE_SF_SETSEL 0x02000000 // move the caret + select the occurrence found #define NPE_SF_REPLACEALL 0x10000000 // replace all the occurrences from the current pos to the end diff --git a/NppExec/Release/NppExec/Notepad_plus_msgs.h b/NppExec/Release/NppExec/Notepad_plus_msgs.h index a2261b0..03e1cbf 100644 --- a/NppExec/Release/NppExec/Notepad_plus_msgs.h +++ b/NppExec/Release/NppExec/Notepad_plus_msgs.h @@ -1,5 +1,5 @@ // This file is part of Notepad++ project -// Copyright (C)2021 Don HO +// Copyright (C)2025 Don HO // 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 @@ -15,14 +15,18 @@ // along with this program. If not, see . + +// For more comprehensive information on plugin communication, please refer to the following resource: +// https://npp-user-manual.org/docs/plugin-communication/ + + #pragma once #include -#include enum LangType {L_TEXT, L_PHP , L_C, L_CPP, L_CS, L_OBJC, L_JAVA, L_RC,\ L_HTML, L_XML, L_MAKEFILE, L_PASCAL, L_BATCH, L_INI, L_ASCII, L_USER,\ - L_ASP, L_SQL, L_VB, L_JS, L_CSS, L_PERL, L_PYTHON, L_LUA, \ + L_ASP, L_SQL, L_VB, L_JS_EMBEDDED, L_CSS, L_PERL, L_PYTHON, L_LUA, \ L_TEX, L_FORTRAN, L_BASH, L_FLASH, L_NSIS, L_TCL, L_LISP, L_SCHEME,\ L_ASM, L_DIFF, L_PROPS, L_PS, L_RUBY, L_SMALLTALK, L_VHDL, L_KIX, L_AU3,\ L_CAML, L_ADA, L_VERILOG, L_MATLAB, L_HASKELL, L_INNO, L_SEARCHRESULT,\ @@ -33,436 +37,1024 @@ enum LangType {L_TEXT, L_PHP , L_C, L_CPP, L_CS, L_OBJC, L_JAVA, L_RC,\ L_CSOUND, L_ERLANG, L_ESCRIPT, L_FORTH, L_LATEX, \ L_MMIXAL, L_NIM, L_NNCRONTAB, L_OSCRIPT, L_REBOL, \ L_REGISTRY, L_RUST, L_SPICE, L_TXT2TAGS, L_VISUALPROLOG,\ - // Don't use L_JS, use L_JAVASCRIPT instead - // The end of enumated language type, so it should be always at the end + L_TYPESCRIPT, L_JSON5, L_MSSQL, L_GDSCRIPT, L_HOLLYWOOD,\ + L_GOLANG, L_RAKU, L_TOML, L_SAS, L_ERRORLIST, \ + // Don't use L_JS_EMBEDDED, use L_JAVASCRIPT instead + // The end of enumerated language type, so it should be always at the end L_EXTERNAL}; +enum class ExternalLexerAutoIndentMode { Standard, C_Like, Custom }; +enum class MacroStatus { Idle, RecordInProgress, RecordingStopped, PlayingBack }; -enum winVer{ WV_UNKNOWN, WV_WIN32S, WV_95, WV_98, WV_ME, WV_NT, WV_W2K, WV_XP, WV_S2003, WV_XPX64, WV_VISTA, WV_WIN7, WV_WIN8, WV_WIN81, WV_WIN10}; -enum Platform { PF_UNKNOWN, PF_X86, PF_X64, PF_IA64 }; +enum winVer { WV_UNKNOWN, WV_WIN32S, WV_95, WV_98, WV_ME, WV_NT, WV_W2K, WV_XP, WV_S2003, WV_XPX64, WV_VISTA, WV_WIN7, WV_WIN8, WV_WIN81, WV_WIN10, WV_WIN11 }; +enum Platform { PF_UNKNOWN, PF_X86, PF_X64, PF_IA64, PF_ARM64 }; #define NPPMSG (WM_USER + 1000) - #define NPPM_GETCURRENTSCINTILLA (NPPMSG + 4) - #define NPPM_GETCURRENTLANGTYPE (NPPMSG + 5) - #define NPPM_SETCURRENTLANGTYPE (NPPMSG + 6) - - #define NPPM_GETNBOPENFILES (NPPMSG + 7) - #define ALL_OPEN_FILES 0 - #define PRIMARY_VIEW 1 - #define SECOND_VIEW 2 - - #define NPPM_GETOPENFILENAMES (NPPMSG + 8) - - - #define NPPM_MODELESSDIALOG (NPPMSG + 12) - #define MODELESSDIALOGADD 0 - #define MODELESSDIALOGREMOVE 1 + #define NPPM_GETCURRENTSCINTILLA (NPPMSG + 4) + // BOOL NPPM_GETCURRENTSCINTILLA(0, int* iScintillaView) + // Get current Scintilla view. + // wParam: 0 (not used) + // lParam[out]: iScintillaView could be 0 (Main View) or 1 (Sub View) + // return TRUE + + #define NPPM_GETCURRENTLANGTYPE (NPPMSG + 5) + // BOOL NPPM_GETCURRENTLANGTYPE(0, int* langType) + // Get the programming language type from the current used document. + // wParam: 0 (not used) + // lParam[out]: langType - see "enum LangType" for all valid values + // return TRUE + + #define NPPM_SETCURRENTLANGTYPE (NPPMSG + 6) + // BOOL NPPM_SETCURRENTLANGTYPE(0, int langType) + // Set a new programming language type to the current used document. + // wParam: 0 (not used) + // lParam[in]: langType - see "enum LangType" for all valid values + // return TRUE + + #define NPPM_GETNBOPENFILES (NPPMSG + 7) + #define ALL_OPEN_FILES 0 + #define PRIMARY_VIEW 1 + #define SECOND_VIEW 2 + // int NPPM_GETNBOPENFILES(0, int iViewType) + // Get the number of files currently open. + // wParam: 0 (not used) + // lParam[in]: iViewType - could be PRIMARY_VIEW (value 1), SECOND_VIEW (value 2) or ALL_OPEN_FILES (value 0) + // return the number of opened files + + #define NPPM_GETOPENFILENAMES_DEPRECATED (NPPMSG + 8) + // BOOL NPPM_GETOPENFILENAMES_DEPRECATED(wchar_t** fileNames, int nbFileNames) - DEPRECATED: It is kept for the compatibility. Use NPPM_GETBUFFERIDFROMPOS & NPPM_GETFULLPATHFROMBUFFERID instead. + // Get the open files full paths of both views. User is responsible to allocate a big enough fileNames array by using NPPM_GETNBOPENFILES. + // wParam[out]: fileNames - array of file path + // lParam[in]: nbFileNames is the number of file path. + // return value: The number of files copied into fileNames array + + #define NPPM_MODELESSDIALOG (NPPMSG + 12) + #define MODELESSDIALOGADD 0 + #define MODELESSDIALOGREMOVE 1 + // HWND NPPM_MODELESSDIALOG(int action, HWND hDlg) + // Register (or unregister) plugin's dialog handle. + // For each created dialog in your plugin, you should register it (and unregister while destroy it) to Notepad++ by using this message. + // If this message is ignored, then your dialog won't react with the key stroke messages such as TAB, Ctrl-C or Ctrl-V key. + // For the good functioning of your plugin dialog, you're recommended to not ignore this message. + // wParam[in]: action is MODELESSDIALOGADD (for registering your hDlg) or MODELESSDIALOGREMOVE (for unregistering your hDlg) + // lParam[in]: hDlg is the handle of dialog to register/unregister + // return hDlg (HWND) on success, NULL on failure #define NPPM_GETNBSESSIONFILES (NPPMSG + 13) + // int NPPM_GETNBSESSIONFILES (BOOL* pbIsValidXML, wchar_t* sessionFileName) + // Get the number of files to load in the session sessionFileName. sessionFileName should be a full path name of an xml file. + // wParam[out]: pbIsValidXML, if the lParam pointer is null, then this parameter will be ignored. TRUE if XML is valid, otherwise FALSE. + // lParam[in]: sessionFileName is XML session full path + // return value: The number of files in XML session file + #define NPPM_GETSESSIONFILES (NPPMSG + 14) - #define NPPM_SAVESESSION (NPPMSG + 15) - #define NPPM_SAVECURRENTSESSION (NPPMSG + 16) + // BOOL NPPM_GETSESSIONFILES (wchar_t** sessionFileArray, wchar_t* sessionFileName) + // the files' full path name from a session file. + // wParam[out]: sessionFileArray is the array in which the files' full path of the same group are written. To allocate the array with the proper size, send message NPPM_GETNBSESSIONFILES. + // lParam[in]: sessionFileName is XML session full path + // Return FALSE on failure, TRUE on success + #define NPPM_SAVESESSION (NPPMSG + 15) struct sessionInfo { - TCHAR* sessionFilePathName; - int nbFile; - TCHAR** files; + wchar_t* sessionFilePathName; // Full session file path name to be saved + int nbFile; // Size of "files" array - number of files to be saved in session + wchar_t** files; // Array of file name (full path) to be saved in session }; + // NPPM_SAVESESSION(0, sessionInfo* si) + // Creates an session file for a defined set of files. + // Contrary to NPPM_SAVECURRENTSESSION (see below), which saves the current opened files, this call can be used to freely define any file which should be part of a session. + // wParam: 0 (not used) + // lParam[in]: si is a pointer to sessionInfo structure + // Returns sessionFileName on success, NULL otherwise - #define NPPM_GETOPENFILENAMESPRIMARY (NPPMSG + 17) - #define NPPM_GETOPENFILENAMESSECOND (NPPMSG + 18) + #define NPPM_SAVECURRENTSESSION (NPPMSG + 16) + // wchar_t* NPPM_SAVECURRENTSESSION(0, wchar_t* sessionFileName) + // Saves the current opened files in Notepad++ as a group of files (session) as an xml file. + // wParam: 0 (not used) + // lParam[in]: sessionFileName is the xml full path name + // Returns sessionFileName on success, NULL otherwise + + + #define NPPM_GETOPENFILENAMESPRIMARY_DEPRECATED (NPPMSG + 17) + // BOOL NPPM_GETOPENFILENAMESPRIMARY_DEPRECATED(wchar_t** fileNames, int nbFileNames) - DEPRECATED: It is kept for the compatibility. Use NPPM_GETBUFFERIDFROMPOS & NPPM_GETFULLPATHFROMBUFFERID instead. + // Get the open files full paths of main view. User is responsible to allocate an big enough fileNames array by using NPPM_GETNBOPENFILES. + // wParam[out]: fileNames - array of file path + // lParam[in]: nbFileNames is the number of file path. + // return value: The number of files copied into fileNames array + + #define NPPM_GETOPENFILENAMESSECOND_DEPRECATED (NPPMSG + 18) + // BOOL NPPM_GETOPENFILENAMESSECOND_DEPRECATED(wchar_t** fileNames, int nbFileNames) - DEPRECATED: It is kept for the compatibility. Use NPPM_GETBUFFERIDFROMPOS & NPPM_GETFULLPATHFROMBUFFERID instead. + // Get the open files full paths of sub-view. User is responsible to allocate an big enough fileNames array by using NPPM_GETNBOPENFILES. + // wParam[out]: fileNames - array of file path + // lParam[in]: nbFileNames is the number of file path. + // return value: The number of files copied into fileNames array #define NPPM_CREATESCINTILLAHANDLE (NPPMSG + 20) - #define NPPM_DESTROYSCINTILLAHANDLE (NPPMSG + 21) + // HWND NPPM_CREATESCINTILLAHANDLE(0, HWND hParent) + // A plugin can create a Scintilla for its usage by sending this message to Notepad++. + // wParam: 0 (not used) + // lParam[in]: hParent - If set (non NULL), it will be the parent window of this created Scintilla handle, otherwise the parent window is Notepad++ + // return the handle of created Scintilla handle + + #define NPPM_DESTROYSCINTILLAHANDLE_DEPRECATED (NPPMSG + 21) + // BOOL NPPM_DESTROYSCINTILLAHANDLE_DEPRECATED(0, HWND hScintilla) - DEPRECATED: It is kept for the compatibility. + // Notepad++ will deallocate every created Scintilla control on exit, this message returns TRUE but does nothing. + // wParam: 0 (not used) + // lParam[in]: hScintilla is Scintilla handle + // Return TRUE + #define NPPM_GETNBUSERLANG (NPPMSG + 22) + // int NPPM_GETNBUSERLANG(0, int* udlID) + // Get the number of user defined languages and, optionally, the starting menu id. + // wParam: 0 (not used) + // lParam[out]: udlID is optional, if not used set it to 0, otherwise an integer pointer is needed to retrieve the menu identifier. + // Return the number of user defined languages identified #define NPPM_GETCURRENTDOCINDEX (NPPMSG + 23) #define MAIN_VIEW 0 #define SUB_VIEW 1 + // int NPPM_GETCURRENTDOCINDEX(0, int inView) + // Get the current index of the given view. + // wParam: 0 (not used) + // lParam[in]: inView, should be 0 (main view) or 1 (sub-view) + // Return -1 if the view is invisible (hidden), otherwise is the current index. #define NPPM_SETSTATUSBAR (NPPMSG + 24) - #define STATUSBAR_DOC_TYPE 0 - #define STATUSBAR_DOC_SIZE 1 - #define STATUSBAR_CUR_POS 2 - #define STATUSBAR_EOF_FORMAT 3 + #define STATUSBAR_DOC_TYPE 0 + #define STATUSBAR_DOC_SIZE 1 + #define STATUSBAR_CUR_POS 2 + #define STATUSBAR_EOF_FORMAT 3 #define STATUSBAR_UNICODE_TYPE 4 - #define STATUSBAR_TYPING_MODE 5 + #define STATUSBAR_TYPING_MODE 5 + // BOOL NPPM_SETSTATUSBAR(int whichPart, wchar_t *str2set) + // Set string in the specified field of a statusbar. + // wParam[in]: whichPart for indicating the statusbar part you want to set. It can be only the above value (0 - 5) + // lParam[in]: str2set is the string you want to write to the part of statusbar. + // Return FALSE on failure, TRUE on success #define NPPM_GETMENUHANDLE (NPPMSG + 25) #define NPPPLUGINMENU 0 #define NPPMAINMENU 1 - // INT NPPM_GETMENUHANDLE(INT menuChoice, 0) + // int NPPM_GETMENUHANDLE(int menuChoice, 0) + // Get menu handle (HMENU) of choice. + // wParam[in]: menuChoice could be main menu (NPPMAINMENU) or Plugin menu (NPPPLUGINMENU) + // lParam: 0 (not used) // Return: menu handle (HMENU) of choice (plugin menu handle or Notepad++ main menu handle) #define NPPM_ENCODESCI (NPPMSG + 26) - //ascii file to unicode - //int NPPM_ENCODESCI(MAIN_VIEW/SUB_VIEW, 0) - //return new unicodeMode + // int NPPM_ENCODESCI(int inView, 0) + // Changes current buffer in view to UTF-8. + // wParam[in]: inView - main view (0) or sub-view (1) + // lParam: 0 (not used) + // return new UniMode, with the following value: + // 0: ANSI + // 1: UTF-8 with BOM + // 2: UTF-16 Big Ending with BOM + // 3: UTF-16 Little Ending with BOM + // 4: UTF-8 without BOM + // 5: uni7Bit + // 6: UTF-16 Big Ending without BOM + // 7: UTF-16 Little Ending without BOM #define NPPM_DECODESCI (NPPMSG + 27) - //unicode file to ascii - //int NPPM_DECODESCI(MAIN_VIEW/SUB_VIEW, 0) - //return old unicodeMode + // int NPPM_DECODESCI(int inView, 0) + // Changes current buffer in view to ANSI. + // wParam[in]: inView - main view (0) or sub-view (1) + // lParam: 0 (not used) + // return old UniMode - see above #define NPPM_ACTIVATEDOC (NPPMSG + 28) - //void NPPM_ACTIVATEDOC(int view, int index2Activate) + // BOOL NPPM_ACTIVATEDOC(int inView, int index2Activate) + // Switch to the document by the given view and index. + // wParam[in]: inView - main view (0) or sub-view (1) + // lParam[in]: index2Activate - index (in the view indicated above) where is the document to be activated + // Return TRUE #define NPPM_LAUNCHFINDINFILESDLG (NPPMSG + 29) - //void NPPM_LAUNCHFINDINFILESDLG(TCHAR * dir2Search, TCHAR * filtre) + // BOOL NPPM_LAUNCHFINDINFILESDLG(wchar_t * dir2Search, wchar_t * filtre) + // Launch Find in Files dialog and set "Find in" directory and filters with the given arguments. + // wParam[in]: if dir2Search is not NULL, it will be set as working directory in which Notepad++ will search + // lParam[in]: if filtre is not NULL, filtre string will be set into filter field + // Return TRUE #define NPPM_DMMSHOW (NPPMSG + 30) - //void NPPM_DMMSHOW(0, tTbData->hClient) + // BOOL NPPM_DMMSHOW(0, HWND hDlg) + // Show the dialog which was previously registered by NPPM_DMMREGASDCKDLG. + // wParam: 0 (not used) + // lParam[in]: hDlg is the handle of dialog to show + // Return TRUE #define NPPM_DMMHIDE (NPPMSG + 31) - //void NPPM_DMMHIDE(0, tTbData->hClient) + // BOOL NPPM_DMMHIDE(0, HWND hDlg) + // Hide the dialog which was previously registered by NPPM_DMMREGASDCKDLG. + // wParam: 0 (not used) + // lParam[in]: hDlg is the handle of dialog to hide + // Return TRUE #define NPPM_DMMUPDATEDISPINFO (NPPMSG + 32) - //void NPPM_DMMUPDATEDISPINFO(0, tTbData->hClient) + // BOOL NPPM_DMMUPDATEDISPINFO(0, HWND hDlg) + // Redraw the dialog. + // wParam: 0 (not used) + // lParam[in]: hDlg is the handle of dialog to redraw + // Return TRUE #define NPPM_DMMREGASDCKDLG (NPPMSG + 33) - //void NPPM_DMMREGASDCKDLG(0, &tTbData) + // BOOL NPPM_DMMREGASDCKDLG(0, tTbData* pData) + // Pass the necessary dockingData to Notepad++ in order to make your dialog dockable. + // wParam: 0 (not used) + // lParam[in]: pData is the pointer of tTbData. Please check tTbData structure in "Docking.h" + // Minimum information which needs to be filled out are hClient, pszName, dlgID, uMask and pszModuleName. + // Notice that rcFloat and iPrevCont shouldn't be filled. They are used internally. + // Return TRUE #define NPPM_LOADSESSION (NPPMSG + 34) - //void NPPM_LOADSESSION(0, const TCHAR* file name) + // BOOL NPPM_LOADSESSION(0, wchar_t* sessionFileName) + // Open all files of same session in Notepad++ via a xml format session file sessionFileName. + // wParam: 0 (not used) + // lParam[in]: sessionFileName is the full file path of session file to reload + // Return TRUE #define NPPM_DMMVIEWOTHERTAB (NPPMSG + 35) - //void WM_DMM_VIEWOTHERTAB(0, tTbData->pszName) + // BOOL WM_DMM_VIEWOTHERTAB(0, wchar_t* name) + // Show the plugin dialog (switch to plugin tab) with the given name. + // wParam: 0 (not used) + // lParam[in]: name should be the same value as previously used to register the dialog (pszName of tTbData) + // Return TRUE #define NPPM_RELOADFILE (NPPMSG + 36) - //BOOL NPPM_RELOADFILE(BOOL withAlert, TCHAR *filePathName2Reload) + // BOOL NPPM_RELOADFILE(BOOL withAlert, wchar_t *filePathName2Reload) + // Reload the document which matches with the given filePathName2Reload. + // wParam: 0 (not used) + // lParam[in]: filePathName2Reload is the full file path of document to reload + // Return TRUE if reloading file succeeds, otherwise FALSE #define NPPM_SWITCHTOFILE (NPPMSG + 37) - //BOOL NPPM_SWITCHTOFILE(0, TCHAR *filePathName2switch) + // BOOL NPPM_SWITCHTOFILE(0, wchar_t* filePathName2switch) + // Switch to the document which matches with the given filePathName2switch. + // wParam: 0 (not used) + // lParam[in]: filePathName2switch is the full file path of document to switch + // Return TRUE #define NPPM_SAVECURRENTFILE (NPPMSG + 38) - //BOOL NPPM_SAVECURRENTFILE(0, 0) + // BOOL NPPM_SAVECURRENTFILE(0, 0) + // Save current activated document. + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return TRUE if file is saved, otherwise FALSE (the file doesn't need to be saved, or other reasons). #define NPPM_SAVEALLFILES (NPPMSG + 39) - //BOOL NPPM_SAVEALLFILES(0, 0) + // BOOL NPPM_SAVEALLFILES(0, 0) + // Save all opened document. + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return FALSE when no file needs to be saved, else TRUE if there is at least one file saved. #define NPPM_SETMENUITEMCHECK (NPPMSG + 40) - //void WM_PIMENU_CHECK(UINT funcItem[X]._cmdID, TRUE/FALSE) + // BOOL NPPM_SETMENUITEMCHECK(UINT pluginCmdID, BOOL doCheck) + // Set or remove the check on a item of plugin menu and tool bar (if any). + // wParam[in]: pluginCmdID is the plugin command ID which corresponds to the menu item: funcItem[X]._cmdID + // lParam[in]: if doCheck value is TRUE, item will be checked, FALSE makes item unchecked. + // Return TRUE #define NPPM_ADDTOOLBARICON_DEPRECATED (NPPMSG + 41) - //void NPPM_ADDTOOLBARICON(UINT funcItem[X]._cmdID, toolbarIcons iconHandles) -- DEPRECATED : use NPPM_ADDTOOLBARICON_FORDARKMODE instead - //2 formats of icon are needed: .ico & .bmp - //Both handles below should be set so the icon will be displayed correctly if toolbar icon sets are changed by users struct toolbarIcons { HBITMAP hToolbarBmp; HICON hToolbarIcon; }; + // BOOL NPPM_ADDTOOLBARICON_DEPRECATED(UINT pluginCmdID, toolbarIcons* iconHandles) -- DEPRECATED: use NPPM_ADDTOOLBARICON_FORDARKMODE instead + // Add an icon to the toolbar. + // wParam[in]: pluginCmdID is the plugin command ID which corresponds to the menu item: funcItem[X]._cmdID + // lParam[in]: iconHandles of toolbarIcons structure. 2 formats ".ico" & ".bmp" are needed + // Both handles should be set so the icon will be displayed correctly if toolbar icon sets are changed by users + // Return TRUE + #define NPPM_GETWINDOWSVERSION (NPPMSG + 42) - //winVer NPPM_GETWINDOWSVERSION(0, 0) + // winVer NPPM_GETWINDOWSVERSION(0, 0) + // Get OS (Windows) version. + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return enum winVer, which is defined at the beginning of this file #define NPPM_DMMGETPLUGINHWNDBYNAME (NPPMSG + 43) - //HWND WM_DMM_GETPLUGINHWNDBYNAME(const TCHAR *windowName, const TCHAR *moduleName) - // if moduleName is NULL, then return value is NULL - // if windowName is NULL, then the first found window handle which matches with the moduleName will be returned + // HWND NPPM_DMMGETPLUGINHWNDBYNAME(const wchar_t *windowName, const wchar_t *moduleName) + // Retrieve the dialog handle corresponds to the windowName and moduleName. You may need this message if you want to communicate with another plugin "dockable" dialog. + // wParam[in]: windowName - if windowName is NULL, then the first found window handle which matches with the moduleName will be returned + // lParam[in] : moduleName - if moduleName is NULL, then return value is NULL + // Return NULL if moduleName is NULL. If windowName is NULL, then the first found window handle which matches with the moduleName will be returned. #define NPPM_MAKECURRENTBUFFERDIRTY (NPPMSG + 44) - //BOOL NPPM_MAKECURRENTBUFFERDIRTY(0, 0) - - #define NPPM_GETENABLETHEMETEXTUREFUNC (NPPMSG + 45) - //BOOL NPPM_GETENABLETHEMETEXTUREFUNC(0, 0) + // BOOL NPPM_MAKECURRENTBUFFERDIRTY(0, 0) + // Make the current document dirty, aka set the save state to unsaved. + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return TRUE + + #define NPPM_GETENABLETHEMETEXTUREFUNC_DEPRECATED (NPPMSG + 45) + // THEMEAPI NPPM_GETENABLETHEMETEXTUREFUNC(0, 0) -- DEPRECATED: plugin can use EnableThemeDialogTexture directly from uxtheme.h instead + // Get "EnableThemeDialogTexture" function address. + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return a proc address or NULL #define NPPM_GETPLUGINSCONFIGDIR (NPPMSG + 46) - //INT NPPM_GETPLUGINSCONFIGDIR(int strLen, TCHAR *str) + // int NPPM_GETPLUGINSCONFIGDIR(int strLen, wchar_t *str) // Get user's plugin config directory path. It's useful if plugins want to save/load parameters for the current user - // Returns the number of TCHAR copied/to copy. - // Users should call it with "str" be NULL to get the required number of TCHAR (not including the terminating nul character), - // allocate "str" buffer with the return value + 1, then call it again to get the path. + // wParam[in]: strLen is length of allocated buffer in which directory path is copied + // lParam[out] : str is the allocated buffere. User should call this message twice - + // The 1st call with "str" be NULL to get the required number of wchar_t (not including the terminating nul character) + // The 2nd call to allocate "str" buffer with the 1st call's return value + 1, then call it again to get the path + // Return value: The 1st call - the number of wchar_t to copy. + // The 2nd call - FALSE on failure, TRUE on success #define NPPM_MSGTOPLUGIN (NPPMSG + 47) - //BOOL NPPM_MSGTOPLUGIN(TCHAR *destModuleName, CommunicationInfo *info) - // return value is TRUE when the message arrive to the destination plugins. - // if destModule or info is NULL, then return value is FALSE struct CommunicationInfo { - long internalMsg; - const TCHAR * srcModuleName; - void * info; // defined by plugin + long internalMsg; // an integer defined by plugin Y, known by plugin X, identifying the message being sent. + const wchar_t * srcModuleName; // the complete module name (with the extension .dll) of caller (plugin X). + void* info; // defined by plugin, the information to be exchanged between X and Y. It's a void pointer so it should be defined by plugin Y and known by plugin X. }; + // BOOL NPPM_MSGTOPLUGIN(wchar_t *destModuleName, CommunicationInfo *info) + // Send a private information to a plugin with given plugin name. This message allows the communication between 2 plugins. + // For example, plugin X can execute a command of plugin Y if plugin X knows the command ID and the file name of plugin Y. + // wParam[in]: destModuleName is the destination complete module file name (with the file extension ".dll") + // lParam[in]: info - See above "CommunicationInfo" structure + // The returned value is TRUE if Notepad++ found the plugin by its module name (destModuleName), and pass the info (communicationInfo) to the module. + // The returned value is FALSE if no plugin with such name is found. #define NPPM_MENUCOMMAND (NPPMSG + 48) - //void NPPM_MENUCOMMAND(0, int cmdID) - // uncomment //#include "menuCmdID.h" - // in the beginning of this file then use the command symbols defined in "menuCmdID.h" file - // to access all the Notepad++ menu command items + // BOOL NPPM_MENUCOMMAND(0, int cmdID) + // Run Notepad++ command with the given command ID. + // wParam: 0 (not used) + // lParam[in]: cmdID - See "menuCmdID.h" for all the Notepad++ menu command items + // Return TRUE #define NPPM_TRIGGERTABBARCONTEXTMENU (NPPMSG + 49) - //void NPPM_TRIGGERTABBARCONTEXTMENU(int view, int index2Activate) + // BOOL NPPM_TRIGGERTABBARCONTEXTMENU(int inView, int index2Activate) + // Switch to the document by the given view and index and trigger the context menu + // wParam[in]: inView - main view (0) or sub-view (1) + // lParam[in]: index2Activate - index (in the view indicated above) where is the document to have the context menu + // Return TRUE #define NPPM_GETNPPVERSION (NPPMSG + 50) - // int NPPM_GETNPPVERSION(0, 0) - // return version - // ex : v4.6 - // HIWORD(version) == 4 - // LOWORD(version) == 6 + // int NPPM_GETNPPVERSION(BOOL ADD_ZERO_PADDING, 0) + // Get Notepad++ version. + // wParam[in]: ADD_ZERO_PADDING (see below) + // lParam: 0 (not used) + // return value: + // HIWORD(returned_value) is major part of version: the 1st number + // LOWORD(returned_value) is minor part of version: the 3 last numbers + // + // ADD_ZERO_PADDING == TRUE + // + // version | HIWORD | LOWORD + //------------------------------ + // 8.9.6.4 | 8 | 964 + // 9 | 9 | 0 + // 6.9 | 6 | 900 + // 6.6.6 | 6 | 660 + // 13.6.6.6 | 13 | 666 + // + // + // ADD_ZERO_PADDING == FALSE + // + // version | HIWORD | LOWORD + //------------------------------ + // 8.9.6.4 | 8 | 964 + // 9 | 9 | 0 + // 6.9 | 6 | 9 + // 6.6.6 | 6 | 66 + // 13.6.6.6 | 13 | 666 #define NPPM_HIDETABBAR (NPPMSG + 51) // BOOL NPPM_HIDETABBAR(0, BOOL hideOrNot) - // if hideOrNot is set as TRUE then tab bar will be hidden - // otherwise it'll be shown. - // return value : the old status value + // Hide (or show) tab bar. + // wParam: 0 (not used) + // lParam[in]: if hideOrNot is set as TRUE then tab bar will be hidden, otherwise it'll be shown. + // return value: the old status value #define NPPM_ISTABBARHIDDEN (NPPMSG + 52) // BOOL NPPM_ISTABBARHIDDEN(0, 0) - // returned value : TRUE if tab bar is hidden, otherwise FALSE + // Get tab bar status. + // wParam: 0 (not used) + // lParam: 0 (not used) + // return value: TRUE if tool bar is hidden, otherwise FALSE #define NPPM_GETPOSFROMBUFFERID (NPPMSG + 57) - // INT NPPM_GETPOSFROMBUFFERID(UINT_PTR bufferID, INT priorityView) - // Return VIEW|INDEX from a buffer ID. -1 if the bufferID non existing - // if priorityView set to SUB_VIEW, then SUB_VIEW will be search firstly + // int NPPM_GETPOSFROMBUFFERID(UINT_PTR bufferID, int priorityView) + // Get document position (VIEW and INDEX) from a buffer ID, according priorityView. + // wParam[in]: BufferID of document + // lParam[in]: priorityView is the target VIEW. However, if the given bufferID cannot be found in the target VIEW, the other VIEW will be searched. + // Return -1 if the bufferID non existing, else return value contains VIEW & INDEX: // // VIEW takes 2 highest bits and INDEX (0 based) takes the rest (30 bits) - // Here's the values for the view : + // Here's the values for the view: // MAIN_VIEW 0 // SUB_VIEW 1 + // + // if priorityView set to SUB_VIEW, then SUB_VIEW will be search firstly #define NPPM_GETFULLPATHFROMBUFFERID (NPPMSG + 58) - // INT NPPM_GETFULLPATHFROMBUFFERID(UINT_PTR bufferID, TCHAR *fullFilePath) - // Get full path file name from a bufferID. - // Return -1 if the bufferID non existing, otherwise the number of TCHAR copied/to copy - // User should call it with fullFilePath be NULL to get the number of TCHAR (not including the nul character), - // allocate fullFilePath with the return values + 1, then call it again to get full path file name + // int NPPM_GETFULLPATHFROMBUFFERID(UINT_PTR bufferID, wchar_t* fullFilePath) + // Get full path file name from a bufferID (the pointer of buffer). + // wParam[in]: bufferID + // lParam[out]: fullFilePath - User should call it with fullFilePath be NULL to get the number of wchar_t (not including the nul character), + // allocate fullFilePath with the return values + 1, then call it again to get full path file name + // Return -1 if the bufferID non existing, otherwise the number of wchar_t copied/to copy #define NPPM_GETBUFFERIDFROMPOS (NPPMSG + 59) - // LRESULT NPPM_GETBUFFERIDFROMPOS(INT index, INT iView) - // wParam: Position of document - // lParam: View to use, 0 = Main, 1 = Secondary - // Returns 0 if invalid + // UINT_PTR NPPM_GETBUFFERIDFROMPOS(int index, int iView) + // Get the document bufferID from the given position (iView & index). + // wParam[in]: Position (0 based) of document + // lParam[in]: Main or sub View in which document is, 0 = Main, 1 = Sub + // Returns NULL if invalid, otherwise bufferID #define NPPM_GETCURRENTBUFFERID (NPPMSG + 60) - // LRESULT NPPM_GETCURRENTBUFFERID(0, 0) - // Returns active Buffer + // UINT_PTR NPPM_GETCURRENTBUFFERID(0, 0) + // Get active document BufferID. + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return active document BufferID #define NPPM_RELOADBUFFERID (NPPMSG + 61) - // VOID NPPM_RELOADBUFFERID(UINT_PTR bufferID, BOOL alert) - // Reloads Buffer - // wParam: Buffer to reload - // lParam: 0 if no alert, else alert + // BOOL NPPM_RELOADBUFFERID(UINT_PTR bufferID, BOOL alert) + // Reloads document with the given BufferID + // wParam[in]: BufferID of document to reload + // lParam[in]: set TRUE to let user confirm or reject the reload; setting FALSE will reload with no alert. + // Returns TRUE on success, FALSE otherwise #define NPPM_GETBUFFERLANGTYPE (NPPMSG + 64) - // INT NPPM_GETBUFFERLANGTYPE(UINT_PTR bufferID, 0) - // wParam: BufferID to get LangType from - // lParam: 0 + // int NPPM_GETBUFFERLANGTYPE(UINT_PTR bufferID, 0) + // Retrieves the language type of the document with the given bufferID. + // wParam[in]: BufferID of document to get LangType from + // lParam: 0 (not used) // Returns as int, see LangType. -1 on error #define NPPM_SETBUFFERLANGTYPE (NPPMSG + 65) - // BOOL NPPM_SETBUFFERLANGTYPE(UINT_PTR bufferID, INT langType) - // wParam: BufferID to set LangType of - // lParam: LangType + // BOOL NPPM_SETBUFFERLANGTYPE(UINT_PTR bufferID, int langType) + // Set the language type of the document based on the given bufferID. + // wParam[in]: BufferID to set LangType of + // lParam[in]: langType as int, enum LangType for valid values (L_USER and L_EXTERNAL are not supported) // Returns TRUE on success, FALSE otherwise - // use int, see LangType for possible values - // L_USER and L_EXTERNAL are not supported #define NPPM_GETBUFFERENCODING (NPPMSG + 66) - // INT NPPM_GETBUFFERENCODING(UINT_PTR bufferID, 0) - // wParam: BufferID to get encoding from - // lParam: 0 - // returns as int, see UniMode. -1 on error + // int NPPM_GETBUFFERENCODING(UINT_PTR bufferID, 0) + // Get encoding from the document with the given bufferID + // wParam[in]: BufferID to get encoding from + // lParam: 0 (not used) + // returns -1 on error, otherwise UniMode, with the following value: + // 0: ANSI + // 1: UTF-8 with BOM + // 2: UTF-16 Big Ending with BOM + // 3: UTF-16 Little Ending with BOM + // 4: UTF-8 without BOM + // 5: uni7Bit + // 6: UTF-16 Big Ending without BOM + // 7: UTF-16 Little Ending without BOM #define NPPM_SETBUFFERENCODING (NPPMSG + 67) - // BOOL NPPM_SETBUFFERENCODING(UINT_PTR bufferID, INT encoding) + // BOOL NPPM_SETBUFFERENCODING(UINT_PTR bufferID, int encoding) + // Set encoding to the document with the given bufferID // wParam: BufferID to set encoding of - // lParam: encoding + // lParam: encoding, see UniMode value in NPPM_GETBUFFERENCODING (above) // Returns TRUE on success, FALSE otherwise - // use int, see UniMode // Can only be done on new, unedited files #define NPPM_GETBUFFERFORMAT (NPPMSG + 68) - // INT NPPM_GETBUFFERFORMAT(UINT_PTR bufferID, 0) - // wParam: BufferID to get EolType format from - // lParam: 0 - // returns as int, see EolType format. -1 on error + // int NPPM_GETBUFFERFORMAT(UINT_PTR bufferID, 0) + // Get the EOL format of the document with given bufferID. + // wParam[in]: BufferID to get EolType format from + // lParam: 0 (not used) + // Returned value is -1 on error, otherwise EolType format: + // 0: Windows (CRLF) + // 1: Macos (CR) + // 2: Unix (LF) + // 3. Unknown #define NPPM_SETBUFFERFORMAT (NPPMSG + 69) - // BOOL NPPM_SETBUFFERFORMAT(UINT_PTR bufferID, INT format) - // wParam: BufferID to set EolType format of - // lParam: format + // BOOL NPPM_SETBUFFERFORMAT(UINT_PTR bufferID, int format) + // Set the EOL format to the document with given bufferID. + // wParam[in]: BufferID to set EolType format of + // lParam[in]: EolType format. For EolType format value, see NPPM_GETBUFFERFORMAT (above) // Returns TRUE on success, FALSE otherwise - // use int, see EolType format - #define NPPM_HIDETOOLBAR (NPPMSG + 70) // BOOL NPPM_HIDETOOLBAR(0, BOOL hideOrNot) - // if hideOrNot is set as TRUE then tool bar will be hidden - // otherwise it'll be shown. - // return value : the old status value + // Hide (or show) the toolbar. + // wParam: 0 (not used) + // lParam[in]: if hideOrNot is set as TRUE then tool bar will be hidden, otherwise it'll be shown. + // return value: the old status value #define NPPM_ISTOOLBARHIDDEN (NPPMSG + 71) // BOOL NPPM_ISTOOLBARHIDDEN(0, 0) - // returned value : TRUE if tool bar is hidden, otherwise FALSE + // Get toolbar status. + // wParam: 0 (not used) + // lParam: 0 (not used) + // return value: TRUE if tool bar is hidden, otherwise FALSE #define NPPM_HIDEMENU (NPPMSG + 72) // BOOL NPPM_HIDEMENU(0, BOOL hideOrNot) - // if hideOrNot is set as TRUE then menu will be hidden - // otherwise it'll be shown. - // return value : the old status value + // Hide (or show) menu bar. + // wParam: 0 (not used) + // lParam[in]: if hideOrNot is set as TRUE then menu will be hidden, otherwise it'll be shown. + // return value: the old status value #define NPPM_ISMENUHIDDEN (NPPMSG + 73) // BOOL NPPM_ISMENUHIDDEN(0, 0) - // returned value : TRUE if menu is hidden, otherwise FALSE + // Get menu bar status. + // wParam: 0 (not used) + // lParam: 0 (not used) + // return value: TRUE if menu bar is hidden, otherwise FALSE #define NPPM_HIDESTATUSBAR (NPPMSG + 74) // BOOL NPPM_HIDESTATUSBAR(0, BOOL hideOrNot) - // if hideOrNot is set as TRUE then STATUSBAR will be hidden - // otherwise it'll be shown. - // return value : the old status value + // Hide (or show) status bar. + // wParam: 0 (not used) + // lParam[in]: if hideOrNot is set as TRUE then status bar will be hidden, otherwise it'll be shown. + // return value: the old status value #define NPPM_ISSTATUSBARHIDDEN (NPPMSG + 75) // BOOL NPPM_ISSTATUSBARHIDDEN(0, 0) - // returned value : TRUE if STATUSBAR is hidden, otherwise FALSE + // Get status bar status. + // wParam: 0 (not used) + // lParam: 0 (not used) + // return value: TRUE if status bar is hidden, otherwise FALSE #define NPPM_GETSHORTCUTBYCMDID (NPPMSG + 76) - // BOOL NPPM_GETSHORTCUTBYCMDID(int cmdID, ShortcutKey *sk) - // get your plugin command current mapped shortcut into sk via cmdID - // You may need it after getting NPPN_READY notification - // returned value : TRUE if this function call is successful and shortcut is enable, otherwise FALSE + // BOOL NPPM_GETSHORTCUTBYCMDID(int cmdID, ShortcutKey* sk) + // Get your plugin command current mapped shortcut into sk via cmdID. + // wParam[in]: cmdID is your plugin command ID + // lParam[out]: sk is a pointer of ShortcutKey strcture which will receive the requested CMD shortcut. It should be allocated in the plugin before being used. + // For ShortcutKey strcture, see in "PluginInterface.h". You may need it after getting NPPN_READY notification. + // return value: TRUE if this function call is successful and shortcut is enable, otherwise FALSE #define NPPM_DOOPEN (NPPMSG + 77) - // BOOL NPPM_DOOPEN(0, const TCHAR *fullPathName2Open) - // fullPathName2Open indicates the full file path name to be opened. - // The return value is TRUE (1) if the operation is successful, otherwise FALSE (0). + // BOOL NPPM_DOOPEN(0, const wchar_t* fullPathName2Open) + // Open a file with given fullPathName2Open. + // If fullPathName2Open has been already opened in Notepad++, the it will be activated and becomes the current document. + // wParam: 0 (not used) + // lParam[in]: fullPathName2Open indicates the full file path name to be opened + // The return value is TRUE if the operation is successful, otherwise FALSE #define NPPM_SAVECURRENTFILEAS (NPPMSG + 78) - // BOOL NPPM_SAVECURRENTFILEAS (BOOL asCopy, const TCHAR* filename) + // BOOL NPPM_SAVECURRENTFILEAS (BOOL saveAsCopy, const wchar_t* filename) + // Save the current activated document. + // wParam[in]: saveAsCopy must be either FALSE to save, or TRUE to save a copy of the current filename ("Save a Copy As..." action) + // lParam[in]: filename indicates the full file path name to be saved + // The return value is TRUE if the operation is successful, otherwise FALSE #define NPPM_GETCURRENTNATIVELANGENCODING (NPPMSG + 79) - // INT NPPM_GETCURRENTNATIVELANGENCODING(0, 0) - // returned value : the current native language encoding + // int NPPM_GETCURRENTNATIVELANGENCODING(0, 0) + // Get the code page associated with the current localisation of Notepad++. + // wParam: 0 (not used) + // lParam: 0 (not used) + // return value: the current native language encoding + + #define NPPM_ALLOCATESUPPORTED_DEPRECATED (NPPMSG + 80) + // DEPRECATED: the message has been made (since 2010 AD) for checking if NPPM_ALLOCATECMDID is supported. This message is no more needed. + // BOOL NPPM_ALLOCATESUPPORTED_DEPRECATED(0, 0) + // Get NPPM_ALLOCATECMDID supported status. Use to identify if subclassing is necessary + // wParam: 0 (not used) + // lParam: 0 (not used) + // returns TRUE if NPPM_ALLOCATECMDID is supported - #define NPPM_ALLOCATESUPPORTED (NPPMSG + 80) - // returns TRUE if NPPM_ALLOCATECMDID is supported - // Use to identify if subclassing is necessary #define NPPM_ALLOCATECMDID (NPPMSG + 81) - // BOOL NPPM_ALLOCATECMDID(int numberRequested, int* startNumber) - // sets startNumber to the initial command ID if successful - // Returns: TRUE if successful, FALSE otherwise. startNumber will also be set to 0 if unsuccessful + // BOOL NPPM_ALLOCATECMDID(int numberRequested, int* startNumber) + // Obtain a number of consecutive menu item IDs for creating menus dynamically, with the guarantee of these IDs not clashing with any other plugins. + // wParam[in]: numberRequested is the number of ID you request for the reservation + // lParam[out]: startNumber will be set to the initial command ID if successful + // Returns: TRUE if successful, FALSE otherwise. startNumber will also be set to 0 if unsuccessful + // + // Example: If a plugin needs 4 menu item ID, the following code can be used: + // + // int idBegin; + // BOOL isAllocatedSuccessful = ::SendMessage(nppData._nppHandle, NPPM_ALLOCATECMDID, 4, &idBegin); + // + // if isAllocatedSuccessful is TRUE, and value of idBegin is 46581 + // then menu item ID 46581, 46582, 46583 and 46584 are preserved by Notepad++, and they are safe to be used by the plugin. #define NPPM_ALLOCATEMARKER (NPPMSG + 82) // BOOL NPPM_ALLOCATEMARKER(int numberRequested, int* startNumber) - // sets startNumber to the initial command ID if successful - // Allocates a marker number to a plugin - // Returns: TRUE if successful, FALSE otherwise. startNumber will also be set to 0 if unsuccessful + // Allocate a number of consecutive marker IDs to a plugin: if a plugin need to add a marker on Notepad++'s Scintilla marker margin, + // it has to use this message to get marker number, in order to prevent from the conflict with the other plugins. + // wParam[in]: numberRequested is the number of ID you request for the reservation + // lParam[out]: startNumber will be set to the initial command ID if successful + // Return TRUE if successful, FALSE otherwise. startNumber will also be set to 0 if unsuccessful + // + // Example: If a plugin needs 3 marker ID, the following code can be used: + // + // int idBegin; + // BOOL isAllocatedSuccessful = ::SendMessage(nppData._nppHandle, NPPM_ALLOCATEMARKER, 3, &idBegin); + // + // if isAllocatedSuccessful is TRUE, and value of idBegin is 16 + // then marker ID 16, 17 and 18 are preserved by Notepad++, and they are safe to be used by the plugin. #define NPPM_GETLANGUAGENAME (NPPMSG + 83) - // INT NPPM_GETLANGUAGENAME(int langType, TCHAR *langName) - // Get programming language name from the given language type (LangType) + // int NPPM_GETLANGUAGENAME(LangType langType, wchar_t* langName) + // Get programming language name from the given language type (enum LangType). + // wParam[in]: langType is the number of LangType + // lParam[out]: langName is the buffer to receive the language name string // Return value is the number of copied character / number of character to copy (\0 is not included) + // // You should call this function 2 times - the first time you pass langName as NULL to get the number of characters to copy. // You allocate a buffer of the length of (the number of characters + 1) then call NPPM_GETLANGUAGENAME function the 2nd time // by passing allocated buffer as argument langName #define NPPM_GETLANGUAGEDESC (NPPMSG + 84) - // INT NPPM_GETLANGUAGEDESC(int langType, TCHAR *langDesc) - // Get programming language short description from the given language type (LangType) + // INT NPPM_GETLANGUAGEDESC(int langType, wchar_t *langDesc) + // Get programming language short description from the given language type (enum LangType) + // wParam[in]: langType is the number of LangType + // lParam[out]: langDesc is the buffer to receive the language description string // Return value is the number of copied character / number of character to copy (\0 is not included) + // // You should call this function 2 times - the first time you pass langDesc as NULL to get the number of characters to copy. // You allocate a buffer of the length of (the number of characters + 1) then call NPPM_GETLANGUAGEDESC function the 2nd time // by passing allocated buffer as argument langDesc - #define NPPM_SHOWDOCSWITCHER (NPPMSG + 85) - // VOID NPPM_SHOWDOCSWITCHER(0, BOOL toShowOrNot) - // Send this message to show or hide doc switcher. - // if toShowOrNot is TRUE then show doc switcher, otherwise hide it. + #define NPPM_SHOWDOCLIST (NPPMSG + 85) + // BOOL NPPM_SHOWDOCLIST(0, BOOL toShowOrNot) + // Show or hide the Document List panel. + // wParam: 0 (not used) + // lParam[in]: toShowOrNot - if toShowOrNot is TRUE, the Document List panel is shown otherwise it is hidden. + // Return TRUE - #define NPPM_ISDOCSWITCHERSHOWN (NPPMSG + 86) - // BOOL NPPM_ISDOCSWITCHERSHOWN(0, 0) - // Check to see if doc switcher is shown. + #define NPPM_ISDOCLISTSHOWN (NPPMSG + 86) + // BOOL NPPM_ISDOCLISTSHOWN(0, 0) + // Checks the visibility of the Document List panel. + // wParam: 0 (not used) + // lParam: 0 (not used) + // return value: TRUE if the Document List panel is currently shown, FALSE otherwise #define NPPM_GETAPPDATAPLUGINSALLOWED (NPPMSG + 87) // BOOL NPPM_GETAPPDATAPLUGINSALLOWED(0, 0) // Check to see if loading plugins from "%APPDATA%\..\Local\Notepad++\plugins" is allowed. + // wParam: 0 (not used) + // lParam: 0 (not used) + // return value: TRUE if loading plugins from %APPDATA% is allowed, FALSE otherwise #define NPPM_GETCURRENTVIEW (NPPMSG + 88) - // INT NPPM_GETCURRENTVIEW(0, 0) + // int NPPM_GETCURRENTVIEW(0, 0) + // Get the current used view. + // wParam: 0 (not used) + // lParam: 0 (not used) // Return: current edit view of Notepad++. Only 2 possible values: 0 = Main, 1 = Secondary - #define NPPM_DOCSWITCHERDISABLECOLUMN (NPPMSG + 89) - // VOID NPPM_DOCSWITCHERDISABLECOLUMN(0, BOOL disableOrNot) - // Disable or enable extension column of doc switcher + #define NPPM_DOCLISTDISABLEEXTCOLUMN (NPPMSG + 89) + // BOOL NPPM_DOCLISTDISABLEEXTCOLUMN(0, BOOL disableOrNot) + // Disable or enable extension column of Document List + // wParam: 0 (not used) + // lParam[in]: disableOrNot - if disableOrNot is TRUE, extension column is hidden otherwise it is visible. + // Return TRUE + + #define NPPM_DOCLISTDISABLEPATHCOLUMN (NPPMSG + 102) + // BOOL NPPM_DOCLISTDISABLEPATHCOLUMN(0, BOOL disableOrNot) + // Disable or enable path column of Document List + // wParam: 0 (not used) + // lParam[in]: disableOrNot - if disableOrNot is TRUE, extension column is hidden otherwise it is visible. + // Return TRUE #define NPPM_GETEDITORDEFAULTFOREGROUNDCOLOR (NPPMSG + 90) - // INT NPPM_GETEDITORDEFAULTFOREGROUNDCOLOR(0, 0) - // Return: current editor default foreground color. You should convert the returned value in COLORREF + // int NPPM_GETEDITORDEFAULTFOREGROUNDCOLOR(0, 0) + // Get the current editor default foreground color. + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return: the color as integer with hex format being 0x00bbggrr #define NPPM_GETEDITORDEFAULTBACKGROUNDCOLOR (NPPMSG + 91) - // INT NPPM_GETEDITORDEFAULTBACKGROUNDCOLOR(0, 0) - // Return: current editor default background color. You should convert the returned value in COLORREF + // int NPPM_GETEDITORDEFAULTBACKGROUNDCOLOR(0, 0) + // Get the current editor default background color. + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return: the color as integer with hex format being 0x00bbggrr #define NPPM_SETSMOOTHFONT (NPPMSG + 92) - // VOID NPPM_SETSMOOTHFONT(0, BOOL setSmoothFontOrNot) + // BOOL NPPM_SETSMOOTHFONT(0, BOOL setSmoothFontOrNot) + // Set (or remove) smooth font. The API uses underlying Scintilla command SCI_SETFONTQUALITY to manage the font quality. + // wParam: 0 (not used) + // lParam[in]: setSmoothFontOrNot - if value is TRUE, this message sets SC_EFF_QUALITY_LCD_OPTIMIZED else SC_EFF_QUALITY_DEFAULT + // Return TRUE #define NPPM_SETEDITORBORDEREDGE (NPPMSG + 93) - // VOID NPPM_SETEDITORBORDEREDGE(0, BOOL withEditorBorderEdgeOrNot) + // BOOL NPPM_SETEDITORBORDEREDGE(0, BOOL withEditorBorderEdgeOrNot) + // Add (or remove) an additional sunken edge style to the Scintilla window else it removes the extended style from the window. + // wParam: 0 (not used) + // lParam[in]: withEditorBorderEdgeOrNot - TRUE for adding border edge on Scintilla window, FALSE for removing it + // Return TRUE #define NPPM_SAVEFILE (NPPMSG + 94) - // VOID NPPM_SAVEFILE(0, const TCHAR *fileNameToSave) + // BOOL NPPM_SAVEFILE(0, const wchar_t *fileNameToSave) + // Save the file (opened in Notepad++) with the given full file name path. + // wParam: 0 (not used) + // lParam[in]: fileNameToSave must be the full file path for the file to be saved. + // Return TRUE on success, FALSE on fileNameToSave is not found #define NPPM_DISABLEAUTOUPDATE (NPPMSG + 95) // 2119 in decimal - // VOID NPPM_DISABLEAUTOUPDATE(0, 0) + // BOOL NPPM_DISABLEAUTOUPDATE(0, 0) + // Disable Notepad++ auto-update. + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return TRUE #define NPPM_REMOVESHORTCUTBYCMDID (NPPMSG + 96) // 2120 in decimal - // BOOL NPPM_REMOVESHORTCUTASSIGNMENT(int cmdID) - // removes the assigned shortcut mapped to cmdID - // returned value : TRUE if function call is successful, otherwise FALSE + // BOOL NPPM_REMOVESHORTCUTBYCMDID(int pluginCmdID, 0) + // Remove the assigned shortcut mapped to pluginCmdID + // wParam[in]: pluginCmdID + // lParam: 0 (not used) + // return value: TRUE if function call is successful, otherwise FALSE #define NPPM_GETPLUGINHOMEPATH (NPPMSG + 97) - // INT NPPM_GETPLUGINHOMEPATH(size_t strLen, TCHAR *pluginRootPath) - // Get plugin home root path. It's useful if plugins want to get its own path - // by appending which is the name of plugin without extension part. - // Returns the number of TCHAR copied/to copy. - // Users should call it with pluginRootPath be NULL to get the required number of TCHAR (not including the terminating nul character), - // allocate pluginRootPath buffer with the return value + 1, then call it again to get the path. + // int NPPM_GETPLUGINHOMEPATH(size_t strLen, wchar_t* pluginRootPath) + // Get plugin home root path. It's useful if plugins want to get its own path by appending which is the name of plugin without extension part. + // wParam[in]: strLen - size of allocated buffer "pluginRootPath" + // lParam[out]: pluginRootPath - Users should call it with pluginRootPath be NULL to get the required number of wchar_t (not including the terminating nul character), + // allocate pluginRootPath buffer with the return value + 1, then call it again to get the path. + // Return the number of wchar_t copied/to copy, 0 on copy failed #define NPPM_GETSETTINGSONCLOUDPATH (NPPMSG + 98) - // INT NPPM_GETSETTINGSCLOUDPATH(size_t strLen, TCHAR *settingsOnCloudPath) + // int NPPM_GETSETTINGSCLOUDPATH(size_t strLen, wchar_t *settingsOnCloudPath) // Get settings on cloud path. It's useful if plugins want to store its settings on Cloud, if this path is set. - // Returns the number of TCHAR copied/to copy. If the return value is 0, then this path is not set, or the "strLen" is not enough to copy the path. - // Users should call it with settingsCloudPath be NULL to get the required number of TCHAR (not including the terminating nul character), - // allocate settingsCloudPath buffer with the return value + 1, then call it again to get the path. + // wParam[in]: strLen - size of allocated buffer "settingsOnCloudPath" + // lParam[out]: settingsOnCloudPath - Users should call it with settingsOnCloudPath be NULL to get the required number of wchar_t (not including the terminating nul character), + // allocate settingsOnCloudPath buffer with the return value + 1, then call it again to get the path. + // Returns the number of wchar_t copied/to copy. If the return value is 0, then this path is not set, or the "strLen" is not enough to copy the path. #define NPPM_SETLINENUMBERWIDTHMODE (NPPMSG + 99) #define LINENUMWIDTH_DYNAMIC 0 #define LINENUMWIDTH_CONSTANT 1 - // BOOL NPPM_SETLINENUMBERWIDTHMODE(0, INT widthMode) + // BOOL NPPM_SETLINENUMBERWIDTHMODE(0, int widthMode) // Set line number margin width in dynamic width mode (LINENUMWIDTH_DYNAMIC) or constant width mode (LINENUMWIDTH_CONSTANT) // It may help some plugins to disable non-dynamic line number margins width to have a smoothly visual effect while vertical scrolling the content in Notepad++ - // If calling is successful return TRUE, otherwise return FALSE. + // wParam: 0 (not used) + // lParam[in]: widthMode should be LINENUMWIDTH_DYNAMIC or LINENUMWIDTH_CONSTANT + // return TRUE if calling is successful, otherwise return FALSE #define NPPM_GETLINENUMBERWIDTHMODE (NPPMSG + 100) - // INT NPPM_GETLINENUMBERWIDTHMODE(0, 0) + // int NPPM_GETLINENUMBERWIDTHMODE(0, 0) // Get line number margin width in dynamic width mode (LINENUMWIDTH_DYNAMIC) or constant width mode (LINENUMWIDTH_CONSTANT) + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return current line number margin width mode (LINENUMWIDTH_DYNAMIC or LINENUMWIDTH_CONSTANT) #define NPPM_ADDTOOLBARICON_FORDARKMODE (NPPMSG + 101) - // VOID NPPM_ADDTOOLBARICON_FORDARKMODE(UINT funcItem[X]._cmdID, toolbarIconsWithDarkMode iconHandles) - // Use NPPM_ADDTOOLBARICON_FORDARKMODE instead obsolete NPPM_ADDTOOLBARICON which doesn't support the dark mode - // 2 formats / 3 icons are needed: 1 * BMP + 2 * ICO - // All 3 handles below should be set so the icon will be displayed correctly if toolbar icon sets are changed by users, also in dark mode struct toolbarIconsWithDarkMode { HBITMAP hToolbarBmp; HICON hToolbarIcon; HICON hToolbarIconDarkMode; }; + // BOOL NPPM_ADDTOOLBARICON_FORDARKMODE(UINT pluginCmdID, toolbarIconsWithDarkMode* iconHandles) + // Use NPPM_ADDTOOLBARICON_FORDARKMODE instead obsolete NPPM_ADDTOOLBARICON (DEPRECATED) which doesn't support the dark mode + // wParam[in]: pluginCmdID + // lParam[in]: iconHandles is the pointer of toolbarIconsWithDarkMode structure + // All 3 handles below should be set so the icon will be displayed correctly if toolbar icon sets are changed by users, also in dark mode + // Return TRUE + + #define NPPM_GETEXTERNALLEXERAUTOINDENTMODE (NPPMSG + 103) + // BOOL NPPM_GETEXTERNALLEXERAUTOINDENTMODE(const wchar_t* languageName, ExternalLexerAutoIndentMode* autoIndentMode) + // Get ExternalLexerAutoIndentMode for an installed external programming language. + // wParam[in]: languageName is external language name to search + // lParam[out]: autoIndentMode could receive one of three following values + // - Standard (0) means Notepad++ will keep the same TAB indentation between lines; + // - C_Like (1) means Notepad++ will perform a C-Language style indentation for the selected external language; + // - Custom (2) means a Plugin will be controlling auto-indentation for the current language. + // returned values: TRUE for successful searches, otherwise FALSE. + + #define NPPM_SETEXTERNALLEXERAUTOINDENTMODE (NPPMSG + 104) + // BOOL NPPM_SETEXTERNALLEXERAUTOINDENTMODE(const wchar_t* languageName, ExternalLexerAutoIndentMode autoIndentMode) + // Set ExternalLexerAutoIndentMode for an installed external programming language. + // wParam[in]: languageName is external language name to set + // lParam[in]: autoIndentMode could receive one of three following values + // - Standard (0) means Notepad++ will keep the same TAB indentation between lines; + // - C_Like (1) means Notepad++ will perform a C-Language style indentation for the selected external language; + // - Custom (2) means a Plugin will be controlling auto-indentation for the current language. + // return value: TRUE if function call was successful, otherwise FALSE. + + #define NPPM_ISAUTOINDENTON (NPPMSG + 105) + // BOOL NPPM_ISAUTOINDENTON(0, 0) + // Get the current use Auto-Indentation setting in Notepad++ Preferences. + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return TRUE if Auto-Indentation is on, FALSE otherwise + + #define NPPM_GETCURRENTMACROSTATUS (NPPMSG + 106) + // MacroStatus NPPM_GETCURRENTMACROSTATUS(0, 0) + // Get current enum class MacroStatus { Idle, RecordInProgress, RecordingStopped, PlayingBack } + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return MacroStatus as int: + // 0: Idle - macro is not in use and it's empty + // 1: RecordInProgress - macro is currently being recorded + // 2: RecordingStopped - macro recording has been stopped + // 3: PlayingBack - macro is currently being played back + + #define NPPM_ISDARKMODEENABLED (NPPMSG + 107) + // BOOL NPPM_ISDARKMODEENABLED(0, 0) + // Get Notepad++ Dark Mode status (ON or OFF). + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return TRUE if Dark Mode is enable, otherwise FALSE + + #define NPPM_GETDARKMODECOLORS (NPPMSG + 108) + // BOOL NPPM_GETDARKMODECOLORS (size_t cbSize, NppDarkMode::Colors* returnColors) + // Get the colors used in Dark Mode. + // wParam[in]: cbSize must be filled with sizeof(NppDarkMode::Colors). + // lParam[out]: returnColors must be a pre-allocated NppDarkMode::Colors struct. + // Return TRUE when successful, FALSE otherwise. + // You need to uncomment the following code to use NppDarkMode::Colors structure: + // + // namespace NppDarkMode + // { + // struct Colors + // { + // COLORREF background = 0; + // COLORREF softerBackground = 0; + // COLORREF hotBackground = 0; + // COLORREF pureBackground = 0; + // COLORREF errorBackground = 0; + // COLORREF text = 0; + // COLORREF darkerText = 0; + // COLORREF disabledText = 0; + // COLORREF linkText = 0; + // COLORREF edge = 0; + // COLORREF hotEdge = 0; + // COLORREF disabledEdge = 0; + // }; + // } + // + // Note: in the case of calling failure ("false" is returned), you may need to change NppDarkMode::Colors structure to: + // https://github.com/notepad-plus-plus/notepad-plus-plus/blob/master/PowerEditor/src/NppDarkMode.h#L32 + + #define NPPM_GETCURRENTCMDLINE (NPPMSG + 109) + // int NPPM_GETCURRENTCMDLINE(size_t strLen, wchar_t *commandLineStr) + // Get the Current Command Line string. + // Users should call it with commandLineStr as NULL to get the required number of wchar_t (not including the terminating nul character), + // allocate commandLineStr buffer with the return value + 1, then call it again to get the current command line string. + // wParam[in]: strLen is "commandLineStr" buffer length + // lParam[out]: commandLineStr receives all copied command line string + // Return the number of wchar_t copied/to copy + + + #define NPPM_CREATELEXER (NPPMSG + 110) + // void* NPPM_CREATELEXER(0, const wchar_t* lexer_name) + // Get the ILexer pointer created by Lexilla. Call the lexilla "CreateLexer()" function to allow plugins to set the lexer for a Scintilla instance created by NPPM_CREATESCINTILLAHANDLE. + // wParam: 0 (not used) + // lParam[in]: lexer_name is the name of the lexer + // Return the ILexer pointer + + #define NPPM_GETBOOKMARKID (NPPMSG + 111) + // int NPPM_GETBOOKMARKID(0, 0) + // Get the bookmark ID - use this API to get bookmark ID dynamically that guarantees you get always the right bookmark ID even it's been changed through the different versions. + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return bookmark ID + + #define NPPM_DARKMODESUBCLASSANDTHEME (NPPMSG + 112) + namespace NppDarkMode + { + // Standard flags for main parent after its children are initialized. + constexpr ULONG dmfInit = 0x0000000BUL; + + // Standard flags for main parent usually used in NPPN_DARKMODECHANGED. + constexpr ULONG dmfHandleChange = 0x0000000CUL; + }; + + // ULONG NPPM_DARKMODESUBCLASSANDTHEME(ULONG dmFlags, HWND hwnd) + // Add support for generic dark mode to plugin dialog. Subclassing is applied automatically unless DWS_USEOWNDARKMODE flag is used. + // Might not work properly in C# plugins. + // wParam[in]: dmFlags has 2 possible value dmfInit (0x0000000BUL) & dmfHandleChange (0x0000000CUL) - see above definition + // lParam[in]: hwnd is the dialog handle of plugin - Docking panels don't need to call NPPM_DARKMODESUBCLASSANDTHEME + // Returns successful combinations of flags. + + // Examples: + // + // - after controls initializations in WM_INITDIALOG, in WM_CREATE or after CreateWindow: + // + //auto success = static_cast(::SendMessage(nppData._nppHandle, NPPM_DARKMODESUBCLASSANDTHEME, static_cast(NppDarkMode::dmfInit), reinterpret_cast(mainHwnd))); + // + // - handling dark mode change: + // + //extern "C" __declspec(dllexport) void beNotified(SCNotification * notifyCode) + //{ + // switch (notifyCode->nmhdr.code) + // { + // case NPPN_DARKMODECHANGED: + // { + // ::SendMessage(nppData._nppHandle, NPPM_DARKMODESUBCLASSANDTHEME, static_cast(dmfHandleChange), reinterpret_cast(mainHwnd)); + // ::SetWindowPos(mainHwnd, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); // to redraw titlebar and window + // break; + // } + // } + //} + + #define NPPM_ALLOCATEINDICATOR (NPPMSG + 113) + // BOOL NPPM_ALLOCATEINDICATOR(int numberRequested, int* startNumber) + // Allocates an indicator number to a plugin: if a plugin needs to add an indicator, + // it has to use this message to get the indicator number, in order to prevent a conflict with the other plugins. + // wParam[in]: numberRequested is the number of ID you request for the reservation + // lParam[out]: startNumber will be set to the initial command ID if successful + // Return TRUE if successful, FALSE otherwise. startNumber will also be set to 0 if unsuccessful + // + // Example: If a plugin needs 1 indicator ID, the following code can be used : + // + // int idBegin; + // BOOL isAllocatedSuccessful = ::SendMessage(nppData._nppHandle, NPPM_ALLOCATEINDICATOR, 1, &idBegin); + // + // if isAllocatedSuccessful is TRUE, and value of idBegin is 7 + // then indicator ID 7 is preserved by Notepad++, and it is safe to be used by the plugin. + + #define NPPM_GETTABCOLORID (NPPMSG + 114) + // int NPPM_GETTABCOLORID(int view, int tabIndex) + // Get the tab color ID with given tab index and view. + // wParam[in]: view - main view (0) or sub-view (1) or -1 (active view) + // lParam[in]: tabIndex - index (in the view indicated above). -1 for currently active tab + // Return tab color ID which contains the following values: 0 (yellow), 1 (green), 2 (blue), 3 (orange), 4 (pink) or -1 (no color) + // + // Note: there's no symmetric command NPPM_SETTABCOLORID. Plugins can use NPPM_MENUCOMMAND to set current tab color with the desired tab color ID. + + #define NPPM_SETUNTITLEDNAME (NPPMSG + 115) + // BOOL NPPM_SETUNTITLEDNAME(BufferID id, const wchar_t* newName) + // Rename the tab name for an untitled tab. + // wParam[in]: id - BufferID of the tab. -1 for currently active tab + // lParam[in]: newName - the desired new name of the tab + // Return TRUE upon success; FALSE upon failure + + #define NPPM_GETNATIVELANGFILENAME (NPPMSG + 116) + // int NPPM_GETNATIVELANGFILENAME(size_t strLen, char* nativeLangFileName) + // Get the Current native language file name string. Use it after getting NPPN_READY notification to find out which native language is used. + // Users should call it with nativeLangFileName as NULL to get the required number of char (not including the terminating nul character), + // allocate language file name string buffer with the return value + 1, then call it again to get the current native language file name string. + // If there's no localization file applied, the returned value is 0. + // wParam[in]: strLen is "language file name string" buffer length + // lParam[out]: language file name string receives all copied native language file name string + // Return the number of char copied/to copy + + #define NPPM_ADDSCNMODIFIEDFLAGS (NPPMSG + 117) + // BOOL NPPM_ADDSCNMODIFIEDFLAGS(0, unsigned long scnModifiedFlags2Add) + // Add the necessary SCN_MODIFIED flags so that your plugin will receive the SCN_MODIFIED notification for these events, enabling your specific treatments. + // By default, Notepad++ only forwards SCN_MODIFIED with the following 5 flags/events: + // SC_MOD_DELETETEXT | SC_MOD_INSERTTEXT | SC_PERFORMED_UNDO | SC_PERFORMED_REDO | SC_MOD_CHANGEINDICATOR to plugins. + // If your plugin needs to process other SCN_MODIFIED events, you should add the required flags by sending this message to Notepad++. You can send it immediately after receiving NPPN_READY, + // or only when your plugin needs to listen to specific events (to avoid penalizing Notepad++'s performance). Just ensure that the message is sent only once. + // wParam: 0 (not used) + // lParam[in]: scnModifiedFlags2Add - Scintilla SCN_MODIFIED flags to add. + // Return TRUE + // + // Example: + // + // extern "C" __declspec(dllexport) void beNotified(SCNotification* notifyCode) + // { + // switch (notifyCode->nmhdr.code) + // { + // case NPPN_READY: + // { + // // Add SC_MOD_BEFOREDELETE and SC_MOD_BEFOREINSERT to listen to the 2 events of SCN_MODIFIED + // ::SendMessage(nppData._nppHandle, NPPM_ADDSCNMODIFIEDFLAGS, 0, SC_MOD_BEFOREDELETE | SC_MOD_BEFOREINSERT); + // } + // break; + // ... + // } + // ... + // } + + #define NPPM_GETTOOLBARICONSETCHOICE (NPPMSG + 118) + // BOOL NPPM_GETTOOLBARICONSETCHOICE(0, 0) + // Get Notepad++ toolbar icon set choice (Fluent UI: small, Fluent UI: large, Filled Fluent UI: small, Filled Fluent UI: large and Standard icons: small. + // wParam: 0 (not used) + // lParam: 0 (not used) + // Return toolbar icon set choice as an integer value. Here are 5 possible values: + // 0 (Fluent UI: small), 1 (Fluent UI: large), 2 (Filled Fluent UI: small), 3 (Filled Fluent UI: large) and 4 (Standard icons: small). + + #define NPPM_GETNPPSETTINGSDIRPATH (NPPMSG + 119) + // int NPPM_GETNPPSETTINGSDIRPATH(size_t strLen, wchar_t *settingsDirPath) + // Get path for the active Notepad++ settings: it will use -settingsDir path if that's defined; if not, it will use Cloud directory if that's defined; + // if not, it will use the AppData settings directory, or finally the installation path. This allows plugins to have one interface to find out + // where the active Notepad++ settings are stored, whichever location they are currently set to. + // wParam[in]: strLen - size of allocated buffer "settingsDirPath" + // lParam[out]: settingsDirPath - Users should call it with settingsDirPath be NULL to get the required number of wchar_t (not including the terminating nul character), + // allocate settingsDirPath buffer with the return value + 1, then call it again to get the path. + // Returns the number of wchar_t copied/to copy. If the return value is 0, then the "strLen" is not enough to copy the path, or the settings path could not be determined. + // + // Note: This message is for the active Notepad++ configuration location. If you are looking for the settings directory for plugins (...\Plugins\Config\), + // use NPPM_GETPLUGINSCONFIGDIR instead. + +// For RUNCOMMAND_USER + #define VAR_NOT_RECOGNIZED 0 + #define FULL_CURRENT_PATH 1 + #define CURRENT_DIRECTORY 2 + #define FILE_NAME 3 + #define NAME_PART 4 + #define EXT_PART 5 + #define CURRENT_WORD 6 + #define NPP_DIRECTORY 7 + #define CURRENT_LINE 8 + #define CURRENT_COLUMN 9 + #define NPP_FULL_FILE_PATH 10 + #define GETFILENAMEATCURSOR 11 + #define CURRENT_LINESTR 12 + + #define RUNCOMMAND_USER (WM_USER + 3000) -#define VAR_NOT_RECOGNIZED 0 -#define FULL_CURRENT_PATH 1 -#define CURRENT_DIRECTORY 2 -#define FILE_NAME 3 -#define NAME_PART 4 -#define EXT_PART 5 -#define CURRENT_WORD 6 -#define NPP_DIRECTORY 7 -#define CURRENT_LINE 8 -#define CURRENT_COLUMN 9 -#define NPP_FULL_FILE_PATH 10 -#define GETFILENAMEATCURSOR 11 - -#define RUNCOMMAND_USER (WM_USER + 3000) #define NPPM_GETFULLCURRENTPATH (RUNCOMMAND_USER + FULL_CURRENT_PATH) #define NPPM_GETCURRENTDIRECTORY (RUNCOMMAND_USER + CURRENT_DIRECTORY) #define NPPM_GETFILENAME (RUNCOMMAND_USER + FILE_NAME) @@ -470,27 +1062,35 @@ enum Platform { PF_UNKNOWN, PF_X86, PF_X64, PF_IA64 }; #define NPPM_GETEXTPART (RUNCOMMAND_USER + EXT_PART) #define NPPM_GETCURRENTWORD (RUNCOMMAND_USER + CURRENT_WORD) #define NPPM_GETNPPDIRECTORY (RUNCOMMAND_USER + NPP_DIRECTORY) + #define NPPM_GETNPPFULLFILEPATH (RUNCOMMAND_USER + NPP_FULL_FILE_PATH) #define NPPM_GETFILENAMEATCURSOR (RUNCOMMAND_USER + GETFILENAMEATCURSOR) - // BOOL NPPM_GETXXXXXXXXXXXXXXXX(size_t strLen, TCHAR *str) - // where str is the allocated TCHAR array, - // strLen is the allocated array size - // The return value is TRUE when get generic_string operation success - // Otherwise (allocated array size is too small) FALSE + #define NPPM_GETCURRENTLINESTR (RUNCOMMAND_USER + CURRENT_LINESTR) + // BOOL NPPM_GETXXXXXXXXXXXXXXXX(size_t strLen, wchar_t *str) + // Get XXX string operations. + // wParam[in]: strLen is the allocated array size + // lParam[out]: str is the allocated wchar_t array + // The return value is TRUE when get std::wstring operation success, otherwise FALSE (allocated array size is too small) + #define NPPM_GETCURRENTLINE (RUNCOMMAND_USER + CURRENT_LINE) - // INT NPPM_GETCURRENTLINE(0, 0) + // int NPPM_GETCURRENTLINE(0, 0) + // Get current line number. + // wParam: 0 (not used) + // lParam: 0 (not used) // return the caret current position line + #define NPPM_GETCURRENTCOLUMN (RUNCOMMAND_USER + CURRENT_COLUMN) - // INT NPPM_GETCURRENTCOLUMN(0, 0) + // int NPPM_GETCURRENTCOLUMN(0, 0) + // Get current column number. + // wParam: 0 (not used) + // lParam: 0 (not used) // return the caret current position column - #define NPPM_GETNPPFULLFILEPATH (RUNCOMMAND_USER + NPP_FULL_FILE_PATH) - // Notification code #define NPPN_FIRST 1000 - #define NPPN_READY (NPPN_FIRST + 1) // To notify plugins that all the procedures of launchment of notepad++ are done. + #define NPPN_READY (NPPN_FIRST + 1) // To notify plugins that all the initialization for launching Notepad++ is complete. //scnNotification->nmhdr.code = NPPN_READY; //scnNotification->nmhdr.hwndFrom = hwndNpp; //scnNotification->nmhdr.idFrom = 0; @@ -521,7 +1121,7 @@ enum Platform { PF_UNKNOWN, PF_X86, PF_X64, PF_IA64 }; //scnNotification->nmhdr.idFrom = BufferID; #define NPPN_FILEBEFORESAVE (NPPN_FIRST + 7) // To notify plugins that the current file is about to be saved - //scnNotification->nmhdr.code = NPPN_FILEBEFOREOPEN; + //scnNotification->nmhdr.code = NPPN_FILEBEFORESAVE; //scnNotification->nmhdr.hwndFrom = hwndNpp; //scnNotification->nmhdr.idFrom = BufferID; @@ -551,7 +1151,7 @@ enum Platform { PF_UNKNOWN, PF_X86, PF_X64, PF_IA64 }; //scnNotification->nmhdr.idFrom = currentBufferID; #define NPPN_SHORTCUTREMAPPED (NPPN_FIRST + 13) // To notify plugins that plugin command shortcut is remapped. - //scnNotification->nmhdr.code = NPPN_SHORTCUTSREMAPPED; + //scnNotification->nmhdr.code = NPPN_SHORTCUTREMAPPED; //scnNotification->nmhdr.hwndFrom = ShortcutKeyStructurePointer; //scnNotification->nmhdr.idFrom = cmdID; //where ShortcutKeyStructurePointer is pointer of struct ShortcutKey: @@ -563,12 +1163,12 @@ enum Platform { PF_UNKNOWN, PF_X86, PF_X64, PF_IA64 }; //}; #define NPPN_FILEBEFORELOAD (NPPN_FIRST + 14) // To notify plugins that the current file is about to be loaded - //scnNotification->nmhdr.code = NPPN_FILEBEFOREOPEN; + //scnNotification->nmhdr.code = NPPN_FILEBEFORELOAD; //scnNotification->nmhdr.hwndFrom = hwndNpp; //scnNotification->nmhdr.idFrom = NULL; #define NPPN_FILELOADFAILED (NPPN_FIRST + 15) // To notify plugins that file open operation failed - //scnNotification->nmhdr.code = NPPN_FILEOPENFAILED; + //scnNotification->nmhdr.code = NPPN_FILELOADFAILED; //scnNotification->nmhdr.hwndFrom = hwndNpp; //scnNotification->nmhdr.idFrom = BufferID; @@ -631,3 +1231,58 @@ enum Platform { PF_UNKNOWN, PF_X86, PF_X64, PF_IA64 }; //scnNotification->nmhdr.code = NPPN_FILEDELETED; //scnNotification->nmhdr.hwndFrom = hwndNpp; //scnNotification->nmhdr.idFrom = BufferID; + + #define NPPN_DARKMODECHANGED (NPPN_FIRST + 27) // To notify plugins that Dark Mode was enabled/disabled + //scnNotification->nmhdr.code = NPPN_DARKMODECHANGED; + //scnNotification->nmhdr.hwndFrom = hwndNpp; + //scnNotification->nmhdr.idFrom = 0; + + #define NPPN_CMDLINEPLUGINMSG (NPPN_FIRST + 28) // To notify plugins that there are plugin arguments pluginMessage (wchar_t*) is available + //scnNotification->nmhdr.code = NPPN_CMDLINEPLUGINMSG; + //scnNotification->nmhdr.hwndFrom = hwndNpp; + //scnNotification->nmhdr.idFrom = pluginMessage; //where pluginMessage is pointer of type wchar_t + // + // User can pass arguments to plugins via command line argument using: + // -pluginMessage="PLUGIN1_ARG1=V1;PLUGIN1_ARG2=V2;PLUGIN2_ARG=V;..." + // + // The full string (wchar_t*) will be delivered to all plugins via the NPPN_CMDLINEPLUGINMSG notification. Each plugins can parse and extract the arguments relevant to itself. + // + // To avoid the collisions among plugins, the following protocol should be followed: + // 1. Each plugin must use its unique namespace (its folder name in plugins directory) as a prefix for its argument names. + // 2. The symbol ';' must be used as the delimiter between arguments when there are 2 or more arguments in the pluginMessage string. + // 3. The symbol '=' must be used as delimiter between argument names and their values. + // + // Example (via the command line): + // -pluginMessage="NppExecScriptPath=C:\Program Files\Notepad++\plugins\NppExec\init.py;NppExecArg2=arg2Value;mimeToolsSettings=disable;pluginYInfo=show" + // + // Interpretation: + // - Plugin "NppExec" processes: NppExecScriptPath=C:\Program Files\Notepad++\plugins\NppExec\init.py & NppExecArg2=arg2Value + // - Plugin "mimeTools" processes: mimeToolsSettings=disable + // - Plugin "pluginY" processes: pluginYInfo=show + + #define NPPN_EXTERNALLEXERBUFFER (NPPN_FIRST + 29) // To notify lexer plugins that the buffer (in idFrom) is just applied to a external lexer + //scnNotification->nmhdr.code = NPPN_EXTERNALLEXERBUFFER; + //scnNotification->nmhdr.hwndFrom = hwndNpp; + //scnNotification->nmhdr.idFrom = BufferID; //where pluginMessage is pointer of type wchar_t + + #define NPPN_GLOBALMODIFIED (NPPN_FIRST + 30) // To notify plugins that the current document is just modified by Replace All action. + // For solving the performance issue (from v8.6.4), Notepad++ doesn't trigger SCN_MODIFIED during Replace All action anymore. + // As a result, the plugins which monitor SCN_MODIFIED should also monitor NPPN_GLOBALMODIFIED. + // This notification is implemented in Notepad++ v8.6.5. + //scnNotification->nmhdr.code = NPPN_GLOBALMODIFIED; + //scnNotification->nmhdr.hwndFrom = BufferID; + //scnNotification->nmhdr.idFrom = 0; // preserved for the future use, must be zero + + #define NPPN_NATIVELANGCHANGED (NPPN_FIRST + 31) // To notify plugins that the current native language is just changed to another one. + // Use NPPM_GETNATIVELANGFILENAME to get current native language file name. + // Use NPPM_GETMENUHANDLE(NPPPLUGINMENU, 0) to get submenu "Plugins" handle (HMENU) + //scnNotification->nmhdr.code = NPPN_NATIVELANGCHANGED; + //scnNotification->nmhdr.hwndFrom = hwndNpp + //scnNotification->nmhdr.idFrom = 0; // preserved for the future use, must be zero + + #define NPPN_TOOLBARICONSETCHANGED (NPPN_FIRST + 32) // To notify plugins that toolbar icon set selection has changed + //scnNotification->nmhdr.code = NPPN_TOOLBARICONSETCHANGED; + //scnNotification->nmhdr.hwndFrom = hwndNpp; + //scnNotification->nmhdr.idFrom = iconSetChoice; + // where iconSetChoice could be 1 of 5 possible values: + // 0 (Fluent UI: small), 1 (Fluent UI: large), 2 (Filled Fluent UI: small), 3 (Filled Fluent UI: large) and 4 (Standard icons: small). diff --git a/NppExec/Release/NppExec/Scintilla.h b/NppExec/Release/NppExec/Scintilla.h index f5cd312..67927ec 100644 --- a/NppExec/Release/NppExec/Scintilla.h +++ b/NppExec/Release/NppExec/Scintilla.h @@ -20,7 +20,6 @@ extern "C" { int Scintilla_RegisterClasses(void *hInstance); int Scintilla_ReleaseResources(void); #endif -int Scintilla_LinkLexers(void); #ifdef __cplusplus } @@ -37,6 +36,7 @@ typedef intptr_t sptr_t; #include "Sci_Position.h" typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, sptr_t lParam); +typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, sptr_t lParam, int *pStatus); #ifndef SCI_DISABLE_AUTOGENERATED @@ -57,11 +57,15 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_GETCURRENTPOS 2008 #define SCI_GETANCHOR 2009 #define SCI_GETSTYLEAT 2010 +#define SCI_GETSTYLEINDEXAT 2038 #define SCI_REDO 2011 #define SCI_SETUNDOCOLLECTION 2012 #define SCI_SELECTALL 2013 #define SCI_SETSAVEPOINT 2014 -#define SCI_GETSTYLEDTEXT 2015 +//deprecated by N++ 2GB+ support via new scintilla interfaces from 5.2.3 (see https://www.scintilla.org/ScintillaHistory.html), +//please use SCI_GETTEXTRANGEFULL, SCI_FINDTEXTFULL,SCI_GETSTYLEDTEXTFULL and SCI_FORMATRANGEFULL and corresponding defines/structs +//#define SCI_GETSTYLEDTEXT 2015 +#define SCI_GETSTYLEDTEXTFULL 2778 #define SCI_CANREDO 2016 #define SCI_MARKERLINEFROMHANDLE 2017 #define SCI_MARKERDELETEHANDLE 2018 @@ -104,6 +108,8 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_GETNEXTTABSTOP 2677 #define SC_CP_UTF8 65001 #define SCI_SETCODEPAGE 2037 +#define SCI_SETFONTLOCALE 2760 +#define SCI_GETFONTLOCALE 2761 #define SC_IME_WINDOWED 0 #define SC_IME_INLINE 1 #define SCI_GETIMEINTERACTION 2678 @@ -149,7 +155,12 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_MARK_RGBAIMAGE 30 #define SC_MARK_BOOKMARK 31 #define SC_MARK_VERTICALBOOKMARK 32 +#define SC_MARK_BAR 33 #define SC_MARK_CHARACTER 10000 +#define SC_MARKNUM_HISTORY_REVERTED_TO_ORIGIN 21 +#define SC_MARKNUM_HISTORY_SAVED 22 +#define SC_MARKNUM_HISTORY_MODIFIED 23 +#define SC_MARKNUM_HISTORY_REVERTED_TO_MODIFIED 24 #define SC_MARKNUM_FOLDEREND 25 #define SC_MARKNUM_FOLDEROPENMID 26 #define SC_MARKNUM_FOLDERMIDTAIL 27 @@ -157,11 +168,16 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_MARKNUM_FOLDERSUB 29 #define SC_MARKNUM_FOLDER 30 #define SC_MARKNUM_FOLDEROPEN 31 +#define SC_MASK_HISTORY 0x01E00000 #define SC_MASK_FOLDERS 0xFE000000 #define SCI_MARKERDEFINE 2040 #define SCI_MARKERSETFORE 2041 #define SCI_MARKERSETBACK 2042 #define SCI_MARKERSETBACKSELECTED 2292 +#define SCI_MARKERSETFORETRANSLUCENT 2294 +#define SCI_MARKERSETBACKTRANSLUCENT 2295 +#define SCI_MARKERSETBACKSELECTEDTRANSLUCENT 2296 +#define SCI_MARKERSETSTROKEWIDTH 2297 #define SCI_MARKERENABLEHIGHLIGHT 2293 #define SCI_MARKERADD 2043 #define SCI_MARKERDELETE 2044 @@ -172,6 +188,8 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_MARKERDEFINEPIXMAP 2049 #define SCI_MARKERADDSET 2466 #define SCI_MARKERSETALPHA 2476 +#define SCI_MARKERGETLAYER 2734 +#define SCI_MARKERSETLAYER 2735 #define SC_MAX_MARGIN 4 #define SC_MARGIN_SYMBOL 0 #define SC_MARGIN_NUMBER 1 @@ -264,12 +282,65 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_STYLEGETWEIGHT 2064 #define SCI_STYLESETCHARACTERSET 2066 #define SCI_STYLESETHOTSPOT 2409 +#define SCI_STYLESETCHECKMONOSPACED 2254 +#define SCI_STYLEGETCHECKMONOSPACED 2255 +#define SC_STRETCH_ULTRA_CONDENSED 1 +#define SC_STRETCH_EXTRA_CONDENSED 2 +#define SC_STRETCH_CONDENSED 3 +#define SC_STRETCH_SEMI_CONDENSED 4 +#define SC_STRETCH_NORMAL 5 +#define SC_STRETCH_SEMI_EXPANDED 6 +#define SC_STRETCH_EXPANDED 7 +#define SC_STRETCH_EXTRA_EXPANDED 8 +#define SC_STRETCH_ULTRA_EXPANDED 9 +#define SCI_STYLESETSTRETCH 2258 +#define SCI_STYLEGETSTRETCH 2259 +#define SCI_STYLESETINVISIBLEREPRESENTATION 2256 +#define SCI_STYLEGETINVISIBLEREPRESENTATION 2257 +#define SC_ELEMENT_LIST 0 +#define SC_ELEMENT_LIST_BACK 1 +#define SC_ELEMENT_LIST_SELECTED 2 +#define SC_ELEMENT_LIST_SELECTED_BACK 3 +#define SC_ELEMENT_SELECTION_TEXT 10 +#define SC_ELEMENT_SELECTION_BACK 11 +#define SC_ELEMENT_SELECTION_ADDITIONAL_TEXT 12 +#define SC_ELEMENT_SELECTION_ADDITIONAL_BACK 13 +#define SC_ELEMENT_SELECTION_SECONDARY_TEXT 14 +#define SC_ELEMENT_SELECTION_SECONDARY_BACK 15 +#define SC_ELEMENT_SELECTION_INACTIVE_TEXT 16 +#define SC_ELEMENT_SELECTION_INACTIVE_BACK 17 +#define SC_ELEMENT_SELECTION_INACTIVE_ADDITIONAL_TEXT 18 +#define SC_ELEMENT_SELECTION_INACTIVE_ADDITIONAL_BACK 19 +#define SC_ELEMENT_CARET 40 +#define SC_ELEMENT_CARET_ADDITIONAL 41 +#define SC_ELEMENT_CARET_LINE_BACK 50 +#define SC_ELEMENT_WHITE_SPACE 60 +#define SC_ELEMENT_WHITE_SPACE_BACK 61 +#define SC_ELEMENT_HOT_SPOT_ACTIVE 70 +#define SC_ELEMENT_HOT_SPOT_ACTIVE_BACK 71 +#define SC_ELEMENT_FOLD_LINE 80 +#define SC_ELEMENT_HIDDEN_LINE 81 +#define SCI_SETELEMENTCOLOUR 2753 +#define SCI_GETELEMENTCOLOUR 2754 +#define SCI_RESETELEMENTCOLOUR 2755 +#define SCI_GETELEMENTISSET 2756 +#define SCI_GETELEMENTALLOWSTRANSLUCENT 2757 +#define SCI_GETELEMENTBASECOLOUR 2758 #define SCI_SETSELFORE 2067 #define SCI_SETSELBACK 2068 #define SCI_GETSELALPHA 2477 #define SCI_SETSELALPHA 2478 #define SCI_GETSELEOLFILLED 2479 #define SCI_SETSELEOLFILLED 2480 +#define SC_LAYER_BASE 0 +#define SC_LAYER_UNDER_TEXT 1 +#define SC_LAYER_OVER_TEXT 2 +#define SCI_GETSELECTIONLAYER 2762 +#define SCI_SETSELECTIONLAYER 2763 +#define SCI_GETCARETLINELAYER 2764 +#define SCI_SETCARETLINELAYER 2765 +#define SCI_GETCARETLINEHIGHLIGHTSUBLINE 2773 +#define SCI_SETCARETLINEHIGHLIGHTSUBLINE 2774 #define SCI_SETCARETFORE 2069 #define SCI_ASSIGNCMDKEY 2070 #define SCI_CLEARCMDKEY 2071 @@ -284,6 +355,21 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_GETCHARACTERCATEGORYOPTIMIZATION 2721 #define SCI_BEGINUNDOACTION 2078 #define SCI_ENDUNDOACTION 2079 +#define SCI_GETUNDOSEQUENCE 2799 +#define SCI_GETUNDOACTIONS 2790 +#define SCI_SETUNDOSAVEPOINT 2791 +#define SCI_GETUNDOSAVEPOINT 2792 +#define SCI_SETUNDODETACH 2793 +#define SCI_GETUNDODETACH 2794 +#define SCI_SETUNDOTENTATIVE 2795 +#define SCI_GETUNDOTENTATIVE 2796 +#define SCI_SETUNDOCURRENT 2797 +#define SCI_GETUNDOCURRENT 2798 +#define SCI_PUSHUNDOACTIONTYPE 2800 +#define SCI_CHANGELASTUNDOACTIONTEXT 2801 +#define SCI_GETUNDOACTIONTYPE 2802 +#define SCI_GETUNDOACTIONPOSITION 2803 +#define SCI_GETUNDOACTIONTEXT 2804 #define INDIC_PLAIN 0 #define INDIC_SQUIGGLE 1 #define INDIC_TT 2 @@ -306,7 +392,8 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define INDIC_POINTCHARACTER 19 #define INDIC_GRADIENT 20 #define INDIC_GRADIENTCENTRE 21 -#define INDIC_EXPLORERLINK 22 +#define INDIC_POINT_TOP 22 +#define INDIC_EXPLORERLINK 23 #define INDIC_CONTAINER 8 #define INDIC_IME 32 #define INDIC_IME_MAX 35 @@ -314,7 +401,15 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define INDICATOR_CONTAINER 8 #define INDICATOR_IME 32 #define INDICATOR_IME_MAX 35 -#define INDICATOR_MAX 35 +#define INDICATOR_HISTORY_REVERTED_TO_ORIGIN_INSERTION 36 +#define INDICATOR_HISTORY_REVERTED_TO_ORIGIN_DELETION 37 +#define INDICATOR_HISTORY_SAVED_INSERTION 38 +#define INDICATOR_HISTORY_SAVED_DELETION 39 +#define INDICATOR_HISTORY_MODIFIED_INSERTION 40 +#define INDICATOR_HISTORY_MODIFIED_DELETION 41 +#define INDICATOR_HISTORY_REVERTED_TO_MODIFIED_INSERTION 42 +#define INDICATOR_HISTORY_REVERTED_TO_MODIFIED_DELETION 43 +#define INDICATOR_MAX 43 #define SCI_INDICSETSTYLE 2080 #define SCI_INDICGETSTYLE 2081 #define SCI_INDICSETFORE 2082 @@ -327,9 +422,12 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_INDICGETHOVERFORE 2683 #define SC_INDICVALUEBIT 0x1000000 #define SC_INDICVALUEMASK 0xFFFFFF +#define SC_INDICFLAG_NONE 0 #define SC_INDICFLAG_VALUEFORE 1 #define SCI_INDICSETFLAGS 2684 #define SCI_INDICGETFLAGS 2685 +#define SCI_INDICSETSTROKEWIDTH 2751 +#define SCI_INDICGETSTROKEWIDTH 2752 #define SCI_SETWHITESPACEFORE 2084 #define SCI_SETWHITESPACEBACK 2085 #define SCI_SETWHITESPACESIZE 2086 @@ -363,6 +461,11 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_USERLISTSHOW 2117 #define SCI_AUTOCSETAUTOHIDE 2118 #define SCI_AUTOCGETAUTOHIDE 2119 +#define SC_AUTOCOMPLETE_NORMAL 0 +#define SC_AUTOCOMPLETE_FIXED_SIZE 1 +#define SC_AUTOCOMPLETE_SELECT_FIRST_ITEM 2 +#define SCI_AUTOCSETOPTIONS 2638 +#define SCI_AUTOCGETOPTIONS 2639 #define SCI_AUTOCSETDROPRESTOFWORD 2270 #define SCI_AUTOCGETDROPRESTOFWORD 2271 #define SCI_REGISTERIMAGE 2405 @@ -373,6 +476,10 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_AUTOCGETMAXWIDTH 2209 #define SCI_AUTOCSETMAXHEIGHT 2210 #define SCI_AUTOCGETMAXHEIGHT 2211 +#define SCI_AUTOCSETSTYLE 2109 +#define SCI_AUTOCGETSTYLE 2120 +#define SCI_AUTOCSETIMAGESCALE 2815 +#define SCI_AUTOCGETIMAGESCALE 2816 #define SCI_SETINDENT 2122 #define SCI_GETINDENT 2123 #define SCI_SETUSETABS 2124 @@ -420,11 +527,31 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCFIND_REGEXP 0x00200000 #define SCFIND_POSIX 0x00400000 #define SCFIND_CXX11REGEX 0x00800000 -#define SCI_FINDTEXT 2150 -#define SCI_FORMATRANGE 2151 +//deprecated by N++ 2GB+ support via new scintilla interfaces from 5.2.3 (see https://www.scintilla.org/ScintillaHistory.html), +//please use SCI_GETTEXTRANGEFULL, SCI_FINDTEXTFULL,SCI_GETSTYLEDTEXTFULL and SCI_FORMATRANGEFULL and corresponding defines/structs +//#define SCI_FINDTEXT 2150 +#define SCI_FINDTEXTFULL 2196 +//deprecated by N++ 2GB+ support via new scintilla interfaces from 5.2.3 (see https://www.scintilla.org/ScintillaHistory.html), +//please use SCI_GETTEXTRANGEFULL, SCI_FINDTEXTFULL,SCI_GETSTYLEDTEXTFULL and SCI_FORMATRANGEFULL and corresponding defines/structs +//#define SCI_FORMATRANGE 2151 +#define SCI_FORMATRANGEFULL 2777 +#define SC_CHANGE_HISTORY_DISABLED 0 +#define SC_CHANGE_HISTORY_ENABLED 1 +#define SC_CHANGE_HISTORY_MARKERS 2 +#define SC_CHANGE_HISTORY_INDICATORS 4 +#define SCI_SETCHANGEHISTORY 2780 +#define SCI_GETCHANGEHISTORY 2781 +#define SC_UNDO_SELECTION_HISTORY_DISABLED 0 +#define SC_UNDO_SELECTION_HISTORY_ENABLED 1 +#define SC_UNDO_SELECTION_HISTORY_SCROLL 2 +#define SCI_SETUNDOSELECTIONHISTORY 2782 +#define SCI_GETUNDOSELECTIONHISTORY 2783 +#define SCI_SETSELECTIONSERIALIZED 2784 +#define SCI_GETSELECTIONSERIALIZED 2785 #define SCI_GETFIRSTVISIBLELINE 2152 #define SCI_GETLINE 2153 #define SCI_GETLINECOUNT 2154 +#define SCI_ALLOCATELINES 2089 #define SCI_SETMARGINLEFT 2155 #define SCI_GETMARGINLEFT 2156 #define SCI_SETMARGINRIGHT 2157 @@ -432,13 +559,18 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_GETMODIFY 2159 #define SCI_SETSEL 2160 #define SCI_GETSELTEXT 2161 -#define SCI_GETTEXTRANGE 2162 +//deprecated by N++ 2GB+ support via new scintilla interfaces from 5.2.3 (see https://www.scintilla.org/ScintillaHistory.html), +//please use SCI_GETTEXTRANGEFULL, SCI_FINDTEXTFULL,SCI_GETSTYLEDTEXTFULL and SCI_FORMATRANGEFULL and corresponding defines/structs +//#define SCI_GETTEXTRANGE 2162 +#define SCI_GETTEXTRANGEFULL 2039 #define SCI_HIDESELECTION 2163 +#define SCI_GETSELECTIONHIDDEN 2088 #define SCI_POINTXFROMPOSITION 2164 #define SCI_POINTYFROMPOSITION 2165 #define SCI_LINEFROMPOSITION 2166 #define SCI_POSITIONFROMLINE 2167 #define SCI_LINESCROLL 2168 +#define SCI_SCROLLVERTICAL 2817 #define SCI_SCROLLCARET 2169 #define SCI_SCROLLRANGE 2569 #define SCI_REPLACESEL 2170 @@ -456,6 +588,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_GETTEXT 2182 #define SCI_GETTEXTLENGTH 2183 #define SCI_GETDIRECTFUNCTION 2184 +#define SCI_GETDIRECTSTATUSFUNCTION 2772 #define SCI_GETDIRECTPOINTER 2185 #define SCI_SETOVERTYPE 2186 #define SCI_GETOVERTYPE 2187 @@ -475,6 +608,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_TARGETWHOLEDOCUMENT 2690 #define SCI_REPLACETARGET 2194 #define SCI_REPLACETARGETRE 2195 +#define SCI_REPLACETARGETMINIMAL 2779 #define SCI_SEARCHINTARGET 2197 #define SCI_SETSEARCHFLAGS 2198 #define SCI_GETSEARCHFLAGS 2199 @@ -492,6 +626,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_VISIBLEFROMDOCLINE 2220 #define SCI_DOCLINEFROMVISIBLE 2221 #define SCI_WRAPCOUNT 2235 +#define SC_FOLDLEVELNONE 0x0 #define SC_FOLDLEVELBASE 0x400 #define SC_FOLDLEVELWHITEFLAG 0x1000 #define SC_FOLDLEVELHEADERFLAG 0x2000 @@ -518,16 +653,19 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_FOLDACTION_CONTRACT 0 #define SC_FOLDACTION_EXPAND 1 #define SC_FOLDACTION_TOGGLE 2 +#define SC_FOLDACTION_CONTRACT_EVERY_LEVEL 4 #define SCI_FOLDLINE 2237 #define SCI_FOLDCHILDREN 2238 #define SCI_EXPANDCHILDREN 2239 #define SCI_FOLDALL 2662 #define SCI_ENSUREVISIBLE 2232 +#define SC_AUTOMATICFOLD_NONE 0x0000 #define SC_AUTOMATICFOLD_SHOW 0x0001 #define SC_AUTOMATICFOLD_CLICK 0x0002 #define SC_AUTOMATICFOLD_CHANGE 0x0004 #define SCI_SETAUTOMATICFOLD 2663 #define SCI_GETAUTOMATICFOLD 2664 +#define SC_FOLDFLAG_NONE 0x0000 #define SC_FOLDFLAG_LINEBEFORE_EXPANDED 0x0002 #define SC_FOLDFLAG_LINEBEFORE_CONTRACTED 0x0004 #define SC_FOLDFLAG_LINEAFTER_EXPANDED 0x0008 @@ -648,7 +786,9 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_CANCEL 2325 #define SCI_DELETEBACK 2326 #define SCI_TAB 2327 +#define SCI_LINEINDENT 2813 #define SCI_BACKTAB 2328 +#define SCI_LINEDEDENT 2814 #define SCI_NEWLINE 2329 #define SCI_FORMFEED 2330 #define SCI_VCHOME 2331 @@ -787,7 +927,9 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_SEL_LINES 2 #define SC_SEL_THIN 3 #define SCI_SETSELECTIONMODE 2422 +#define SCI_CHANGESELECTIONMODE 2659 #define SCI_GETSELECTIONMODE 2423 +#define SCI_SETMOVEEXTENDSSELECTION 2719 #define SCI_GETMOVEEXTENDSSELECTION 2706 #define SCI_GETLINESELSTARTPOSITION 2424 #define SCI_GETLINESELENDPOSITION 2425 @@ -841,6 +983,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_TOGGLECARETSTICKY 2459 #define SCI_SETPASTECONVERTENDINGS 2467 #define SCI_GETPASTECONVERTENDINGS 2468 +#define SCI_REPLACERECTANGULAR 2771 #define SCI_SELECTIONDUPLICATE 2469 #define SCI_SETCARETLINEBACKALPHA 2470 #define SCI_GETCARETLINEBACKALPHA 2471 @@ -849,6 +992,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define CARETSTYLE_BLOCK 2 #define CARETSTYLE_OVERSTRIKE_BAR 0 #define CARETSTYLE_OVERSTRIKE_BLOCK 0x10 +#define CARETSTYLE_CURSES 0x20 #define CARETSTYLE_INS_MASK 0xF #define CARETSTYLE_BLOCK_AFTER 0x100 #define SCI_SETCARETSTYLE 2512 @@ -865,7 +1009,12 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_INDICATOREND 2509 #define SCI_SETPOSITIONCACHE 2514 #define SCI_GETPOSITIONCACHE 2515 +#define SCI_SETLAYOUTTHREADS 2775 +#define SCI_GETLAYOUTTHREADS 2776 #define SCI_COPYALLOWLINE 2519 +#define SCI_CUTALLOWLINE 2810 +#define SCI_SETCOPYSEPARATOR 2811 +#define SCI_GETCOPYSEPARATOR 2812 #define SCI_GETCHARACTERPOINTER 2520 #define SCI_GETRANGEPOINTER 2643 #define SCI_GETGAPPOSITION 2644 @@ -929,6 +1078,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_CLEARSELECTIONS 2571 #define SCI_SETSELECTION 2572 #define SCI_ADDSELECTION 2573 +#define SCI_SELECTIONFROMPOINT 2474 #define SCI_DROPSELECTIONN 2671 #define SCI_SETMAINSELECTION 2574 #define SCI_GETMAINSELECTION 2575 @@ -990,6 +1140,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_TECHNOLOGY_DIRECTWRITE 1 #define SC_TECHNOLOGY_DIRECTWRITERETAIN 2 #define SC_TECHNOLOGY_DIRECTWRITEDC 3 +#define SC_TECHNOLOGY_DIRECT_WRITE_1 4 #define SCI_SETTECHNOLOGY 2630 #define SCI_GETTECHNOLOGY 2631 #define SCI_CREATELOADER 2632 @@ -1008,29 +1159,57 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_SETREPRESENTATION 2665 #define SCI_GETREPRESENTATION 2666 #define SCI_CLEARREPRESENTATION 2667 +#define SCI_CLEARALLREPRESENTATIONS 2770 +#define SC_REPRESENTATION_PLAIN 0 +#define SC_REPRESENTATION_BLOB 1 +#define SC_REPRESENTATION_COLOUR 0x10 +#define SCI_SETREPRESENTATIONAPPEARANCE 2766 +#define SCI_GETREPRESENTATIONAPPEARANCE 2767 +#define SCI_SETREPRESENTATIONCOLOUR 2768 +#define SCI_GETREPRESENTATIONCOLOUR 2769 #define SCI_EOLANNOTATIONSETTEXT 2740 #define SCI_EOLANNOTATIONGETTEXT 2741 #define SCI_EOLANNOTATIONSETSTYLE 2742 #define SCI_EOLANNOTATIONGETSTYLE 2743 #define SCI_EOLANNOTATIONCLEARALL 2744 -#define EOLANNOTATION_HIDDEN 0 -#define EOLANNOTATION_STANDARD 1 -#define EOLANNOTATION_BOXED 2 +#define EOLANNOTATION_HIDDEN 0x0 +#define EOLANNOTATION_STANDARD 0x1 +#define EOLANNOTATION_BOXED 0x2 +#define EOLANNOTATION_STADIUM 0x100 +#define EOLANNOTATION_FLAT_CIRCLE 0x101 +#define EOLANNOTATION_ANGLE_CIRCLE 0x102 +#define EOLANNOTATION_CIRCLE_FLAT 0x110 +#define EOLANNOTATION_FLATS 0x111 +#define EOLANNOTATION_ANGLE_FLAT 0x112 +#define EOLANNOTATION_CIRCLE_ANGLE 0x120 +#define EOLANNOTATION_FLAT_ANGLE 0x121 +#define EOLANNOTATION_ANGLES 0x122 #define SCI_EOLANNOTATIONSETVISIBLE 2745 #define SCI_EOLANNOTATIONGETVISIBLE 2746 #define SCI_EOLANNOTATIONSETSTYLEOFFSET 2747 #define SCI_EOLANNOTATIONGETSTYLEOFFSET 2748 +#define SC_SUPPORTS_LINE_DRAWS_FINAL 0 +#define SC_SUPPORTS_PIXEL_DIVISIONS 1 +#define SC_SUPPORTS_FRACTIONAL_STROKE_WIDTH 2 +#define SC_SUPPORTS_TRANSLUCENT_STROKE 3 +#define SC_SUPPORTS_PIXEL_MODIFICATION 4 +#define SC_SUPPORTS_THREAD_SAFE_MEASURE_WIDTHS 5 +#define SCI_SUPPORTSFEATURE 2750 +#define SC_LINECHARACTERINDEX_NONE 0 +#define SC_LINECHARACTERINDEX_UTF32 1 +#define SC_LINECHARACTERINDEX_UTF16 2 +#define SCI_GETLINECHARACTERINDEX 2710 +#define SCI_ALLOCATELINECHARACTERINDEX 2711 +#define SCI_RELEASELINECHARACTERINDEX 2712 +#define SCI_LINEFROMINDEXPOSITION 2713 +#define SCI_INDEXPOSITIONFROMLINE 2714 #define SCI_STARTRECORD 3001 #define SCI_STOPRECORD 3002 -#define SCI_SETLEXER 4001 #define SCI_GETLEXER 4002 #define SCI_COLOURISE 4003 #define SCI_SETPROPERTY 4004 -// #define KEYWORDSET_MAX 8 #define KEYWORDSET_MAX 30 #define SCI_SETKEYWORDS 4005 -#define SCI_SETLEXERLANGUAGE 4006 -#define SCI_LOADLEXERLIBRARY 4007 #define SCI_GETPROPERTY 4008 #define SCI_GETPROPERTYEXPANDED 4009 #define SCI_GETPROPERTYINT 4010 @@ -1083,7 +1262,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_MOD_CHANGETABSTOPS 0x200000 #define SC_MOD_CHANGEEOLANNOTATION 0x400000 #define SC_MODEVENTMASKALL 0x7FFFFF -#define SC_SEARCHRESULT_LINEBUFFERMAXLENGTH 2048 +#define SC_UPDATE_NONE 0x0 #define SC_UPDATE_CONTENT 0x1 #define SC_UPDATE_SELECTION 0x2 #define SC_UPDATE_V_SCROLL 0x4 @@ -1122,6 +1301,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_AC_TAB 3 #define SC_AC_NEWLINE 4 #define SC_AC_COMMAND 5 +#define SC_AC_SINGLE_CHOICE 6 #define SC_CHARACTERSOURCE_DIRECT_INPUT 0 #define SC_CHARACTERSOURCE_TENTATIVE_INPUT 1 #define SC_CHARACTERSOURCE_IME_RESULT 2 @@ -1163,21 +1343,11 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_BIDIRECTIONAL_R2L 2 #define SCI_GETBIDIRECTIONAL 2708 #define SCI_SETBIDIRECTIONAL 2709 -#define SC_LINECHARACTERINDEX_NONE 0 -#define SC_LINECHARACTERINDEX_UTF32 1 -#define SC_LINECHARACTERINDEX_UTF16 2 -#define SCI_GETLINECHARACTERINDEX 2710 -#define SCI_ALLOCATELINECHARACTERINDEX 2711 -#define SCI_RELEASELINECHARACTERINDEX 2712 -#define SCI_LINEFROMINDEXPOSITION 2713 -#define SCI_INDEXPOSITIONFROMLINE 2714 #endif +#define SC_SEARCHRESULT_LINEBUFFERMAXLENGTH 2048 #define SCI_GETBOOSTREGEXERRMSG 5000 - -#define SCN_SCROLLED 2080 #define SCN_FOLDINGSTATECHANGED 2081 - /* --Autogenerated -- end of section automatically generated from Scintilla.iface */ #endif @@ -1186,20 +1356,42 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, * CHARRANGE, TEXTRANGE, FINDTEXTEX, FORMATRANGE, and NMHDR structs. * So older code that treats Scintilla as a RichEdit will work. */ -struct Sci_CharacterRange { - Sci_PositionCR cpMin; - Sci_PositionCR cpMax; +//deprecated by N++ 2GB+ support via new scintilla interfaces from 5.2.3 (see https://www.scintilla.org/ScintillaHistory.html), +//please use SCI_GETTEXTRANGEFULL, SCI_FINDTEXTFULL, and SCI_FORMATRANGEFULL and corresponding defines/structs +//struct Sci_CharacterRange { +// Sci_PositionCR cpMin; +// Sci_PositionCR cpMax; +//}; + +struct Sci_CharacterRangeFull { + Sci_Position cpMin; + Sci_Position cpMax; }; -struct Sci_TextRange { - struct Sci_CharacterRange chrg; +//deprecated by N++ 2GB+ support via new scintilla interfaces from 5.2.3 (see https://www.scintilla.org/ScintillaHistory.html), +//please use SCI_GETTEXTRANGEFULL, SCI_FINDTEXTFULL, and SCI_FORMATRANGEFULL and corresponding defines/structs +//struct Sci_TextRange { +// struct Sci_CharacterRange chrg; +// char *lpstrText; +//}; + +struct Sci_TextRangeFull { + struct Sci_CharacterRangeFull chrg; char *lpstrText; }; -struct Sci_TextToFind { - struct Sci_CharacterRange chrg; +//deprecated by N++ 2GB+ support via new scintilla interfaces from 5.2.3 (see https://www.scintilla.org/ScintillaHistory.html), +//please use SCI_GETTEXTRANGEFULL, SCI_FINDTEXTFULL, and SCI_FORMATRANGEFULL and corresponding defines/structs +//struct Sci_TextToFind { +// struct Sci_CharacterRange chrg; +// const char *lpstrText; +// struct Sci_CharacterRange chrgText; +//}; + +struct Sci_TextToFindFull { + struct Sci_CharacterRangeFull chrg; const char *lpstrText; - struct Sci_CharacterRange chrgText; + struct Sci_CharacterRangeFull chrgText; }; typedef void *Sci_SurfaceID; @@ -1214,17 +1406,27 @@ struct Sci_Rectangle { /* This structure is used in printing and requires some of the graphics types * from Platform.h. Not needed by most client code. */ -struct Sci_RangeToFormat { +//deprecated by N++ 2GB+ support via new scintilla interfaces from 5.2.3 (see https://www.scintilla.org/ScintillaHistory.html), +//please use SCI_GETTEXTRANGEFULL, SCI_FINDTEXTFULL, and SCI_FORMATRANGEFULL and corresponding defines/structs +//struct Sci_RangeToFormat { +// Sci_SurfaceID hdc; +// Sci_SurfaceID hdcTarget; +// struct Sci_Rectangle rc; +// struct Sci_Rectangle rcPage; +// struct Sci_CharacterRange chrg; +//}; + +struct Sci_RangeToFormatFull { Sci_SurfaceID hdc; Sci_SurfaceID hdcTarget; struct Sci_Rectangle rc; struct Sci_Rectangle rcPage; - struct Sci_CharacterRange chrg; + struct Sci_CharacterRangeFull chrg; }; #ifndef __cplusplus /* For the GTK+ platform, g-ir-scanner needs to have these typedefs. This - * is not required in C++ code and actually seems to break ScintillaEditPy */ + * is not required in C++ code and has caused problems in the past. */ typedef struct Sci_NotifyHeader Sci_NotifyHeader; typedef struct SCNotification SCNotification; #endif @@ -1242,10 +1444,12 @@ struct SCNotification { Sci_NotifyHeader nmhdr; Sci_Position position; /* SCN_STYLENEEDED, SCN_DOUBLECLICK, SCN_MODIFIED, SCN_MARGINCLICK, */ - /* SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, SCN_CALLTIPCLICK, */ + /* SCN_MARGINRIGHTCLICK, SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, */ + /* SCN_CALLTIPCLICK, */ /* SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, SCN_HOTSPOTRELEASECLICK, */ /* SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */ - /* SCN_USERLISTSELECTION, SCN_AUTOCSELECTION */ + /* SCN_USERLISTSELECTION, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */ + /* SCN_AUTOCSELECTIONCHANGE */ int ch; /* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */ @@ -1253,10 +1457,12 @@ struct SCNotification { int modifiers; /* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */ /* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */ + /* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */ int modificationType; /* SCN_MODIFIED */ const char *text; - /* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_AUTOCSELECTION, SCN_URIDROPPED */ + /* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_URIDROPPED, */ + /* SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, SCN_AUTOCSELECTIONCHANGE */ Sci_Position length; /* SCN_MODIFIED */ Sci_Position linesAdded; /* SCN_MODIFIED */ @@ -1266,28 +1472,27 @@ struct SCNotification { Sci_Position line; /* SCN_MODIFIED */ int foldLevelNow; /* SCN_MODIFIED */ int foldLevelPrev; /* SCN_MODIFIED */ - int margin; /* SCN_MARGINCLICK */ - int listType; /* SCN_USERLISTSELECTION */ + int margin; /* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */ + int listType; /* SCN_USERLISTSELECTION, SCN_AUTOCSELECTIONCHANGE */ int x; /* SCN_DWELLSTART, SCN_DWELLEND */ int y; /* SCN_DWELLSTART, SCN_DWELLEND */ int token; /* SCN_MODIFIED with SC_MOD_CONTAINER */ Sci_Position annotationLinesAdded; /* SCN_MODIFIED with SC_MOD_CHANGEANNOTATION */ int updated; /* SCN_UPDATEUI */ int listCompletionMethod; - /* SCN_AUTOCSELECTION, SCN_AUTOCCOMPLETED, SCN_USERLISTSELECTION, */ + /* SCN_AUTOCSELECTION, SCN_AUTOCCOMPLETED, SCN_USERLISTSELECTION */ int characterSource; /* SCN_CHARADDED */ }; -struct SearchResultMarking { - long _start; - long _end; +#include +struct SearchResultMarkingLine { // each line could have several segments if user want to see only 1 found line which contains several results + std::vector> _segmentPostions; // a vector of pair of start & end of occurrence for colourizing }; struct SearchResultMarkings { - long _length; - SearchResultMarking *_markings; + intptr_t _length; + SearchResultMarkingLine *_markings; }; - #ifdef INCLUDE_DEPRECATED_FEATURES #define SCI_SETKEYSUNICODE 2521 diff --git a/NppExec/Release/NppExec/menuCmdID.h b/NppExec/Release/NppExec/menuCmdID.h index 9a76213..85efc46 100644 --- a/NppExec/Release/NppExec/menuCmdID.h +++ b/NppExec/Release/NppExec/menuCmdID.h @@ -1,5 +1,5 @@ // This file is part of Notepad++ project -// Copyright (C)2021 Don HO +// Copyright (C)2025 Don HO // 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 @@ -43,14 +43,15 @@ #define IDM_FILE_OPEN_FOLDER (IDM_FILE + 19) #define IDM_FILE_OPEN_CMD (IDM_FILE + 20) #define IDM_FILE_RESTORELASTCLOSEDFILE (IDM_FILE + 21) - #define IDM_FILE_OPENFOLDERASWORSPACE (IDM_FILE + 22) + #define IDM_FILE_OPENFOLDERASWORKSPACE (IDM_FILE + 22) #define IDM_FILE_OPEN_DEFAULT_VIEWER (IDM_FILE + 23) #define IDM_FILE_CLOSEALL_UNCHANGED (IDM_FILE + 24) #define IDM_FILE_CONTAININGFOLDERASWORKSPACE (IDM_FILE + 25) + #define IDM_FILE_CLOSEALL_BUT_PINNED (IDM_FILE + 26) // IMPORTANT: If list above is modified, you have to change the following values: // To be updated if new menu item(s) is (are) added in menu "File" - #define IDM_FILEMENU_LASTONE IDM_FILE_CONTAININGFOLDERASWORKSPACE + #define IDM_FILEMENU_LASTONE IDM_FILE_CLOSEALL_BUT_PINNED // 0 based position of command "Exit" including the bars in the file menu // and without counting "Recent files history" items @@ -68,7 +69,7 @@ //10 Rename... //11 Close //12 Close All -//13 Close More +//13 Close Multiple Documents //14 Move to Recycle Bin //15 -------- //16 Load Session... @@ -109,12 +110,12 @@ #define IDM_MACRO_SAVECURRENTMACRO (IDM_EDIT + 25) #define IDM_EDIT_RTL (IDM_EDIT + 26) #define IDM_EDIT_LTR (IDM_EDIT + 27) - #define IDM_EDIT_SETREADONLY (IDM_EDIT + 28) + #define IDM_EDIT_TOGGLEREADONLY (IDM_EDIT + 28) #define IDM_EDIT_FULLPATHTOCLIP (IDM_EDIT + 29) #define IDM_EDIT_FILENAMETOCLIP (IDM_EDIT + 30) #define IDM_EDIT_CURRENTDIRTOCLIP (IDM_EDIT + 31) #define IDM_MACRO_RUNMULTIMACRODLG (IDM_EDIT + 32) - #define IDM_EDIT_CLEARREADONLY (IDM_EDIT + 33) + #define IDM_EDIT_TOGGLESYSTEMREADONLY (IDM_EDIT + 33) #define IDM_EDIT_COLUMNMODE (IDM_EDIT + 34) #define IDM_EDIT_BLOCK_COMMENT_SET (IDM_EDIT + 35) #define IDM_EDIT_BLOCK_UNCOMMENT (IDM_EDIT + 36) @@ -165,11 +166,33 @@ #define IDM_EDIT_SORTLINES_LEXICO_CASE_INSENS_DESCENDING (IDM_EDIT + 81) #define IDM_EDIT_COPY_LINK (IDM_EDIT + 82) #define IDM_EDIT_SORTLINES_REVERSE_ORDER (IDM_EDIT + 83) + #define IDM_EDIT_INSERT_DATETIME_SHORT (IDM_EDIT + 84) + #define IDM_EDIT_INSERT_DATETIME_LONG (IDM_EDIT + 85) + #define IDM_EDIT_INSERT_DATETIME_CUSTOMIZED (IDM_EDIT + 86) + #define IDM_EDIT_COPY_ALL_NAMES (IDM_EDIT + 87) + #define IDM_EDIT_COPY_ALL_PATHS (IDM_EDIT + 88) + #define IDM_EDIT_BEGINENDSELECT_COLUMNMODE (IDM_EDIT + 89) + #define IDM_EDIT_MULTISELECTALL (IDM_EDIT + 90) + #define IDM_EDIT_MULTISELECTALLMATCHCASE (IDM_EDIT + 91) + #define IDM_EDIT_MULTISELECTALLWHOLEWORD (IDM_EDIT + 92) + #define IDM_EDIT_MULTISELECTALLMATCHCASEWHOLEWORD (IDM_EDIT + 93) + #define IDM_EDIT_MULTISELECTNEXT (IDM_EDIT + 94) + #define IDM_EDIT_MULTISELECTNEXTMATCHCASE (IDM_EDIT + 95) + #define IDM_EDIT_MULTISELECTNEXTWHOLEWORD (IDM_EDIT + 96) + #define IDM_EDIT_MULTISELECTNEXTMATCHCASEWHOLEWORD (IDM_EDIT + 97) + #define IDM_EDIT_MULTISELECTUNDO (IDM_EDIT + 98) + #define IDM_EDIT_MULTISELECTSSKIP (IDM_EDIT + 99) + #define IDM_EDIT_SORTLINES_LOCALE_ASCENDING (IDM_EDIT + 100) + #define IDM_EDIT_SORTLINES_LOCALE_DESCENDING (IDM_EDIT + 101) + #define IDM_EDIT_SETREADONLYFORALLDOCS (IDM_EDIT + 102) + #define IDM_EDIT_CLEARREADONLYFORALLDOCS (IDM_EDIT + 103) #define IDM_EDIT_AUTOCOMPLETE (50000 + 0) #define IDM_EDIT_AUTOCOMPLETE_CURRENTFILE (50000 + 1) #define IDM_EDIT_FUNCCALLTIP (50000 + 2) #define IDM_EDIT_AUTOCOMPLETE_PATH (50000 + 6) + #define IDM_EDIT_FUNCCALLTIP_PREVIOUS (50000 + 10) + #define IDM_EDIT_FUNCCALLTIP_NEXT (50000 + 11) #define IDM_SEARCH (IDM + 3000) @@ -243,41 +266,47 @@ #define IDM_SEARCH_MARKONEEXT4 (IDM_SEARCH + 65) #define IDM_SEARCH_MARKONEEXT5 (IDM_SEARCH + 66) + #define IDM_SEARCH_CHANGED_NEXT (IDM_SEARCH + 67) + #define IDM_SEARCH_CHANGED_PREV (IDM_SEARCH + 68) + #define IDM_SEARCH_CLEAR_CHANGE_HISTORY (IDM_SEARCH + 69) + #define IDM_MISC (IDM + 3500) - #define IDM_FILESWITCHER_FILESCLOSE (IDM_MISC + 1) - #define IDM_FILESWITCHER_FILESCLOSEOTHERS (IDM_MISC + 2) + #define IDM_DOCLIST_FILESCLOSE (IDM_MISC + 1) + #define IDM_DOCLIST_FILESCLOSEOTHERS (IDM_MISC + 2) + #define IDM_DOCLIST_COPYNAMES (IDM_MISC + 3) + #define IDM_DOCLIST_COPYPATHS (IDM_MISC + 4) #define IDM_VIEW (IDM + 4000) //#define IDM_VIEW_TOOLBAR_HIDE (IDM_VIEW + 1) - #define IDM_VIEW_TOOLBAR_REDUCE (IDM_VIEW + 2) - #define IDM_VIEW_TOOLBAR_ENLARGE (IDM_VIEW + 3) - #define IDM_VIEW_TOOLBAR_STANDARD (IDM_VIEW + 4) - #define IDM_VIEW_REDUCETABBAR (IDM_VIEW + 5) - #define IDM_VIEW_LOCKTABBAR (IDM_VIEW + 6) - #define IDM_VIEW_DRAWTABBAR_TOPBAR (IDM_VIEW + 7) - #define IDM_VIEW_DRAWTABBAR_INACIVETAB (IDM_VIEW + 8) + //#define IDM_VIEW_TOOLBAR_REDUCE (IDM_VIEW + 2) + //#define IDM_VIEW_TOOLBAR_ENLARGE (IDM_VIEW + 3) + //#define IDM_VIEW_TOOLBAR_STANDARD (IDM_VIEW + 4) + //#define IDM_VIEW_REDUCETABBAR (IDM_VIEW + 5) + //#define IDM_VIEW_LOCKTABBAR (IDM_VIEW + 6) + //#define IDM_VIEW_DRAWTABBAR_TOPBAR (IDM_VIEW + 7) + //#define IDM_VIEW_DRAWTABBAR_INACTIVETAB (IDM_VIEW + 8) #define IDM_VIEW_POSTIT (IDM_VIEW + 9) - #define IDM_VIEW_TOGGLE_FOLDALL (IDM_VIEW + 10) + #define IDM_VIEW_FOLDALL (IDM_VIEW + 10) #define IDM_VIEW_DISTRACTIONFREE (IDM_VIEW + 11) - #define IDM_VIEW_LINENUMBER (IDM_VIEW + 12) - #define IDM_VIEW_SYMBOLMARGIN (IDM_VIEW + 13) - #define IDM_VIEW_FOLDERMAGIN (IDM_VIEW + 14) - #define IDM_VIEW_FOLDERMAGIN_SIMPLE (IDM_VIEW + 15) - #define IDM_VIEW_FOLDERMAGIN_ARROW (IDM_VIEW + 16) - #define IDM_VIEW_FOLDERMAGIN_CIRCLE (IDM_VIEW + 17) - #define IDM_VIEW_FOLDERMAGIN_BOX (IDM_VIEW + 18) + //#define IDM_VIEW_LINENUMBER (IDM_VIEW + 12) + //#define IDM_VIEW_SYMBOLMARGIN (IDM_VIEW + 13) + //#define IDM_VIEW_FOLDERMARGIN (IDM_VIEW + 14) + //#define IDM_VIEW_FOLDERMARGIN_SIMPLE (IDM_VIEW + 15) + //#define IDM_VIEW_FOLDERMARGIN_ARROW (IDM_VIEW + 16) + //#define IDM_VIEW_FOLDERMARGIN_CIRCLE (IDM_VIEW + 17) + //#define IDM_VIEW_FOLDERMARGIN_BOX (IDM_VIEW + 18) #define IDM_VIEW_ALL_CHARACTERS (IDM_VIEW + 19) #define IDM_VIEW_INDENT_GUIDE (IDM_VIEW + 20) - #define IDM_VIEW_CURLINE_HILITING (IDM_VIEW + 21) + //#define IDM_VIEW_CURLINE_HILITING (IDM_VIEW + 21) #define IDM_VIEW_WRAP (IDM_VIEW + 22) #define IDM_VIEW_ZOOMIN (IDM_VIEW + 23) #define IDM_VIEW_ZOOMOUT (IDM_VIEW + 24) #define IDM_VIEW_TAB_SPACE (IDM_VIEW + 25) #define IDM_VIEW_EOL (IDM_VIEW + 26) - #define IDM_VIEW_TOOLBAR_REDUCE_SET2 (IDM_VIEW + 27) - #define IDM_VIEW_TOOLBAR_ENLARGE_SET2 (IDM_VIEW + 28) - #define IDM_VIEW_TOGGLE_UNFOLDALL (IDM_VIEW + 29) + //#define IDM_VIEW_TOOLBAR_REDUCE_SET2 (IDM_VIEW + 27) + //#define IDM_VIEW_TOOLBAR_ENLARGE_SET2 (IDM_VIEW + 28) + #define IDM_VIEW_UNFOLDALL (IDM_VIEW + 29) #define IDM_VIEW_FOLD_CURRENT (IDM_VIEW + 30) #define IDM_VIEW_UNFOLD_CURRENT (IDM_VIEW + 31) #define IDM_VIEW_FULLSCREENTOGGLE (IDM_VIEW + 32) @@ -286,17 +315,17 @@ #define IDM_VIEW_SYNSCROLLV (IDM_VIEW + 35) #define IDM_VIEW_SYNSCROLLH (IDM_VIEW + 36) //#define IDM_VIEW_EDGENONE (IDM_VIEW + 37) - #define IDM_VIEW_DRAWTABBAR_CLOSEBOTTUN (IDM_VIEW + 38) - #define IDM_VIEW_DRAWTABBAR_DBCLK2CLOSE (IDM_VIEW + 39) - #define IDM_VIEW_REFRESHTABAR (IDM_VIEW + 40) + //#define IDM_VIEW_DRAWTABBAR_CLOSEBOTTUN (IDM_VIEW + 38) + //#define IDM_VIEW_DRAWTABBAR_DBCLK2CLOSE (IDM_VIEW + 39) + //#define IDM_VIEW_REFRESHTABAR (IDM_VIEW + 40) #define IDM_VIEW_WRAP_SYMBOL (IDM_VIEW + 41) #define IDM_VIEW_HIDELINES (IDM_VIEW + 42) - #define IDM_VIEW_DRAWTABBAR_VERTICAL (IDM_VIEW + 43) - #define IDM_VIEW_DRAWTABBAR_MULTILINE (IDM_VIEW + 44) - #define IDM_VIEW_DOCCHANGEMARGIN (IDM_VIEW + 45) - #define IDM_VIEW_LWDEF (IDM_VIEW + 46) - #define IDM_VIEW_LWALIGN (IDM_VIEW + 47) - #define IDM_VIEW_LWINDENT (IDM_VIEW + 48) + //#define IDM_VIEW_DRAWTABBAR_VERTICAL (IDM_VIEW + 43) + //#define IDM_VIEW_DRAWTABBAR_MULTILINE (IDM_VIEW + 44) + //#define IDM_VIEW_DOCCHANGEMARGIN (IDM_VIEW + 45) + //#define IDM_VIEW_LWDEF (IDM_VIEW + 46) + //#define IDM_VIEW_LWALIGN (IDM_VIEW + 47) + #define IDM_PINTAB (IDM_VIEW + 48) #define IDM_VIEW_SUMMARY (IDM_VIEW + 49) #define IDM_VIEW_FOLD (IDM_VIEW + 50) @@ -319,7 +348,7 @@ #define IDM_VIEW_UNFOLD_7 (IDM_VIEW_UNFOLD + 7) #define IDM_VIEW_UNFOLD_8 (IDM_VIEW_UNFOLD + 8) - #define IDM_VIEW_FILESWITCHER_PANEL (IDM_VIEW + 70) + #define IDM_VIEW_DOCLIST (IDM_VIEW + 70) #define IDM_VIEW_SWITCHTO_OTHER_VIEW (IDM_VIEW + 72) #define IDM_EXPORT_FUNC_LIST_AND_QUIT (IDM_VIEW + 73) @@ -356,12 +385,26 @@ #define IDM_VIEW_SWITCHTO_PROJECT_PANEL_3 (IDM_VIEW + 106) #define IDM_VIEW_SWITCHTO_FILEBROWSER (IDM_VIEW + 107) #define IDM_VIEW_SWITCHTO_FUNC_LIST (IDM_VIEW + 108) + #define IDM_VIEW_SWITCHTO_DOCLIST (IDM_VIEW + 109) + + #define IDM_VIEW_TAB_COLOUR_NONE (IDM_VIEW + 110) + #define IDM_VIEW_TAB_COLOUR_1 (IDM_VIEW + 111) + #define IDM_VIEW_TAB_COLOUR_2 (IDM_VIEW + 112) + #define IDM_VIEW_TAB_COLOUR_3 (IDM_VIEW + 113) + #define IDM_VIEW_TAB_COLOUR_4 (IDM_VIEW + 114) + #define IDM_VIEW_TAB_COLOUR_5 (IDM_VIEW + 115) + #define IDM_VIEW_TAB_START (IDM_VIEW + 116) + #define IDM_VIEW_TAB_END (IDM_VIEW + 117) + + #define IDM_VIEW_NPC (IDM_VIEW + 130) + #define IDM_VIEW_NPC_CCUNIEOL (IDM_VIEW + 131) #define IDM_VIEW_GOTO_ANOTHER_VIEW 10001 #define IDM_VIEW_CLONE_TO_ANOTHER_VIEW 10002 #define IDM_VIEW_GOTO_NEW_INSTANCE 10003 #define IDM_VIEW_LOAD_IN_NEW_INSTANCE 10004 - + #define IDM_VIEW_GOTO_START 10005 + #define IDM_VIEW_GOTO_END 10006 #define IDM_FORMAT (IDM + 5000) #define IDM_FORMAT_TODOS (IDM_FORMAT + 1) @@ -430,7 +473,6 @@ #define IDM_FORMAT_KOI8R_CYRILLIC (IDM_FORMAT_ENCODE + 48) #define IDM_FORMAT_ENCODE_END IDM_FORMAT_KOI8R_CYRILLIC - //#define IDM_FORMAT_CONVERT 200 #define IDM_LANG (IDM + 6000) #define IDM_LANGSTYLE_CONFIG_DLG (IDM_LANG + 1) @@ -516,14 +558,25 @@ #define IDM_LANG_SPICE (IDM_LANG + 81) #define IDM_LANG_TXT2TAGS (IDM_LANG + 82) #define IDM_LANG_VISUALPROLOG (IDM_LANG + 83) + #define IDM_LANG_TYPESCRIPT (IDM_LANG + 84) + #define IDM_LANG_JSON5 (IDM_LANG + 85) + #define IDM_LANG_MSSQL (IDM_LANG + 86) + #define IDM_LANG_GDSCRIPT (IDM_LANG + 87) + #define IDM_LANG_HOLLYWOOD (IDM_LANG + 88) + #define IDM_LANG_GOLANG (IDM_LANG + 89) + #define IDM_LANG_RAKU (IDM_LANG + 90) + #define IDM_LANG_TOML (IDM_LANG + 91) + #define IDM_LANG_SAS (IDM_LANG + 92) + #define IDM_LANG_ERRORLIST (IDM_LANG + 93) #define IDM_LANG_EXTERNAL (IDM_LANG + 165) #define IDM_LANG_EXTERNAL_LIMIT (IDM_LANG + 179) #define IDM_LANG_USER (IDM_LANG + 180) //46180: Used for translation - #define IDM_LANG_USER_LIMIT (IDM_LANG + 210) //46210: Ajust with IDM_LANG_USER + #define IDM_LANG_USER_LIMIT (IDM_LANG + 210) //46210: Adjust with IDM_LANG_USER #define IDM_LANG_USER_DLG (IDM_LANG + 250) //46250: Used for translation #define IDM_LANG_OPENUDLDIR (IDM_LANG + 300) + #define IDM_LANG_UDLCOLLECTION_PROJECT_SITE (IDM_LANG + 301) @@ -534,7 +587,7 @@ #define IDM_FORUM (IDM_ABOUT + 4) //#define IDM_PLUGINSHOME (IDM_ABOUT + 5) #define IDM_UPDATE_NPP (IDM_ABOUT + 6) - #define IDM_WIKIFAQ (IDM_ABOUT + 7) + //#define IDM_WIKIFAQ (IDM_ABOUT + 7) //#define IDM_HELP (IDM_ABOUT + 8) #define IDM_CONFUPDATERPROXY (IDM_ABOUT + 9) #define IDM_CMDLINEARGUMENTS (IDM_ABOUT + 10) @@ -543,12 +596,12 @@ #define IDM_SETTING (IDM + 8000) -// #define IDM_SETTING_TAB_SIZE (IDM_SETTING + 1) -// #define IDM_SETTING_TAB_REPLCESPACE (IDM_SETTING + 2) -// #define IDM_SETTING_HISTORY_SIZE (IDM_SETTING + 3) -// #define IDM_SETTING_EDGE_SIZE (IDM_SETTING + 4) +// #define IDM_SETTING_TAB_SIZE (IDM_SETTING + 1) +// #define IDM_SETTING_TAB_REPLACESPACE (IDM_SETTING + 2) +// #define IDM_SETTING_HISTORY_SIZE (IDM_SETTING + 3) +// #define IDM_SETTING_EDGE_SIZE (IDM_SETTING + 4) #define IDM_SETTING_IMPORTPLUGIN (IDM_SETTING + 5) - #define IDM_SETTING_IMPORTSTYLETHEMS (IDM_SETTING + 6) + #define IDM_SETTING_IMPORTSTYLETHEMES (IDM_SETTING + 6) #define IDM_SETTING_TRAYICON (IDM_SETTING + 8) #define IDM_SETTING_SHORTCUT_MAPPER (IDM_SETTING + 9) #define IDM_SETTING_REMEMBER_LAST_SESSION (IDM_SETTING + 10) @@ -566,6 +619,12 @@ #define IDM_TOOL_SHA256_GENERATE (IDM_TOOL + 4) #define IDM_TOOL_SHA256_GENERATEFROMFILE (IDM_TOOL + 5) #define IDM_TOOL_SHA256_GENERATEINTOCLIPBOARD (IDM_TOOL + 6) + #define IDM_TOOL_SHA1_GENERATE (IDM_TOOL + 7) + #define IDM_TOOL_SHA1_GENERATEFROMFILE (IDM_TOOL + 8) + #define IDM_TOOL_SHA1_GENERATEINTOCLIPBOARD (IDM_TOOL + 9) + #define IDM_TOOL_SHA512_GENERATE (IDM_TOOL + 10) + #define IDM_TOOL_SHA512_GENERATEFROMFILE (IDM_TOOL + 11) + #define IDM_TOOL_SHA512_GENERATEINTOCLIPBOARD (IDM_TOOL + 12) #define IDM_EXECUTE (IDM + 9000) @@ -575,3 +634,24 @@ #define IDM_SYSTRAYPOPUP_NEW_AND_PASTE (IDM_SYSTRAYPOPUP + 3) #define IDM_SYSTRAYPOPUP_OPENFILE (IDM_SYSTRAYPOPUP + 4) #define IDM_SYSTRAYPOPUP_CLOSE (IDM_SYSTRAYPOPUP + 5) + +#define IDR_WINDOWS_MENU 11000 + #define IDM_WINDOW_WINDOWS (IDR_WINDOWS_MENU + 1) + #define IDM_WINDOW_SORT_FN_ASC (IDR_WINDOWS_MENU + 2) + #define IDM_WINDOW_SORT_FN_DSC (IDR_WINDOWS_MENU + 3) + #define IDM_WINDOW_SORT_FP_ASC (IDR_WINDOWS_MENU + 4) + #define IDM_WINDOW_SORT_FP_DSC (IDR_WINDOWS_MENU + 5) + #define IDM_WINDOW_SORT_FT_ASC (IDR_WINDOWS_MENU + 6) + #define IDM_WINDOW_SORT_FT_DSC (IDR_WINDOWS_MENU + 7) + #define IDM_WINDOW_SORT_FS_ASC (IDR_WINDOWS_MENU + 8) + #define IDM_WINDOW_SORT_FS_DSC (IDR_WINDOWS_MENU + 9) + #define IDM_WINDOW_SORT_FD_ASC (IDR_WINDOWS_MENU + 10) + #define IDM_WINDOW_SORT_FD_DSC (IDR_WINDOWS_MENU + 11) + #define IDM_WINDOW_MRU_FIRST (IDR_WINDOWS_MENU + 20) + #define IDM_WINDOW_MRU_LIMIT (IDR_WINDOWS_MENU + 59) + #define IDM_WINDOW_COPY_NAME (IDM_WINDOW_MRU_LIMIT + 1) + #define IDM_WINDOW_COPY_PATH (IDM_WINDOW_MRU_LIMIT + 2) + +#define IDR_DROPLIST_MENU 14000 + #define IDM_DROPLIST_LIST (IDR_DROPLIST_MENU + 1) + #define IDM_DROPLIST_MRU_FIRST (IDR_DROPLIST_MENU + 20) diff --git a/NppExec/doc/NppExec/NppExec_Manual.chm b/NppExec/doc/NppExec/NppExec_Manual.chm deleted file mode 100644 index a9b5d5d..0000000 Binary files a/NppExec/doc/NppExec/NppExec_Manual.chm and /dev/null differ diff --git a/NppExec/doc/NppExec/NppExec_Manual/2.4.html b/NppExec/doc/NppExec/NppExec_Manual/2.4.html deleted file mode 100644 index b50ddf0..0000000 --- a/NppExec/doc/NppExec/NppExec_Manual/2.4.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - -2.4. Using several copies of NppExec - - -

2.4. Using several copies of NppExec

-

You can have several copies of "NppExec.dll" in - your Notepad++'es Plugins subfolder in order to have several NppExec's Console - windows. Each copy of NppExec saves its own options and its own console commands - history (if it is enabled in NppExec's options). In the same time, saved -NppExec's scripts are shared between several copies of NppExec.

-

To have several copies of "NppExec.dll", just copy it with different name(s), for example, "NppExec2.dll", "NppExecCpp.dll", "NppExecWeb.dll" and so on. This will give you additional NppExec's Console windows with the corresponding titles: "Console2", "ConsoleCpp", "ConsoleWeb" and -so on.

- - diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.7.html b/NppExec/doc/NppExec/NppExec_Manual/3.7.html deleted file mode 100644 index 81e33ad..0000000 --- a/NppExec/doc/NppExec/NppExec_Manual/3.7.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - -3.7. NppExec's script - - -

3.7. NppExec's script

-

NppExec's script is a set of NppExec's - commands. NppExec's command can be an internal command such as "cls", "npp_save", "npe_debuglog" etc. or it can be a (path)name of an executable such as "cmd", "calc", "C:\tools\tcc\tcc.exe" etc. - Each command, depending on its meaning, can have one or more parameters. -For example:

-
-
INPUTBOX "Input something:" : something
-NPP_EXEC "script name" "param 1" "param 2"
-cmd /c copy /?
-"C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)"
-
-

and - so on. You can use "//" to comment a whole line or right part of a line (after "//"):

-
-
// this is a comment
-ECHO You'll see this // but not this (comment)
-
-

You - can create and save NppExec's scripts using the "Execute NppExec Script..." dialog [3.6]. However, NppExec's script can also be located in a text file. I.e. you can create a text file which contains some NppExec's commands (one command per one line) and then execute this file (commands from this file) in NppExec. Such text file can be an ANSI file for ANSI version of NppExec and can be an ANSI or Unicode (UCS-2 LE/UCS-2 BE/UTF-8) file for Unicode version of NppExec. Note that Unicode text file must contain leading "BOM" bytes to be recognized by Unicode version of NppExec (by default, these bytes are present - until you force saving without "BOM"). To execute NppExec's script from a text file, use the "npp_exec" command. - This command allows to execute commands from a previously saved (internal) - script or from an (external) text file.

-

As you can store your NppExec's script in a text file, you can edit such file - directly in Notepad++ and execute it with the following command(s):

-
-
NPP_SAVE  // save current file (NppExec's script)...
-NPP_EXEC "$(FULL_CURRENT_PATH)"  // ...and execute it
-
-

With the Console Commands History enabled, you can type this command:

-
-
NPP_EXEC "$(FULL_CURRENT_PATH)"
-
-

in NppExec's Console once, then use the Arrow Up key to repeat this command. However, be sure to save current file (with Ctrl+S) before executing it.

-

To create a menu item for NppExec's script, use NppExec's Advanced Options dialog. Then a shortcut key can be assigned to it: -

    -
  1. Create a menu item for the script using Plugins -> NppExec -> Advanced options (select a script in the "Associated script" drop-down list, specify its menu item name - by default it's the same as the script name - and press the "Add/Modify" button).
  2. -
  3. Restart Notepad++ to get this new menu item.
  4. -
  5. Assign a shortcut key to this new menu item using Notepad++'es Settings -> Shortcut Mapper -> Plugin commands (you'll find the menu item there).
  6. -
-

-

NppExec stores your scripts in Notepad++'es "$(PLUGINS_CONFIG_DIR)" folder. The "npes_saved.txt" file stores all the scripts except the temporary one which is stored inside "npes_temp.txt".

-

See also: "Execute NppExec Script..." [3.6]; Run-time parameters [4.3].

-

 

- - diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.6.4.html b/NppExec/doc/NppExec/NppExec_Manual/4.6.4.html deleted file mode 100644 index 61aeec4..0000000 --- a/NppExec/doc/NppExec/NppExec_Manual/4.6.4.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - -4.6.4. Running Python & wxPython - - -

4.6.4. Running Python & wxPython

- -

1. Interactive Python inside NppExec

-

Running "python -?" gives the following help information, in particular:

-
    -
  • -i : inspect interactively after running script, (also PYTHONINSPECT=x) and force prompts, even if stdin does not appear to be a terminal
  • -
  • -u : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x) see man page for details on internal buffering relating to '-u'
  • -
-

The text in italic exactly refers to what is stated in NppExec's Manual, sections 1.3 and 3.1 by "NppExec is not a console emulator".

-

So, by running "python -i -u" in NppExec's Console, you get the interactive Python inside Notepad++.

-

Here is an advanced example of NppExec's script to be used to test a Python's program interactively:

-
-
npp_console local -  // disable any output to the Console
-npp_save  // save current file (a .py file is expected)
-cd "$(CURRENT_DIRECTORY)"  // use the current file's dir
-set local @exit_cmd_silent = exit()  // allows to exit Python automatically
-env_set local PATH = $(SYS.PATH);C:\Python27  // use Python 2.7
-npp_setfocus con  // set the focus to the Console
-npp_console local +  // enable output to the Console
-python -i -u "$(FILE_NAME)"  // run Python's program interactively
-
-
-
-
 
-
- -

2. Python and UTF-8

-

If your python's program contains some non-ASCII characters, you can get the following error from Python: "SyntaxError: Non-ASCII character".

-

To be able to represent such non-ASCII characters correctly on any system, -such source file should be saved as UTF-8 (either without BOM or with BOM). -Though the error mentioned above still remains. -To avoid this error, acccording to http://www.python.org/dev/peps/pep-0263/ , -you just need to specify

-
-
# coding=utf-8
-
-

or

-
-
# -*- coding: utf-8 -*-
-
-

at the beginning of your python's program.

-

Another thing is to output something to console as UTF-8.

-

In this case, you can get something similar from Python: "UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-2: character maps to <undefined>".

-

To fix this last one, it's enough to specify the environment variable PYTHONIOENCODING by setting it to "utf-8". I.e.

-
-
// within NppExec
-env_set PYTHONIOENCODING=utf-8
-python my_program.py
-
-
-
 
-
- -

3. Running Python scripts using wxPython

-

[the text below has been originally posted by cioma in NppExec's forum]

-

[ cioma: ]

-
-

I use NPP as an IDE for Python. And I use NppExec to run scripts directly from NPP, highlight script syntax and runtime errors (if any) and link errors to a line of code.

-

Some time ago I started using wxPython GUI library and faced problems with running such scripts from within NppExec.

-

If I run this (in NppExec prompt):

-
-
python -t -B -u "$(FULL_CURRENT_PATH)" 
-
-

...then GUI part of wxPython is not shown. I guess the reason is that wxPython requires a "real" console buffer and NppExec doesn't provide that.

-

If I just run script over NPP "Run" dialog (no NppExec) then GUI is shown but if there are errors there is no way to easily relate them to line of code in NPP.

-

So I found this solution to work:

-

1. When creating wxPython application in the script make sure it's STDOUT is not redirected:

-
-
app = App(redirect=False) 
-
-

2. Run in NppExec:

-
-
cmd /C python -t -B -u "$(FULL_CURRENT_PATH)" 
-
-

Voila! We have both wxPython GUI running and its STDOUT redirected to NppExec.

-
-

[ DV: ]

-
-

Just one thing. For more details regarding runtime errors parsing (keyword: Highlight filters), refer to [4.7.4] and "help con_filter".

-
- - diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.6.8.html b/NppExec/doc/NppExec/NppExec_Manual/4.6.8.html deleted file mode 100644 index 3166b57..0000000 --- a/NppExec/doc/NppExec/NppExec_Manual/4.6.8.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - -4.6.8. Clipboard, keysrokes and much more - - -

4.6.8. Clipboard, keysrokes and much more

- -

You can always extend NppExec's functionality by using different external tools.

-

For example:

-
    -
  • NirCmd (http://www.nirsoft.net) allows to work with the clipboard, send keystrokes to the system, modify the Registry and ini-files - and much more;
  • -
  • Swiss File Knife (http://sourceforge.net/projects/swissfileknife/) allows various operations on text and binary files;
  • -
  • wget (http://gnuwin32.sourceforge.net/packages/wget.htm) allows to download from the network;
  • -
  • winapiexec (http://rammichael.com/winapiexec) allows to run WinAPI functions through command line parameters.
  • -
-

The list of such useful programs can go on and on - and the main idea here is the ability of "communication" between these programs and NppExec. As you can use different tools with different parameters and then retrieve and process the produced output, there theoretically is no limit of what you can achieve by this approach. This reminds us the section [3.1]: "So, generally speaking, NppExec is a tool" - and what this tool can do for you depends on how you use it. So use it wisely :)

- - - diff --git a/NppExec/doc/NppExec/NppExec_Manual/Questions_suggestions.html b/NppExec/doc/NppExec/NppExec_Manual/Questions_suggestions.html deleted file mode 100644 index 5da5a64..0000000 --- a/NppExec/doc/NppExec/NppExec_Manual/Questions_suggestions.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - -Questions/suggestions? - - -

Questions/suggestions?

-

Did not find an answer for your question? You can try the following:

-
    -
  1. Read - this manual once again ;)
  2. -
  3. Visit - https://sourceforge.net/projects/npp-plugins/ and search NppExec's forum - for the answer or ask your question there.
  4. -
-

Have a suggestion? Visit NppExec's forum and let me know.

- - diff --git a/NppExec/doc/NppExec/NppExec_Manual/style.css b/NppExec/doc/NppExec/NppExec_Manual/style.css deleted file mode 100644 index 459b130..0000000 --- a/NppExec/doc/NppExec/NppExec_Manual/style.css +++ /dev/null @@ -1,23 +0,0 @@ -h1 { - font-family: Arial, Helvetica, sans-serif; -} - -h3 { - font-family: Arial, Helvetica, sans-serif; -} - -li { - font-family: Arial, Helvetica, sans-serif; -} - -p { - font-family: Arial, Helvetica, sans-serif; -} - -td { - font-family: Arial, Helvetica, sans-serif; -} - -pre { - font-family: "Courier New", Courier, mono; -} diff --git a/NppExec/src/CAnyRichEdit.cpp b/NppExec/src/CAnyRichEdit.cpp index 9b0cbd6..2f3c48f 100644 --- a/NppExec/src/CAnyRichEdit.cpp +++ b/NppExec/src/CAnyRichEdit.cpp @@ -212,6 +212,11 @@ INT CAnyRichEdit::GetTextLengthEx() const return (INT) SendMsg(EM_GETTEXTLENGTHEX, (WPARAM) >le, 0); } +BOOL CAnyRichEdit::IsEmpty() const +{ + return (GetTextLengthEx() == 0); +} + INT CAnyRichEdit::LineFromChar(INT nCharacterIndex) const { return ((INT) SendMsg(EM_LINEFROMCHAR, (WPARAM) nCharacterIndex, 0)); diff --git a/NppExec/src/CAnyRichEdit.h b/NppExec/src/CAnyRichEdit.h index 65726a8..a67a7e6 100644 --- a/NppExec/src/CAnyRichEdit.h +++ b/NppExec/src/CAnyRichEdit.h @@ -57,6 +57,7 @@ class CAnyRichEdit : public CAnyWindow { INT GetSelPos(INT* pnStartPos = NULL, INT* pnEndPos = NULL) const; INT GetTextAt(INT nPos, INT nLen, TCHAR* lpText) const; INT GetTextLengthEx() const; + BOOL IsEmpty() const; INT LineFromChar(INT nCharacterIndex) const; INT LineIndex(INT nLineNumber) const; INT LineLength(INT nCharacterIndex) const; diff --git a/NppExec/src/CAnyWindow.cpp b/NppExec/src/CAnyWindow.cpp index b7e2e72..be9fd1f 100644 --- a/NppExec/src/CAnyWindow.cpp +++ b/NppExec/src/CAnyWindow.cpp @@ -18,9 +18,8 @@ along with this program. If not, see . #include "CAnyWindow.h" -CAnyWindow::CAnyWindow() +CAnyWindow::CAnyWindow() : m_hWnd(NULL) { - m_hWnd = NULL; } CAnyWindow::~CAnyWindow() diff --git a/NppExec/src/CAnyWindow.h b/NppExec/src/CAnyWindow.h index a2292c1..c4ee95b 100644 --- a/NppExec/src/CAnyWindow.h +++ b/NppExec/src/CAnyWindow.h @@ -32,6 +32,7 @@ class CAnyWindow { CAnyWindow(); ~CAnyWindow(); + HWND GetWindowHandle() { return m_hWnd; } BOOL BringWindowToTop(); BOOL CenterWindow(HWND hParentWnd, BOOL bRepaint = FALSE); BOOL EnableWindow(BOOL bEnable = TRUE); diff --git a/NppExec/src/CFileModificationChecker.cpp b/NppExec/src/CFileModificationChecker.cpp index a52e42e..852abbf 100644 --- a/NppExec/src/CFileModificationChecker.cpp +++ b/NppExec/src/CFileModificationChecker.cpp @@ -17,106 +17,256 @@ along with this program. If not, see . */ #include "CFileModificationChecker.h" +#include "NppExecHelpers.h" -CFileModificationChecker::CFileModificationChecker() : - m_bTimeIsValid(FALSE), m_bSizeIsValid(FALSE) + +namespace { + tstr getFileDir(LPCTSTR cszFilePath, LPCTSTR* ppFileName = nullptr) + { + tstr sDir = cszFilePath; + int nPos = sDir.RFindOneOf(_T("\\/")); + if ( nPos != -1 ) + { + sDir.SetSize(nPos); + if ( ppFileName ) + *ppFileName = cszFilePath + nPos + 1; + } + else + { + sDir = _T("."); + if ( ppFileName ) + *ppFileName = cszFilePath; + } + + return sDir; + } } -CFileModificationChecker::~CFileModificationChecker() + +// CDirectoryWatcher +CDirectoryWatcher::CDirectoryWatcher() { + m_hStopWatchThreadEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); + m_hWatchThreadDoneEvent = ::CreateEvent(NULL, TRUE, TRUE, NULL); + m_isWatchThreadStarted = false; } -BOOL CFileModificationChecker::getFileTime(HANDLE hFile, FILETIME* lpLastWriteTime) +CDirectoryWatcher::~CDirectoryWatcher() { - return ::GetFileTime(hFile, NULL, NULL, lpLastWriteTime); + StopWatching(); + ::CloseHandle(m_hWatchThreadDoneEvent); + ::CloseHandle(m_hStopWatchThreadEvent); } -DWORD CFileModificationChecker::getFileSize(HANDLE hFile) +DWORD WINAPI CDirectoryWatcher::WatchThreadProc(LPVOID lpParam) { - return ::GetFileSize(hFile, NULL); + CDirectoryWatcher* pDirWatcher = (CDirectoryWatcher *) lpParam; + + ::ResetEvent(pDirWatcher->m_hWatchThreadDoneEvent); + + const DWORD nObjs = static_cast(pDirWatcher->m_Dirs.size()) + 1; + std::unique_ptr hWaitObjs(new HANDLE[nObjs]); + + hWaitObjs[0] = pDirWatcher->m_hStopWatchThreadEvent; + + DWORD i = 1; + for ( const auto& pDir : pDirWatcher->m_Dirs ) + { + hWaitObjs[i] = ::FindFirstChangeNotification(pDir->sDirectory.c_str(), pDir->bRecursive, pDir->dwNotifyFilter); + ++i; + } + + for ( ; ; ) + { + DWORD dwWaitStatus = ::WaitForMultipleObjects(nObjs, hWaitObjs.get(), FALSE, INFINITE); + + if ( dwWaitStatus == WAIT_OBJECT_0 ) // m_hStopWatchThreadEvent + break; + + if ( (dwWaitStatus > WAIT_OBJECT_0) && (dwWaitStatus < WAIT_OBJECT_0 + nObjs) ) + { + i = dwWaitStatus - WAIT_OBJECT_0; + auto& pDir = pDirWatcher->m_Dirs[i - 1]; + if ( pDir->pChangeListener ) + { + pDir->pChangeListener->HandleDirectoryChange(pDir.get()); + } + + HANDLE hChange = hWaitObjs[i]; + ::FindNextChangeNotification(hChange); + } + } + + for ( i = 1; i < nObjs; ++i ) + { + HANDLE hChange = hWaitObjs[i]; + ::FindCloseChangeNotification(hChange); + } + + ::SetEvent(pDirWatcher->m_hWatchThreadDoneEvent); + return 0; } -HANDLE CFileModificationChecker::openTheFile() +CDirectoryWatcher::dir_items_type::iterator CDirectoryWatcher::findDir(const tstr& sDirectory) { - HANDLE hFile = ::CreateFile( m_path.c_str(), GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); - return ( (hFile != INVALID_HANDLE_VALUE) ? hFile : NULL ); + auto itrEnd = m_Dirs.end(); + for ( auto itr = m_Dirs.begin(); itr != itrEnd; ++itr ) + { + const auto& pDir = *itr; + if ( pDir->sDirectory == sDirectory ) + return itr; + } + return itrEnd; } -BOOL CFileModificationChecker::AssignFile(const TCHAR* cszFilePathName) +void CDirectoryWatcher::AddDir(LPCTSTR cszDirectory, IDirectoryChangeListener* pChangeListener, DWORD dwNotifyFilter, BOOL bRecursive) { - m_path = cszFilePathName; - return UpdateFileInfo(); + if ( findDir(cszDirectory) == m_Dirs.end() ) + { + m_Dirs.push_back( std::make_unique(this, pChangeListener, dwNotifyFilter, bRecursive, cszDirectory) ); + } +} + +void CDirectoryWatcher::AddFile(LPCTSTR cszFilePath, IFileChangeListener* pChangeListener, DWORD dwNotifyFilter) +{ + tstr sDir = getFileDir(cszFilePath); + + auto itr = findDir(sDir); + if ( itr == m_Dirs.end() ) + { + m_Dirs.push_back( std::make_unique(this, &m_DirChangeListener, dwNotifyFilter, FALSE, sDir.c_str()) ); + m_Dirs.back()->AddFile(pChangeListener, cszFilePath); + } + else + { + auto& pDir = *itr; + pDir->dwNotifyFilter |= dwNotifyFilter; + pDir->AddFile(pChangeListener, cszFilePath); + } } -long CFileModificationChecker::IsFileSizeChanged(DWORD dwFileSize) +void CDirectoryWatcher::StartWatching() { - if ( !m_bSizeIsValid ) - m_dwFileSize = 0; - return ((long) m_dwFileSize) - ((long) dwFileSize); + if ( m_isWatchThreadStarted ) + return; + + ::ResetEvent(m_hStopWatchThreadEvent); + if ( NppExecHelpers::CreateNewThread(WatchThreadProc, this) ) + { + m_isWatchThreadStarted = true; + } } -long CFileModificationChecker::IsFileTimeChanged(const FILETIME* lpFileTime) +void CDirectoryWatcher::StopWatching() { - if ( !m_bTimeIsValid ) - return -1; - return ::CompareFileTime( &m_modificationTime, lpFileTime ); + ::SetEvent(m_hStopWatchThreadEvent); + ::WaitForSingleObject(m_hWatchThreadDoneEvent, INFINITE); + m_isWatchThreadStarted = false; } -BOOL CFileModificationChecker::RequestFileTime(FILETIME* lpLastWriteTime) +void CDirectoryWatcher::CInternalDirectoryChangeListener::HandleDirectoryChange(const DirWatchStruct* pDir) { - BOOL bResult = FALSE; - if ( lpLastWriteTime ) + for ( auto& pFile : pDir->Files ) { - HANDLE hFile = openTheFile(); - if ( hFile ) + FileInfoStruct fileNow(pFile->pChangeListener, pFile->filePath); + + if ( !pFile->HasEqualSizeAndTime(fileNow) ) { - bResult = getFileTime(hFile, lpLastWriteTime); - ::CloseHandle(hFile); + pFile->CopySizeAndTime(fileNow); + if ( pFile->pChangeListener ) + { + pFile->pChangeListener->HandleFileChange(pFile.get()); + } } } - return bResult; } -BOOL CFileModificationChecker::RequestFileSize(DWORD* lpdwSize) + +// CFileModificationWatcher +void CFileModificationWatcher::AddFile(LPCTSTR cszFilePath, IFileChangeListener* pChangeListener) +{ + m_DirWatcher.AddFile(cszFilePath, pChangeListener, FILE_NOTIFY_CHANGE_LAST_WRITE); +} + +void CFileModificationWatcher::StartWatching() +{ + m_DirWatcher.StartWatching(); +} + +void CFileModificationWatcher::StopWatching() +{ + m_DirWatcher.StopWatching(); +} + + +// FileInfoStruct +FileInfoStruct::FileInfoStruct(IFileChangeListener* pChangeListener_, const tstr& filePath_) : + pChangeListener(pChangeListener_), filePath(filePath_) +{ + GetFileSizeAndTime(filePath.c_str(), &fileSize, &fileLastWriteTime); +} + +BOOL FileInfoStruct::GetFileSizeAndTime(LPCTSTR cszFilePath, LARGE_INTEGER* pliSize, FILETIME* pLastWriteTime) { - if ( lpdwSize ) + ::ZeroMemory(pliSize, sizeof(LARGE_INTEGER)); + ::ZeroMemory(pLastWriteTime, sizeof(FILETIME)); + + BOOL bResult = FALSE; + HANDLE hFile = ::CreateFile( cszFilePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); + + if ( hFile != INVALID_HANDLE_VALUE) { - HANDLE hFile = openTheFile(); - if ( hFile ) - { - *lpdwSize = getFileSize(hFile); - ::CloseHandle(hFile); - return TRUE; - } + if ( ::GetFileSizeEx(hFile, pliSize) ) + bResult = TRUE; + + if ( !::GetFileTime(hFile, NULL, NULL, pLastWriteTime) ) + bResult = FALSE; + + ::CloseHandle(hFile); } - return FALSE; + + return bResult; } -void CFileModificationChecker::SetTime(const FILETIME* lpFileTime) +bool FileInfoStruct::HasEqualSizeAndTime(const FileInfoStruct& other) const { - ::CopyMemory( &m_modificationTime, lpFileTime, sizeof(FILETIME) ); - m_bTimeIsValid = TRUE; + return ( fileSize.LowPart == other.fileSize.LowPart && + fileSize.HighPart == other.fileSize.HighPart && + ::CompareFileTime(&fileLastWriteTime, &other.fileLastWriteTime) == 0 ); } -void CFileModificationChecker::SetSize(DWORD dwFileSize) +void FileInfoStruct::CopySizeAndTime(const FileInfoStruct& other) { - m_dwFileSize = dwFileSize; - m_bSizeIsValid = TRUE; + ::CopyMemory(&fileSize, &other.fileSize, sizeof(fileSize)); + ::CopyMemory(&fileLastWriteTime, &other.fileLastWriteTime, sizeof(fileLastWriteTime)); } -BOOL CFileModificationChecker::UpdateFileInfo() + +// DirWatchStruct +DirWatchStruct::DirWatchStruct(CDirectoryWatcher* pDirWatcher_, IDirectoryChangeListener* pChangeListener_, + DWORD dwNotifyFilter_, BOOL bRecursive_, const tstr& sDirectory_) : + pDirWatcher(pDirWatcher_), pChangeListener(pChangeListener_), + dwNotifyFilter(dwNotifyFilter_), bRecursive(bRecursive_), sDirectory(sDirectory_) { - HANDLE hFile = openTheFile(); - if ( hFile ) +} + +void DirWatchStruct::AddFile(IFileChangeListener* pChangeListener_, const tstr& sFilePath) +{ + if ( findFile(sFilePath) == Files.end() ) { - m_bTimeIsValid = getFileTime(hFile, &m_modificationTime); - m_dwFileSize = getFileSize(hFile); - m_bSizeIsValid = TRUE; - ::CloseHandle(hFile); - return m_bTimeIsValid; + Files.push_back( std::make_unique(pChangeListener_, sFilePath) ); } - return FALSE; } +DirWatchStruct::file_items_type::iterator DirWatchStruct::findFile(const tstr& sFilePath) +{ + auto itrEnd = Files.end(); + for ( auto itr = Files.begin(); itr != itrEnd; ++itr ) + { + const auto& pFile = *itr; + if ( pFile->filePath == sFilePath ) + return itr; + } + return itrEnd; +} diff --git a/NppExec/src/CFileModificationChecker.h b/NppExec/src/CFileModificationChecker.h index 4cca529..17e4a02 100644 --- a/NppExec/src/CFileModificationChecker.h +++ b/NppExec/src/CFileModificationChecker.h @@ -20,34 +20,112 @@ along with this program. If not, see . #define _file_modification_watcher_h_ //--------------------------------------------------------------------------- #include "base.h" -#include "NppExec.h" +#include "cpp/CStrT.h" +#include +#include -class CFileModificationChecker +struct FileInfoStruct; +struct DirWatchStruct; + +class IDirectoryChangeListener +{ +public: + IDirectoryChangeListener() { } + virtual ~IDirectoryChangeListener() { } + + virtual void HandleDirectoryChange(const DirWatchStruct* pDir) = 0; +}; + +class IFileChangeListener { +public: + IFileChangeListener() { } + virtual ~IFileChangeListener() { } + + virtual void HandleFileChange(const FileInfoStruct* pFile) = 0; +}; + +class CDirectoryWatcher +{ +public: + typedef std::vector< std::unique_ptr > dir_items_type; + typedef std::vector< std::unique_ptr > file_items_type; + +public: + CDirectoryWatcher(); + ~CDirectoryWatcher(); + + // call these methods _before_ the StartWatching() + // dwNotifyFilter: see FILE_NOTIFY_CHANGE_* notifications, e.g. FILE_NOTIFY_CHANGE_LAST_WRITE + void AddDir(LPCTSTR cszDirectory, IDirectoryChangeListener* pChangeListener, DWORD dwNotifyFilter, BOOL bRecursive); + void AddFile(LPCTSTR cszFilePath, IFileChangeListener* pChangeListener, DWORD dwNotifyFilter); + + // invoke StartWatching() _after_ all the AddDir/AddFile calls + void StartWatching(); + void StopWatching(); + private: - tstr m_path; - FILETIME m_modificationTime; - DWORD m_dwFileSize; - BOOL m_bTimeIsValid; - BOOL m_bSizeIsValid; + dir_items_type::iterator findDir(const tstr& sDirectory); + static DWORD WINAPI WatchThreadProc(LPVOID lpParam); - BOOL getFileTime(HANDLE hFile, FILETIME* lpLastWriteTime); - DWORD getFileSize(HANDLE hFile); - HANDLE openTheFile(); + class CInternalDirectoryChangeListener : public IDirectoryChangeListener + { + public: + virtual void HandleDirectoryChange(const DirWatchStruct* pDir) override; + }; +private: + HANDLE m_hStopWatchThreadEvent; + HANDLE m_hWatchThreadDoneEvent; + bool m_isWatchThreadStarted; + CInternalDirectoryChangeListener m_DirChangeListener; + dir_items_type m_Dirs; +}; + +class CFileModificationWatcher +{ public: - CFileModificationChecker(); - ~CFileModificationChecker(); - - BOOL AssignFile(const TCHAR* cszFilePathName); // assign a file - long IsFileSizeChanged(DWORD dwFileSize); // comparison - long IsFileTimeChanged(const FILETIME* lpFileTime); - BOOL RequestFileSize(DWORD* lpdwSize); // no internal update - BOOL RequestFileTime(FILETIME* lpLastWriteTime); // no internal update - void SetSize(DWORD dwFileSize); // internal update - void SetTime(const FILETIME* lpFileTime); // internal update - BOOL UpdateFileInfo(); // request & update values of file time & size - + void AddFile(LPCTSTR cszFilePath, IFileChangeListener* pChangeListener); + + void StartWatching(); + void StopWatching(); + +private: + CDirectoryWatcher m_DirWatcher; +}; + +struct FileInfoStruct +{ + IFileChangeListener* pChangeListener; + tstr filePath; + LARGE_INTEGER fileSize; + FILETIME fileLastWriteTime; + + FileInfoStruct(IFileChangeListener* pChangeListener_, const tstr& filePath_); + + static BOOL GetFileSizeAndTime(LPCTSTR cszFilePath, LARGE_INTEGER* pliSize, FILETIME* pLastWriteTime); + + bool HasEqualSizeAndTime(const FileInfoStruct& other) const; + void CopySizeAndTime(const FileInfoStruct& other); +}; + +struct DirWatchStruct +{ + typedef std::vector< std::unique_ptr > file_items_type; + + CDirectoryWatcher* pDirWatcher; + IDirectoryChangeListener* pChangeListener; + DWORD dwNotifyFilter; + BOOL bRecursive; + tstr sDirectory; + file_items_type Files; + + DirWatchStruct(CDirectoryWatcher* pDirWatcher_, IDirectoryChangeListener* pChangeListener_, + DWORD dwNotifyFilter_, BOOL bRecursive_, const tstr& sDirectory_); + + void AddFile(IFileChangeListener* pChangeListener_, const tstr& sFilePath); + + file_items_type::iterator findFile(const tstr& sFilePath); }; //--------------------------------------------------------------------------- diff --git a/NppExec/src/CPopupListBox.cpp b/NppExec/src/CPopupListBox.cpp index 8e9f1b6..298258b 100644 --- a/NppExec/src/CPopupListBox.cpp +++ b/NppExec/src/CPopupListBox.cpp @@ -21,7 +21,7 @@ along with this program. If not, see . #include "NppExecEngine.h" -const TCHAR* NpeSearchFlagsList[] = { +const TCHAR* const NpeSearchFlagsList[] = { // search flags: _T("NPE_SF_MATCHCASE"), _T("NPE_SF_WHOLEWORD"), @@ -31,15 +31,15 @@ const TCHAR* NpeSearchFlagsList[] = { _T("NPE_SF_CXX11REGEX"), _T("NPE_SF_BACKWARD"), _T("NPE_SF_NEXT"), + _T("NPE_SF_INENTIRETEXT"), _T("NPE_SF_INSELECTION"), - _T("NPE_SF_INWHOLETEXT"), _T("NPE_SF_SETPOS"), _T("NPE_SF_SETSEL"), _T("NPE_SF_REPLACEALL"), _T("NPE_SF_PRINTALL") }; -const TCHAR* VariablesList[] = { +const TCHAR* const VariablesList[] = { _T("$(#1)"), // $(#1) MACRO_EXIT_CMD, // $(@EXIT_CMD) MACRO_EXIT_CMD_SILENT, // $(@EXIT_CMD_SILENT) @@ -52,6 +52,7 @@ const TCHAR* VariablesList[] = { MACRO_CURRENT_COLUMN, // $(CURRENT_COLUMN) MACRO_FILE_DIRPATH, // $(CURRENT_DIRECTORY) MACRO_CURRENT_LINE, // $(CURRENT_LINE) + MACRO_CURRENT_LINESTR, // $(CURRENT_LINESTR) MACRO_CURRENT_WORD, // $(CURRENT_WORD) MACRO_CURRENT_WORKING_DIR, // $(CWD) MACRO_EXITCODE, // $(EXITCODE) @@ -62,6 +63,7 @@ const TCHAR* VariablesList[] = { MACRO_FILE_FULLPATH, // $(FULL_CURRENT_PATH) MACRO_INPUT, // $(INPUT) _T("$(INPUT[1])"), // $(INPUT[1]) + MACRO_IS_PROCESS, // $(IS_PROCESS) MACRO_LAST_CMD_RESULT, // $(LAST_CMD_RESULT) MACRO_LEFT_VIEW_FILE, // $(LEFT_VIEW_FILE) MACRO_MSG_LPARAM, // $(MSG_LPARAM) @@ -71,6 +73,8 @@ const TCHAR* VariablesList[] = { MACRO_NPP_DIRECTORY, // $(NPP_DIRECTORY) MACRO_NPP_FULL_FILE_PATH, // $(NPP_FULL_FILE_PATH) MACRO_NPP_HWND, // $(NPP_HWND) + MACRO_NPP_PID, // $(NPP_PID) + MACRO_NPP_SETTINGS_DIR, // $(NPP_SETTINGS_DIR) MACRO_OUTPUT, // $(OUTPUT) MACRO_OUTPUT1, // $(OUTPUT1) MACRO_OUTPUTL, // $(OUTPUTL) @@ -80,6 +84,9 @@ const TCHAR* VariablesList[] = { _T("$(RARGV[1])"), // $(RARGV[1]) MACRO_RIGHT_VIEW_FILE, // $(RIGHT_VIEW_FILE) MACRO_SCI_HWND, // $(SCI_HWND) + MACRO_SCI_HWND1, // $(SCI_HWND1) + MACRO_SCI_HWND2, // $(SCI_HWND2) + MACRO_SELECTED_TEXT, // $(SELECTED_TEXT) _T("$(SYS.PATH)"), // $(SYS.PATH) MACRO_WORKSPACE_ITEM_DIR, // $(WORKSPACE_ITEM_DIR) MACRO_WORKSPACE_ITEM_NAME, // $(WORKSPACE_ITEM_NAME) @@ -87,7 +94,11 @@ const TCHAR* VariablesList[] = { MACRO_WORKSPACE_ITEM_ROOT // $(WORKSPACE_ITEM_ROOT) }; -CPopupListBox::CPopupListBox() : CAnyListBox() +const TCHAR* const DirectivesList[] = { + DIRECTIVE_COLLATERAL +}; + +CPopupListBox::CPopupListBox() : CAnyListBox(), m_hParentWnd(NULL) { } @@ -102,19 +113,17 @@ HWND CPopupListBox::Create(HWND hParentWnd, { m_hWnd = ::CreateWindowEx(WS_EX_TOPMOST | WS_EX_CLIENTEDGE, _T("LISTBOX"), _T(""), - WS_CHILD | WS_BORDER | WS_VSCROLL | LBS_HASSTRINGS | LBS_SORT, + WS_CHILD | WS_BORDER | WS_VSCROLL | LBS_HASSTRINGS | LBS_SORT | LBS_NOTIFY, left, top, width, height, hParentWnd, NULL, NULL, NULL); - + if (m_hWnd) { - HFONT hFont; - - hFont = (HFONT) ::SendMessage(hParentWnd, WM_GETFONT, 0, 0); - ::SendMessage(m_hWnd, WM_SETFONT, (WPARAM) hFont, (LPARAM) FALSE); + HFONT hFont = (HFONT) ::SendMessage(hParentWnd, WM_GETFONT, 0, 0); + ::SendMessage(m_hWnd, WM_SETFONT, (WPARAM) hFont, (LPARAM) 0); m_hParentWnd = hParentWnd; } - + return m_hWnd; } @@ -132,7 +141,7 @@ bool CPopupListBox::FillPopupList(const TCHAR* szCurrentWord) { ShowWindow(SW_HIDE); ResetContent(); - + int nLen = (szCurrentWord == NULL) ? 0 : lstrlen(szCurrentWord); if (nLen > 0) { @@ -142,7 +151,7 @@ bool CPopupListBox::FillPopupList(const TCHAR* szCurrentWord) WordUpper = szCurrentWord; NppExecHelpers::StrUpper(WordUpper); - + if ( ((nLen >= 3) && (WordUpper.StartsWith(_T("NPP")) || WordUpper.StartsWith(_T("CON")) || @@ -169,6 +178,7 @@ bool CPopupListBox::FillPopupList(const TCHAR* szCurrentWord) continue; if (S == CScriptEngine::DoEchoCommand::Name() || + S == CScriptEngine::DoCalcEchoCommand::Name() || S == CScriptEngine::DoGoToCommand::Name() || S == CScriptEngine::DoElseCommand::Name() || S == CScriptEngine::DoEndIfCommand::Name() || @@ -207,7 +217,7 @@ bool CPopupListBox::FillPopupList(const TCHAR* szCurrentWord) const TCHAR ch = szCurrentWord[0]; if ((ch >= _T('A')) && (ch <= _T('Z'))) { - AddString(S.c_str());; // flags can be in upper case only + AddString(S.c_str()); // flags can be in upper case only } } else @@ -224,7 +234,7 @@ bool CPopupListBox::FillPopupList(const TCHAR* szCurrentWord) } return ((GetCount() > 0) ? true : false); } - + if ((nLen >= 2) && (WordUpper.StartsWith(_T("$(")))) { bExactMatch = false; @@ -250,7 +260,38 @@ bool CPopupListBox::FillPopupList(const TCHAR* szCurrentWord) } return ((GetCount() > 0) ? true : false); } - + + if ((nLen >= 2) && WordUpper.StartsWith(_T("!"))) + { + bExactMatch = false; + for (const TCHAR* const& d : DirectivesList) + { + S = d; + if (S.StartsWith(WordUpper)) + { + if (S != WordUpper) + { + const TCHAR ch = szCurrentWord[1]; + if ((ch >= _T('a')) && (ch <= _T('z'))) + { + NppExecHelpers::StrLower(S); // preserve lower case + } + AddString(S.c_str()); + } + else + { + bExactMatch = true; + break; + } + } + } + if (bExactMatch) + { + ResetContent(); + } + return ((GetCount() > 0) ? true : false); + } + } return false; } @@ -265,6 +306,49 @@ void CPopupListBox::SetParentWnd(HWND hParentWnd) m_hParentWnd = hParentWnd; } +int CPopupListBox::getRequiredWidth() +{ + int nWidth = 0; + + HDC hDC = ::GetDC(m_hWnd); + if (hDC) + { + HFONT hFont = (HFONT) ::SendMessage(m_hWnd, WM_GETFONT, 0, 0); + HGDIOBJ hPrevFont = ::SelectObject(hDC, hFont); + SIZE sz; + TCHAR szItemText[64]; + + int nItems = GetCount(); + for (int n = 0; n < nItems; ++n) + { + sz.cx = 0; + sz.cy = 0; + + int nItemTextLen = GetString(n, szItemText); + szItemText[nItemTextLen++] = _T('W'); + szItemText[nItemTextLen] = 0; + ::GetTextExtentPoint32(hDC, szItemText, nItemTextLen, &sz); + + if (nWidth < sz.cx) + nWidth = sz.cx; + } + + ::SelectObject(hDC, hPrevFont); + ::ReleaseDC(m_hWnd, hDC); + } + + if (nWidth > 0) + { + int nScrollBarWidth = ::GetSystemMetrics(SM_CXVSCROLL); + nWidth += nScrollBarWidth; + } + else + { + nWidth = 160; + } + return nWidth; +} + bool CPopupListBox::Show(const TCHAR* szCurrentWord) { if (FillPopupList(szCurrentWord)) @@ -288,7 +372,7 @@ bool CPopupListBox::Show(const TCHAR* szCurrentWord) int y; int height; int x = pt.x; - int width = 160; + int width = getRequiredWidth(); int ih = (itemHeight > 0) ? itemHeight : 12; if (x + width > rc.right - rc.left) { diff --git a/NppExec/src/CPopupListBox.h b/NppExec/src/CPopupListBox.h index 8212daf..c8c2e27 100644 --- a/NppExec/src/CPopupListBox.h +++ b/NppExec/src/CPopupListBox.h @@ -38,6 +38,9 @@ class CPopupListBox : public CAnyListBox HWND GetParentWnd() const; void SetParentWnd(HWND hParentWnd); bool Show(const TCHAR* szCurrentWord); + +private: + int getRequiredWidth(); }; //--------------------------------------------------------------------------- diff --git a/NppExec/src/CSimpleLogger.h b/NppExec/src/CSimpleLogger.h index eb2cc55..9bebd6c 100644 --- a/NppExec/src/CSimpleLogger.h +++ b/NppExec/src/CSimpleLogger.h @@ -33,7 +33,6 @@ class LogFileWriter; class CSimpleLogger { public: - typedef CStrT tstr; typedef void (*OUTPUTFUNC)(const TCHAR* str, int len); public: diff --git a/NppExec/src/CStaticOptionsManager.cpp b/NppExec/src/CStaticOptionsManager.cpp index a6e90b2..626b2f9 100644 --- a/NppExec/src/CStaticOptionsManager.cpp +++ b/NppExec/src/CStaticOptionsManager.cpp @@ -18,7 +18,7 @@ along with this program. If not, see . #include "CStaticOptionsManager.h" -CStaticOptionsManager::tstr CStaticOptionsManager::_emptyStr; +tstr CStaticOptionsManager::_emptyStr; CByteBuf CStaticOptionsManager::_emptyBuf; CStaticOptionsManager::CStaticOptionsManager(const TCHAR* name, @@ -577,7 +577,7 @@ int CStaticOptionsManager::getIntListItem(void* listItemPtr, } // Internal function. For OPTT_STR only!!! -const CStaticOptionsManager::tstr& CStaticOptionsManager::getStrListItem( +const tstr& CStaticOptionsManager::getStrListItem( void* listItemPtr, bool actual) const { if ( !listItemPtr ) diff --git a/NppExec/src/CStaticOptionsManager.h b/NppExec/src/CStaticOptionsManager.h index 9aa83ff..f03d86f 100644 --- a/NppExec/src/CStaticOptionsManager.h +++ b/NppExec/src/CStaticOptionsManager.h @@ -58,8 +58,6 @@ class CStaticOptionsManager MAX_STRSIZE = 1024 }; - typedef CStrT tstr; - typedef struct OPT_ITM { unsigned int id; // option's unique id unsigned int flags; // flags = (OPTT_xx | OPTF_yy) diff --git a/NppExec/src/ChildProcess.cpp b/NppExec/src/ChildProcess.cpp new file mode 100644 index 0000000..c4d765e --- /dev/null +++ b/NppExec/src/ChildProcess.cpp @@ -0,0 +1,1533 @@ +#include "ChildProcess.h" +#include "NppExecHelpers.h" +#include "NppExec.h" +#include "NppExecEngine.h" +#include "DlgConsoleEncoding.h" +#include "cpp/StrSplitT.h" +#include "c_base/MatchMask.h" +#include "c_base/int2str.h" + +PseudoConsoleHelper g_pseudoCon; + +const int nPseudoConWidth = 192; +const int nPseudoConHeight = 1000; + +enum eNewLine { + nlNone = 0, + nlLF = 1, // \n + nlCR = 3, // \r + nlBS = 7 // \b +}; + +CChildProcess::CChildProcess(CScriptEngine* pScriptEngine) +{ + m_strInstance = NppExecHelpers::GetInstanceAsString(this); + + m_pNppExec = pScriptEngine->GetNppExec(); + m_pScriptEngine = pScriptEngine; + + reset(); + + Runtime::GetLogger().AddEx_WithoutOutput( _T("; CChildProcess - create (instance = %s)"), GetInstanceStr() ); +} + +CChildProcess::~CChildProcess() +{ + Runtime::GetLogger().AddEx_WithoutOutput( _T("; CChildProcess - destroy (instance = %s)"), GetInstanceStr() ); +} + +const TCHAR* CChildProcess::GetInstanceStr() const +{ + return m_strInstance.c_str(); +} + +void CChildProcess::applyCommandLinePolicy(tstr& sCmdLine, eCommandLinePolicy mode) +{ + if ( mode == clpNone ) + return; // nothing to do + + CStrSplitT args; + if ( args.SplitToArgs(sCmdLine, 2) == 0 ) + return; // empty sCmdLine, nothing to do + + const tstr sFileName = args.Arg(0); + + if ( mode == clpComSpec ) + { + tstr sComSpec = NppExecHelpers::GetEnvironmentVar( _T("COMSPEC") ); + if ( sComSpec.IsEmpty() ) + sComSpec = _T("cmd"); + + const tstr sComSpecNamePart = NppExecHelpers::GetFileNamePart(sComSpec, NppExecHelpers::fnpName); + const tstr sFileNamePart = NppExecHelpers::GetFileNamePart(sFileName, NppExecHelpers::fnpName); + if ( NppExecHelpers::StrCmpNoCase(sComSpecNamePart, sFileNamePart) == 0 ) + return; // sCmdLine already starts with "cmd" + + if ( sComSpec.Find(_T(' ')) >= 0 ) + NppExecHelpers::StrQuote(sComSpec); + + sComSpec += _T(' '); // e.g. "cmd " (notice the trailing space!) + + tstr sComSpecSwitches = Runtime::GetNppExec().GetOptions().GetStr(OPTS_CHILDP_COMSPECSWITCHES); + if ( !sComSpecSwitches.IsEmpty() ) + { + sComSpec += sComSpecSwitches; + sComSpec += _T(' '); // e.g. "cmd /C " (notice the trailing space!) + } + + sCmdLine.Insert(0, sComSpec); + return; + } + + // mode == clpPathExt + tstr sPathExtensions = NppExecHelpers::GetEnvironmentVar( _T("PATHEXT") ); + if ( !sPathExtensions.IsEmpty() ) + NppExecHelpers::StrLower(sPathExtensions); // in lower case! + else + sPathExtensions = _T(".com;.exe;.bat;.cmd"); // in lower case! + + CListT pathExts; + if ( StrSplitAsArgs(sPathExtensions.c_str(), pathExts, _T(';')) == 0 ) + return; // no extensions to check, nothing to do + + const tstr existingExt = NppExecHelpers::GetFileNamePart(sFileName, NppExecHelpers::fnpExt); + if ( !existingExt.IsEmpty() ) + { + const CListItemT* pExt = pathExts.Find( [&existingExt](const tstr& ext) { return (NppExecHelpers::StrCmpNoCase(ext, existingExt) == 0); } ); + if ( pExt ) + return; // the extension from %PATHEXT% is specified explicitly + + // As the existingExt is not empty, we may return here. + // However, a file name itself may have a form of "file.name", so + // we still need to inspect all the extensions from %PATHEXT% to + // check for all possible "file.name.ext" in paths from %PATH%. + } + + auto findMatchingExtension = [](const tstr& fileName, const CListT& exts, const auto& Predicate) + { + for ( const CListItemT* pExt = exts.GetFirst(); pExt != NULL; pExt = pExt->GetNext() ) + { + const tstr& ext = pExt->GetItem(); + if ( Predicate(fileName, ext) ) + return ext; + } + return tstr(); + }; + + auto fexistsWithExt = [](const tstr& fileName, const tstr& ext) + { + tstr fileNameExt = fileName; + fileNameExt += ext; + return NppExecHelpers::CheckFileExists(fileNameExt); + }; + + tstr ext; + if ( NppExecHelpers::IsFullPath(sFileName) ) + { + // full path specified... + if ( NppExecHelpers::CheckFileExists(sFileName) ) + return; // cmd does not try %PATHEXT% for an _existing_ file name + + // check the file extensions in %PATHEXT%... + ext = findMatchingExtension(sFileName, pathExts, fexistsWithExt); + } + else + { + // no path specified - check the paths in %PATH% and file extensions in %PATHEXT%... + tstr sPaths = NppExecHelpers::GetEnvironmentVar( _T("PATH") ); + CListT paths; + if ( !sPaths.IsEmpty() ) + { + StrSplitAsArgs(sPaths.c_str(), paths, _T(';')); + } + + const tstr sCurDir = NppExecHelpers::GetCurrentDir(); + if ( !sCurDir.IsEmpty() ) + { + CListItemT* pItem = paths.Find( [&sCurDir](const tstr& path) { return (NppExecHelpers::StrCmpNoCase(path, sCurDir) == 0); } ); + if ( pItem ) + { + paths.Delete(pItem); + } + paths.InsertFirst(sCurDir); + } + + for ( const CListItemT* pPath = paths.GetFirst(); pPath != NULL; pPath = pPath->GetNext() ) + { + tstr sPathName = pPath->GetItem(); + if ( !sPathName.EndsWith(_T('\\')) && !sPathName.EndsWith(_T('/')) ) + sPathName += _T('\\'); + sPathName += sFileName; + if ( NppExecHelpers::CheckFileExists(sPathName) ) + return; // cmd does not try %PATHEXT% for an _existing_ file name + + // check the file extensions in %PATHEXT%... + ext = findMatchingExtension(sPathName, pathExts, fexistsWithExt); + if ( !ext.IsEmpty() ) + break; + } + } + + if ( ext.IsEmpty() ) + return; // no existing full path found - nothing to do + + tstr sFileNameExt = sFileName; + sFileNameExt += ext; + + int nPos = sCmdLine.Find(sFileName); + sCmdLine.Replace(nPos, sFileName.length(), sFileNameExt); +} + +// cszCommandLine must be transformed by ModifyCommandLine(...) already +bool CChildProcess::Create(HWND /*hParentWnd*/, LPCTSTR cszCommandLine) +{ + SECURITY_DESCRIPTOR sd; + SECURITY_ATTRIBUTES sa; + STARTUPINFOEX si; + + reset(); + + if ( IsWindowsNT() ) + { + // security stuff for NT + InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); + SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); + sa.lpSecurityDescriptor = &sd; + } + else + { + sa.lpSecurityDescriptor = NULL; + } + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + + const int DEFAULT_PIPE_SIZE = 0; + + // Create the Pipe and get r/w handles + if ( !::CreatePipe(&m_hStdOutReadPipe, &m_hStdOutWritePipe, &sa, DEFAULT_PIPE_SIZE) ) + { + m_pNppExec->GetConsole().PrintError( _T("CreatePipe() failed") ); + return false; + } + if ( m_hStdOutWritePipe == NULL ) + { + if ( m_hStdOutReadPipe != NULL ) + ::CloseHandle(m_hStdOutReadPipe); + m_pNppExec->GetConsole().PrintError( _T("hStdOutWritePipe = NULL") ); + return false; + } + if ( m_hStdOutReadPipe == NULL ) + { + ::CloseHandle(m_hStdOutWritePipe); + m_pNppExec->GetConsole().PrintError( _T("hStdOutReadPipe = NULL") ); + return false; + } + + if ( !::CreatePipe(&m_hStdInReadPipe, &m_hStdInWritePipe, &sa, DEFAULT_PIPE_SIZE) ) + { + m_pNppExec->GetConsole().PrintError( _T("CreatePipe() failed") ); + return false; + } + if ( m_hStdInWritePipe == NULL ) + { + if ( m_hStdInReadPipe != NULL ) + ::CloseHandle(m_hStdInReadPipe); + m_pNppExec->GetConsole().PrintError( _T("hStdInWritePipe = NULL") ); + return false; + } + if ( m_hStdInReadPipe == NULL ) + { + ::CloseHandle(m_hStdInWritePipe); + m_pNppExec->GetConsole().PrintError( _T("hStdInReadPipe = NULL") ); + return false; + } + + ::SetHandleInformation(m_hStdInWritePipe, HANDLE_FLAG_INHERIT, 0); + ::SetHandleInformation(m_hStdOutReadPipe, HANDLE_FLAG_INHERIT, 0); + + m_hPseudoCon = NULL; + m_pAttributeList = NULL; + + if ( m_pNppExec->GetOptions().GetBool(OPTB_CHILDP_PSEUDOCONSOLE) && (g_pseudoCon.pfnCreatePseudoConsole != nullptr) ) + { + COORD conSize = { nPseudoConWidth, nPseudoConHeight }; + HRESULT hr = g_pseudoCon.pfnCreatePseudoConsole(conSize, m_hStdInReadPipe, m_hStdOutWritePipe, 0, &m_hPseudoCon); + if ( FAILED(hr) ) + { + m_hPseudoCon = NULL; + } + } + + // Job object + HANDLE hJob = NULL; + if ( m_pNppExec->GetOptions().GetBool(OPTB_CONSOLE_KILLPROCTREE) ) + { + hJob = ::CreateJobObject(NULL, NULL); + if ( hJob != NULL ) + { + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; + + ::ZeroMemory(&jeli, sizeof(jeli)); + jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + // Causes all processes associated with the job to terminate when the last handle to the job is closed. + if ( !::SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)) ) + { + ::CloseHandle(hJob); + hJob = NULL; + } + } + } + + /* + DWORD dwMode = PIPE_READMODE_BYTE | PIPE_NOWAIT; + SetNamedPipeHandleState(m_hStdOutWritePipe, &dwMode, NULL, NULL); + dwMode = PIPE_READMODE_BYTE | PIPE_NOWAIT; + SetNamedPipeHandleState(m_hStdOutReadPipe, &dwMode, NULL, NULL); + */ + + DWORD dwCreationFlags = 0; + + // initialize STARTUPINFOEX struct + ::ZeroMemory(&si, sizeof(STARTUPINFOEX)); + si.StartupInfo.cb = sizeof(STARTUPINFOEX); + si.StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + si.StartupInfo.wShowWindow = SW_HIDE; + if ( m_hPseudoCon ) + { + SIZE_T bytesRequired = 0; + g_pseudoCon.pfnInitializeProcThreadAttributeList(NULL, 1, 0, &bytesRequired); + si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST) ::HeapAlloc(::GetProcessHeap(), 0, bytesRequired); + if ( si.lpAttributeList ) + { + if ( g_pseudoCon.pfnInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &bytesRequired) ) + { + if ( g_pseudoCon.pfnUpdateProcThreadAttribute( + si.lpAttributeList, + 0, + PseudoConsoleHelper::constPROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, + m_hPseudoCon, + sizeof(m_hPseudoCon), + NULL, + NULL) ) + { + dwCreationFlags |= PseudoConsoleHelper::constEXTENDED_STARTUPINFO_PRESENT; + m_pAttributeList = si.lpAttributeList; + } + else + { + HeapFree(GetProcessHeap(), 0, si.lpAttributeList); + closePseudoConsole(); + } + } + else + { + HeapFree(GetProcessHeap(), 0, si.lpAttributeList); + closePseudoConsole(); + } + } + else + { + closePseudoConsole(); + } + } + + if ( !m_hPseudoCon ) + { + si.StartupInfo.hStdInput = m_hStdInReadPipe; + si.StartupInfo.hStdOutput = m_hStdOutWritePipe; + si.StartupInfo.hStdError = m_hStdOutWritePipe; + } + + eCommandLinePolicy mode = clpNone; + switch ( m_pNppExec->GetOptions().GetInt(OPTU_CHILDP_RUNPOLICY) ) + { + case clpPathExt: + mode = clpPathExt; + break; + case clpComSpec: + mode = clpComSpec; + break; + }; + tstr sCmdLine = cszCommandLine; + applyCommandLinePolicy(sCmdLine, mode); + + if ( hJob != NULL ) + { + BOOL bIsProcessInJob = FALSE; + if ( ::IsProcessInJob(GetCurrentProcess(), NULL, &bIsProcessInJob) ) + { + if ( bIsProcessInJob ) + dwCreationFlags |= CREATE_BREAKAWAY_FROM_JOB; + } + } + + if ( ::CreateProcess( + NULL, + sCmdLine.data(), + NULL, // security + NULL, // security + TRUE, // inherits handles + dwCreationFlags, // creation flags + NULL, // environment + NULL, // current directory + &si.StartupInfo, // startup info + &m_ProcessInfo // process info + ) ) + { + if ( hJob != NULL ) + { + if ( !::AssignProcessToJobObject(hJob, m_ProcessInfo.hProcess) ) + { + ::CloseHandle(hJob); + hJob = NULL; + } + } + + ::CloseHandle(m_ProcessInfo.hThread); m_ProcessInfo.hThread = NULL; + if ( m_hPseudoCon ) + { + ::CloseHandle(m_hStdOutWritePipe); m_hStdOutWritePipe = NULL; + ::CloseHandle(m_hStdInReadPipe); m_hStdInReadPipe = NULL; + } + + bool isConsoleProcessRunning = true; + + const UINT nMsgFlags = CNppExecConsole::pfLogThisMsg | CNppExecConsole::pfNewLine | CNppExecConsole::pfIsInternalMsg; + m_pNppExec->GetConsole().PrintMessage( tstr().Format(80, _T("Process started (PID=%u) >>>"), m_ProcessInfo.dwProcessId), nMsgFlags ); + + { + TCHAR szProcessId[50]; + c_base::_tint2str(GetProcessId(), szProcessId); + tstr varName = MACRO_PID; + m_pNppExec->GetMacroVars().SetUserMacroVar( m_pScriptEngine, varName, szProcessId, CNppExecMacroVars::svLocalVar ); // local var + } + + // this pause is necessary for child processes that return immediatelly + ::WaitForSingleObject(m_ProcessInfo.hProcess, m_pNppExec->GetOptions().GetUint(OPTU_CHILDP_STARTUPTIMEOUT_MS)); + + CStrT bufLine; + bool bPrevLineEmpty = false; + bool bDoOutputNext = true; + int nPrevState = nlNone; + DWORD dwRead = 0; + unsigned int nEmptyCount = 0; + const DWORD dwCycleTimeOut = m_pNppExec->GetOptions().GetUint(OPTU_CHILDP_CYCLETIMEOUT_MS); + const DWORD dwExitTimeOut = m_pNppExec->GetOptions().GetUint(OPTU_CHILDP_EXITTIMEOUT_MS); + + bufLine.Clear(); // just in case :-) + + do + { + // inside this cycle: the bOutputAll parameter must be controlled within readPipesAndOutput + dwRead = readPipesAndOutput(bufLine, bPrevLineEmpty, nPrevState, false, bDoOutputNext); + + if ( CNppExec::_bIsNppShutdown ) + { + // Notepad++ is exiting + if ( dwRead == 0 ) + { + // no output from the child process + ++nEmptyCount; + if ( nEmptyCount > (dwExitTimeOut/dwCycleTimeOut) ) + { + // no output during more than dwExitTimeOut ms, let's kill the process... + m_nBreakMethod = CProcessKiller::killCtrlBreak; + } + } + else + nEmptyCount = 0; + } + + } + while ( (isConsoleProcessRunning = (::WaitForSingleObject(m_ProcessInfo.hProcess, dwCycleTimeOut) == WAIT_TIMEOUT)) + && m_pScriptEngine->ContinueExecution() && !isBreaking() ); + // NOTE: time-out inside WaitForSingleObject() prevents from 100% CPU usage! + + if ( m_pScriptEngine->ContinueExecution() && (!isBreaking()) && !m_pScriptEngine->GetTriedExitCmd() ) + { + // maybe the child process is exited but not all its data is read + readPipesAndOutput(bufLine, bPrevLineEmpty, nPrevState, true, bDoOutputNext); + } + + if ( (!m_pScriptEngine->ContinueExecution()) || isBreaking() ) + { + if ( isConsoleProcessRunning ) + { + int nKillMethods = 0; + CProcessKiller::eKillMethod arrKillMethods[4]; + + tstr sAppName; + CListT ArgsList; + if (StrSplitToArgs(cszCommandLine, ArgsList, 2) > 0) + { + sAppName = ArgsList.GetFirst()->GetItem(); + NppExecHelpers::StrLower(sAppName); + } + + if ( (sAppName == _T("cmd")) || (sAppName == _T("cmd.exe")) ) + { + // cmd can't be closed with Ctrl-Break for unknown reason... + } + else + { + if ( m_nBreakMethod == CProcessKiller::killCtrlC ) + arrKillMethods[nKillMethods++] = CProcessKiller::killCtrlC; + else + arrKillMethods[nKillMethods++] = CProcessKiller::killCtrlBreak; + } + arrKillMethods[nKillMethods++] = CProcessKiller::killWmClose; + + Runtime::GetLogger().AddEx( _T("; trying to kill the child process... (instance = %s)"), GetInstanceStr() ); + + unsigned int nWaitTimeout = m_pNppExec->GetOptions().GetUint(OPTU_CHILDP_KILLTIMEOUT_MS); + CProcessKiller::eKillMethod nSucceededKillMethod = CProcessKiller::killNone; + if ( Kill(arrKillMethods, nKillMethods, nWaitTimeout, &nSucceededKillMethod) ) + { + Runtime::GetLogger().AddEx( _T("; the child process has been killed (instance = %s)"), GetInstanceStr() ); + + if ( !m_pNppExec->GetOptions().GetBool(OPTB_CONSOLE_NOINTMSGS) ) + { + tstr Msg; + Msg.Format( 80, _T("<<< Process has been killed (PID=%d)"), m_ProcessInfo.dwProcessId ); + switch ( nSucceededKillMethod ) + { + case CProcessKiller::killCtrlBreak: + Msg += _T(" with Ctrl-Break"); + break; + case CProcessKiller::killCtrlC: + Msg += _T(" with Ctrl-C"); + break; + case CProcessKiller::killWmClose: + Msg += _T(" with WM_CLOSE"); + break; + } + Msg += _T('.'); + const UINT nPrintMsgFlags = CNppExecConsole::pfLogThisMsg | CNppExecConsole::pfNewLine | CNppExecConsole::pfIsInternalMsg; + m_pNppExec->GetConsole().PrintMessage( Msg.c_str(), nPrintMsgFlags ); + } + else + { + if (nPrevState != nlLF /* new line */ ) + { + const UINT nPrintMsgFlags = CNppExecConsole::pfLogThisMsg | CNppExecConsole::pfNewLine; + m_pNppExec->GetConsole().PrintMessage( _T(""), nPrintMsgFlags ); + } + } + } + else + { + Runtime::GetLogger().AddEx( _T("; trying to terminate the child process... (instance = %s)"), GetInstanceStr() ); + + if ( ::TerminateProcess(m_ProcessInfo.hProcess, 0) ) + { + Runtime::GetLogger().AddEx( _T("; the child process has been terminated (instance = %s)"), GetInstanceStr() ); + + if ( !m_pNppExec->GetOptions().GetBool(OPTB_CONSOLE_NOINTMSGS) ) + { + const UINT nPrintMsgFlags = CNppExecConsole::pfLogThisMsg | CNppExecConsole::pfNewLine | CNppExecConsole::pfIsInternalMsg; + m_pNppExec->GetConsole().PrintMessage( tstr().Format(80, _T("<<< Process has been terminated (PID=%d)."), m_ProcessInfo.dwProcessId), nPrintMsgFlags ); + } + else + { + if (nPrevState != nlLF /* new line */ ) + { + const UINT nPrintMsgFlags = CNppExecConsole::pfLogThisMsg | CNppExecConsole::pfNewLine; + m_pNppExec->GetConsole().PrintMessage( _T(""), nPrintMsgFlags ); + } + } + } + else + { + m_pNppExec->GetConsole().PrintError( tstr().Format(80, _T("<<< TerminateProcess() returned FALSE (PID=%d)."), m_ProcessInfo.dwProcessId) ); + } + } + + } + } + + DWORD dwExitCode = (DWORD)(-1); + ::GetExitCodeProcess(m_ProcessInfo.hProcess, &dwExitCode); + m_nExitCode = (int) dwExitCode; + + // Process cleanup + ::CloseHandle(m_ProcessInfo.hProcess); m_ProcessInfo.hProcess = NULL; + closePseudoConsole(); + closePipes(); + if ( hJob != NULL ) + { + ::CloseHandle(hJob); + hJob = NULL; + } + + if ( m_pScriptEngine->ContinueExecution() && !isBreaking() ) + { + if ( !m_pNppExec->GetOptions().GetBool(OPTB_CONSOLE_NOINTMSGS) ) + { + const UINT nPrintMsgFlags = CNppExecConsole::pfLogThisMsg | CNppExecConsole::pfNewLine | CNppExecConsole::pfIsInternalMsg; + m_pNppExec->GetConsole().PrintMessage( tstr().Format(100, _T("<<< Process finished (PID=%u). (Exit code %d)"), m_ProcessInfo.dwProcessId, m_nExitCode), nPrintMsgFlags ); + } + else + { + if (nPrevState != nlLF /* new line */ ) + { + const UINT nPrintMsgFlags = CNppExecConsole::pfLogThisMsg | CNppExecConsole::pfNewLine; + m_pNppExec->GetConsole().PrintMessage( _T(""), nPrintMsgFlags ); + } + } + } + + return true; + } + else + { + DWORD dwErrorCode = ::GetLastError(); + + closePseudoConsole(); + closePipes(); + if ( hJob != NULL ) + { + ::CloseHandle(hJob); + hJob = NULL; + } + + if ( m_pScriptEngine ) + { + m_pNppExec->GetConsole().PrintError( m_pScriptEngine->GetLastLoggedCmd().c_str() ); + } + m_pNppExec->GetConsole().PrintSysError( _T("CreateProcess()"), dwErrorCode ); + + return false; + } +} + +void CChildProcess::reset() +{ + m_strOutput.Clear(); + m_nExitCode = -1; + m_nBreakMethod = CProcessKiller::killNone; + m_hStdInReadPipe = NULL; + m_hStdInWritePipe = NULL; + m_hStdOutReadPipe = NULL; + m_hStdOutWritePipe = NULL; + m_hPseudoCon = NULL; + m_pAttributeList = NULL; + ::ZeroMemory(&m_ProcessInfo, sizeof(PROCESS_INFORMATION)); +} + +bool CChildProcess::isBreaking() const +{ + return (m_nBreakMethod != CProcessKiller::killNone); +} + +bool CChildProcess::applyOutputFilters(const tstr& _line, bool bOutput) +{ + const bool bConFltrEnable = m_pNppExec->GetOptions().GetBool(OPTB_CONFLTR_ENABLE); + const int nConFltrInclMask = m_pNppExec->GetOptions().GetInt(OPTI_CONFLTR_INCLMASK); + const int nConFltrExclMask = m_pNppExec->GetOptions().GetInt(OPTI_CONFLTR_EXCLMASK); + + tstr _mask; + tstr sLine; + + // >>> console output filters + if ( bConFltrEnable && ((nConFltrInclMask > 0) || (nConFltrExclMask > 0)) ) + { + for ( int i = 0; bOutput && + (i < CConsoleOutputFilterDlg::FILTER_ITEMS); i++ ) + { + int len = 0; + const TCHAR* cszLine = m_pNppExec->GetOptions().GetStr(OPTS_CONFLTR_INCLLINE1 + i, &len); + sLine = cszLine; + if ( m_pNppExec->GetMacroVars().CheckAllMacroVars(m_pScriptEngine, sLine, false) ) + { + cszLine = sLine.c_str(); + len = sLine.length(); + } + + if ( (nConFltrInclMask & (0x01 << i)) && (len > 0) ) + { + _mask = cszLine; + NppExecHelpers::StrLower(_mask); + if ( !c_base::_tmatch_mask(_mask.c_str(), _line.c_str()) ) + { + bOutput = false; + } + } + + len = 0; + cszLine = m_pNppExec->GetOptions().GetStr(OPTS_CONFLTR_EXCLLINE1 + i, &len); + sLine = cszLine; + if ( m_pNppExec->GetMacroVars().CheckAllMacroVars(m_pScriptEngine, sLine, false) ) + { + cszLine = sLine.c_str(); + len = sLine.length(); + } + + if ( bOutput && (nConFltrExclMask & (0x01 << i)) && (len > 0) ) + { + _mask = cszLine; + NppExecHelpers::StrLower(_mask); + if ( c_base::_tmatch_mask(_mask.c_str(), _line.c_str()) ) + { + bOutput = false; + } + } + } + } + // <<< console output filters + + return bOutput; +} + +bool CChildProcess::applyReplaceFilters(tstr& _line, tstr& printLine, bool bOutput) +{ + const bool bRplcFltrEnable = m_pNppExec->GetOptions().GetBool(OPTB_CONFLTR_R_ENABLE); + const bool bRplcFltrExclEmpty = m_pNppExec->GetOptions().GetBool(OPTB_CONFLTR_R_EXCLEMPTY); + const int nRplcFltrFindMask = m_pNppExec->GetOptions().GetInt(OPTI_CONFLTR_R_FINDMASK); + const int nRplcFltrCaseMask = m_pNppExec->GetOptions().GetInt(OPTI_CONFLTR_R_CASEMASK); + + tstr _mask; + tstr sFind; + tstr sRplc; + + // >>> console replace filters + if ( bOutput && bRplcFltrEnable && (nRplcFltrFindMask > 0) ) + { + bool bModified = false; + + // >>> for ... + for ( int i = 0; bOutput && + (i < CConsoleOutputFilterDlg::REPLACE_ITEMS); i++ ) + { + int lenFind = 0; + const TCHAR* cszFind = m_pNppExec->GetOptions().GetStr(OPTS_CONFLTR_R_FIND1 + i, &lenFind); + sFind = cszFind; + if ( m_pNppExec->GetMacroVars().CheckAllMacroVars(m_pScriptEngine, sFind, false) ) + { + cszFind = sFind.c_str(); + lenFind = sFind.length(); + } + + if ( (nRplcFltrFindMask & (0x01 << i)) && + ( ((lenFind > 0) && (_line.length() > 0)) || + ((lenFind == 0) && (_line.length() == 0)) ) + ) + { + int lenRplc = 0; + const TCHAR* cszRplc = m_pNppExec->GetOptions().GetStr(OPTS_CONFLTR_R_RPLC1 + i, &lenRplc); + sRplc = cszRplc; + if ( m_pNppExec->GetMacroVars().CheckAllMacroVars(m_pScriptEngine, sRplc, false) ) + { + cszRplc = sRplc.c_str(); + lenRplc = sRplc.length(); + } + + if ( lenFind > 0 ) + { + // original string is not empty + + int pos = 0; + if ( nRplcFltrCaseMask & (0x01 << i) ) + { + // match case + while ( (pos = printLine.Find(cszFind, pos)) >= 0 ) + { + bModified = true; + + // both variables must be changed to stay synchronized + _line.Replace(pos, lenFind, cszRplc, lenRplc); + printLine.Replace(pos, lenFind, cszRplc, lenRplc); + pos += lenRplc; + } + } + else + { + // case-insensitive + _mask = cszFind; + NppExecHelpers::StrLower(_mask); + while ( (pos = _line.Find(_mask.c_str(), pos)) >= 0 ) + { + bModified = true; + + // both variables must be changed to stay synchronized + _line.Replace(pos, lenFind, cszRplc, lenRplc); + printLine.Replace(pos, lenFind, cszRplc, lenRplc); + pos += lenRplc; + } + } + } + else + { + // replacing original empty string with cszRplc + + bModified = true; + _line = cszRplc; + printLine = cszRplc; + } + + if ( bRplcFltrExclEmpty && bModified && (printLine.length() == 0) ) + { + bOutput = false; + } + } + } + // <<< for ... + + } + // <<< console replace filters + + return bOutput; +} + +DWORD CChildProcess::readPipesAndOutput(CStrT& bufLine, + bool& bPrevLineEmpty, + int& nPrevState, + bool bOutputAll, + bool& bDoOutputNext) +{ + DWORD dwBytesRead = 0; + char Buf[CONSOLEPIPE_BUFSIZE]; + CStrT outLine; + + bool bSomethingHasBeenReadFromThePipe = false; // great name for a local variable :-) + + const bool bConFltrEnable = m_pNppExec->GetOptions().GetBool(OPTB_CONFLTR_ENABLE); + const bool bConFltrExclAllEmpty = m_pNppExec->GetOptions().GetBool(OPTB_CONFLTR_EXCLALLEMPTY); + const bool bConFltrExclDupEmpty = m_pNppExec->GetOptions().GetBool(OPTB_CONFLTR_EXCLDUPEMPTY); + const bool bOutputVar = m_pNppExec->GetOptions().GetBool(OPTB_CONSOLE_SETOUTPUTVAR); + const unsigned int nAnsiEscSeq = GetAnsiEscSeq(); + + const int nBufLineLength = bufLine.length(); + + do + { + ::Sleep(10); // it prevents from 100% CPU usage while reading! + dwBytesRead = 0; + if ( !::PeekNamedPipe(m_hStdOutReadPipe, NULL, 0, NULL, &dwBytesRead, NULL) ) + { + dwBytesRead = 0; + } + if ( !dwBytesRead ) + { + // no data in the pipe + if ( !bSomethingHasBeenReadFromThePipe ) + { + // did we read something from the pipe already? + // if no, then let's output the data from bufLine (if any) + bOutputAll = true; + } + } + if ( (dwBytesRead > 0) || bOutputAll ) + { + // some data is in the Pipe or bOutputAll==true + + bool bContainsData = (dwBytesRead > 0) ? true : false; + // without bContainsData==true the ReadFile operation will never return + + if ( bContainsData ) + ::ZeroMemory(Buf, CONSOLEPIPE_BUFSIZE); + dwBytesRead = 0; + if ( (bContainsData + && ::ReadFile(m_hStdOutReadPipe, Buf, (CONSOLEPIPE_BUFSIZE-1)*sizeof(char), &dwBytesRead, NULL) + && (dwBytesRead > 0)) || bOutputAll ) + { + // some data has been read from the Pipe or bOutputAll==true + + int copy_len; + + Buf[dwBytesRead/sizeof(char)] = 0; + + bufLine.Append( Buf, dwBytesRead/sizeof(char) ); + + if ( dwBytesRead > 0 ) + { + bSomethingHasBeenReadFromThePipe = true; + } + + // The following lines are needed for filtered output only. + // I.e. you can replace all these lines by this one: + // GetConsole().PrintOutput(Buf); + // if you don't need filtered output. (*) + // (*) But don't forget about Unicode version: + // OEM -> WideChar or UTF-8 -> WideChar + + /**/ + do { + + copy_len = -1; + + for ( int pos = 0; pos < bufLine.length(); pos++ ) + { + int nIsNewLine = nlNone; + if ( bufLine[pos] == '\n' ) + { + nIsNewLine = nlLF; + } + else if ( bufLine[pos] == '\r' ) + { + if ( bufLine[pos+1] != '\n' ) + { + // not "\r\n" pair + if ( (bufLine[pos+1] != '\r') || (bufLine.GetAt(pos+2) != '\n') ) + { + // not "\r\r\n" (stupid M$'s line ending) + // just "\r" + nIsNewLine = nlCR; + } + } + } + else if ( bufLine[pos] == '\b' ) + { + nIsNewLine = nlBS; + } + + if ( nIsNewLine || (bOutputAll && (pos == bufLine.length()-1)) ) + { + copy_len = pos; + if ( !nIsNewLine ) + { + // i.e. bOutputAll is true + copy_len++; + } + else if ( (pos > 0) && (bufLine[pos-1] == '\r') ) + { + copy_len--; + if ( (pos > 1) && (bufLine[pos-2] == '\r') ) + copy_len--; + } + + outLine.Assign(bufLine.c_str(), copy_len); + + if ( nIsNewLine == nlBS ) // '\b' + { + // counting "\b\b..." and skip them + while ( bufLine[pos+1] == '\b' ) + { + ++nIsNewLine; + ++pos; + } + } + + bufLine.Delete(0, pos+1); + if ( (copy_len > 0) || + ( ((!bConFltrExclAllEmpty) || (!bConFltrEnable)) && + ((!bPrevLineEmpty) || (!bConFltrEnable) || (!bConFltrExclDupEmpty)) + ) ) + { + tstr printLine; + bool bOutput = bConFltrEnable ? bDoOutputNext : true; + + if ( bOutput ) + { + tstr _line; + + if ( outLine.length() > 0 ) + { + unsigned int enc = CConsoleEncodingDlg::getOutputEncoding(GetEncoding()); + + #ifdef UNICODE + + switch ( enc ) + { + case CConsoleEncodingDlg::ENC_OEM : + _line = NppExecHelpers::CStrToWStr(outLine, CP_OEMCP); + break; + + case CConsoleEncodingDlg::ENC_UTF8 : + _line = NppExecHelpers::CStrToWStr(outLine, CP_UTF8); + break; + + default: + _line = NppExecHelpers::CStrToWStr(outLine, CP_ACP); + break; + } + + { + wchar_t wchNulChar = CNppConsoleRichEdit::GetNulChar(); + if ( wchNulChar != 0 ) + { + _line.Replace( wchar_t(0x0000), wchNulChar ); // e.g. to 0x25E6 - the "White Bullet" symbol + } + } + + #else + + { + char chNulChar = CNppConsoleRichEdit::GetNulChar(); + if ( chNulChar != 0 ) + { + outLine.Replace( char(0x00), chNulChar ); // e.g. to 0x17 - the "End of Text Block" symbol + } + } + + switch ( enc ) + { + case CConsoleEncodingDlg::ENC_OEM : + if ( _line.SetSize(outLine.length() + 1) ) + { + ::OemToChar( outLine.c_str(), _line.c_str() ); + _line.CalculateLength(); + } + break; + + case CConsoleEncodingDlg::ENC_UTF8 : + { + char* pStr = SysUniConv::newUTF8ToMultiByte( outLine.c_str() ); + if ( pStr ) + { + _line = pStr; + delete [] pStr; + } + } + break; + + default: + _line = outLine; + break; + } + + #endif + + printLine = _line; + NppExecHelpers::StrLower(_line); + } + + // >>> console output filters + bOutput = applyOutputFilters(_line, bOutput); + // <<< console output filters + + // >>> console replace filters + bOutput = applyReplaceFilters(_line, printLine, bOutput); + // <<< console replace filters + } + + if ( bOutput ) + { + bool bPrintThisLine = true; + + if ( nAnsiEscSeq == escRemove ) + { + bPrintThisLine = RemoveAnsiEscSequencesFromLine(printLine); + } + + if ( nPrevState == nlCR ) // '\r' + { + if ( !(nIsNewLine == nlLF && pos <= 1 && copy_len == 0) ) + m_pNppExec->GetConsole().ProcessSlashR(); + } + else if ( nPrevState >= nlBS ) // '\b'... + { + m_pNppExec->GetConsole().ProcessSlashB( (nPrevState - nlBS) + 1 ); + } + + if ( bPrintThisLine ) + { + if ( bOutputVar ) + { + m_strOutput += printLine; + if ( nIsNewLine == nlLF ) + { + m_strOutput += _T("\n"); + } + } + + UINT nPrintOutFlags = CNppExecConsole::pfLogThisMsg; + if ( nIsNewLine == nlLF ) + nPrintOutFlags |= CNppExecConsole::pfNewLine; + m_pNppExec->GetConsole().PrintOutput( printLine.c_str(), nPrintOutFlags ); + } + } + + // if the current line is not over, then the current filter + // must be applied to the rest of this line + bDoOutputNext = bOutput; + } + bPrevLineEmpty = (copy_len > 0) ? false : true; + nPrevState = nIsNewLine; + if ( nIsNewLine == nlLF ) + { + // current line is over - abort current filter + bDoOutputNext = true; + } + break; + } + + } + } while ( copy_len >= 0 ); + /**/ + + } + } + + } + while ( (dwBytesRead > 0) && m_pScriptEngine->ContinueExecution() && !isBreaking() ); + + if ( bOutputAll && !dwBytesRead ) dwBytesRead = nBufLineLength; + return dwBytesRead; +} + +bool CChildProcess::RemoveAnsiEscSequencesFromLine(tstr& Line) +{ + // ANSI escape codes, references: + // https://en.wikipedia.org/wiki/ANSI_escape_code + // https://en.wikipedia.org/wiki/ISO/IEC_2022 + // https://man7.org/linux/man-pages/man4/console_codes.4.html + // http://ascii-table.com/ansi-escape-sequences.php + // http://ascii-table.com/ansi-escape-sequences-vt-100.php + // https://invisible-island.net/xterm/ctlseqs/ctlseqs.html + // https://stackoverflow.com/questions/4842424/list-of-ansi-color-escape-sequences + + enum eEscState { + esNone = 0, + esEsc, // ESC symbol found + esCsi, // CSI sequence + esOsc, // OSC sequence + esWaitSt, // wait for ST (ESC \) + esWait1, // wait for 1 symbol + esWait2 // wait for 2 symbols + }; + + + const TCHAR* p = Line.c_str(); + eEscState state = esNone; + TCHAR curr_ch = 0; + TCHAR wait1_ch = 0; + TCHAR wait2_ch = 0; + tstr outputLine; + + outputLine.Reserve(Line.length()); + + while ( (curr_ch = *p) != 0 ) + { + switch ( state ) + { + case esNone: + if ( curr_ch == 0x1B ) // ESC + { + state = esEsc; + } + else + { + outputLine.Append(curr_ch); + } + break; + + case esEsc: + switch ( curr_ch ) + { + case _T('['): // CSI + state = esCsi; + break; + case _T(']'): // OSC + state = esOsc; + break; + case _T('P'): // DCS + case _T('X'): // SOS + case _T('^'): // PM + case _T('_'): // APC + state = esWaitSt; + break; + case _T('$'): // G?DM? + state = esWait2; + wait2_ch = curr_ch; + break; + case _T('!'): // C0-designate + case _T('"'): // C1-designate + case _T('#'): // single control function + case _T('%'): // DOCS + case _T('&'): // IRR + case _T('('): // G0 character set + case _T(')'): // G1 character set + case _T('*'): // G2 character set + case _T('+'): // G3 character set + case _T('-'): // G1 character set, VT300 + case _T('.'): // G2 character set, VT300 + case _T('/'): // G3 character set, VT300 + case _T(' '): // ACS + state = esWait1; + wait1_ch = curr_ch; + break; + default: // RIS, IND, NEL, HTS, RI, ... + state = esNone; + break; + } + break; + + case esCsi: + if ( (curr_ch >= _T('A') && curr_ch <= _T('Z')) || + (curr_ch >= _T('a') && curr_ch <= _T('z')) || + (curr_ch == _T('@')) || + (curr_ch == _T('[')) || + (curr_ch == _T('\\')) || + (curr_ch == _T(']')) || + (curr_ch == _T('^')) || + (curr_ch == _T('_')) || + (curr_ch == _T('`')) || + (curr_ch == _T('{')) || + (curr_ch == _T('|')) || + (curr_ch == _T('}')) || + (curr_ch == _T('~')) ) + { + // the "final byte" of the CSI sequence + state = esNone; + } + // else waiting for the CSI final character... + break; + + case esOsc: + case esWaitSt: + if ( curr_ch == 0x1B ) // ESC + { + const TCHAR next_ch = *(p + 1); + if ( next_ch == _T('\\') ) // ST + { + ++p; // skipping the next character as well + state = esNone; + } + else // ? + { + state = esEsc; // ? + } + } + // else waiting for the ST... + break; + + case esWait1: + state = esNone; + if ( wait1_ch == _T('%') ) + { + switch ( curr_ch ) + { + case _T('/'): // ESC % / F + state = esWait1; + break; + } + } + wait1_ch = 0; + break; + + case esWait2: + state = esWait1; + if ( wait2_ch == _T('$') ) + { + switch ( curr_ch ) + { + case _T('@'): // ESC $ @ + case _T('A'): // ESC $ A + case _T('B'): // ESC $ B + state = esNone; + break; + } + } + wait2_ch = 0; + break; + } + + ++p; + } + + Line.Swap(outputLine); + return (!Line.IsEmpty() || outputLine.IsEmpty()); +} + +void CChildProcess::MustBreak(unsigned int nBreakMethod) +{ + m_nBreakMethod = nBreakMethod; +} + +bool CChildProcess::Kill(const CProcessKiller::eKillMethod arrKillMethods[], int nKillMethods, + unsigned int nWaitTimeout, + CProcessKiller::eKillMethod* pnSucceededKillMethod) +{ + bool isKilled = false; + CProcessKiller pk(GetProcessInfo()); + for ( int i = 0; i < nKillMethods; i++ ) + { + CProcessKiller::eKillMethod nKillMethod = arrKillMethods[i]; + isKilled = pk.Kill(nKillMethod, nWaitTimeout); + if ( isKilled ) + { + if ( pnSucceededKillMethod ) + *pnSucceededKillMethod = nKillMethod; + break; + } + } + return isKilled; +} + +bool CChildProcess::WriteInput(const TCHAR* szLine, bool bFFlush ) +{ + if ( (!szLine) || (!m_hStdInWritePipe) ) + return false; + + Runtime::GetLogger().AddEx_WithoutOutput( _T("; CChildProcess::WriteInput(\"%s\") (instance = %s)"), szLine, GetInstanceStr() ); + + char* pStr = NULL; + int len = 0; + DWORD dwBytesWritten = 0; + unsigned int enc = CConsoleEncodingDlg::getInputEncoding(GetEncoding()); + + #ifdef UNICODE + + switch ( enc ) + { + case CConsoleEncodingDlg::ENC_OEM : + pStr = SysUniConv::newUnicodeToMultiByte( szLine, -1, CP_OEMCP, &len ); + break; + + case CConsoleEncodingDlg::ENC_UTF8 : + pStr = SysUniConv::newUnicodeToUTF8( szLine, -1, &len ); + break; + + default: + pStr = SysUniConv::newUnicodeToMultiByte( szLine, -1, CP_ACP, &len ); + break; + } + + if ( pStr ) + { + ::WriteFile(m_hStdInWritePipe, pStr, len*sizeof(char), &dwBytesWritten, NULL); + if ( bFFlush ) + { + // beware! this may hang the application (due to MustDie's pipes) + ::FlushFileBuffers(m_hStdInWritePipe); + } + delete [] pStr; + } + + #else + + bool bNewMemory = false; + + switch ( enc ) + { + case CConsoleEncodingDlg::ENC_OEM : + len = lstrlen(szLine); + pStr = new char[len + 1]; + if ( pStr ) + { + ::CharToOem(szLine, pStr); + bNewMemory = true; + } + break; + + case CConsoleEncodingDlg::ENC_UTF8 : + pStr = SysUniConv::newMultiByteToUTF8(szLine, -1, CP_ACP, &len); + if ( pStr ) + { + bNewMemory = true; + } + break; + + default: + len = lstrlen(szLine); + pStr = (char *) szLine; + bNewMemory = false; + break; + } + + if ( pStr ) + { + ::WriteFile(m_hStdInWritePipe, pStr, len*sizeof(char), &dwBytesWritten, NULL); + if ( bFFlush ) + { + // beware! this may hang the application (due to MustDie's pipes) + ::FlushFileBuffers(m_hStdInWritePipe); + } + if ( bNewMemory ) + delete [] pStr; + } + + #endif + + return true; +} + +void CChildProcess::closePipes() +{ + auto closePipe = [](HANDLE& hPipe) + { + if ( hPipe ) + { + ::CloseHandle(hPipe); + hPipe = NULL; + } + }; + + closePipe(m_hStdOutReadPipe); + closePipe(m_hStdOutWritePipe); + closePipe(m_hStdInReadPipe); + closePipe(m_hStdInWritePipe); +} + +void CChildProcess::closePseudoConsole() +{ + if ( g_pseudoCon.pfnClosePseudoConsole && m_hPseudoCon ) + { + g_pseudoCon.pfnClosePseudoConsole(m_hPseudoCon); m_hPseudoCon = NULL; + } + if ( m_pAttributeList ) + { + g_pseudoCon.pfnDeleteProcThreadAttributeList(m_pAttributeList); m_pAttributeList = NULL; + } +} + +tstr& CChildProcess::GetOutput() +{ + return m_strOutput; +} + +int CChildProcess::GetExitCode() const +{ + return m_nExitCode; +} + +DWORD CChildProcess::GetProcessId() const +{ + return m_ProcessInfo.dwProcessId; +} + +const PROCESS_INFORMATION* CChildProcess::GetProcessInfo() const +{ + return &m_ProcessInfo; +} + +bool CChildProcess::IsPseudoCon() const +{ + // See also: CNppExecCommandExecutor::IsChildProcessPseudoCon() + return (m_hPseudoCon ? true : false); +} + +const TCHAR* CChildProcess::GetNewLine() const +{ + return (m_hPseudoCon ? _T("\r") : m_pNppExec->GetOptions().GetStr(OPTS_KEY_ENTER)); +} + +unsigned int CChildProcess::GetEncoding() const +{ + return (m_hPseudoCon ? CConsoleEncodingDlg::getPseudoConsoleEncoding() : m_pNppExec->GetOptions().GetUint(OPTU_CONSOLE_ENCODING)); +} + +unsigned int CChildProcess::GetAnsiEscSeq() const +{ + int nAnsiEscSeq = m_pNppExec->GetOptions().GetInt(OPTI_CONSOLE_ANSIESCSEQ); + if ( m_hPseudoCon ) + { + // TODO: NppExec simply removes ANSI Escape Sequences + // (PsequdoConsole requires _full_ support of them) + if ( nAnsiEscSeq == escKeepRaw ) + nAnsiEscSeq = escProcess; + } + return nAnsiEscSeq; +} + +bool CChildProcess::IsWindowsNT() +{ +#ifdef _WIN64 + return true; // 64-bit Windows XP or later? Definitely Windows NT! +#elif defined(_MSC_VER) && (_MSC_VER >= 1910) // Visual Studio 2017 or later + return true; +#else + OSVERSIONINFO osv; + osv.dwOSVersionInfoSize = sizeof(osv); + GetVersionEx(&osv); + return (osv.dwPlatformId == VER_PLATFORM_WIN32_NT); +#endif +} + +///////////////////////////////////////////////////////////////////////////// + +CProcessKiller::CProcessKiller(const PROCESS_INFORMATION* pProcInfo) +{ + ::CopyMemory(&m_ProcInfo, pProcInfo, sizeof(PROCESS_INFORMATION)); +} + +CProcessKiller::~CProcessKiller() +{ +} + +bool CProcessKiller::Kill(eKillMethod nKillMethod, unsigned int nWaitTimeout) +{ + bool isKilled = !IsProcessActive(); + if ( !isKilled ) + { + switch ( nKillMethod ) + { + case killCtrlBreak: + isKilled = KillByCtrlBreak(nWaitTimeout); + break; + case killCtrlC: + isKilled = KillByCtrlC(nWaitTimeout); + break; + case killWmClose: + isKilled = KillByWmClose(nWaitTimeout); + break; + } + } + return isKilled; +} + +bool CProcessKiller::KillByCtrlBreak(unsigned int nWaitTimeout) +{ + return KillByConsoleCtrlEvent(CTRL_BREAK_EVENT, nWaitTimeout); +} + +bool CProcessKiller::KillByCtrlC(unsigned int nWaitTimeout) +{ + return KillByConsoleCtrlEvent(CTRL_C_EVENT, nWaitTimeout); +} + +bool CProcessKiller::KillByWmClose(unsigned int nWaitTimeout) +{ + bool isKilled = false; + ::EnumWindows(KillAppEnumFunc, m_ProcInfo.dwProcessId); + if ( ::WaitForSingleObject(m_ProcInfo.hProcess, nWaitTimeout) == WAIT_OBJECT_0 ) + { + isKilled = true; + } + return isKilled; +} + +BOOL CALLBACK CProcessKiller::KillAppEnumFunc(HWND hWnd, LPARAM lParam) +{ + DWORD dwID = 0; + GetWindowThreadProcessId(hWnd, &dwID); + if ( dwID == (DWORD) lParam ) + { + ::PostMessage(hWnd, WM_CLOSE, 0, 0) ; + } + return TRUE; // continue enumeration +} + +bool CProcessKiller::KillByConsoleCtrlEvent(unsigned int nCtrlEvent, unsigned int nWaitTimeout) +{ + typedef BOOL (WINAPI * PFNATTCON)(DWORD); + + bool isKilled = false; + HMODULE hKernel32 = ::GetModuleHandle(_T("kernel32")); + if ( hKernel32 ) + { + PFNATTCON pfnAttachConsole = (PFNATTCON) ::GetProcAddress(hKernel32, "AttachConsole"); + if ( pfnAttachConsole ) + { + if ( pfnAttachConsole(m_ProcInfo.dwProcessId) ) + { + ::SetConsoleCtrlHandler(NULL, TRUE); // Disable Ctrl-C handling for our program + ::GenerateConsoleCtrlEvent(nCtrlEvent, m_ProcInfo.dwProcessId); + if ( ::WaitForSingleObject(m_ProcInfo.hProcess, nWaitTimeout) == WAIT_OBJECT_0 ) + { + isKilled = true; + } + ::FreeConsole(); + ::SetConsoleCtrlHandler(NULL, FALSE); // Re-enable Ctrl-C handling + } + } + } + return isKilled; +} + +bool CProcessKiller::IsProcessActive() const +{ + DWORD dwExitCode = (DWORD)(-1); + ::GetExitCodeProcess(m_ProcInfo.hProcess, &dwExitCode); + return (dwExitCode == STILL_ACTIVE); +} diff --git a/NppExec/src/ChildProcess.h b/NppExec/src/ChildProcess.h new file mode 100644 index 0000000..1c80364 --- /dev/null +++ b/NppExec/src/ChildProcess.h @@ -0,0 +1,184 @@ +#ifndef _child_process_h_ +#define _child_process_h_ +//-------------------------------------------------------------------- + +#include "base.h" +#include "cpp/CStrT.h" + +class CNppExec; +class CScriptEngine; + +class CProcessKiller +{ + public: + enum eKillMethod { + killNone = 0, // do nothing + killCtrlBreak = 1, + killCtrlC, + killWmClose + }; + + CProcessKiller(const PROCESS_INFORMATION* pProcInfo); + ~CProcessKiller(); + + bool Kill(eKillMethod nKillMethod, unsigned int nWaitTimeout = 0); + + protected: + bool KillByCtrlBreak(unsigned int nWaitTimeout); + bool KillByCtrlC(unsigned int nWaitTimeout); + bool KillByWmClose(unsigned int nWaitTimeout); + + static BOOL CALLBACK KillAppEnumFunc(HWND hWnd, LPARAM lParam); + bool KillByConsoleCtrlEvent(unsigned int nCtrlEvent, unsigned int nWaitTimeout); + bool IsProcessActive() const; + + protected: + PROCESS_INFORMATION m_ProcInfo; +}; + +struct PseudoConsoleHelper +{ + static const DWORD constPROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE = 0x00020016; + static const DWORD constEXTENDED_STARTUPINFO_PRESENT = 0x00080000; + + typedef HANDLE typeHPCON; + + typedef HRESULT (WINAPI *typeCreatePseudoConsole)( + _In_ COORD size, + _In_ HANDLE hInput, + _In_ HANDLE hOutput, + _In_ DWORD dwFlags, + _Out_ typeHPCON* phPC + ); + + typedef HRESULT (WINAPI *typeResizePseudoConsole)( + _In_ typeHPCON hPC, + _In_ COORD size + ); + + typedef void (WINAPI *typeClosePseudoConsole)( + _In_ typeHPCON hPC + ); + + typedef BOOL (WINAPI *typeInitializeProcThreadAttributeList)( + LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, + DWORD dwAttributeCount, + DWORD dwFlags, + PSIZE_T lpSize + ); + + typedef BOOL (WINAPI *typeUpdateProcThreadAttribute)( + LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, + DWORD dwFlags, + DWORD_PTR Attribute, + PVOID lpValue, + SIZE_T cbSize, + PVOID lpPreviousValue, + PSIZE_T lpReturnSize + ); + + typedef VOID (WINAPI *typeDeleteProcThreadAttributeList)( + LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList + ); + + PseudoConsoleHelper() + { + HMODULE hKernel32 = ::GetModuleHandle(_T("kernel32")); + if (hKernel32) + { + // Available from Windows 10 October 2018 Update (version 1809) + pfnCreatePseudoConsole = (typeCreatePseudoConsole) ::GetProcAddress(hKernel32, "CreatePseudoConsole"); + pfnResizePseudoConsole = (typeResizePseudoConsole) ::GetProcAddress(hKernel32, "ResizePseudoConsole"); + pfnClosePseudoConsole = (typeClosePseudoConsole) ::GetProcAddress(hKernel32, "ClosePseudoConsole"); + + // Available from Windows Vista + pfnInitializeProcThreadAttributeList = (typeInitializeProcThreadAttributeList) ::GetProcAddress(hKernel32, "InitializeProcThreadAttributeList"); + pfnUpdateProcThreadAttribute = (typeUpdateProcThreadAttribute) ::GetProcAddress(hKernel32, "UpdateProcThreadAttribute"); + pfnDeleteProcThreadAttributeList = (typeDeleteProcThreadAttributeList) ::GetProcAddress(hKernel32, "DeleteProcThreadAttributeList"); + } + } + + typeCreatePseudoConsole pfnCreatePseudoConsole = nullptr; + typeResizePseudoConsole pfnResizePseudoConsole = nullptr; + typeClosePseudoConsole pfnClosePseudoConsole = nullptr; + typeInitializeProcThreadAttributeList pfnInitializeProcThreadAttributeList = nullptr; + typeUpdateProcThreadAttribute pfnUpdateProcThreadAttribute = nullptr; + typeDeleteProcThreadAttributeList pfnDeleteProcThreadAttributeList = nullptr; +}; + +class CChildProcess +{ + public: + enum eAnsiEscSeq { + escKeepRaw = 0, // keep the esc-sequence characters without processing + escRemove, // remove the esc-sequence characters + escProcess = escRemove, // = escRemove (the processing is not implemented yet) + + escTotalCount // the last item here! + }; + + public: + //CChildProcess(); + CChildProcess(CScriptEngine* pScriptEngine); + ~CChildProcess(); + const TCHAR* GetInstanceStr() const; + bool Create(HWND hParentWnd, LPCTSTR cszCommandLine); + bool Kill(const CProcessKiller::eKillMethod arrKillMethods[], int nKillMethods, + unsigned int nWaitTimeout, + CProcessKiller::eKillMethod* pnSucceededKillMethod); + void MustBreak(unsigned int nBreakMethod); + + bool WriteInput(const TCHAR* szLine, bool bFFlush = false); + + tstr& GetOutput(); // non-const allows to avoid copying at the very end + int GetExitCode() const; + DWORD GetProcessId() const; + const PROCESS_INFORMATION* GetProcessInfo() const; + + bool IsPseudoCon() const; + const TCHAR* GetNewLine() const; // usually "\n" or "\r" + unsigned int GetEncoding() const; + unsigned int GetAnsiEscSeq() const; + + static bool RemoveAnsiEscSequencesFromLine(tstr& Line); + + protected: + static bool IsWindowsNT(); + + enum eCommandLinePolicy { + clpNone = 0, // do nothing + clpPathExt, // try %PATH% and extensions from %PATHEXT% + clpComSpec // start with "%COMSPEC% /C" or "cmd /C" + }; + static void applyCommandLinePolicy(tstr& sCmdLine, eCommandLinePolicy mode); + + void reset(); + bool isBreaking() const; + void closePipes(); + void closePseudoConsole(); + bool applyOutputFilters(const tstr& _line, bool bOutput); + bool applyReplaceFilters(tstr& _line, tstr& printLine, bool bOutput); + DWORD readPipesAndOutput(CStrT& bufLine, + bool& bPrevLineEmpty, + int& nPrevState, + bool bOutputAll, + bool& bDoOutputNext); + + private: + CNppExec* m_pNppExec; + CScriptEngine* m_pScriptEngine; + tstr m_strInstance; + tstr m_strOutput; + int m_nExitCode; + unsigned int m_nBreakMethod; + HANDLE m_hStdInReadPipe; + HANDLE m_hStdInWritePipe; + HANDLE m_hStdOutReadPipe; + HANDLE m_hStdOutWritePipe; + PseudoConsoleHelper::typeHPCON m_hPseudoCon; + LPPROC_THREAD_ATTRIBUTE_LIST m_pAttributeList; + PROCESS_INFORMATION m_ProcessInfo; +}; + +//-------------------------------------------------------------------- +#endif diff --git a/NppExec/src/ConsoleChildProcess.txt b/NppExec/src/ConsoleChildProcess.txt deleted file mode 100644 index 1ef16f7..0000000 --- a/NppExec/src/ConsoleChildProcess.txt +++ /dev/null @@ -1,209 +0,0 @@ - -Well, let's follow all the steps of child console process'es execution. - - -(1) -In the beginning, there was a plugin's script. -Script's commands (which will be executed) are located inside -g_nppExec.m_CmdList - bidirectional list of strings. Each string -is a separate command. - - -(2) -When a script is to be executed, a new thread is created: - - if (!CreateNewThread(dwCreateConsoleProcess, NULL)) - { - ConsoleError("CreateThread() failed"); - } - -You can find the "CreateNewThread" function inside "NppExec.cpp". -Now let's refer to the "dwCreateConsoleProcess" function, which -actually is executed in another thread. You can find this function -inside "NppExecEngine.cpp". - - -(3) -dwCreateConsoleProcess is one of the basic functions of the -plugin. All the commands from g_nppExec.m_CmdList are executed here. -You can ensure it by looking at the brief code of this function: - - ... - p = g_nppExec.m_CmdList.GetFirst(); // first list item - while (p && g_nppExec._consoleIsVisible) - { - S = p->GetItem(); // extract a string - if (S.length() > 0) - { - dwCmdType = ModifyCommandLine(szCmdLine, S.c_str()); - S = szCmdLine; - ... - } - p = p->GetNext(); // next list item - } - ... - -The following line: - - dwCmdType = ModifyCommandLine(szCmdLine, S.c_str()); - -returns an identifier of internal command such as NPP_EXEC, NPP_RUN and -so on. In the same time, it substitutes corresponding strings instead of -$(FILE_NAME), $(NPP_DIRECTORY) and so on. -And the following line: - - S = szCmdLine; - -stores the returned string szCmdLine, which now actually is a parameter -of some internal command, in the string S. - - -(4) -A condition (dwCmdType == 0) means the following: current string does not -contain any internal command, so it is interpretted as external command - -i.e. a path to some executable file. Let's look at the corresponding -source code: - - ... - else if (dwCmdType == 0) - { - g_nppExec.ConsoleMessage(S.c_str()); - lstrcpy(g_nppExec._consoleCmdLine, szCmdLine); - g_nppExec.CreateChildProcess( - g_nppExec._consoleParentWnd, - g_nppExec._consoleCmdLine - ); - // this function does not return until child process exists - } - ... - -As you can see, it calls the "g_nppExec.CreateChildProcess" function with -szCmdLine as a parameter. So, let's refer to this function. You can find -it inside "NppExec.cpp". - - -(5) -The first intelligible thing inside CreateChildProcess is a creation of -input/output pipes (m_hStd-In/Out-Read/Write-Pipe). These pipes are -"information channels" between the plugin and a child process which -will be created soon. Don't forget about the pipes - we'll return to -them later. -The second intelligible thing is actually the creation of a child -process. Here is the corresponding code: - - // initialize STARTUPINFO struct - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; - si.wShowWindow = SW_HIDE; - si.hStdInput = m_hStdInReadPipe; // pipe for user's input (stdin) - si.hStdOutput = m_hStdOutWritePipe; // pipe for process'es stdout - si.hStdError = m_hStdOutWritePipe; // pipe for process'es stderr - - _consoleStrToWrite[0] = 0; - _consoleStdInWritePipe = m_hStdInWritePipe; - - lstrcpy(szCmdLine, cszCommandLine); - //ShowWarning(szCmdLine); - - if (CreateProcess(NULL, szCmdLine, ...)) - { - ... - } - -As you can see, the second parameter of CNppExec::CreateChildProcess is -directly passed to system's function CreateProcess. This parameter is a -path to executable which will be run as a child process of the plugin. - - -(6) -Now the child process is created. Let's assume it is a console process. -As you remember, the whole "dwCreateConsoleProcess" function is running -in another thread, so this child process is run in that thread also. -You can use the plugin's ConsoleDlg as the child console process'es -input while this process is running. I.e. when you type some string in -the ConsoleDlg's RichEdit control and press Enter, this string will be -passed to the child process. You can find the corresponding code inside -the "ConsoleDlg::OnNotify" function inside "DlgConsole.cpp". Search for -"::WriteFile(g_nppExec._consoleStdInWritePipe". -But let's return to the capturing of the child process'es output. - - -(7) -This is a complete code of the capturing: - - tstr bufLine; // a buffer for child process'es output - bool bPrevLineEmpty = false; - int nPrevState = 0; - - bufLine.Clear(); // just in case :-) - - do - { - Console_ReadPipesAndOutput(bufLine, bPrevLineEmpty, nPrevState, false); - - } - while ((_consoleProcessIsRunning = (WaitForSingleObject(pi.hProcess, - opt_ChildProcess_dwCycleTimeout_ms) == WAIT_TIMEOUT)) - && _consoleIsVisible && !_consoleProcessBreak); - // NOTE: time-out inside WaitForSingleObject() prevents from 100% CPU usage! - - if (_consoleIsVisible && !_consoleProcessBreak) - { - // maybe the child process is exited but not all its data is read - Console_ReadPipesAndOutput(bufLine, bPrevLineEmpty, nPrevState, true); - // ShowWarning("All is read!"); - } - -As you can see, we try to read data from the console process while it is not -finished and while the plugin's ConsoleDlg is visible. -And, at last, we see the "Console_ReadPipesAndOutput" function which actually -does all the work about the capturing of the child console process'es output -and shows this output in the ConsoleDlg. - - -(8) -The whole "Console_ReadPipesAndOutput" function can drive you crazy (I wrote -this function by parts ;-)) but, in brief, it's very simple: - - ... - do - { - Sleep(10); // it prevents from 100% CPU usage while reading! - dwBytesRead = 0; - if ((PeekNamedPipe(m_hStdOutReadPipe, NULL, 0, NULL, &dwBytesRead, NULL) - && (dwBytesRead > 0)) || bOutputAll) - { - // some data is in the Pipe or bOutputAll==true - - bool bContainsData = (dwBytesRead > 0) ? true : false; - // without bContainsData==true the ReadFile operation will never return - - if (bContainsData) - ZeroMemory(Buf, BUF_SIZE); - dwBytesRead = 0; - if ((bContainsData - && ReadFile(m_hStdOutReadPipe, Buf, (BUF_SIZE-1)*sizeof(TCHAR), &dwBytesRead, NULL) - && (dwBytesRead > 0)) || bOutputAll) - { - // some data has been read from the Pipe or bOutputAll==true - ... - } - } - } - while (dwBytesRead > 0); - -As you can see, at first we verify if there something in the pipe: - - if ( (PeekNamedPipe(..., &dwBytesRead,...)) && (dwBytesRead > 0) ) - -then we read the data: - - ReadFile(...) - - -[old part of the text, possibly non-actual anymore] - -And here is the problem. Sometimes PeekNamedPipe returns FALSE or -returns dwBytesRead == 0 though some data must be in the output pipe -already. diff --git a/NppExec/src/DlgAdvancedOptions.cpp b/NppExec/src/DlgAdvancedOptions.cpp index 46ce37a..3f00dee 100644 --- a/NppExec/src/DlgAdvancedOptions.cpp +++ b/NppExec/src/DlgAdvancedOptions.cpp @@ -18,6 +18,7 @@ along with this program. If not, see . #include "DlgAdvancedOptions.h" #include "CAnyWindow.h" +#include "PickColorBtn.h" #include "NppExec.h" #include "DlgDoExec.h" #include "DlgConsole.h" @@ -26,23 +27,21 @@ along with this program. If not, see . #include "c_base/str2int.h" #include "c_base/str_func.h" -const TCHAR* cszUserMenuItemSep = _T(" :: "); -const TCHAR* cszUserMenuSeparator = _T("---- ----"); +const TCHAR* const cszUserMenuItemSep = _T(" :: "); +const TCHAR* const cszUserMenuSeparator = _T("---- ----"); extern COLORREF g_colorTextNorm; extern COLORREF g_colorTextErr; extern COLORREF g_colorTextMsg; extern COLORREF g_colorBkgnd; -typedef const c_base::byte_t * lpcbyte_t; - CAdvOptDlg advOptDlg; INT_PTR CALLBACK AdvancedOptionsDlgProc( HWND hDlg, UINT uMessage, WPARAM wParam, - LPARAM /*lParam*/) + LPARAM lParam) { if ( uMessage == WM_COMMAND ) { @@ -116,18 +115,28 @@ INT_PTR CALLBACK AdvancedOptionsDlgProc( } break; } + case IDC_CH_OPT_USEEDITORCOLORS_CONSOLE: + { + if ( HIWORD(wParam) == BN_CLICKED ) + { + advOptDlg.OnChEditorColorsConsole(); + } + break; + } case IDOK: { if ( advOptDlg.OnBtOK() ) { - EndDialog(hDlg, 1); + advOptDlg.OnEndDlg(); + ::EndDialog(hDlg, 1); } return 1; } case IDCANCEL: { advOptDlg.OnBtCancel(); - EndDialog(hDlg, 0); + advOptDlg.OnEndDlg(); + ::EndDialog(hDlg, 0); return 1; } default: @@ -135,12 +144,18 @@ INT_PTR CALLBACK AdvancedOptionsDlgProc( } } + else if ( uMessage == WM_NOTIFY ) + { + PickColorBtn_HandleTooltipsNotify(hDlg, wParam, lParam); + } + else if ( uMessage == WM_SYSCOMMAND ) { if ( wParam == SC_CLOSE ) { advOptDlg.OnBtCancel(); - EndDialog(hDlg, 0); + advOptDlg.OnEndDlg(); + ::EndDialog(hDlg, 0); return 1; } } @@ -150,7 +165,9 @@ INT_PTR CALLBACK AdvancedOptionsDlgProc( advOptDlg.OnInitDlg(hDlg); } - return 0; + // Note: This is greedy and must be the last handler + if (PickColorBtn_HandleMessageForDialog(hDlg, uMessage, wParam, lParam)) return TRUE; + return FALSE; } CAdvOptDlg::CAdvOptDlg() : CAnyWindow() @@ -164,6 +181,7 @@ CAdvOptDlg::~CAdvOptDlg() void CAdvOptDlg::OnInitDlg(HWND hDlg) { CNppExec& NppExec = Runtime::GetNppExec(); + CStaticOptionsManager& Options = NppExec.GetOptions(); m_hWnd = hDlg; @@ -187,17 +205,15 @@ void CAdvOptDlg::OnInitDlg(HWND hDlg) m_btMoveDown.m_hWnd = ::GetDlgItem(hDlg, IDC_BT_MOVEDOWN); m_btModify.m_hWnd = ::GetDlgItem(hDlg, IDC_BT_ITEMNEW); m_btDelete.m_hWnd = ::GetDlgItem(hDlg, IDC_BT_ITEMDELETE); + m_chUseEditorColorsInConsole.m_hWnd = ::GetDlgItem(hDlg, IDC_CH_OPT_USEEDITORCOLORS_CONSOLE); + m_chUseEditorColorsInExecDlg.m_hWnd = ::GetDlgItem(hDlg, IDC_CH_OPT_USEEDITORCOLORS_EXECDLG); m_edItemName.SendMsg(EM_LIMITTEXT, MAX_SCRIPTNAME/2, 0); m_edCommentDelim.SendMsg(EM_LIMITTEXT, 9, 0); - m_edTextColorNorm.SendMsg(EM_LIMITTEXT, 9, 0); - m_edTextColorErr.SendMsg(EM_LIMITTEXT, 9, 0); - m_edTextColorMsg.SendMsg(EM_LIMITTEXT, 9, 0); - m_edBkColor.SendMsg(EM_LIMITTEXT, 9, 0); // notepad++ macros submenu... - - m_chMacrosSubmenu.SetCheck( NppExec.GetOptions().GetBool(OPTB_USERMENU_NPPMACROS) ? TRUE : FALSE ); + + m_chMacrosSubmenu.SetCheck( Options.GetBool(OPTB_USERMENU_NPPMACROS) ? TRUE : FALSE ); int i; LPCTSTR psz; @@ -206,7 +222,7 @@ void CAdvOptDlg::OnInitDlg(HWND hDlg) for ( i = 0; i < MAX_USERMENU_ITEMS; i++ ) { - psz = NppExec.GetOptions().GetStr(OPTS_USERMENU_ITEM01 + i); + psz = Options.GetStr(OPTS_USERMENU_ITEM01 + i); if ( psz && psz[0] ) { m_lbMenuItems.AddString(psz); @@ -233,7 +249,7 @@ void CAdvOptDlg::OnInitDlg(HWND hDlg) } i = 0; - psz = NppExec.GetOptions().GetStr(OPTS_SCRIPT_NPPSTART); + psz = Options.GetStr(OPTS_SCRIPT_NPPSTART); if ( psz ) { i = m_cbScriptNppStart.FindStringExact( psz ); @@ -242,7 +258,7 @@ void CAdvOptDlg::OnInitDlg(HWND hDlg) m_cbScriptNppStart.SetCurSel(i); i = 0; - psz = NppExec.GetOptions().GetStr(OPTS_SCRIPT_NPPEXIT); + psz = Options.GetStr(OPTS_SCRIPT_NPPEXIT); if ( psz ) { i = m_cbScriptNppExit.FindStringExact( psz ); @@ -265,7 +281,7 @@ void CAdvOptDlg::OnInitDlg(HWND hDlg) m_cbHotKey.AddString( _T("F10") ); m_cbHotKey.AddString( _T("F11") ); m_cbHotKey.AddString( _T("F12") ); - unsigned int uHotKey = NppExec.GetOptions().GetUint(OPTU_PLUGIN_HOTKEY); + unsigned int uHotKey = Options.GetUint(OPTU_PLUGIN_HOTKEY); for ( i = 0; i < 12; i++ ) { if ( uHotKey == static_cast(VK_F1 + i) ) @@ -277,12 +293,21 @@ void CAdvOptDlg::OnInitDlg(HWND hDlg) // fill toolbar btn combo-box... - m_cbToolbarBtn.AddString( _T("none") ); - m_cbToolbarBtn.AddString( _T("Console") ); - m_cbToolbarBtn.AddString( _T("Execute") ); - m_cbToolbarBtn.AddString( _T("ExecPrev") ); - i = NppExec.GetOptions().GetInt(OPTI_TOOLBARBTN); - if ( i < 0 || i > 3 ) i = 0; + const TCHAR* szToolbarBtns[] = { + _T("none"), + _T("Console"), + _T("Execute"), + _T("ExecPrev"), + _T("ExecSel"), + _T("ExecClip") + }; + for ( const auto& btnName : szToolbarBtns ) + { + m_cbToolbarBtn.AddString( btnName ); + } + const int nMaxBtn = m_cbToolbarBtn.GetCount() - 1; + i = Options.GetInt(OPTI_TOOLBARBTN); + if ( i < 0 || i > nMaxBtn ) i = 0; m_cbToolbarBtn.SetCurSel(i); // fill console visible combo-box... @@ -290,7 +315,7 @@ void CAdvOptDlg::OnInitDlg(HWND hDlg) m_cbConVisible.AddString( _T("Auto") ); m_cbConVisible.AddString( _T("Yes") ); m_cbConVisible.AddString( _T("No") ); - i = NppExec.GetOptions().GetInt(OPTI_CONSOLE_VISIBLE); + i = Options.GetInt(OPTI_CONSOLE_VISIBLE); if ( i < CON_AUTO || i > CON_NO ) i = CON_AUTO; m_cbConVisible.SetCurSel(i); @@ -298,46 +323,40 @@ void CAdvOptDlg::OnInitDlg(HWND hDlg) m_cbConShowHelp.AddString( _T("No") ); m_cbConShowHelp.AddString( _T("Yes") ); - i = NppExec.GetOptions().GetBool(OPTB_CONSOLE_SHOWHELP) ? 1 : 0; + i = Options.GetBool(OPTB_CONSOLE_SHOWHELP) ? 1 : 0; m_cbConShowHelp.SetCurSel(i); // fill save cmd history combo-box... m_cbSaveCmdHst.AddString( _T("No") ); m_cbSaveCmdHst.AddString( _T("Yes") ); - i = NppExec.GetOptions().GetBool(OPTB_CONSOLE_SAVECMDHISTORY) ? 1 : 0; + i = Options.GetBool(OPTB_CONSOLE_SAVECMDHISTORY) ? 1 : 0; m_cbSaveCmdHst.SetCurSel(i); // fill edit-controls... - TCHAR szText[64]; - - S = NppExec.GetOptions().GetStr(OPTS_COMMENTDELIMITER); + S = Options.GetStr(OPTS_COMMENTDELIMITER); m_edCommentDelim.SetWindowText(S.c_str()); - - szText[0] = 0; - c_base::_tbuf2hexstr( (lpcbyte_t) &g_colorTextNorm, 3, szText, 64 - 1, _T(" ") ); - m_edTextColorNorm.SetWindowText(szText); - - szText[0] = 0; - c_base::_tbuf2hexstr( (lpcbyte_t) &g_colorTextErr, 3, szText, 64 - 1, _T(" ") ); - m_edTextColorErr.SetWindowText(szText); - - szText[0] = 0; - c_base::_tbuf2hexstr( (lpcbyte_t) &g_colorTextMsg, 3, szText, 64 - 1, _T(" ") ); - m_edTextColorMsg.SetWindowText(szText); - - if ( g_colorBkgnd == 0xFFFFFFFF ) - { - m_edBkColor.SetWindowText( _T("0") ); - } - else + + PickColorBtn_SetColor(m_edTextColorNorm.GetWindowHandle(), g_colorTextNorm); + PickColorBtn_SetColor(m_edTextColorErr.GetWindowHandle(), g_colorTextErr); + PickColorBtn_SetColor(m_edTextColorMsg.GetWindowHandle(), g_colorTextMsg); + COLORREF bkColor = g_colorBkgnd; + if ( bkColor == COLOR_CON_BKGND ) { - szText[0] = 0; - c_base::_tbuf2hexstr( (lpcbyte_t) &g_colorBkgnd, 3, szText, 64 - 1, _T(" ") ); - m_edBkColor.SetWindowText(szText); + bkColor = ::GetSysColor(COLOR_WINDOW); } - + PickColorBtn_SetColor(m_edBkColor.GetWindowHandle(), bkColor); + + m_hToolTip = PickColorBtn_InitializeTooltips(hDlg, IDC_ED_OPT_TEXTCOLORNORM, IDC_ED_OPT_BKCOLOR); + + BOOL bUseEditorColors = Options.GetBool(OPTB_CONSOLE_USEEDITORCOLORS) ? TRUE : FALSE; + m_chUseEditorColorsInConsole.SetCheck(bUseEditorColors); + OnChEditorColorsConsole(); + + bUseEditorColors = Options.GetBool(OPTB_EXECDLG_USEEDITORCOLORS) ? TRUE : FALSE; + m_chUseEditorColorsInExecDlg.SetCheck(bUseEditorColors); + // buttons... if ( m_lbMenuItems.GetCount() > 1 ) @@ -352,10 +371,10 @@ void CAdvOptDlg::OnInitDlg(HWND hDlg) } m_btModify.EnableWindow(FALSE); m_btDelete.EnableWindow(FALSE); - + // finally... - m_nREMaxLen = NppExec.GetOptions().GetInt(OPTI_RICHEDIT_MAXTEXTLEN); + m_nREMaxLen = Options.GetInt(OPTI_RICHEDIT_MAXTEXTLEN); colorValuesInit(); // some options do not require n++ to be restarted @@ -364,115 +383,71 @@ void CAdvOptDlg::OnInitDlg(HWND hDlg) advOptDlg.CenterWindow(NppExec.m_nppData._nppHandle); } +void CAdvOptDlg::OnEndDlg() +{ + if ( m_hToolTip ) + { + ::DestroyWindow(m_hToolTip); + m_hToolTip = NULL; + } +} + +static void SaveColorOption( + CStaticOptionsManager& Options, CAnyWindow &Wnd, + UINT Optd, COLORREF &Var, COLORREF Default) +{ + c_base::byte_t bt[4]; + bool invalid = false; + COLORREF clr = PickColorBtn_GetColor(Wnd.GetWindowHandle()); + bt[0] = GetRValue(clr); bt[1] = GetGValue(clr); bt[2] = GetBValue(clr); + if (clr & 0xff000000) + { + clr = Default; + invalid = true; + bt[0] = 0; + } + Options.SetData(Optd, bt, invalid ? 1 : 3); + Var = clr; +} + BOOL CAdvOptDlg::OnBtOK() { CNppExec& NppExec = Runtime::GetNppExec(); - c_base::byte_t bt[4]; + CStaticOptionsManager& Options = NppExec.GetOptions(); + TCHAR szText[MAX_SCRIPTNAME]; int i; - + // text/background colours... - - bt[0] = 0; - szText[0] = 0; - m_edTextColorNorm.GetWindowText(szText, MAX_SCRIPTNAME - 1); - i = c_base::_thexstr2buf( szText, bt, 4 ); - if ( i >= 3 ) - { - NppExec.GetOptions().SetData(OPTD_COLOR_TEXTNORM, bt, 3); - g_colorTextNorm = RGB( bt[0], bt[1], bt[2] ); - } - else if ( i <= 1 ) - { - NppExec.GetOptions().SetData(OPTD_COLOR_TEXTNORM, bt, 1); - g_colorTextNorm = COLOR_CON_TEXTNORM; - } - else - { - ShowError( _T("Incorrect value of TextColorNormal") ); - return FALSE; - } - - bt[0] = 0; - szText[0] = 0; - m_edTextColorErr.GetWindowText(szText, MAX_SCRIPTNAME - 1); - i = c_base::_thexstr2buf( szText, bt, 4 ); - if ( i >= 3 ) - { - NppExec.GetOptions().SetData(OPTD_COLOR_TEXTERR, bt, 3); - g_colorTextErr = RGB( bt[0], bt[1], bt[2] ); - } - else if ( i <= 1 ) - { - NppExec.GetOptions().SetData(OPTD_COLOR_TEXTERR, bt, 1); - g_colorTextErr = COLOR_CON_TEXTERR; - } - else - { - ShowError( _T("Incorrect value of TextColorError") ); - return FALSE; - } - - bt[0] = 0; - szText[0] = 0; - m_edTextColorMsg.GetWindowText(szText, MAX_SCRIPTNAME - 1); - i = c_base::_thexstr2buf( szText, bt, 4 ); - if ( i >= 3 ) - { - NppExec.GetOptions().SetData(OPTD_COLOR_TEXTMSG, bt, 3); - g_colorTextMsg = RGB( bt[0], bt[1], bt[2] ); - } - else if ( i <= 1 ) - { - NppExec.GetOptions().SetData(OPTD_COLOR_TEXTMSG, bt, 1); - g_colorTextMsg = COLOR_CON_TEXTMSG; - } - else - { - ShowError( _T("Incorrect value of TextColorMessage") ); - return FALSE; - } - - bt[0] = 0; - szText[0] = 0; - m_edBkColor.GetWindowText(szText, MAX_SCRIPTNAME - 1); - i = c_base::_thexstr2buf( szText, bt, 4 ); - if ( i >= 3 ) - { - NppExec.GetOptions().SetData(OPTD_COLOR_BKGND, bt, 3); - g_colorBkgnd = RGB( bt[0], bt[1], bt[2] ); - } - else if ( i <= 1 ) - { - NppExec.GetOptions().SetData(OPTD_COLOR_BKGND, bt, 1); - g_colorBkgnd = COLOR_CON_BKGND; - } - else - { - ShowError( _T("Incorrect value of BackgroundColor") ); - return FALSE; - } - + + SaveColorOption(Options, m_edTextColorNorm, OPTD_COLOR_TEXTNORM, g_colorTextNorm, COLOR_CON_TEXTNORM); + SaveColorOption(Options, m_edTextColorErr, OPTD_COLOR_TEXTERR, g_colorTextErr, COLOR_CON_TEXTERR); + SaveColorOption(Options, m_edTextColorMsg, OPTD_COLOR_TEXTMSG, g_colorTextMsg, COLOR_CON_TEXTMSG); + SaveColorOption(Options, m_edBkColor, OPTD_COLOR_BKGND, g_colorBkgnd, COLOR_CON_BKGND); + + Options.SetBool( OPTB_CONSOLE_USEEDITORCOLORS, m_chUseEditorColorsInConsole.IsChecked() ? true : false ); + Options.SetBool( OPTB_EXECDLG_USEEDITORCOLORS, m_chUseEditorColorsInExecDlg.IsChecked() ? true : false ); + // notepad++ macros submenu... - - NppExec.GetOptions().SetBool(OPTB_USERMENU_NPPMACROS, m_chMacrosSubmenu.IsChecked() ? true : false ); - + + Options.SetBool( OPTB_USERMENU_NPPMACROS, m_chMacrosSubmenu.IsChecked() ? true : false ); + // user menu items... - + i = m_lbMenuItems.GetCount(); if ( i > MAX_USERMENU_ITEMS ) i = MAX_USERMENU_ITEMS; for ( int j = 0; j < i; j++ ) { szText[0] = 0; m_lbMenuItems.GetString(j, szText); - NppExec.GetOptions().SetStr( OPTS_USERMENU_ITEM01 + j, szText ); + Options.SetStr( OPTS_USERMENU_ITEM01 + j, szText ); } while ( i < MAX_USERMENU_ITEMS ) { - NppExec.GetOptions().SetStr( OPTS_USERMENU_ITEM01 + i, _T("") ); + Options.SetStr( OPTS_USERMENU_ITEM01 + i, _T("") ); ++i; } - + // npp start/exit scripts... i = m_cbScriptNppStart.GetCurSel(); @@ -480,7 +455,7 @@ BOOL CAdvOptDlg::OnBtOK() { szText[0] = 0; m_cbScriptNppStart.GetLBText(i, szText); - NppExec.GetOptions().SetStr(OPTS_SCRIPT_NPPSTART, szText); + Options.SetStr(OPTS_SCRIPT_NPPSTART, szText); } i = m_cbScriptNppExit.GetCurSel(); @@ -488,15 +463,15 @@ BOOL CAdvOptDlg::OnBtOK() { szText[0] = 0; m_cbScriptNppExit.GetLBText(i, szText); - NppExec.GetOptions().SetStr(OPTS_SCRIPT_NPPEXIT, szText); + Options.SetStr(OPTS_SCRIPT_NPPEXIT, szText); } - + // plugin hot-key... - + i = m_cbHotKey.GetCurSel(); if ( i >= 0 ) { - NppExec.GetOptions().SetUint(OPTU_PLUGIN_HOTKEY, VK_F1 + i); + Options.SetUint(OPTU_PLUGIN_HOTKEY, VK_F1 + i); } // toolbar btn... @@ -504,51 +479,60 @@ BOOL CAdvOptDlg::OnBtOK() i = m_cbToolbarBtn.GetCurSel(); if ( i >= 0 ) { - NppExec.GetOptions().SetInt(OPTI_TOOLBARBTN, i); + Options.SetInt(OPTI_TOOLBARBTN, i); } - + // console visible... - + i = m_cbConVisible.GetCurSel(); if ( i >= 0 ) { - NppExec.GetOptions().SetInt(OPTI_CONSOLE_VISIBLE, i); + Options.SetInt(OPTI_CONSOLE_VISIBLE, i); } - + // console show help... - + i = m_cbConShowHelp.GetCurSel(); if ( i >= 0 ) { - NppExec.GetOptions().SetBool(OPTB_CONSOLE_SHOWHELP, i ? true : false); + Options.SetBool(OPTB_CONSOLE_SHOWHELP, i ? true : false); } // save cmd history... i = m_cbSaveCmdHst.GetCurSel(); if ( i >= 0 ) { - NppExec.GetOptions().SetBool(OPTB_CONSOLE_SAVECMDHISTORY, i ? true : false); + Options.SetBool(OPTB_CONSOLE_SAVECMDHISTORY, i ? true : false); } - + // comment delimiter... - + szText[0] = 0; m_edCommentDelim.GetWindowText(szText, MAX_SCRIPTNAME - 1); - NppExec.GetOptions().SetStr(OPTS_COMMENTDELIMITER, szText); - + Options.SetStr(OPTS_COMMENTDELIMITER, szText); + // applying options... - + if ( colorValuesChanged() ) { + if ( Options.GetBool(OPTB_CONSOLE_USEEDITORCOLORS) ) + { + NppExec.GetConsole().ApplyEditorColours(false); + } + else + { + NppExec.GetConsole().SetCurrentColorTextNorm(g_colorTextNorm); + NppExec.GetConsole().SetCurrentColorBkgnd(g_colorBkgnd); + } NppExec.GetConsole().UpdateColours(); } - - i = NppExec.GetOptions().GetInt(OPTI_RICHEDIT_MAXTEXTLEN); + + i = Options.GetInt(OPTI_RICHEDIT_MAXTEXTLEN); if ( m_nREMaxLen != i ) { NppExec.GetConsole().GetConsoleEdit().ExLimitText(i); } - + NppExec.SaveOptions(); if ( m_bNppRestartRequired ) @@ -740,6 +724,13 @@ void CAdvOptDlg::OnChMacrosSubmenu() m_bNppRestartRequired = true; } +void CAdvOptDlg::OnChEditorColorsConsole() +{ + BOOL bIsChecked = m_chUseEditorColorsInConsole.IsChecked(); + m_edTextColorNorm.EnableWindow(!bIsChecked); + m_edBkColor.EnableWindow(!bIsChecked); +} + void CAdvOptDlg::OnEdItemNameChange() { if ( m_edItemName.GetTextLength() > 0 ) @@ -795,10 +786,12 @@ void CAdvOptDlg::OnLbMenuItemsSelChange() i = c_base::_tstr_unsafe_rfind(szItemName, i, cszUserMenuItemSep); if ( i >= 0 ) { - p = c_base::_tstr_unsafe_rskip_tabspaces(szItemName, i); + p = szItemName + i - 1; + while ( NppExecHelpers::IsAnySpaceChar(*p) ) --p; *(++p) = 0; // cut at cszItemSep position i += lstrlen(cszUserMenuItemSep); // postion after cszItemSep - p = c_base::_tstr_unsafe_skip_tabspaces(szItemName + i); + p = szItemName + i; + while ( NppExecHelpers::IsAnySpaceChar(*p) ) ++p; lstrcpy(szItemScript, p); } else @@ -830,37 +823,35 @@ void CAdvOptDlg::OnLbMenuItemsSelChange() void CAdvOptDlg::ShowError(LPCTSTR szMessage) { - ::MessageBox(m_hWnd, szMessage, + ::MessageBox(m_hWnd, szMessage, _T("NppExec Advanced Options"), MB_OK | MB_ICONERROR); } void CAdvOptDlg::ShowWarning(LPCTSTR szMessage) { - ::MessageBox(m_hWnd, szMessage, + ::MessageBox(m_hWnd, szMessage, _T("NppExec Advanced Options"), MB_OK | MB_ICONWARNING); } void CAdvOptDlg::colorValuesInit() { - m_bufColorTextNorm.Assign( (lpcbyte_t) &g_colorTextNorm, sizeof(COLORREF) ); - m_bufColorTextErr.Assign( (lpcbyte_t) &g_colorTextErr, sizeof(COLORREF) ); - m_bufColorTextMsg.Assign( (lpcbyte_t) &g_colorTextMsg, sizeof(COLORREF) ); - m_bufColorBkgnd.Assign( (lpcbyte_t) &g_colorBkgnd, sizeof(COLORREF) ); + m_OrgColorTextNorm = g_colorTextNorm; + m_OrgColorTextErr = g_colorTextErr; + m_OrgColorTextMsg = g_colorTextMsg; + m_OrgColorBkgnd = g_colorBkgnd; + m_bUseEditorColorsInConsole = Runtime::GetNppExec().GetOptions().GetBool(OPTB_CONSOLE_USEEDITORCOLORS); } BOOL CAdvOptDlg::colorValuesChanged() { - if ( m_bufColorTextNorm.Compare((lpcbyte_t) &g_colorTextNorm, sizeof(COLORREF)) != 0 ) - return TRUE; - - if ( m_bufColorTextErr.Compare((lpcbyte_t) &g_colorTextErr, sizeof(COLORREF)) != 0 ) - return TRUE; - - if ( m_bufColorTextMsg.Compare((lpcbyte_t) &g_colorTextMsg, sizeof(COLORREF)) != 0 ) + if ( m_OrgColorTextNorm != g_colorTextNorm || + m_OrgColorTextErr != g_colorTextErr || + m_OrgColorTextMsg != g_colorTextMsg || + m_OrgColorBkgnd != g_colorBkgnd || + m_bUseEditorColorsInConsole != Runtime::GetNppExec().GetOptions().GetBool(OPTB_CONSOLE_USEEDITORCOLORS) ) + { return TRUE; + } - if ( m_bufColorBkgnd.Compare((lpcbyte_t) &g_colorBkgnd, sizeof(COLORREF)) != 0 ) - return TRUE; - return FALSE; } diff --git a/NppExec/src/DlgAdvancedOptions.h b/NppExec/src/DlgAdvancedOptions.h index d9cef19..fce1919 100644 --- a/NppExec/src/DlgAdvancedOptions.h +++ b/NppExec/src/DlgAdvancedOptions.h @@ -28,8 +28,8 @@ along with this program. If not, see . #include "cpp/CBufT.h" -extern const TCHAR* cszUserMenuItemSep; -extern const TCHAR* cszUserMenuSeparator; +extern const TCHAR* const cszUserMenuItemSep; +extern const TCHAR* const cszUserMenuSeparator; INT_PTR CALLBACK AdvancedOptionsDlgProc(HWND, UINT, WPARAM, LPARAM); @@ -63,12 +63,17 @@ class CAdvOptDlg : public CAnyWindow CAnyWindow m_btMoveDown; CAnyWindow m_btModify; CAnyWindow m_btDelete; + CAnyCheckBox m_chUseEditorColorsInConsole; + CAnyCheckBox m_chUseEditorColorsInExecDlg; - CByteBuf m_bufColorTextNorm; - CByteBuf m_bufColorTextErr; - CByteBuf m_bufColorTextMsg; - CByteBuf m_bufColorBkgnd; + HWND m_hToolTip; + + COLORREF m_OrgColorTextNorm; + COLORREF m_OrgColorTextErr; + COLORREF m_OrgColorTextMsg; + COLORREF m_OrgColorBkgnd; int m_nREMaxLen; + bool m_bUseEditorColorsInConsole; bool m_bNppRestartRequired; protected: @@ -80,6 +85,7 @@ class CAdvOptDlg : public CAnyWindow ~CAdvOptDlg(); void OnInitDlg(HWND hDlg); + void OnEndDlg(); BOOL OnBtOK(); void OnBtCancel(); void OnBtItemNew(); @@ -90,6 +96,7 @@ class CAdvOptDlg : public CAnyWindow void OnCbOptHotkeySelChange(); void OnCbOptToolbarBtnSelChange(); void OnChMacrosSubmenu(); + void OnChEditorColorsConsole(); void OnEdItemNameChange(); void OnLbMenuItemsSelChange(); diff --git a/NppExec/src/DlgConsole.cpp b/NppExec/src/DlgConsole.cpp index 467bfb7..c7847d2 100644 --- a/NppExec/src/DlgConsole.cpp +++ b/NppExec/src/DlgConsole.cpp @@ -19,6 +19,7 @@ along with this program. If not, see . #include "DlgConsole.h" #include "NppExec.h" #include "NppExecEngine.h" +#include "ChildProcess.h" #include "npp_files/PluginInterface.h" // docking feature #include "npp_files/Docking.h" // docking feature #include "WarningAnalyzer.h" @@ -44,6 +45,7 @@ extern COLORREF g_colorBkgnd; extern COLORREF g_colorTextNorm; INT nConsoleFirstUnlockedPos = 0; +bool bFuncItemEntered = false; const TCHAR CONSOLE_CMD_HELP[] = _T("HELP"); // show console commands const TCHAR CONSOLE_CMD_VER[] = _T("VER"); // show plugin's version @@ -51,7 +53,7 @@ const TCHAR CONSOLE_CMD_MANUAL[] = _T("MANUAL"); // show plugin's manual const TCHAR CONSOLE_CMD_ABOUT[] = _T("ABOUT"); // show plugin's about #ifdef UNICODE -const TCHAR PLUGIN_CURRENT_VER[] = NPPEXEC_VER_STR _T(" Unicode"); // see also: NppExecPluginInterface.cpp +const TCHAR PLUGIN_CURRENT_VER[] = NPPEXEC_VER_STR; // see also: NppExecPluginInterface.cpp #else const TCHAR PLUGIN_CURRENT_VER[] = NPPEXEC_VER_STR _T(" ANSI"); // see also: NppExecPluginInterface.cpp #endif @@ -60,6 +62,7 @@ const TCHAR PLUGIN_CURRENT_VER[] = NPPEXEC_VER_STR _T(" ANSI"); // see also: Npp const TCHAR CONSOLE_COMMANDS_INFO[] = _T_RE_EOL \ _T("-------- Console keys --------") _T_RE_EOL \ _T("Enter - executes entered command") _T_RE_EOL \ + _T("Shift+Enter - new line") _T_RE_EOL \ _T("Tab - auto-completes current command/looks through the commands history") _T_RE_EOL \ _T("Shift+Tab - the same as Tab but backwards") _T_RE_EOL \ _T("Arrow Up - previous command (when Console Commands History is enabled)") _T_RE_EOL \ @@ -93,6 +96,7 @@ const TCHAR CONSOLE_COMMANDS_INFO[] = _T_RE_EOL \ _T("dir - lists files and subdirs") _T_RE_EOL \ _T("dir - lists files/subdirs matched the mask") _T_RE_EOL \ _T("echo - prints a text in the Console") _T_RE_EOL \ + _T("echo~ - prints the calculated/transformed result") _T_RE_EOL \ _T("if goto ~ strescape - simple character escaping (e.g. to '\\t')") _T_RE_EOL \ _T("set ~ strunescape - simple character unescaping (e.g. '\\n' to )") _T_RE_EOL \ _T("set ~ strexpand - expands all $(sub) values within ") _T_RE_EOL \ - _T("set ~ normpath - returns a normalized path") _T_RE_EOL \ _T("set ~ strfromhex - returns a string from the hex-string") _T_RE_EOL \ _T("set ~ strtohex - returns a hex-string from the string") _T_RE_EOL \ _T("set ~ chr - returns a character from a character code ") _T_RE_EOL \ _T("set ~ ord - returns a decimal character code of a character ") _T_RE_EOL \ _T("set ~ ordx - returns a hexadecimal character code of a character ") _T_RE_EOL \ + _T("set ~ normpath - returns a normalized path") _T_RE_EOL \ + _T("set ~ fileexists - checks if a given file exists") _T_RE_EOL \ + _T("set ~ direxists - checks if a given directory exists") _T_RE_EOL \ _T("set local - shows all user\'s local variables") _T_RE_EOL \ _T("set local - shows the value of user\'s local variable ") _T_RE_EOL \ _T("set local = ... - sets the value of user\'s local variable ") _T_RE_EOL \ _T("set local ~ ... - calculates the value of user\'s local variable") _T_RE_EOL \ + _T("set +v = ... - sets the value of using delayed vars substitution") _T_RE_EOL \ + _T("set +v local = ... - sets the local using delayed vars substitution") _T_RE_EOL \ _T("unset - removes user\'s variable ") _T_RE_EOL \ _T("unset = - removes user\'s variable ") _T_RE_EOL \ _T("unset local - removes user\'s local variable ") _T_RE_EOL \ @@ -162,15 +170,16 @@ const TCHAR CONSOLE_COMMANDS_INFO[] = _T_RE_EOL \ _T("sel_save : - see \"sel_saveto\"") _T_RE_EOL \ _T("sel_settext - replace current selection with the text specified") _T_RE_EOL \ _T("sel_settext+ - replace current selection with the text specified") _T_RE_EOL \ - _T("text_loadfrom - replace the whole text with a file\'s content") _T_RE_EOL \ + _T("text_loadfrom - replace the entire text with a file\'s content") _T_RE_EOL \ _T("text_load - see \"text_loadfrom\"") _T_RE_EOL \ - _T("text_saveto - save the whole text to a file") _T_RE_EOL \ - _T("text_saveto : - save the whole text to a file") _T_RE_EOL \ + _T("text_saveto - save the entire text to a file") _T_RE_EOL \ + _T("text_saveto : - save the entire text to a file") _T_RE_EOL \ _T("text_save : - see \"text_saveto\"") _T_RE_EOL \ _T("clip_settext - set the clipboard text") _T_RE_EOL \ _T("npp_exec ', content) + header = """""".format(name) + + if old_script is not None: + if not rewrite: + return + start, end = old_script.span() + new_script = header.strip() + content = content.replace(content[start:end], new_script) + html.truncate(0) + else: + head = re.search(r'(?i)', content) + if head is not None: + endtag = head.group() + content = content.replace(endtag, "{0}\n{1}".format(header, endtag)) + + html.seek(0) + html.write(content) + + try: + src = Path(PurePath(sys.path[0]) / 'docs' / name) + out = doc.parent / src.name + if rewrite or not out.exists(): + out.write_bytes(src.read_bytes()) + except (AttributeError, TypeError, FileNotFoundError) as e: + print(str(e), file=sys.stderr) + sys.exit(2) + + +def run(format_opts: dict, script_opts: dict): + parser = NppExecDocParser() + docdir = Path(PurePath(sys.path[0]) / 'docs' / 'NppExec_Manual') + topics = Path(PurePath(sys.path[0]) / 'docs' / 'topics.js') + + if not docdir.exists(): + print('No such directory:', docdir) + sys.exit(1) + + print('Parsing docs in', docdir, '...') + + for doc in docdir.glob('**/*.html'): + if doc.stem in ['toc', 'index']: + continue + if script_opts.get('add_script', False): + rewrite = script_opts.get('update', False) + name = script_opts.get('script_name', 'show_matches.js') + include_finder_script(doc, name, rewrite) + + parser.collect_info(docdir, doc) + + print('Found', len(parser.topics.keys()), 'topics') + + with open (topics, 'w', encoding=NppExecDocParser.CHARSET) as out: + out.write("var NPPEXEC_HELP_TOPICS = {0}".format(json.dumps(parser.topics, **format_opts))) + + +def parse_options(): + arg_parser = ArgumentParser(description="Extract metadata from NppExec's HTML docs.") + arg_parser.add_argument('-i', '--indent-width', action='store', type=int, + dest='indent', metavar='n', default=None, + help='use %(metavar)s number of spaces to indent JSON properties') + arg_parser.add_argument('-s', '--sort-keys', action='store_true', + dest='sort_keys', default=False, + help='sort JSON properties in ascending order') + arg_parser.add_argument('-a', '--add-finder-script', action='store_true', + dest='add_script', default=False, + # must be given if '-u' is given + required=bool(set(sys.argv).intersection(['-u', '--update-script'])), + help='rewrite docs with a script to highlight matching search strings') + arg_parser.add_argument('-u', '--update-script', action='store_true', + dest='update_script', default=False, + help='rewrite docs even if the already has a + + +
+

 

+

NppExec User Guide

+

by

+

Vitaliy Dovgan

+

A Notepad++ Plugin that Allows You to Run Commands and Programs Directly from the Editor

+

 

+

User Guide Version 3.4

+

October 2025

+

 

+

 

+
+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/1.1.html b/docs/NppExec_Manual/1.1.html similarity index 63% rename from NppExec/doc/NppExec/NppExec_Manual/1.1.html rename to docs/NppExec_Manual/1.1.html index e5dcc17..41e8116 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/1.1.html +++ b/docs/NppExec_Manual/1.1.html @@ -1,19 +1,20 @@ - - - - - -1.1. Introduction - - -

1.1. Introduction

-

NppExec is a plugin for Notepad++ which allows you to run some commands/programs directly from Notepad++ and provides an output window (NppExec's Console).

-

NppExec can be used for running other programs from Notepad++, passing text from Notepad++ to some external tool, compiling source files (using external compiler) etc.

-

When the NppExec plugin is installed, - you can see its icon "Show NppExec Console" on Notepad++'es toolbar, and - you can find NppExec's submenu under Plugins menu of Notepad++.

-

You can always find the latest version of NppExec at https://sourceforge.net/projects/npp-plugins/ - it is there among other Notepad++'es plugins.

-

The latest sources of NppExec can be found at https://github.com/d0vgan/nppexec/.

- - - + + + + + +1.1. Introduction + + + +

1.1. Introduction

+

NppExec is a plugin for Notepad++ which allows you to run some commands/programs directly from Notepad++ and provides an output window (NppExec's Console).

+

NppExec can be used for running other programs from Notepad++, passing text from Notepad++ to some external tool, compiling source files (using external compiler) etc.

+

When the NppExec plugin is installed, + you can see its icon "Show NppExec Console" on Notepad++'es toolbar, and + you can find NppExec's submenu under Plugins menu of Notepad++.

+

You can always find the latest version of NppExec at https://sourceforge.net/projects/npp-plugins/ - it is there among other Notepad++'es plugins.

+

The latest sources of NppExec can be found at https://github.com/d0vgan/nppexec/ .

+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/1.2.html b/docs/NppExec_Manual/1.2.html similarity index 71% rename from NppExec/doc/NppExec/NppExec_Manual/1.2.html rename to docs/NppExec_Manual/1.2.html index ab6ae6b..2a6d6d6 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/1.2.html +++ b/docs/NppExec_Manual/1.2.html @@ -1,23 +1,23 @@ - - - - - -1.2. NppExec is... - - -

1.2. NppExec is...

-
-

+ NppExec is an intermediary between Notepad++ and external tool/compiler. - It allows to run external tool/compiler directly from Notepad++.

-

+ NppExec is a Console window which can show the running process'es - output, and can redirect the Console window's input to the running process - (with some limitations).

-

+ NppExec is an interpreter of its own internal commands. NppExec can - execute several commands one after another (so-called NppExec's script) - from its "Execute NppExec Script..." dialog - and can execute single command directly from its Console - window.

-
- - + + + + + +1.2. NppExec is... + + + +

1.2. NppExec is...

+
+

+ NppExec is an intermediary between Notepad++ and external tool/compiler. + It allows to run external tool/compiler directly from Notepad++.

+

+ NppExec is a Console window which can show the running process'es + output, and can redirect the Console window's input to the running process + (with some limitations).

+

+ NppExec is an interpreter of its own internal commands. NppExec can + execute several commands one after another (so-called NppExec's script) + from its "Execute NppExec Script..." dialog and can execute + single command or multiple commands directly from its Console window.

+
+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/1.3.html b/docs/NppExec_Manual/1.3.html similarity index 92% rename from NppExec/doc/NppExec/NppExec_Manual/1.3.html rename to docs/NppExec_Manual/1.3.html index 78e8c2d..83f5212 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/1.3.html +++ b/docs/NppExec_Manual/1.3.html @@ -1,32 +1,33 @@ - - - - - -1.3. NppExec is not... - - -

1.3. NppExec is not...

-
-

- NppExec is not a console emulator. NppExec redirects the running process'es - output to its Console window, and can redirect the Console window's - input to - the running process (with some limitations). The NppExec's Console - is not a "real" console window (actually, it uses RichEdit control for - text input/output), it does not provide a console screen buffer. Thus, - a console - application which requires a "real" console - screen buffer must be run in its own console window (using NPP_RUN - command).

-

- NppExec is not a command interpreter. NppExec does not understand such - commands as 'copy', 'call', 'for' and so on because it is neither a "real" console - nor a console emulator. However, NppExec has its own internal implementation - of such commands as 'cls', 'cd', 'dir', 'echo', 'set' ('env_set') and - introduces other, specific, commands. Also you can use "cmd /c <command>" to - execute any cmd's command inside NppExec.

-

- NppExec is not a compiler. NppExec allows you to use external tools and compilers - to process/compile your current file, but it has no ability to do it - by itself. No magic here :)

-
- - + + + + + +1.3. NppExec is not... + + + +

1.3. NppExec is not...

+
+

- NppExec is not a console emulator. NppExec redirects the running process'es + output to its Console window, and can redirect the Console window's + input to + the running process (with some limitations). The NppExec's Console + is not a "real" console window (actually, it uses RichEdit control for + text input/output), it does not provide a console screen buffer. Thus, + a console + application which requires a "real" console + screen buffer must be run in its own console window (using NPP_RUN + command).

+

- NppExec is not a command interpreter. NppExec does not understand such + commands as 'copy', 'call', 'for' and so on because it is neither a "real" console + nor a console emulator. However, NppExec has its own internal implementation + of such commands as 'cls', 'cd', 'dir', 'echo', 'set' ('env_set') and + introduces other, specific, commands. Also you can use "cmd /c <command>" to + execute any cmd's command inside NppExec.

+

- NppExec is not a compiler. NppExec allows you to use external tools and compilers + to process/compile your current file, but it has no ability to do it + by itself. No magic here :)

+
+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/1.html b/docs/NppExec_Manual/1.html similarity index 52% rename from NppExec/doc/NppExec/NppExec_Manual/1.html rename to docs/NppExec_Manual/1.html index 3205d31..b2f312f 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/1.html +++ b/docs/NppExec_Manual/1.html @@ -1,10 +1,12 @@ - - - - - - - -

1. What is NppExec

- - + + + + + +1. What is NppExec + + + +

1. What is NppExec

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/2.1.html b/docs/NppExec_Manual/2.1.html similarity index 81% rename from NppExec/doc/NppExec/NppExec_Manual/2.1.html rename to docs/NppExec_Manual/2.1.html index be4e41e..bcd32b1 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/2.1.html +++ b/docs/NppExec_Manual/2.1.html @@ -1,18 +1,19 @@ - - - - - -2.1. What? Installation? - - -

2.1. What? Installation?

-

Usually the latest stable version of NppExec can be installed via Notepad++'es Plugin Manager, so you don't have to do anything complicated.

-

However, you may want to know:

-
    -
  • what actually is the NppExec plugin and how can it be installed or removed;
  • -
  • how can you install the latest version of NppExec;
  • -
  • how can you use several copies of NppExec.
  • -
- - + + + + + +2.1. What? Installation? + + + +

2.1. What? Installation?

+

Usually the latest stable version of NppExec can be installed via Notepad++'es Plugin Manager, so you don't have to do anything complicated.

+

However, you may want to know:

+
    +
  • what actually is the NppExec plugin and how can it be installed or removed;
  • +
  • how can you install the latest version of NppExec;
  • +
  • how can you use several copies of NppExec.
  • +
+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/2.2.html b/docs/NppExec_Manual/2.2.html similarity index 79% rename from NppExec/doc/NppExec/NppExec_Manual/2.2.html rename to docs/NppExec_Manual/2.2.html index 1cebfe2..7e68a8a 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/2.2.html +++ b/docs/NppExec_Manual/2.2.html @@ -1,15 +1,16 @@ - - - - - -2.2. The NppExec plugin (NppExec.dll) - - -

2.2. The NppExec plugin (NppExec.dll)

-

NppExec is a dynamic-link library - (DLL) implemented as a plugin for Notepad++. Actually (physically) the NppExec - plugin is one file named "NppExec.dll". This file ("NppExec.dll") must be -placed (copied) to Notepad++'es Plugins subfolder in order to work with Notepad++.

- - + + + + + +2.2. The NppExec plugin (NppExec.dll) + + + +

2.2. The NppExec plugin (NppExec.dll)

+

NppExec is a dynamic-link library + (DLL) implemented as a plugin for Notepad++. Actually (physically) the NppExec + plugin is one file named "NppExec.dll". This file ("NppExec.dll") must be +placed (copied) to Notepad++'es Plugins subfolder in order to work with Notepad++.

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/2.3.html b/docs/NppExec_Manual/2.3.html similarity index 72% rename from NppExec/doc/NppExec/NppExec_Manual/2.3.html rename to docs/NppExec_Manual/2.3.html index bd6380b..1bb27eb 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/2.3.html +++ b/docs/NppExec_Manual/2.3.html @@ -1,32 +1,33 @@ - - - - - -2.3. Installing the latest version - - -

2.3. Installing the latest version

-

You can always find the latest version of NppExec at https://sourceforge.net/projects/npp-plugins/ - it is there among other Notepad++'es plugins.

-

The latest sources of NppExec can be found at https://github.com/d0vgan/nppexec/.

-

Once you download the archive containing - the latest "NppExec.dll" file, extract the content of this archive to your Notepad++'es Plugins subfolder (you may need to overwrite your existing NppExec's files with - the latest ones). Also you may be interested in the documentation inside the - archive as it always contains the latest information about NppExec's commands -and variables, advanced options and changes.

-

If you are not sure about the "Notepad++'es Plugins subfolder", -do the following:

-
    -
  1. locate - the file "notepad++.exe" on your computer (usually it is located - somewhere here: C:\Program Files\Notepad++\notepad++.exe);
  2. -
  3. go - to the folder which contains the file "notepad++.exe" (e.g. C:\Program - Files\Notepad++);
  4. -
  5. go - to its subfolder "plugins" (e.g. C:\Program Files\Notepad++\plugins);
  6. -
  7. you - are there! :)
  8. -
- - + + + + + +2.3. Installing the latest version + + + +

2.3. Installing the latest version

+

You can always find the latest version of NppExec at https://sourceforge.net/projects/npp-plugins/ - it is there among other Notepad++'es plugins.

+

The latest sources of NppExec can be found at https://github.com/d0vgan/nppexec/ .

+

Once you download the archive containing + the latest "NppExec.dll" file, extract the content of this archive to your Notepad++'es Plugins subfolder (you may need to overwrite your existing NppExec's files with + the latest ones). Also you may be interested in the documentation inside the + archive as it always contains the latest information about NppExec's commands +and variables, advanced options and changes.

+

If you are not sure about the "Notepad++'es Plugins subfolder", +do the following:

+
    +
  1. locate + the file "notepad++.exe" on your computer (usually it is located + somewhere here: C:\Program Files\Notepad++\notepad++.exe);
  2. +
  3. go + to the folder which contains the file "notepad++.exe" (e.g. C:\Program + Files\Notepad++);
  4. +
  5. go + to its subfolder "plugins" (e.g. C:\Program Files\Notepad++\plugins);
  6. +
  7. you + are there! :)
  8. +
+ + diff --git a/docs/NppExec_Manual/2.4.html b/docs/NppExec_Manual/2.4.html new file mode 100644 index 0000000..cd534b8 --- /dev/null +++ b/docs/NppExec_Manual/2.4.html @@ -0,0 +1,41 @@ + + + + + +2.4. Using several copies of NppExec + + + +

2.4. Using several copies of NppExec

+

You can have several copies of "NppExec.dll" in + your Notepad++'es Plugins subfolder in order to have several NppExec's Console + windows. Each copy of NppExec saves its own options and its own console commands + history (if it is enabled in NppExec's options). In the same time, saved +NppExec's scripts are shared between several copies of NppExec.

+

To have several copies of "NppExec.dll", just copy it with different name(s), for example, "NppExec2.dll", "NppExecCpp.dll", "NppExecWeb.dll" and so on. This will give you additional NppExec's Console windows with the corresponding titles: "Console2", "ConsoleCpp", "ConsoleWeb" and +so on.

+

Note: in modern versions of Notepad++, each instance of NppExec.dll should be located in its own folder.
+Thus, to have e.g. "NppExecCpp.dll", make a copy of the entire folder "plugins\NppExec" as "plugins\NppExecCpp" and then rename "plugins\NppExecCpp\NppExec.dll" to "plugins\NppExecCpp\NppExecCpp.dll". (Be sure that the .dll name matches the folder name!)
+Also, be sure to have the inner subfolder "NppExecCpp\NppExec" (that contains "BaseDef.h", "menuCmdID.h" and so on) because each instance of NppExec.dll needs it near itself. (This inner "NppExec" subfolder should preserve its initial name).
+To sum up, the following files/folders tree is expected in case of "NppExec.dll" and "NppExecCpp.dll":

+
+
plugins\
+    NppExec\
+        NppExec\
+            BaseDef.h
+            menuCmdID.h
+            Notepad_plus_msgs.h
+            Scintilla.h
+        NppExec.dll
+    NppExecCpp\
+        NppExec\
+            BaseDef.h
+            menuCmdID.h
+            Notepad_plus_msgs.h
+            Scintilla.h
+        NppExecCpp.dll
+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/2.5.html b/docs/NppExec_Manual/2.5.html similarity index 94% rename from NppExec/doc/NppExec/NppExec_Manual/2.5.html rename to docs/NppExec_Manual/2.5.html index 40a6ef4..a215c8e 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/2.5.html +++ b/docs/NppExec_Manual/2.5.html @@ -1,17 +1,18 @@ - - - - - -2.5. Unicode and ANSI, 32-bit and 64-bit version - - -

2.5. Unicode and ANSI, 32-bit and 64-bit version

-

Originally there were two builds of NppExec: the Unicode build and the ANSI build. The Unicode build was compatible with Unicode Notepad++ and the ANSI build was compatible with ANSI Notepad++. You could check your version of Notepad++ by pressing F1 or from its main menu (? -> About Notepad++). You would see something similar to "Notepad++ v5.1.3 (UNICODE)" or "Notepad++ v5.1.3 (ANSI)". -The corresponding version of NppExec (Unicode or ANSI) was required.

-

The Unicode version of Notepad++ was recommended. The ANSI version of Notepad++ existed just for compatibility with old non-Unicode systems (such as Windows 98 or Millenium) and with old non-Unicode plugins.

-

Talking about NppExec, its Unicode build is more powerful because it has a fully Unicode interface and supports input files in ANSI, UTF-8, UCS-2 LE (Unicode wide characters in Windows) and UCS-2 BE encodings. The ANSI version of NppExec supported just ANSI input files. It was caused by the following reason: conversion from UTF-8 or UCS-2 to ANSI might lead to loss of some Unicode characters which have no ANSI analogue.

-

Starting from Windows 2000, the operational system (i.e. Windows) itself is Unicode, which means it internally operates with Unicode characters. The next versions of Windows, such as Windows XP, Windows Vista and Windows 7, also have a Unicode core. So now, when most of the people have at least Windows 7 (or even Windows 10), there is no much sense in having a non-Unicode text editor while Windows itself is Unicode natively. So today's Notepad++ is a Unicode program, as well as NppExec, Notepad++'s plugin, is also Unicode.

-

With today's 64-bit (also known as "x64") CPUs and operational systems, more and more software become 64-bit. Notepad++ is also available as a 64-bit (x64) and a 32-bit (x86) application. The 64-bit Notepad++ runs under 64-bit Windows and allows to use more RAM - in practice it means you can open larger files (with the size of 1 GB and more) with it. The 32-bit Notepad++ runs under both 64-bit and 32-bit Windows and additionally supports old 32-bit plugins that have not been ported to 64-bit yet. Luckily, NppExec is available in both 64-bit and 32-bit versions, so it's up to you which version of Notepad++ to choose :)

- - + + + + + +2.5. Unicode and ANSI, 32-bit and 64-bit version + + + +

2.5. Unicode and ANSI, 32-bit and 64-bit version

+

Originally there were two builds of NppExec: the Unicode build and the ANSI build. The Unicode build was compatible with Unicode Notepad++ and the ANSI build was compatible with ANSI Notepad++. You could check your version of Notepad++ by pressing F1 or from its main menu (? -> About Notepad++). You would see something similar to "Notepad++ v5.1.3 (UNICODE)" or "Notepad++ v5.1.3 (ANSI)". +The corresponding version of NppExec (Unicode or ANSI) was required.

+

The Unicode version of Notepad++ was recommended. The ANSI version of Notepad++ existed just for compatibility with old non-Unicode systems (such as Windows 98 or Millenium) and with old non-Unicode plugins.

+

Talking about NppExec, its Unicode build is more powerful because it has a fully Unicode interface and supports input files in ANSI, UTF-8, UCS-2 LE (Unicode wide characters in Windows) and UCS-2 BE encodings. The ANSI version of NppExec supported just ANSI input files. It was caused by the following reason: conversion from UTF-8 or UCS-2 to ANSI might lead to loss of some Unicode characters which have no ANSI analogue.

+

Starting from Windows 2000, the operational system (i.e. Windows) itself is Unicode, which means it internally operates with Unicode characters. The next versions of Windows, such as Windows XP, Windows Vista and Windows 7, also have a Unicode core. So now, when most of the people have at least Windows 7 (or even Windows 10), there is no much sense in having a non-Unicode text editor while Windows itself is Unicode natively. So today's Notepad++ is a Unicode program, as well as NppExec, Notepad++'s plugin, is also Unicode.

+

With today's 64-bit (also known as "x64") CPUs and operational systems, more and more software become 64-bit. Notepad++ is also available as a 64-bit (x64) and a 32-bit (x86) application. The 64-bit Notepad++ runs under 64-bit Windows and allows to use more RAM - in practice it means you can open larger files (with the size of 1 GB and more) with it. The 32-bit Notepad++ runs under both 64-bit and 32-bit Windows and additionally supports old 32-bit plugins that have not been ported to 64-bit yet. Luckily, NppExec is available in both 64-bit and 32-bit versions, so it's up to you which version of Notepad++ to choose :)

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/2.html b/docs/NppExec_Manual/2.html similarity index 52% rename from NppExec/doc/NppExec/NppExec_Manual/2.html rename to docs/NppExec_Manual/2.html index 14f308e..7b904d0 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/2.html +++ b/docs/NppExec_Manual/2.html @@ -1,10 +1,12 @@ - - - - - - - -

2. Installation

- - + + + + + +2. Installation + + + +

2. Installation

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.1.html b/docs/NppExec_Manual/3.1.html similarity index 97% rename from NppExec/doc/NppExec/NppExec_Manual/3.1.html rename to docs/NppExec_Manual/3.1.html index 82c29b1..19a696b 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/3.1.html +++ b/docs/NppExec_Manual/3.1.html @@ -1,52 +1,53 @@ - - - - - -3.1. Getting help - - -

3.1. Getting help

-

The description of all commands - and environment variables supported by current version of NppExec can be -found in the file "NppExec.txt". Usually you can find this file in downloaded NppExec's archive [2.3] or in Notepad++'es Plugins subfolder [2.3] (in its "doc" subfolder). -Also you can open "NppExec.txt" in Notepad++ via Plugins -> NppExec -> Help/Docs...

-

All advanced "hidden" settings of current version of NppExec are described in the file "NppExec_TechInfo.txt". Usually you can find this file in the same place where the file "NppExec.txt" is - located. -Also you can open "NppExec_TechInfo.txt" in Notepad++ via Plugins -> NppExec -> Help/Docs... -Remark: you can change some of the advanced settings using NppExec's -Advanced Options dialog.

-

The most recent and detailed information - about all NppExec's commands and environment variables can be found in NppExec's - built-in help. To use the built-in help, open NppExec's Console [3.5], type "help" and -press Enter. You'll see a long list which contains:

-
-

- NppExec's Console hotkeys;

-

- NppExec's Console commands (which work in the Console only);

-

- NppExec's general commands (which work everywhere in NppExec);

-

- NppExec's predefined environment variables.

-
-

To get detailed help about any NppExec's - command, type "help <command>" and press Enter. For example, "help set", "help inputbox", "help npp_exec" etc. - The detailed help usually contains the command description, examples and -remarks. This is the most essential information.

-

To get all the available NppExec's help at once, type "help all" and press Enter. To save all the help into a text file, type "help all" first and then type the following:

-
-
con_saveto $(NPP_DIRECTORY)\plugins\doc\NppExec\NppExec_HelpAll.txt
-
- -

Some additional information can be found in NppExec's Help/About window. For example:

-
-

- You can execute NppExec's commands and scripts directly from the Console window;

-

- Commands are case-insensitive (i.e. NPP_OPEN is the same as Npp_Open);

-

- and so on.

-
-

And, of course, we should not forget about this manual itself. Its intention is to lead you through NppExec usage from simple to advanced features. So, if you do not understand something in some section, it most likely has been described in previous sections. For example, let's remind the section [1.3]:

-
    -
  • It says "NppExec is not a console emulator". What does it mean to us? Let's analyse. NppExec provides a graphical "Console" window, but it is not a regular text-mode console. The "Console" window only looks similar to a regular text-mode console, but can not provide all the features of it. NppExec's Console window can show you some output and even allows some input - but this may not be possible for some applications which require native features of a regular text-mode console. By the same reason, you may encounter different behaviour of some applications under NppExec's Console and a regular console. (Such limitations are not intentional - they are caused by implementation-specific things which seem to be application-related or system-related and thus out of NppExec's control.)
  • -
  • Also it says "NppExec is not a command interpreter". We already have discussed that NppExec is not a console emulator, and here is another thing to remember: NppExec is not cmd.exe! It means NppExec has nothing to do with native cmd's commands and does not even invoke cmd.exe until you specify it explicitly. NppExec can only execute its own commands and run external executables you specify. Thus, generally speaking, NppExec and cmd.exe are completely different things and you may not expect the same behaviour of NppExec and cmd.exe. Though you can always invoke cmd.exe explicitly. We will return to this in [3.2], [3.3], [4.0], [4.4] and [4.5].
  • -
  • And, finally, it says "NppExec is not a compiler". Do you have some suggestions about this statement already? I guess you do :) Yes, NppExec itself can not compile any file. NppExec simply does not know what to do with that file. It's completely up to you to specify a correct compiler for a certain file - and NppExec will run that compiler for you. But not before you specify it explicitly. We will return to this in [4.0] and [4.7.4].
  • -
-

So, generally speaking, NppExec is a tool. This tool does exactly what you tell it to do - with no assumptions, no implicit invoking of something and so on. No magic here [1.3]. And the goal of this manual is to teach you to use NppExec. Sometimes you will not find direct examples which match your needs exactly - but there will be a general approach which should be used to cope with your task. Applying this general approach to your specific needs, you will be adapting it to these needs anyway - so some effort will be required in any case. And this manual can not - and does not - cover everything. Instead, it demonstrates WHAT you can achieve with NppExec and HOW you can achieve that. Once you understand the principles, you can use NppExec for any purpose. Good luck!

- - + + + + + +3.1. Getting help + + + +

3.1. Getting help

+

The description of all commands + and environment variables supported by current version of NppExec can be +found in the file "NppExec.txt". Usually you can find this file in downloaded NppExec's archive [2.3] or in Notepad++'es Plugins subfolder [2.3] (in its "doc" subfolder). +Also you can open "NppExec.txt" in Notepad++ via Plugins -> NppExec -> Help/Docs...

+

All advanced "hidden" settings of current version of NppExec are described in the file "NppExec_TechInfo.txt". Usually you can find this file in the same place where the file "NppExec.txt" is + located. +Also you can open "NppExec_TechInfo.txt" in Notepad++ via Plugins -> NppExec -> Help/Docs... +Remark: you can change some of the advanced settings using NppExec's +Advanced Options dialog.

+

The most recent and detailed information + about all NppExec's commands and environment variables can be found in NppExec's + built-in help. To use the built-in help, open NppExec's Console [3.5], type "help" and +press Enter. You'll see a long list which contains:

+
+

- NppExec's Console hotkeys;

+

- NppExec's Console commands (which work in the Console only);

+

- NppExec's general commands (which work everywhere in NppExec);

+

- NppExec's predefined environment variables.

+
+

To get detailed help about any NppExec's + command, type "help <command>" and press Enter. For example, "help set", "help inputbox", "help npp_exec" etc. + The detailed help usually contains the command description, examples and +remarks. This is the most essential information.

+

To get all the available NppExec's help at once, type "help all" and press Enter. To save all the help into a text file, type "help all" first and then type the following:

+
+
con_saveto $(NPP_DIRECTORY)\plugins\doc\NppExec\NppExec_HelpAll.txt
+
+ +

Some additional information can be found in NppExec's Help/About window. For example:

+
+

- You can execute NppExec's commands and scripts directly from the Console window;

+

- Commands are case-insensitive (i.e. NPP_OPEN is the same as Npp_Open);

+

- and so on.

+
+

And, of course, we should not forget about this manual itself. Its intention is to lead you through NppExec usage from simple to advanced features. So, if you do not understand something in some section, it most likely has been described in previous sections. For example, let's remind the section [1.3]:

+
    +
  • It says "NppExec is not a console emulator". What does it mean to us? Let's analyse. NppExec provides a graphical "Console" window, but it is not a regular text-mode console. The "Console" window only looks similar to a regular text-mode console, but can not provide all the features of it. NppExec's Console window can show you some output and even allows some input - but this may not be possible for some applications which require native features of a regular text-mode console. By the same reason, you may encounter different behaviour of some applications under NppExec's Console and a regular console. (Such limitations are not intentional - they are caused by implementation-specific things which seem to be application-related or system-related and thus out of NppExec's control.)
  • +
  • Also it says "NppExec is not a command interpreter". We already have discussed that NppExec is not a console emulator, and here is another thing to remember: NppExec is not cmd.exe! It means NppExec has nothing to do with native cmd's commands and does not even invoke cmd.exe until you specify it explicitly. NppExec can only execute its own commands and run external executables you specify. Thus, generally speaking, NppExec and cmd.exe are completely different things and you may not expect the same behaviour of NppExec and cmd.exe. Though you can always invoke cmd.exe explicitly. We will return to this in [3.2], [3.3], [4.0], [4.4] and [4.5].
  • +
  • And, finally, it says "NppExec is not a compiler". Do you have some suggestions about this statement already? I guess you do :) Yes, NppExec itself can not compile any file. NppExec simply does not know what to do with that file. It's completely up to you to specify a correct compiler for a certain file - and NppExec will run that compiler for you. But not before you specify it explicitly. We will return to this in [4.0] and [4.7.4].
  • +
+

So, generally speaking, NppExec is a tool. This tool does exactly what you tell it to do - with no assumptions, no implicit invoking of something and so on. No magic here [1.3]. And the goal of this manual is to teach you to use NppExec. Sometimes you will not find direct examples which match your needs exactly - but there will be a general approach which should be used to cope with your task. Applying this general approach to your specific needs, you will be adapting it to these needs anyway - so some effort will be required in any case. And this manual can not - and does not - cover everything. Instead, it demonstrates WHAT you can achieve with NppExec and HOW you can achieve that. Once you understand the principles, you can use NppExec for any purpose. Good luck!

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.2.html b/docs/NppExec_Manual/3.2.html similarity index 95% rename from NppExec/doc/NppExec/NppExec_Manual/3.2.html rename to docs/NppExec_Manual/3.2.html index 8a454bb..ce5a06f 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/3.2.html +++ b/docs/NppExec_Manual/3.2.html @@ -1,49 +1,50 @@ - - - - - -3.2. Do something (intro) - - -

3.2. Do something (intro)

-

The main principle of NppExec is - the same as Notepad++'es "Run..." command (F5): to execute a command given. - Usually it means to run some program/tool with specified parameters which - can be - passed in a form of Notepad++'es environment variables. For example, it allows - you to launch your current file in Internet Explorer or to compile your current -file using certain compiler. NppExec provides additional abilities for this:

-
-

- it has a Console window to show the console program's output

-

- it allows you to execute several commands one after another

-

- it supports all Notepad++'es environment variables plus several own variables

-

- it has additional commands which allow you to do more than you expect :)

-

- it is cool :)

-
-

NppExec actually provides four different ways to execute some command(s):

-
    -
  1. using - NppExec's Console [3.5] - allows you to enter some command and execute - it by pressing Enter;
  2. -
  3. using - the dialog "Execute NppExec Script..." [3.6] - allows you to enter several - commands (which will be executed one after another) and to save these - commands as NppExec's script;
  4. -
  5. using - NppExec's command "npp_exec <script>" - allows you to execute - commands from existing NppExec's script [3.7];
  6. -
  7. using - NppExec's command "npp_exec <file>" - allows you to execute - commands from existing text file [3.7].
  8. -
-

By the way, NppExec uses the 3rd way (described above) for its menu items which allow you to execute some NppExec's script.

-

Remarks:

-

NppExec by itself understands only its own internal commands and environment variables. When you type another command, - such as "copy", "cmd" or "calc", NppExec tries to run it as a child process - i.e. it performs CreateProcess(...) and waits until this process ends. - (Note: NppExec ver. 0.6 RC3 introduces a new advanced option "ChildProcess_RunPolicy" that allows to modify this behavior. Refer to [4.4] for more details.)

-

When you type something like "npp_run cmd" or "npp_run calc", - NppExec tries to run specified command (the argument of npp_run) as an external - process - i.e. it performs ShellExecute(...) and does not care about this process.

- - + + + + + +3.2. Do something (intro) + + + +

3.2. Do something (intro)

+

The main principle of NppExec is + the same as Notepad++'es "Run..." command (F5): to execute a command given. + Usually it means to run some program/tool with specified parameters which + can be + passed in a form of Notepad++'es environment variables. For example, it allows + you to launch your current file in Internet Explorer or to compile your current +file using certain compiler. NppExec provides additional abilities for this:

+
+

- it has a Console window to show the console program's output

+

- it allows you to execute several commands one after another

+

- it supports all Notepad++'es environment variables plus several own variables

+

- it has additional commands which allow you to do more than you expect :)

+

- it is cool :)

+
+

NppExec actually provides four different ways to execute some command(s):

+
    +
  1. using + NppExec's Console [3.5] - allows you to enter some command and execute + it by pressing Enter;
  2. +
  3. using + the dialog "Execute NppExec Script..." [3.6] - allows you to enter several + commands (which will be executed one after another) and to save these + commands as NppExec's script;
  4. +
  5. using + NppExec's command "npp_exec <script>" - allows you to execute + commands from existing NppExec's script [3.7];
  6. +
  7. using + NppExec's command "npp_exec <file>" - allows you to execute + commands from existing text file [3.7].
  8. +
+

By the way, NppExec uses the 3rd way (described above) for its menu items which allow you to execute some NppExec's script.

+

Remarks:

+

NppExec by itself understands only its own internal commands and environment variables. When you type another command, + such as "copy", "cmd" or "calc", NppExec tries to run it as a child process - i.e. it performs CreateProcess(...) and waits until this process ends. + (Note: NppExec ver. 0.6 RC3 introduces a new advanced option "ChildProcess_RunPolicy" that allows to modify this behavior. Refer to [4.4] for more details.)

+

When you type something like "npp_run cmd" or "npp_run calc", + NppExec tries to run specified command (the argument of npp_run) as an external + process - i.e. it performs ShellExecute(...) and does not care about this process.

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.3.html b/docs/NppExec_Manual/3.3.html similarity index 95% rename from NppExec/doc/NppExec/NppExec_Manual/3.3.html rename to docs/NppExec_Manual/3.3.html index f33e7e5..31a995f 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/3.3.html +++ b/docs/NppExec_Manual/3.3.html @@ -1,63 +1,64 @@ - - - - - -3.3. Do something (how-to) - - -

3.3. Do something (how-to)

-

To run some program (optionally, with parameters) as a child process of NppExec, - just type the (path)name of this program (optionally, with parameters) - in NppExec's Console [3.5] or in the "Execute NppExec Script..." dialog [3.6]. This -makes NppExec to:

-
    -
  1. run the program (optionally, with parameters)
  2. -
  3. show its output in NppExec's Console (if it is a console program)
  4. -
  5. wait until the program exits
  6. -
-

For example, type

-
-
cmd
-
-

to start the "cmd.exe". You will see the cmd's output in NppExec's Console. You can type some cmd's commands in order to cmd to execute them and, finally, type "exit" in -order to exit cmd.

-

Also you can type

-
-
calc
-
-

in order to start the "calc.exe". - NppExec -will wait until you close the calc's window.

-

Finally, here is an example with parameters:

-
-
cmd /c time /t
-
-

The last example shows the output - of cmd's -command "time /t" in NppExec's Console - i.e. it shows current time.

-

The same approach can be used to execute .bat and .cmd files - but the file extension (.bat or .cmd) can not be omitted in this case. -(Note: NppExec ver. 0.6 RC3 introduces a new advanced option "ChildProcess_RunPolicy" that allows to modify this behavior. Refer to [4.4] for more details.)

-

To run some program (optionally, - with parameters) as an external process (with respect to NppExec), type "npp_run " and the (path)name of this program (optionally, with parameters) in NppExec's Console [3.5] or in the "Execute NppExec Script..." dialog -[3.6]. This makes NppExec to:

-
    -
  1. run the program (optionally, with parameters)
  2. -
  3. a console program is shown in its own console window
  4. -
  5. NppExec does not wait until the program exits
  6. -
-

For example, type

-
-
npp_run cmd
-
-

to start the "cmd.exe" in its own -window.

-

(Note: it's possible to start an application in its own window and make NppExec to wait until the application has been executed. To do that, type:

-
-
cmd /c start /wait application.exe
-
-

In this case, NppExec waits for 'cmd' to be executed, while 'cmd' itself starts the 'application.exe' in its own separate window and waits until it has been executed. So "npp_run " is not needed here.)

-

Also you can use "npp_run " to open specified file in its associated program. For example, "npp_run index.htm" opens the .htm file in your default internet browser.

-

See also: Using cmd.exe [4.4].

- - + + + + + +3.3. Do something (how-to) + + + +

3.3. Do something (how-to)

+

To run some program (optionally, with parameters) as a child process of NppExec, + just type the (path)name of this program (optionally, with parameters) + in NppExec's Console [3.5] or in the "Execute NppExec Script..." dialog [3.6]. This +makes NppExec to:

+
    +
  1. run the program (optionally, with parameters)
  2. +
  3. show its output in NppExec's Console (if it is a console program)
  4. +
  5. wait until the program exits
  6. +
+

For example, type

+
+
cmd
+
+

to start the "cmd.exe". You will see the cmd's output in NppExec's Console. You can type some cmd's commands in order to cmd to execute them and, finally, type "exit" in +order to exit cmd.

+

Also you can type

+
+
calc
+
+

in order to start the "calc.exe". + NppExec +will wait until you close the calc's window.

+

Finally, here is an example with parameters:

+
+
cmd /c time /t
+
+

The last example shows the output + of cmd's +command "time /t" in NppExec's Console - i.e. it shows current time.

+

The same approach can be used to execute .bat and .cmd files - but the file extension (.bat or .cmd) can not be omitted in this case. +(Note: NppExec ver. 0.6 RC3 introduces a new advanced option "ChildProcess_RunPolicy" that allows to modify this behavior. Refer to [4.4] for more details.)

+

To run some program (optionally, + with parameters) as an external process (with respect to NppExec), type "npp_run " and the (path)name of this program (optionally, with parameters) in NppExec's Console [3.5] or in the "Execute NppExec Script..." dialog +[3.6]. This makes NppExec to:

+
    +
  1. run the program (optionally, with parameters)
  2. +
  3. a console program is shown in its own console window
  4. +
  5. NppExec does not wait until the program exits
  6. +
+

For example, type

+
+
npp_run cmd
+
+

to start the "cmd.exe" in its own +window.

+

(Note: it's possible to start an application in its own window and make NppExec to wait until the application has been executed. To do that, type:

+
+
cmd /c start /wait application.exe
+
+

In this case, NppExec waits for 'cmd' to be executed, while 'cmd' itself starts the 'application.exe' in its own separate window and waits until it has been executed. So "npp_run " is not needed here.)

+

Also you can use "npp_run " to open specified file in its associated program. For example, "npp_run index.htm" opens the .htm file in your default internet browser.

+

See also: Using cmd.exe [4.4].

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.4.html b/docs/NppExec_Manual/3.4.html similarity index 78% rename from NppExec/doc/NppExec/NppExec_Manual/3.4.html rename to docs/NppExec_Manual/3.4.html index ab5d895..d1d3e4c 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/3.4.html +++ b/docs/NppExec_Manual/3.4.html @@ -1,93 +1,95 @@ - - - - - -3.4. NppExec's submenu - - -

3.4. NppExec's submenu

-

You can access NppExec's submenu - from Notepad++'es main menu: Plugins -> NppExec. This submenu contains - the -following items:

-

Execute NppExec Script...

-
-

- shows the "Execute NppExec Script..." dialog [3.6];

-
-

Execute Previous NppExec Script

-
-

- executes previous NppExec's script [3.7] immediately;

-
-

Show NppExec Console

-
-

- shows/hides NppExec's Console [3.5];

-
-

Toggle NppExec Console

-
-

- activates/deactivates NppExec's Console [3.5] -(depends on Console's option "hide toggled Console");

-
-

Go to next error

-
-

- goes to next error/warning in the Console, basing on the HighLight masks (NppExec Console Filters);

-
-

Go to previous error

-
-

- goes to previous error/warning in the Console, basing on the HighLight masks (NppExec Console Filters);

-
-

Console Commands History

-
-

- enables/disables NppExec's Console's commands history;

-
-

Console Output... {OEM/OEM}

-
-

- shows "Console Output/Input encoding" dialog;

-
-

No internal messages

-
-

- disables command confirmations and so on in NppExec's Console;

-
-

Save all files on execute

-
-

- (always) save all modified files before executing NppExec's script;

-
-

Follow $(CURRENT_DIRECTORY)

-
-

- (always) set current directory to active file's path;

-
-

Disable command aliases

-
-

- disables command aliases (if any - see NPE_CMDALIAS);

-
-

Console Output Filters...

-
-

- shows "NppExec Console Filters" dialog;

-
-

Advanced Options...

-
-

- shows "NppExec Advanced Options" dialog;

-
-

Change Console Font...

-
-

- allows to change the NppExec Console's font [3.5];

-
-

Change Execute Script Font...

-
-

- allows to change the Execute NppExec Script's font [3.6];

-
-

Help/Manual

-
-

- shows this manual;

-
-

Help/Docs...

-
-

- opens "NppExec.txt" and "NppExec_TechInfo.txt" in Notepad++;

-
-

Help/About...

-
-

- shows some information about the plugin.

-
-

Note: You can create additional menu items for NppExec's scripts. See [3.7] for more details.

- - + + + + + +3.4. NppExec's submenu + + + +

3.4. NppExec's submenu

+

You can access NppExec's submenu from Notepad++'es main menu: Plugins -> NppExec. This submenu contains the following items:

+

Execute NppExec Script...

+
+

- shows the "Execute NppExec Script..." dialog [3.6];

+
+

Execute Previous NppExec Script

+
+

- executes previous NppExec's script [3.7] immediately;

+
+

Execute Selected Text

+
+

- executes the text selected in Notepad++ as NppExec's script [3.7] or sends it to the running child process as an input;

+
+

Execute Clipboard Text

+
+

- executes the text in the clipboard as NppExec's script [3.7] or sends it to the running child process as an input;

+
+

Show NppExec Console

+
+

- shows/hides NppExec's Console [3.5];

+
+

Toggle NppExec Console

+
+

- activates/deactivates NppExec's Console [3.5] +(depends on Console's option "Hide toggled Console" [4.1]);

+
+

Go to next error

+
+

- goes to next error/warning in the Console, basing on the HighLight masks (NppExec Console Filters);

+
+

Go to previous error

+
+

- goes to previous error/warning in the Console, basing on the HighLight masks (NppExec Console Filters);

+
+

Console Commands History

+
+

- enables/disables NppExec's Console's commands history;

+
+

Console Output... {OEM/OEM}

+
+

- shows "Console Output/Input encoding" dialog;

+
+

No internal messages

+
+

- disables command confirmations and so on in NppExec's Console;

+
+

Save all files on execute

+
+

- (always) save all modified files before executing NppExec's script;

+
+

Follow $(CURRENT_DIRECTORY)

+
+

- (always) set current directory to active file's path;

+
+

Console Output Filters...

+
+

- shows "NppExec Console Filters" dialog;

+
+

Advanced Options...

+
+

- shows "NppExec Advanced Options" dialog;

+
+

Change Console Font...

+
+

- allows to change the NppExec Console's font [3.5];

+
+

Change Execute Script Font...

+
+

- allows to change the Execute NppExec Script's font [3.6];

+
+

Help/Manual

+
+

- shows this manual;

+
+

Help/Docs...

+
+

- opens "NppExec.txt" and "NppExec_TechInfo.txt" in Notepad++;

+
+

Help/About...

+
+

- shows some information about the plugin.

+
+

Note: You can create additional menu items for NppExec's scripts. See [3.7] for more details.

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.5.html b/docs/NppExec_Manual/3.5.html similarity index 88% rename from NppExec/doc/NppExec/NppExec_Manual/3.5.html rename to docs/NppExec_Manual/3.5.html index 12fa618..98a2b07 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/3.5.html +++ b/docs/NppExec_Manual/3.5.html @@ -1,43 +1,44 @@ - - - - - -3.5. NppExec's Console - - -

3.5. NppExec's Console

-

NppExec's Console can be shown using - the toolbar button "Show NppExec Console" or the menu item "Show NppExec Console" in NppExec's submenu (Plugins -> NppExec -> Show -Console).

-

* By the way, you can reassign the - toolbar -button or even disable it via NppExec's "Advanced options..." dialog.

-

NppExec's Console is used to:

-
    -
  1. show - the running console process'es output; optionally, the Console Output - Filters can be used. This happens when some child console process is - being executed;
  2. -
  3. show - NppExec's internal messages (command confirmations and so on - can be - disabled with "No internal messages" option). This happens when (also - may be before or after) some command is executed;
  4. -
  5. show - NppExec's built-in help. This happens when you type "help" or "help <command>" (e.g. "help - npp_run", "help set" etc.) - in the Console;
  6. -
  7. go - to specified line in specified file by double-clicking the Console's - line which contains the file (path)name and the line - using the Console - Output Filters -> HighLight;
  8. -
  9. execute - a single command by typing it in the Console and pressing Enter;
  10. -
  11. copy - (Ctrl+C) some text from and paste (Ctrl+V) to the Console;
  12. -
  13. and - more; type "help" in the Console for details.
  14. -
-

See also: NppExec's Console behaviour [4.1]; Console output redirection [4.5].

- - + + + + + +3.5. NppExec's Console + + + +

3.5. NppExec's Console

+

NppExec's Console can be shown using + the toolbar button "Show NppExec Console" or the menu item "Show NppExec Console" in NppExec's submenu (Plugins -> NppExec -> Show +Console).

+

* By the way, you can reassign the + toolbar +button or even disable it via NppExec's "Advanced options..." dialog.

+

NppExec's Console is used to:

+
    +
  1. show + the running console process'es output; optionally, the Console Output + Filters can be used. This happens when some child console process is + being executed;
  2. +
  3. show + NppExec's internal messages (command confirmations and so on - can be + disabled with "No internal messages" option). This happens when (also + may be before or after) some command is executed;
  4. +
  5. show + NppExec's built-in help. This happens when you type "help" or "help <command>" (e.g. "help + npp_run", "help set" etc.) + in the Console;
  6. +
  7. go + to specified line in specified file by double-clicking the Console's + line which contains the file (path)name and the line - using the Console + Output Filters -> HighLight;
  8. +
  9. execute + a single command or multiple commands by typing them in the Console and pressing Enter;
  10. +
  11. copy + (Ctrl+C) some text from and paste (Ctrl+V) to the Console;
  12. +
  13. and + more; type "help" in the Console for details.
  14. +
+

See also: NppExec's Console behaviour [4.1]; Console output redirection [4.5].

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.6.html b/docs/NppExec_Manual/3.6.html similarity index 94% rename from NppExec/doc/NppExec/NppExec_Manual/3.6.html rename to docs/NppExec_Manual/3.6.html index 007a817..5b06d1b 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/3.6.html +++ b/docs/NppExec_Manual/3.6.html @@ -1,34 +1,35 @@ - - - - - -3.6. Execute NppExec Script... - - -

3.6. Execute NppExec Script...

-

The "Execute NppExec Script..." dialog can be shown using its hotkey (F6 by default) or the menu item "Execute NppExec Script..." in NppExec's submenu (Plugins -> NppExec -> Execute NppExec Script...).

-

The "Execute NppExec Script..." dialog allows to specify several NppExec's commands (one command per one line) which will be executed one after another. Such set of commands forms so-called NppExec's script. The script can be saved using the "Save..." button of the "Execute NppExec Script..." dialog. - For example, you can create NppExec's script which makes a reserve copy - of current file:

-

1) open the "Execute NppExec Script..." dialog - and type the following

-
-
// save current file
-NPP_SAVE
-// copy current file to C:\Backup
-cmd /c copy "$(FULL_CURRENT_PATH)" "C:\Backup\$(FILE_NAME)" /Y
-
-

2) - press the "Save..." button, type "Reserve Copy" and press the "Save" button.

-

This example allows you to create - and save NppExec's script named "Reserve Copy". You can call this script later from the "Execute NppExec Script..." dialog. Also you can create a menu item for this script using NppExec's Advanced Options (Plugins -> NppExec -> Advanced - Options...).

-

It is not necessary to save a new - script each time you want to execute several commands. You can use the "<temporary script>" for commands you don't need to save. The temporary script is saved automatically when you close Notepad++. Also, if you modify commands of some saved script (e.g. if you modify the "Reserve Copy" script), it will be saved automatically when you close Notepad++. Or you can press the "Save" button - to save it immediately.

-

You can delete previously saved - scripts using the "Execute NppExec Script..." dialog. Press the "Save..." button (yes, the irony :)), select a script name and press the "Delete" button.

-

See also: NppExec's script [3.7].

- - + + + + + +3.6. Execute NppExec Script... + + + +

3.6. Execute NppExec Script...

+

The "Execute NppExec Script..." dialog can be shown using its hotkey (F6 by default) or the menu item "Execute NppExec Script..." in NppExec's submenu (Plugins -> NppExec -> Execute NppExec Script...).

+

The "Execute NppExec Script..." dialog allows to specify several NppExec's commands (one command per one line) which will be executed one after another. Such set of commands forms so-called NppExec's script. The script can be saved using the "Save..." button of the "Execute NppExec Script..." dialog. + For example, you can create NppExec's script which makes a reserve copy + of current file:

+

1) open the "Execute NppExec Script..." dialog + and type the following

+
+
// save current file
+NPP_SAVE
+// copy current file to C:\Backup
+cmd /c copy "$(FULL_CURRENT_PATH)" "C:\Backup\$(FILE_NAME)" /Y
+
+

2) + press the "Save..." button, type "Reserve Copy" and press the "Save" button.

+

This example allows you to create + and save NppExec's script named "Reserve Copy". You can call this script later from the "Execute NppExec Script..." dialog. Also you can create a menu item for this script using NppExec's Advanced Options (Plugins -> NppExec -> Advanced + Options...).

+

It is not necessary to save a new + script each time you want to execute several commands. You can use the "<temporary script>" for commands you don't need to save. The temporary script is saved automatically when you close Notepad++. Also, if you modify commands of some saved script (e.g. if you modify the "Reserve Copy" script), it will be saved automatically when you close Notepad++. Or you can press the "Save" button + to save it immediately.

+

You can delete previously saved + scripts using the "Execute NppExec Script..." dialog. Press the "Save..." button (yes, the irony :)), select a script name and press the "Delete" button.

+

See also: NppExec's script [3.7].

+ + diff --git a/docs/NppExec_Manual/3.7.html b/docs/NppExec_Manual/3.7.html new file mode 100644 index 0000000..429292b --- /dev/null +++ b/docs/NppExec_Manual/3.7.html @@ -0,0 +1,175 @@ + + + + + +3.7. NppExec's script + + + +

3.7. NppExec's script

+

NppExec's script is a set of NppExec's + commands. NppExec's command can be an internal command such as "cls", "npp_save", "npe_debuglog" etc. or it can be a (path)name of an executable such as "cmd", "calc", "C:\tools\tcc\tcc.exe" etc. + Each command, depending on its meaning, can have one or more parameters. +For example:

+
+
INPUTBOX "Input something:" : something
+NPP_EXEC "script name" "param 1" "param 2"
+cmd /c copy /?
+"C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)"
+
+

and so on. You can use "//" to comment an entire line or right part of a line (after "//"):

+
+
// this is a comment
+ECHO You'll see this // but not this (comment)
+
+

You + can create and save NppExec's scripts using the "Execute NppExec Script..." dialog [3.6]. However, NppExec's script can also be located in a text file. I.e. you can create a text file which contains some NppExec's commands (one command per one line) and then execute this file (commands from this file) in NppExec. Such text file can be an ANSI file for ANSI version of NppExec and can be an ANSI or Unicode (UCS-2 LE/UCS-2 BE/UTF-8) file for Unicode version of NppExec. Note that Unicode text file must contain leading "BOM" bytes to be recognized by Unicode version of NppExec (by default, these bytes are present - until you force saving without "BOM"). To execute NppExec's script from a text file, use the "npp_exec" command. + This command allows to execute commands from a previously saved (internal) + script or from an (external) text file.

+

As you can store your NppExec's script in a text file, you can edit such file + directly in Notepad++ and execute it with the following command(s):

+
+
NPP_SAVE  // save current file (NppExec's script)...
+NPP_EXEC "$(FULL_CURRENT_PATH)"  // ...and execute it
+
+

With the Console Commands History enabled, you can type this command:

+
+
NPP_EXEC "$(FULL_CURRENT_PATH)"
+
+

in NppExec's Console once, then use the Arrow Up key to repeat this command. However, be sure to save current file (with Ctrl+S) before executing it.

+

To create a menu item for NppExec's script, use NppExec's Advanced Options dialog. Then a shortcut key can be assigned to it:

+
    +
  1. Create a menu item for the script using Plugins -> NppExec -> Advanced options (select a script in the "Associated script" drop-down list, specify its menu item name - by default it's the same as the script name - and press the "Add/Modify" button).
  2. +
  3. Restart Notepad++ to get this new menu item.
  4. +
  5. Assign a shortcut key to this new menu item using Notepad++'es Settings -> Shortcut Mapper -> Plugin commands (you'll find the menu item there).
  6. +
+

NppExec stores your scripts in Notepad++'es "$(PLUGINS_CONFIG_DIR)" folder. The "npes_saved.txt" file stores all the scripts except the temporary one which is stored inside "npes_temp.txt".

+ +

NppExec's script syntax. General notes:

+
    +
  • Commands are case-insensitive. Thus, npp_open is the same as NPP_OPEN, Npp_Open and so on.
  • +
  • Use help <command> to get detailed help [3.1] on any NppExec's <command>. For example: help npp_open, help set, help sci_sendmsg and so on.
  • +
  • Use spaces to separate parameters of NppExec's command. Do not use neither brackets nor commas:
    +
    sci_sendmsg SCI_SETTEXT 0 "some text"
    +set local pos ~ strfind "Hello world" Hello
    +
  • +
  • Use " ", ` ` and ' ' around parameters that contain spaces or other quote characters [3.8.5] :
    +
    sci_sendmsg SCI_SETTEXT 0 `"some text in quotes"`
    +inputbox 'Hello World!'
    +set local pos ~ strfind "Hello's world" `Hello's`
    +set local len ~ strlen "  34' 78  "  // returns 12, including ""
    +set local len ~ $(len) - 2           // 10, without the ""
    +cd C:\Program Files (x86)  // cd accepts a parameter without quotes
    +Note: when a command expects several parameters, it extracts the parameters' values by removing the surrounding quotes (there are rare exceptions, though, such as substr that preserves the surrounding quotes). If a command expects just one parameter, the surrounding quotes may or may not be removed, depending on the command. Refer to the built-in help by typing e.g. "help sci_sendmsg", "help inputbox", "help set", "help cd" etc. for actual examples. +
    +
  • +
  • Use $(var) to get the value of an internal variable named "var" [3.8.2] . Don't forget to use the form of $(var) in mathematical expressions [3.8.4] as well:
    +
    set local x = 10        // assigns 10 to a variable 'x'
    +set local x ~ $(x) + 1  // accesses the previous value of 'x' and adds 1
    +
  • +
  • Use $(sys.var) to get the value of an environment variable "var" [3.8.3] . NppExec does not understand such form as %var%:
    +
    echo $(SYS.PATH)  // prints the value of %PATH%
    +env_set PATH = $(SYS.PATH);C:\tools  // updates the value of %PATH%
    +
  • +
  • Use cmd /C to explicitly invoke the system's command interpreter (cmd.exe) when needed [4.4] . For example:
    +
    cmd /C echo %PATH%
    +cmd /C time /t >time.txt && type time.txt
    +cmd /C taskkill /? | findstr /ic:pid
    +
  • +
  • Use different forms of IF-GOTO when needed:
    +
    // Simple IF-GOTO
    +if $(x) == 1 goto 1
    +if $(x) == 2 goto 2
    +echo x is neither 1 nor 2
    +goto end
    +:1
    +echo x is 1
    +goto end
    +:2
    +echo x is 2
    +goto end
    +:end
    +
    +// IF-GOTO-ELSE
    +if $(x) == 1 goto 1
    +else if $(x) == 2 goto 2
    +else
    +  echo x is neither 1 nor 2
    +  goto end
    +endif
    +:1
    +echo x is 1
    +goto end
    +:2
    +echo x is 2
    +goto end
    +:end
    +
    +// IF-GOTO Loop
    +set local N = 10
    +set local x = 1
    +:1
    +echo $(x)
    +set local x ~ $(x) + 1
    +if $(x) <= $(N) goto 1
    +
  • +
  • Use different forms of IF-THEN when needed:
    +
    // Simple IF-THEN
    +if $(x) == 1 then
    +  echo x is 1
    +endif
    +if $(x) == 2 then
    +  echo x is 2
    +endif
    +echo x is neither 1 nor 2
    +
    +// IF-THEN-ELSE
    +if $(x) == 1 then
    +  echo x is 1
    +else if $(x) == 2 then
    +  echo x is 2
    +else
    +  echo x is neither 1 nor 2
    +endif
    +
    +// Nested IF-THEN-ELSE
    +if $(x) == 1 then
    +  echo x is 1
    +else
    +  if $(x) == 2 then
    +    echo x is 2
    +  else
    +    echo x is neither 1 nor 2
    +  endif
    +endif
    +
    +// IF-THEN-GOTO Loop
    +set local N = 10
    +set local x = 1
    +:1
    +if $(x) <= $(N) then
    +  echo $(x)
    +  set local x ~ $(x) + 1
    +  goto 1
    +endif
    +
  • +
  • Use IF~ to calculate mathematical expressions during the comparison:
    +
    set local x = 8
    +set local y = 14
    +if~ $(x) + 2 == $(y) - 4 then
    +  echo left == right
    +else
    +  echo left != right
    +endif
    +
  • +
+ +
+
 
+
+ +

See also: "Execute NppExec Script..." [3.6]; Run-time parameters [4.3].

+

 

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.8.1.html b/docs/NppExec_Manual/3.8.1.html similarity index 92% rename from NppExec/doc/NppExec/NppExec_Manual/3.8.1.html rename to docs/NppExec_Manual/3.8.1.html index d1a685b..e6b5fba 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/3.8.1.html +++ b/docs/NppExec_Manual/3.8.1.html @@ -1,34 +1,35 @@ - - - - - -3.8.1. Predefined (read-only) variables - - -

3.8.1. Predefined (read-only) variables

-

NppExec supports all basic (predefined) environment variables of Notepad++ plus several its own (predefined) environment variables. See NppExec's help [3.1] for more details about supported predefined variables.

-

Consider such predefined environment - variables as "read-only": you can use these variables in NppExec's commands - and scripts, -but can not modify their values.

-

These variables exist in NppExec's commands and scripts - actually, these variables are replaced with their current values by NppExec when you use them. These variables do not exist outside of NppExec (do not exist for child processes and so on). It means you can't use such variables as $(FULL_CURRENT_PATH), $(NPP_DIRECTORY), $(#1) and so on inside external programs or tools. However, you can:

-

1) pass the values of these variables as input parameters of external programs/tools, e.g.

-
-
// pass "$(FULL_CURRENT_PATH)" as a parameter of tcc
-tcc -run "$(FULL_CURRENT_PATH)"
-
-

2) - use the command "env_set" to create a heritable environment variable [3.8.3] - which will be accessed inside external programs/tools, e.g.

-
-
// create new environment variable NPPHOME
-ENV_SET NPPHOME = $(NPP_DIRECTORY)
-// start cmd.exe
-cmd
-
-

Now - you can type something similar to "echo %NPPHOME%" inside cmd in order - to use the value of this environment variable.

- - + + + + + +3.8.1. Predefined (read-only) variables + + + +

3.8.1. Predefined (read-only) variables

+

NppExec supports all basic (predefined) environment variables of Notepad++ plus several its own (predefined) environment variables. See NppExec's help [3.1] for more details about supported predefined variables.

+

Consider such predefined environment + variables as "read-only": you can use these variables in NppExec's commands + and scripts, +but can not modify their values.

+

These variables exist in NppExec's commands and scripts - actually, these variables are replaced with their current values by NppExec when you use them. These variables do not exist outside of NppExec (do not exist for child processes and so on). It means you can't use such variables as $(FULL_CURRENT_PATH), $(NPP_DIRECTORY), $(#1) and so on inside external programs or tools. However, you can:

+

1) pass the values of these variables as input parameters of external programs/tools, e.g.

+
+
// pass "$(FULL_CURRENT_PATH)" as a parameter of tcc
+tcc -run "$(FULL_CURRENT_PATH)"
+
+

2) + use the command "env_set" to create a heritable environment variable [3.8.3] + which will be accessed inside external programs/tools, e.g.

+
+
// create new environment variable NPPHOME
+ENV_SET NPPHOME = $(NPP_DIRECTORY)
+// start cmd.exe
+cmd
+
+

Now + you can type something similar to "echo %NPPHOME%" inside cmd in order + to use the value of this environment variable.

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.8.2.html b/docs/NppExec_Manual/3.8.2.html similarity index 93% rename from NppExec/doc/NppExec/NppExec_Manual/3.8.2.html rename to docs/NppExec_Manual/3.8.2.html index f68a895..4cba20d 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/3.8.2.html +++ b/docs/NppExec_Manual/3.8.2.html @@ -1,36 +1,37 @@ - - - - - -3.8.2. User (internal) variables - - -

3.8.2. User (internal) variables

-

NppExec allows you to create, modify - and -remove your own (user) variables using NppExec's commands "set" and "unset". See NppExec's help [3.1] for more details about the commands "set" and "unset".

-

Consider such user variables as "internal": - these variables exist only for NppExec. You can create, modify and remove - such variables in NppExec's commands - and scripts any time you need: to store some value, to set some value in - one script in order to use it in another script etc. These variables do not - exist - outside of NppExec (do not exist for child processes and so on). It means - you can't use these variables inside external programs or tools. However, - you can:

-
    -
  1. pass the values of these variables - as input parameters of external programs/tools (see [3.8.1]);
  2. -
  3. use the command "env_set" to - create a heritable environment variable [3.8.3] which will be accessed - inside external - programs/tools (see [3.8.1]).
  4. -
-

NppExec 0.5.1 introduces so-called "local variables". -They can be created, modified and removed using NppExec's commands "set local" and "unset local". -A local variable lives inside NppExec's script that is being executed, and it is automatically deleted when the script ends. From NppExec 0.6, when something similar to "set local x = 10" is executed directly in NppExec's Console, this variable will live only in NppExec's Console and will not be visible in NppExec's scripts. -Type "help set" in NppExec's Console for more details.

-

See also: Run-time parameters [4.3].

- - + + + + + +3.8.2. User (internal) variables + + + +

3.8.2. User (internal) variables

+

NppExec allows you to create, modify + and +remove your own (user) variables using NppExec's commands "set" and "unset". See NppExec's help [3.1] for more details about the commands "set" and "unset".

+

Consider such user variables as "internal": + these variables exist only for NppExec. You can create, modify and remove + such variables in NppExec's commands + and scripts any time you need: to store some value, to set some value in + one script in order to use it in another script etc. These variables do not + exist + outside of NppExec (do not exist for child processes and so on). It means + you can't use these variables inside external programs or tools. However, + you can:

+
    +
  1. pass the values of these variables + as input parameters of external programs/tools (see [3.8.1]);
  2. +
  3. use the command "env_set" to + create a heritable environment variable [3.8.3] which will be accessed + inside external + programs/tools (see [3.8.1]).
  4. +
+

NppExec 0.5.1 introduces so-called "local variables". +They can be created, modified and removed using NppExec's commands "set local" and "unset local". +A local variable lives inside NppExec's script that is being executed, and it is automatically deleted when the script ends. From NppExec 0.6, when something similar to "set local x = 10" is executed directly in NppExec's Console, this variable will live only in NppExec's Console and will not be visible in NppExec's scripts. +Type "help set" in NppExec's Console for more details.

+

See also: Run-time parameters [4.3].

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.8.3.html b/docs/NppExec_Manual/3.8.3.html similarity index 89% rename from NppExec/doc/NppExec/NppExec_Manual/3.8.3.html rename to docs/NppExec_Manual/3.8.3.html index aa1f1a8..27540b5 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/3.8.3.html +++ b/docs/NppExec_Manual/3.8.3.html @@ -1,19 +1,20 @@ - - - - - -3.8.3. Environment (heritable) variables - - -

3.8.3. Environment (heritable) variables

-

NppExec (ver. 0.3 RC1 or higher) - allows you to create and modify (heritable) environment variables using NppExec's -commands "env_set" and "env_unset". See NppExec's help [3.1] for more details about the commands "env_set" and "env_unset".

-

Consider such heritable environment - variables as "real" environment variables: these variables exist both inside NppExec (in a form of $(SYS.<var>) which allows you to use the var's value inside NppExec) and outside NppExec (usually in a form of %<var>% -which allows to use and modify the var's value inside external tool).

-

NppExec allows to modify and restore a value of such existing environment variable, and to create, modify and remove such new environment variable (which did not exist before you create it in NppExec).

-

See also: Environment [4.2].

- - + + + + + +3.8.3. Environment (heritable) variables + + + +

3.8.3. Environment (heritable) variables

+

NppExec (ver. 0.3 RC1 or higher) + allows you to create and modify (heritable) environment variables using NppExec's +commands "env_set" and "env_unset". See NppExec's help [3.1] for more details about the commands "env_set" and "env_unset".

+

Consider such heritable environment + variables as "real" environment variables: these variables exist both inside NppExec (in a form of $(SYS.<var>) which allows you to use the var's value inside NppExec) and outside NppExec (usually in a form of %<var>% +which allows to use and modify the var's value inside external tool).

+

NppExec allows to modify and restore a value of such existing environment variable, and to create, modify and remove such new environment variable (which did not exist before you create it in NppExec).

+

See also: Environment [4.2].

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.8.4.html b/docs/NppExec_Manual/3.8.4.html similarity index 82% rename from NppExec/doc/NppExec/NppExec_Manual/3.8.4.html rename to docs/NppExec_Manual/3.8.4.html index 55f5446..7435bf1 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/3.8.4.html +++ b/docs/NppExec_Manual/3.8.4.html @@ -1,100 +1,123 @@ - - - - - -3.8.4. Calculations, strlen and so on - - -

3.8.4. Calculations, strlen and so on

-

NppExec ver. 0.4 introduces built-in calculator abilities provided by Function Parser (fparser). To calculate your math expression, use the special form of the SET command:

-
-
set result ~ <math expression>
-
-

For example:

-
-
set result ~ sin(pi/4) + cos(pi/4)
-
-

If this example gives you an error "- fparser calc error: Syntax error: Unknown identifier at pos 4", it means you do not have necessary NppExec files in your "Notepad++\plugins\NppExec" folder. In such case, you need to download the latest NppExec package manually and unpack it to your "Notepad++\plugins" folder [2.3].

-

You can find more details regarding fparser's syntax and abilities inside the file "Notepad++\plugins\doc\NppExec\fparser.html".

-

By the way, NppExec also uses fparser for its own purposes such as internal implementation of NPP_SENDMSG and SCI_SENDMSG. In particular, fparser is used to calculate and store the values of constants defined inside "Notepad_plus_msgs.h", "Scintilla.h" and other files in the "Notepad++\plugins\NppExec" folder. But this is just for information; never mind :)

-
-
 
-
-

There are two special cases of this form of the SET command which are processed by NppExec itself. I am talking about

-
-
set n ~ strlen <string>
-
-

and

-
-
set n ~ strlenutf8 <string>
-
-

These two functions calculate an ANSI and an UTF-8 string length. For Latin characters, both 'strlen' and 'strlenutf8' will return the same value. But for non-Latin characters (such as Cyrillic), 'strlenutf8' will return a greater value than 'strlen' because each non-Latin character in UTF-8 may be represented by 2 or 3 bytes (unlike Latin characters which are always represented by 1 byte in UTF-8). Actually, 'strlenutf8' returns the number of bytes in an UTF-8 string. This number has to be specified for some Scintilla's messages invoked via SCI_SENDMSG. Type "help sci_sendmsg" in NppExec's Console for more details regarding SCI_SENDMSG.

-

Here is an example which uses 'strlen' and SCI_SENDMSG:

-
-
set s = My string
-set n ~ strlen $(s)
-SCI_SENDMSG SCI_APPENDTEXT $(n) "$(s)"
-
-

If you want to add spaces before and after "My string" (e.g. to have " My string "), you should modify the script since NppExec removes leading and trailing spaces around the value:

-
-
set s =  My string   // leading/trailing spaces will be removed
-set n ~ strlen $(s)  // length without leading/trailing spaces
-set n ~ $(n) + 2     // length with additional two spaces
-SCI_SENDMSG SCI_APPENDTEXT $(n) " $(s) "  // adding the spaces
-
-

You will encounter similar problem when calculating 'strlen' of a string which starts or ends with spaces. These spaces will be removed before calculating the string length. To avoid this, you should enclose such string in double quotes:

-
-
set n ~ strlen "  ABC "  // n=8: string length with two " symbols
-set n ~ $(n) - 2         // n=6: length without the " symbols
-
-

NppExec ver. 0.5 introduces several additional functions: strupper, strlower and substr. Type "help set" for more details.

-
-
 
-
-

Now let's discuss something different: pseudo-conditions in NppExec. Pseudo-conditions are available via the NPP_EXEC command plus some variable. The next idea lies behind this: you can form a script name dynamically in order to execute different script basing on some variable's value. Let me explain: a command "NPP_EXEC script$(var)" will execute different script according to the value of $(var). For example, let's assume you want to execute some program and then to have different behaviour depending on successful or unsuccessful execution of that program. Of course, you can use "cmd /c program && do_something_different" to achieve this, but such approach does not allow to use NppExec-specific functions (since everything is executing under cmd.exe). So, let's assume we have the following script:

-
-
program.exe  // execute the program
-NPP_EXEC OnProgramEnd_$(EXITCODE)  // pseudo-condition
-
-

Any program "program.exe" is expected to return 0 in case of its successful execution. Otherwise it returns non-zero value. (This is a common behaviour of executables.) Thus we can create NppExec's script named "OnProgramEnd_0" which will be called only in case of successful execution of "program.exe" -- i.e. when $(EXITCODE) will be 0. Otherwise, in case of -1 or 1 (and so on) we will try to execute non-existing script "OnProgramEnd_-1" or "OnProgramEnd_1" (and so on).

-

For example, create the following script and name it "OnProgramEnd_0" to test the previous statements (and the pseudo-conditions, actually):

-
-
// OnProgramEnd_0
-echo The program returned 0: executed successfully!
-
-

So, we can say that the two above scripts allow us to emulate an IF condition. Here is its meaning: IF (program.exe returns 0) THEN execute "OnProgramEnd_0". Otherwise we try to execute non-existing script that can be treated as "do nothing".

-

Going further, we can implement an IF-THEN-ELSE statement in a similar way. Our script will be changed a little:

-
-
program.exe  // execute the program
-set N ~ $(EXITCODE) != 0
-NPP_EXEC OnProgramEnd_$(N)  // pseudo-condition
-
-

The value of $(N) will be either 1 (true) when $(EXITCODE) is not 0, or 0 (false) when $(EXITCODE) is 0. So we will execute either "OnProgramEnd_0" or "OnProgramEnd_1". Now the only remaining thing is to create a script named "OnProgramEnd_1":

-
-
// OnProgramEnd_1
-echo The program returned non-zero: execution failed.
-
-

NppExec ver. 0.5 introduces native support of IF-GOTO commands. Type "help if" for more details.

-
-
 
-
-

Finally, let's talk about "special" characters in NppExec. I mean "//" (a comment) and a double quote symbol.

-

While using a command with a comment, all the text after "//" is being cut from that command.

-

But what if you want to use "//" as a part of your text? Is it possible to do it?

-

Yes, it's possible. You can use environment variables for that:

-
-
set a = /          //  now $(a) is "/"
-echo $(a)$(a)      //  prints "//"
-set s = $(a)$(a)   //  now $(s) is "//"
-
-

The same technique can be used to pass a double quote symbol:

-
-
NPP_SENDMSG WM_COMMAND IDM_FILE_NEW
-set q = "
-sci_sendmsg SCI_SETTEXT 0 "$(q)some text in double quotes$(q)"
-
-

Not a big trick, actually, but may be useful :)

-

See also: Calculating [4.6.2]; Passing enquoted strings and special characters [3.8.5].

- - + + + + + +3.8.4. Calculations, strlen and so on + + + +

3.8.4. Calculations, strlen and so on

+

NppExec ver. 0.4 introduces built-in calculator abilities provided by Function Parser (fparser). To calculate your math expression, use the special form of the SET command:

+
+
set result ~ <math expression>
+
+

For example:

+
+
set result ~ sin(pi/4) + cos(pi/4)
+
+

If this example gives you an error "- fparser calc error: Syntax error: Unknown identifier at pos 4", it means you do not have necessary NppExec files in your "Notepad++\plugins\NppExec" folder. In such case, you need to download the latest NppExec package manually and unpack it to your "Notepad++\plugins" folder [2.3].

+

You can find more details regarding fparser's syntax and abilities inside the file "Notepad++\plugins\doc\NppExec\fparser.html".

+

By the way, NppExec also uses fparser for its own purposes such as internal implementation of NPP_SENDMSG and SCI_SENDMSG. In particular, fparser is used to calculate and store the values of constants defined inside "Notepad_plus_msgs.h", "Scintilla.h" and other files in the "Notepad++\plugins\NppExec" folder. But this is just for information; never mind :)

+
+
 
+
+

There are two special cases of this form of the SET command which are processed by NppExec itself. I am talking about

+
+
set n ~ strlen <string>
+
+

and

+
+
set n ~ strlenutf8 <string>
+
+

These two functions calculate an ANSI and an UTF-8 string length. For Latin characters, both 'strlen' and 'strlenutf8' will return the same value. But for non-Latin characters (such as Cyrillic), 'strlenutf8' will return a greater value than 'strlen' because each non-Latin character in UTF-8 may be represented by 2 or 3 bytes (unlike Latin characters which are always represented by 1 byte in UTF-8). Actually, 'strlenutf8' returns the number of bytes in an UTF-8 string. This number has to be specified for some Scintilla's messages invoked via SCI_SENDMSG. Type "help sci_sendmsg" in NppExec's Console for more details regarding SCI_SENDMSG.

+

Here is an example which uses 'strlen' and SCI_SENDMSG:

+
+
set s = My string
+set n ~ strlen $(s)
+SCI_SENDMSG SCI_APPENDTEXT $(n) "$(s)"
+
+

If you want to add spaces before and after "My string" (e.g. to have " My string "), you should modify the script since NppExec removes leading and trailing spaces around the value:

+
+
set s =  My string   // leading/trailing spaces will be removed
+set n ~ strlen $(s)  // length without leading/trailing spaces
+set n ~ $(n) + 2     // length with additional two spaces
+SCI_SENDMSG SCI_APPENDTEXT $(n) " $(s) "  // adding the spaces
+
+

You will encounter similar problem when calculating 'strlen' of a string which starts or ends with spaces. These spaces will be removed before calculating the string length. To avoid this, you should enclose such string in double quotes:

+
+
set n ~ strlen "  ABC "  // n=8: string length with two " symbols
+set n ~ $(n) - 2         // n=6: length without the " symbols
+
+

NppExec ver. 0.5 had introduced several additional functions: strupper, strlower and substr. Even more functions have been added later. Type "help set" for more details.

+

Here is an example that uses substr to extract a directory name from $(CURRENT_DIRECTORY) :

+
+
npp_console local -
+set local dirname = $(CURRENT_DIRECTORY)
+set local c ~ substr -1 1 $(dirname)  // trailing character
+if "$(c)" == "\" then
+  set local dirname ~ substr 0 -1 $(dirname)  // removing trailing \
+else if "$(c)" == "/" then
+  set local dirname ~ substr 0 -1 $(dirname)  // removing trailing /
+endif
+set local n1 ~ strrfind "$(dirname)" \  // position of last \
+set local n2 ~ strrfind "$(dirname)" /  // position of last /
+if $(n1) > $(n2) then
+  set local n1 ~ $(n1) + 1
+  set local dirname ~ substr $(n1) - $(dirname)
+else
+  set local n2 ~ $(n2) + 1
+  set local dirname ~ substr $(n2) - $(dirname)
+endif
+npp_console local +
+echo $(dirname)
+
+
+
 
+
+

Now let's discuss something different: pseudo-conditions in NppExec. Pseudo-conditions are available via the NPP_EXEC command plus some variable. The next idea lies behind this: you can form a script name dynamically in order to execute different script basing on some variable's value. Let me explain: a command "NPP_EXEC script$(var)" will execute different script according to the value of $(var). For example, let's assume you want to execute some program and then to have different behaviour depending on successful or unsuccessful execution of that program. Of course, you can use "cmd /c program && do_something_different" to achieve this, but such approach does not allow to use NppExec-specific functions (since everything is executing under cmd.exe). So, let's assume we have the following script:

+
+
program.exe  // execute the program
+NPP_EXEC OnProgramEnd_$(EXITCODE)  // pseudo-condition
+
+

Any program "program.exe" is expected to return 0 in case of its successful execution. Otherwise it returns non-zero value. (This is a common behaviour of executables.) Thus we can create NppExec's script named "OnProgramEnd_0" which will be called only in case of successful execution of "program.exe" -- i.e. when $(EXITCODE) will be 0. Otherwise, in case of -1 or 1 (and so on) we will try to execute non-existing script "OnProgramEnd_-1" or "OnProgramEnd_1" (and so on).

+

For example, create the following script and name it "OnProgramEnd_0" to test the previous statements (and the pseudo-conditions, actually):

+
+
// OnProgramEnd_0
+echo The program returned 0: executed successfully!
+
+

So, we can say that the two above scripts allow us to emulate an IF condition. Here is its meaning: IF (program.exe returns 0) THEN execute "OnProgramEnd_0". Otherwise we try to execute non-existing script that can be treated as "do nothing".

+

Going further, we can implement an IF-THEN-ELSE statement in a similar way. Our script will be changed a little:

+
+
program.exe  // execute the program
+set N ~ $(EXITCODE) != 0
+NPP_EXEC OnProgramEnd_$(N)  // pseudo-condition
+
+

The value of $(N) will be either 1 (true) when $(EXITCODE) is not 0, or 0 (false) when $(EXITCODE) is 0. So we will execute either "OnProgramEnd_0" or "OnProgramEnd_1". Now the only remaining thing is to create a script named "OnProgramEnd_1":

+
+
// OnProgramEnd_1
+echo The program returned non-zero: execution failed.
+
+

NppExec ver. 0.5 introduced native support of IF-GOTO commands. Type "help if" for more details.

+
+
 
+
+

Finally, let's talk about "special" characters in NppExec. I mean "//" (a comment) and a double quote symbol.

+

While using a command with a comment, all the text after "//" is being cut from that command.

+

But what if you want to use "//" as a part of your text? Is it possible to do it?

+

Yes, it's possible. You can use environment variables for that:

+
+
set a = /          //  now $(a) is "/"
+echo $(a)$(a)      //  prints "//"
+set s = $(a)$(a)   //  now $(s) is "//"
+
+

The same technique can be used to pass a double quote symbol:

+
+
NPP_SENDMSG WM_COMMAND IDM_FILE_NEW
+set q = "
+sci_sendmsg SCI_SETTEXT 0 "$(q)some text in double quotes$(q)"
+
+

Not a big trick, actually, but may be useful :)

+

See also: Calculating [4.6.2]; Passing enquoted strings and special characters [3.8.5].

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.8.5.html b/docs/NppExec_Manual/3.8.5.html similarity index 77% rename from NppExec/doc/NppExec/NppExec_Manual/3.8.5.html rename to docs/NppExec_Manual/3.8.5.html index 5cf979f..48d4df3 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/3.8.5.html +++ b/docs/NppExec_Manual/3.8.5.html @@ -1,79 +1,90 @@ - - - - - -3.8.5. Passing enquoted strings and special characters - - -

3.8.5. Passing enquoted strings and special characters

- -

NppExec, starting from version 0.7, allows to use three different quote characters to enquote a string:

-
    -
  • "abc"
  • -
  • 'abc'
  • -
  • `abc`
  • -
-

This allows to pass some quote characters within a string enquoted in the other quote characters. For example:

- -
-
messagebox `"a message in quotes"`  // preserves the "" quotes
-messagebox "Can't stop"             // preserves a single ' quote
-
- -

Here is an advanced example, now using Scintilla as well:

- -
-
set local newline ~ strfromhex 0A 00  // '\n' character
-
-set local s = "a string in double-quotes"
-set local len ~ strlensci $(newline)$(s)
-sci_sendmsg SCI_APPENDTEXT $(len) `$(newline)$(s)`
-
-set local t ~ strreplace '$(s)' '"' `'`
-set local t ~ strreplace `$(t)` "double" "single"
-set local len ~ strlensci $(newline)$(t)
-sci_sendmsg SCI_APPENDTEXT $(len) `$(newline)$(t)`
-
-set local r ~ strreplace `$(t)` `'` "`"
-set local len ~ strlensci $(newline)$(r)
-sci_sendmsg SCI_APPENDTEXT $(len) "$(newline)$(r)"
-
-set local findflags ~ NPE_SF_INWHOLETEXT | NPE_SF_SETSEL
-sci_find $(findflags) `"`
-
- -

The previous example additionally demonstrates a technique of adding a new-line character '\n' to the text. It uses NppExec's function strfromhex to get a Unicode two-byte character '\n' from its hexadecimal representation of 0A 00 (the lower bytes goes first, the upper bytes goes next). This is equal to:

- -
-
set local newline ~ chr 0x0A  // '\n' character
-
- -

Similarly, a tabulation character '\t' can be obtained as:

- -
-
set local tab ~ chr 0x09  // '\t' character
-echo ab$(tab)cd
-
- -

The strfromhex is more powerful than the chr since strfromhex allows to operate with a sequence of bytes while chr is limited to one character. For example, Windows uses '\r\n' line endings that consist of two characters '\r' and '\n'. These two characters are represented by 4 bytes in a Unicode two-byte character string:

- -
-
set local newline ~ strfromhex 0D 00 0A 00  // '\r\n' characters
-
- -

The '\r' is 0D 00 and '\n' is 0A 00 here.

-

Here is an example that uses strunescape to construct a multi-line message:

-
-
set local msg ~ strunescape Drive1 is C:\\\nDrive2 is D:\\
-messagebox `$(msg)`
-
- -

See also: Calculations, strlen and so on [3.8.4].

- -
-
 
-
- - - + + + + + +3.8.5. Passing enquoted strings and special characters + + + +

3.8.5. Passing enquoted strings and special characters

+ +

NppExec, starting from version 0.7, allows to use three different quote characters to enquote a string:

+
    +
  • "abc"
  • +
  • 'abc'
  • +
  • `abc`
  • +
+

This allows to pass some quote characters within a string enquoted in the other quote characters. For example:

+ +
+
messagebox `"a message in quotes"`  // preserves the "" quotes
+messagebox "Can't stop"             // preserves a single ' quote
+
+ +

Here is an advanced example, now using Scintilla as well:

+ +
+
set local newline ~ strfromhex 0A 00  // '\n' character
+
+set local s = "a string in double-quotes"
+set local len ~ strlensci $(newline)$(s)
+sci_sendmsg SCI_APPENDTEXT $(len) `$(newline)$(s)`
+
+set local t ~ strreplace '$(s)' '"' `'`
+set local t ~ strreplace `$(t)` "double" "single"
+set local len ~ strlensci $(newline)$(t)
+sci_sendmsg SCI_APPENDTEXT $(len) `$(newline)$(t)`
+
+set local r ~ strreplace `$(t)` `'` "`"
+set local len ~ strlensci $(newline)$(r)
+sci_sendmsg SCI_APPENDTEXT $(len) "$(newline)$(r)"
+
+set local findflags ~ NPE_SF_INWHOLETEXT | NPE_SF_SETSEL
+sci_find $(findflags) `"`
+
+ +

The previous example additionally demonstrates a technique of adding a new-line character '\n' to the text. It uses NppExec's function strfromhex to get a Unicode two-byte character '\n' from its hexadecimal representation of 0A 00 (the lower bytes goes first, the upper bytes goes next). This is equal to:

+ +
+
set local newline ~ chr 0x0A  // '\n' character
+
+ +

Similarly, a tabulation character '\t' can be obtained as:

+ +
+
set local tab ~ chr 0x09  // '\t' character
+echo ab$(tab)cd
+
+ +

Here is an example that takes the %PATH% environment variable and represents it as a multi-line string by replacing all the ';' with '\n':

+ +
+
npp_console local -
+set local n ~ chr 0x0A // '\n'
+set local s ~ strreplace "$(SYS.PATH)" ; $(n)
+npp_console local +
+echo $(s)
+
+ +

The strfromhex is more powerful than the chr since strfromhex allows to operate with a sequence of bytes while chr is limited to one character. For example, Windows uses '\r\n' line endings that consist of two characters '\r' and '\n'. These two characters are represented by 4 bytes in a Unicode two-byte character string:

+ +
+
set local newline ~ strfromhex 0D 00 0A 00  // '\r\n' characters
+
+ +

The '\r' is 0D 00 and '\n' is 0A 00 here.

+

Here is an example that uses strunescape to construct a multi-line message:

+
+
set local msg ~ strunescape Drive1 is C:\\\nDrive2 is D:\\
+messagebox `$(msg)`
+
+ +

See also: Calculations, strlen and so on [3.8.4].

+ +
+
 
+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.8.html b/docs/NppExec_Manual/3.8.html similarity index 63% rename from NppExec/doc/NppExec/NppExec_Manual/3.8.html rename to docs/NppExec_Manual/3.8.html index c3cffb8..f4e4301 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/3.8.html +++ b/docs/NppExec_Manual/3.8.html @@ -1,11 +1,12 @@ - - - - - -3.8. Environment variables - - -

3.8. Environment variables

- - + + + + + +3.8. Environment variables + + + +

3.8. Environment variables

+ + diff --git a/docs/NppExec_Manual/3.9.html b/docs/NppExec_Manual/3.9.html new file mode 100644 index 0000000..8aec1cb --- /dev/null +++ b/docs/NppExec_Manual/3.9.html @@ -0,0 +1,60 @@ + + + + + +3.9. Command-line arguments: pluginMessage + + + +

3.9. Command-line arguments: pluginMessage

+

1. Notepad++'s pluginMessage

+

NppExec supports Notepad++'s -pluginMessage command-line arguments in the form of:

+
+
notepad++.exe -pluginMessage="NppExecScript=ScriptName"
+
+

and

+
+
notepad++.exe -pluginMessage="NppExecScript=ScriptName;NppExecArg1=Arg1;NppExecArg2=Arg2;...;NppExecArg9=Arg9"
+
+

where

+
    +
  • ScriptName specifies NppExec's script name or a path to a file that contains NppExec's script. The ScriptName may contain spaces since the semicolon character ';' is used as the separator between the arguments of the pluginMessage.
  • +
  • Arg1 is the first argument passed to the given NppExec's script. Up to 9 arguments are supported. These arguments may contain spaces. The semicolon character is used as the separator.
  • +
+

To pass a semicolon character as an argument's value, just specify the first semicolon character as the value and then the second semicolon character as the separator. For example:

+
+
notepad++.exe -pluginMessage="NppExecScript=ScriptName;NppExecArg1=;;NppExecArg2=Arg2"
+
+

While this works with a single semicolon ';' as the value, as well as with consequent semicolons ";;;" as the value, you can't pass a semicolon in the middle of a value, such as "a;b". The last case is not supported currently.

+ +
+
 
+
+ +

2. Example

+

Let's assume we have the following NppExec's script named "test":

+
+
// test
+echo $(argv[1])
+echo $(argv[2])
+
+

And we specify the following command-line arguments to run Notepad++:

+
+
notepad++.exe -pluginMessage="NppExecScript=test;NppExecArg1=;;NppExecArg2=a b c"
+
+

As the result, Notepad++ starts with the following lines shown in NppExec's Console:

+
+
;
+a b c
+
+ +

Note:
+In case a start-up script is specified in NppExec's Advanced Options, NppExec will first run the start-up script and then run the script specified as the NppExecScript value.

+ +
+
 
+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/3.html b/docs/NppExec_Manual/3.html similarity index 52% rename from NppExec/doc/NppExec/NppExec_Manual/3.html rename to docs/NppExec_Manual/3.html index ac90c88..86c7ac9 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/3.html +++ b/docs/NppExec_Manual/3.html @@ -1,10 +1,12 @@ - - - - - - - -

3. Basic usage

- - + + + + + +3. Basic usage + + + +

3. Basic usage

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.0.html b/docs/NppExec_Manual/4.0.html similarity index 96% rename from NppExec/doc/NppExec/NppExec_Manual/4.0.html rename to docs/NppExec_Manual/4.0.html index 30f0b2f..6013b33 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.0.html +++ b/docs/NppExec_Manual/4.0.html @@ -1,149 +1,150 @@ - - - - - -4.0. Introduction to compiling/interpreting/etc. - - -

4.0. Introduction to compiling/interpreting/etc.

-

As you are starting to read about compiling/interpreting, you should know that programmers usually count from 0 instead of 1 -- that's why the number of this section is 4.0 instead of 4.1 :) But let's proceed.

-

So, you want to compile or run something using NppExec. Great, that's the purpose of this plugin. But, before you start to do it, you must understand the principles of NppExec. Let's refer to the section [1.3] of this manual:

-
-
NppExec is not a compiler. NppExec allows you to use external tools 
-and compilers to process/compile your current file, but it has no 
-ability to do it by itself. No magic here :)
-
-

This is the basic idea of advanced usage of NppExec. Whatever source file you want to compile or run - whether it be C, or C++, or Java, or Python, or Perl, etc., etc. - you always need to specify two things:

-
    -
  1. WHAT to compile or run (the source file itself);
  2. -
  3. WHO will do it (the interpreter or compiler).
  4. -
-

If you specify only WHAT to compile or run, NppExec will tell the system exactly the same: run this file. And the system most likely will answer: I don't know how to run this file.

-

If you specify only WHO will do it, NppExec will run the specified interpreter/compiler - but it will not interpret/compile anything because you did not specify WHAT to interpret or compile.

-

Let's repeat it again: NppExec itself does not know anything about your source file and does not make any assumptions regarding it. NppExec just does exactly what you tell it to do - and that's all.

-

OK, but you may ask: why, for example, when I'm double-clicking my GhostScript file (or NSIS file, or Python file, or JavaScript file, whatever) in Windows Explorer, it becomes to be executed - but it does not happen in NppExec? The system seems to know how to run the file, right? - so why isn't it executed from within NppExec?

-

The answer is simple: double-clicking a file in Windows Explorer is not the same as trying to run this file directly. Let me explain: when you double-click a file, Windows Explorer tries to run it using the system file associations. For example, when you double-click a .doc or .docx file, Windows Explorer detects that this file is associated with Microsoft Office - and asks Microsoft Office to open this file. In the same way, if Python files are associated with some Python IDE, Windows Explorer will try to run or open these file using Python IDE.

-

On the other hand, when you want NppExec to run a file, it tells the system: run this file as if it can be executed by itself (without any associated program). That's the difference. The system file associations are not used in this case.

-

But NppExec also has the ability to run a file using the system file associations. I'm talking about "NPP_RUN <file>". In this case NppExec will tell the system: run this file using the system file associations. It will have the same effect as double-clicking in Windows Explorer. The very same effect - so you will not have any output in NppExec's Console because the file will not be executed inside the Console in this case. Refer to the section [3.3] for more details.

-
-
 
-
-

Now I guess it's time to rephrase the basic idea of advanced usage of NppExec:

-
    -
  • To run your source file in NppExec's Console, you always need to specify two things.
  • -
  • The first thing is WHAT to compile or run (the source file itself).
  • -
  • The second thing is WHO will do it (the interpreter or compiler).
  • -
-

Let's name the WHAT thing as <file> (because it's your source file) and the WHO thing as <tool> (because it's the tool which will interpret or compile you file). According to this, you need to specify the following generic command to interpret/compile/run any source file:

-
-
<tool> <file> <arguments> 
-
-

We have one additional thing here: <arguments>. This thing refers to the tool-specific command-line arguments which may (or may not) be needed to interpret/compile/run the source file. I can't give you more information here because this part really differs for different compilers/interpreters. You need to read the compiler/interpreter's documentation regarding this. In some cases you may need to specify additional arguments before the source file name:

-
-
<tool> <arguments> <file> 
-
-

Phew! It was a long way so far, isn't it? ;) But let's proceed.

-

Now you already have (or at least I hope so) a general vision regarding what's needed to interpret/compile/run your source file.

-

Let's take into account one more thing: NppExec is NOT cmd.exe. NppExec allows you to run something and see the console output, but it is NOT a system's command interpreter (cmd.exe) itself and DOES NOT invoke cmd.exe if you did not call it explicitly. (Note: NppExec ver. 0.6 RC3 introduces a new advanced option "ChildProcess_RunPolicy" that allows to modify this behavior. Refer to [4.4] for more details.) Thus you may encounter different behaviour of NppExec's Console and the system's console (cmd.exe). Refer to the section [1.3] for more details.

-

Anyway, you can "ask" cmd.exe to do something for you by calling it from NppExec explicitly. Refer to the section [4.4] for more details.

-
-
 
-
-

So, what's next? Did I tell you everything you need or is there something left? Maybe, enough talking - and let's see some examples? Yes, let's have some practice.

-
-
 
-
-

So, you want NppExec to do something. You open NppExec's Console and type: "something". Then you press Enter. Here is what you see in the Console:

-
-
something
-CreateProcess() failed with error code 2:
-The system cannot find the file specified.
-
-

What the hell happened? Help!

-

Let's analyze. You tried to run "something". What is "something"? It seems to be an executable file bacause you specified it without extension. And what do you have as result? You have "The system cannot find the file specified". So, nothing magical: you tried to run a file which does not exist.

-

Let me write some comments here. When you type "something" and press Enter, it means the following: run an executable file "something" ("something.exe") from current directory or a directory mentioned in %PATH%. This is what the system tries to do. And if you do have "something.exe" in the current directory or somewhere in %PATH%, this file ("something.exe") will be executed and you will not have the error code 2.

-

You can have the very same error when the name of an executable was specified incorrectly. For example:

-
-
%systemroot%\notepad.exe
-CreateProcess() failed with error code 2:
-The system cannot find the file specified.
-
-

What the hell happened? Help!

-

As I already wrote, NppExec is NOT cmd.exe. What does it mean? It means that NppExec, in particular, does NOT know what is %systemroot%. But cmd.exe knows it, right? So you can type the following:

-
-
cmd /c %systemroot%\notepad.exe
-
-

and Notepad will be run for you by cmd.exe (while cmd.exe itself is executing in NppExec).

-

I hope these basic examples were useful, but our goal is to compile/interpret/run something, isn't it? So we want to see an example of something like "<tool> <file> <arguments>", don't we?

-

OK, let's take some source file and try to run it. As I said, we could take any source file - it does not matter what language you are using. But, just for the example purposes, let's assume we have an .awk file with the following text:

-
-
BEGIN {
-  print "Hello!"
-}
-
-

Did you hear something about AWK or do you know something about it? No? That's great, because NppExec also does not!

-

Now I want to repeat: it does not matter what language you are using - it could be Pascal, Java, PHP, Ruby and so on, and so on - but the principle remains the same. NppExec DOES NOT know anything about this language and DOES NOT make any assumptions regarding it. You should exactly specify WHAT to interpret/compile/run (the source file) and WHO will do it (the interpreter/compiler).

-

So, we are assuming we have an opened file "program.awk" with the following text:

-
-
BEGIN {
-  print "Hello!"
-}
-
-

and we want to run it. Right now we are able to specify WHAT we want to run: it's our source file "program.awk". Notepad++ and NppExec provide the following variables which contain the current file name:

-
    -
  • $(FULL_CURRENT_PATH) : full pathname of the current file in Notepad++
  • -
  • $(FILE_NAME) : name and extension of the current file in Notepad++
  • -
-

Now, if you type "$(FULL_CURRENT_PATH)" and press Enter in NppExec's Console, you will see something like the following:

-
-
$(FULL_CURRENT_PATH)
-C:\Documents and Settings\User\My Documents\program.awk
-CreateProcess() failed with error code 193
-
-

If you search Google (or Bing, whatever) for "error code 193", you will find the following description: "%1 is not a valid Win32 application". This is exactly what we have discussed before: the system does not know how to run this file. So, it's our responsibility to specify a valid compiler/interpreter which is able to run it.

-

In our case of an .awk file, we should use ether GAWK or AWK95 interpreter. (In case of another file -- such as .cpp, .java, .php and so on -- you should use appropriate compiler/interpreter.) Let's assume you have downloaded the latest GAWK package and unpacked it to "C:\tools\GAWK". So the path to GAWK executable is "C:\tools\GAWK\gawk.exe".

-

Let's try to run it without parameters:

-
-
C:\tools\GAWK\gawk.exe
-Process started >>>
-Usage: gawk [POSIX or GNU style options] -f progfile [--] file ...
-(...)
-<<< Process finished.
-
-

So, what do we see? We see that we should specify "-f" between "gawk.exe" and the .awk source file.

-

Now let's try to run our file:

-
-
C:\tools\GAWK\gawk.exe -f $(FULL_CURRENT_PATH)
-C:\tools\GAWK\gawk.exe C:\Documents and Settings\User\My Documents\program.awk
-Process started >>>
-gawk: fatal: can't open source file `C:\Documents' for reading (No such file or directory)
-<<< Process finished.
-
-

What the hell happened? Help!

-

Well. If we look at the file pathname "C:\Documents and Settings\User\My Documents\program.awk", we can observe spaces there. What does it mean? According to default system behaviour, ALL file names with spaces should be enclosed in double quotes. Otherwise the system does not understand where is the end of file name and treats spaces as dividers between several file names.

-

So, let's try again:

-
-
"C:\tools\GAWK\gawk.exe" -f "$(FULL_CURRENT_PATH)"
-"C:\tools\GAWK\gawk.exe" -f "C:\Documents and Settings\User\My Documents\program.awk"
-Process started >>>
-Hello!
-<<< Process finished.
-
-

Success! We have successfully run our .awk program using gawk.exe. This illustrates our general principle which could be applied to ANY language: specify WHAT to run (the source file) and WHO will run it (the interpreter or compiler). Additional argument ("-f" in our case) included.

-

The path to the interpreter was also enclosed in double quotes because, in general, it also may contain spaces. Thus I'd recommend to always enclose paths to interpeter/compiler and source file in double quotes.

-
-
 
-
-

Phew!.. Are you still here, with me? ;)

-

What else to say?.. Not much, actually. Often it's better to write some NppExec's script [3.7] for running/compiling purposes, because a lot of actions (commands) may be required for this. You can see several examples under the sections [4.6] and [4.7].

-

And here is one more useful advice. Starting from NppExec v0.4.2, you can use run-time variables in your command aliases. For example, you can define the following alias:

-
-
npe_cmdalias g = "C:\tools\GAWK\gawk.exe" -f "$(FULL_CURRENT_PATH)"
-
-

Once you did it, you can type just "g" to run your current file using gawk.exe. Type "help npe_cmdalias" in NppExec's Console to learn more about the command aliases.

-
-
 
-
- - + + + + + +4.0. Introduction to compiling/interpreting/etc. + + + +

4.0. Introduction to compiling/interpreting/etc.

+

As you are starting to read about compiling/interpreting, you should know that programmers usually count from 0 instead of 1 -- that's why the number of this section is 4.0 instead of 4.1 :) But let's proceed.

+

So, you want to compile or run something using NppExec. Great, that's the purpose of this plugin. But, before you start to do it, you must understand the principles of NppExec. Let's refer to the section [1.3] of this manual:

+
+
NppExec is not a compiler. NppExec allows you to use external tools 
+and compilers to process/compile your current file, but it has no 
+ability to do it by itself. No magic here :)
+
+

This is the basic idea of advanced usage of NppExec. Whatever source file you want to compile or run - whether it be C, or C++, or Java, or Python, or Perl, etc., etc. - you always need to specify two things:

+
    +
  1. WHAT to compile or run (the source file itself);
  2. +
  3. WHO will do it (the interpreter or compiler).
  4. +
+

If you specify only WHAT to compile or run, NppExec will tell the system exactly the same: run this file. And the system most likely will answer: I don't know how to run this file.

+

If you specify only WHO will do it, NppExec will run the specified interpreter/compiler - but it will not interpret/compile anything because you did not specify WHAT to interpret or compile.

+

Let's repeat it again: NppExec itself does not know anything about your source file and does not make any assumptions regarding it. NppExec just does exactly what you tell it to do - and that's all.

+

OK, but you may ask: why, for example, when I'm double-clicking my GhostScript file (or NSIS file, or Python file, or JavaScript file, whatever) in Windows Explorer, it becomes to be executed - but it does not happen in NppExec? The system seems to know how to run the file, right? - so why isn't it executed from within NppExec?

+

The answer is simple: double-clicking a file in Windows Explorer is not the same as trying to run this file directly. Let me explain: when you double-click a file, Windows Explorer tries to run it using the system file associations. For example, when you double-click a .doc or .docx file, Windows Explorer detects that this file is associated with Microsoft Office - and asks Microsoft Office to open this file. In the same way, if Python files are associated with some Python IDE, Windows Explorer will try to run or open these file using Python IDE.

+

On the other hand, when you want NppExec to run a file, it tells the system: run this file as if it can be executed by itself (without any associated program). That's the difference. The system file associations are not used in this case.

+

But NppExec also has the ability to run a file using the system file associations. I'm talking about "NPP_RUN <file>". In this case NppExec will tell the system: run this file using the system file associations. It will have the same effect as double-clicking in Windows Explorer. The very same effect - so you will not have any output in NppExec's Console because the file will not be executed inside the Console in this case. Refer to the section [3.3] for more details.

+
+
 
+
+

Now I guess it's time to rephrase the basic idea of advanced usage of NppExec:

+
    +
  • To run your source file in NppExec's Console, you always need to specify two things.
  • +
  • The first thing is WHAT to compile or run (the source file itself).
  • +
  • The second thing is WHO will do it (the interpreter or compiler).
  • +
+

Let's name the WHAT thing as <file> (because it's your source file) and the WHO thing as <tool> (because it's the tool which will interpret or compile your file). According to this, you need to specify the following generic command to interpret/compile/run any source file:

+
+
<tool> <file> <arguments> 
+
+

We have one additional thing here: <arguments>. This thing refers to the tool-specific command-line arguments which may (or may not) be needed to interpret/compile/run the source file. I can't give you more information here because this part really differs for different compilers/interpreters. You need to read the compiler/interpreter's documentation regarding this. In some cases you may need to specify additional arguments before the source file name:

+
+
<tool> <arguments> <file> 
+
+

Phew! It was a long way so far, isn't it? ;) But let's proceed.

+

Now you already have (or at least I hope so) a general vision regarding what's needed to interpret/compile/run your source file.

+

Let's take into account one more thing: NppExec is NOT cmd.exe. NppExec allows you to run something and see the console output, but it is NOT a system's command interpreter (cmd.exe) itself and DOES NOT invoke cmd.exe if you did not call it explicitly. (Note: NppExec ver. 0.6 RC3 introduces a new advanced option "ChildProcess_RunPolicy" that allows to modify this behavior. Refer to [4.4] for more details.) Thus you may encounter different behaviour of NppExec's Console and the system's console (cmd.exe). Refer to the section [1.3] for more details.

+

Anyway, you can "ask" cmd.exe to do something for you by calling it from NppExec explicitly. Refer to the section [4.4] for more details.

+
+
 
+
+

So, what's next? Did I tell you everything you need or is there something left? Maybe, enough talking - and let's see some examples? Yes, let's have some practice.

+
+
 
+
+

So, you want NppExec to do something. You open NppExec's Console and type: "something". Then you press Enter. Here is what you see in the Console:

+
+
something
+CreateProcess() failed with error code 2:
+The system cannot find the file specified.
+
+

What the hell happened? Help!

+

Let's analyze. You tried to run "something". What is "something"? It seems to be an executable file because you specified it without extension. And what do you have as result? You have "The system cannot find the file specified". So, nothing magical: you tried to run a file which does not exist.

+

Let me write some comments here. When you type "something" and press Enter, it means the following: run an executable file "something" ("something.exe") from current directory or a directory mentioned in %PATH%. This is what the system tries to do. And if you do have "something.exe" in the current directory or somewhere in %PATH%, this file ("something.exe") will be executed and you will not have the error code 2.

+

You can have the very same error when the name of an executable was specified incorrectly. For example:

+
+
%systemroot%\notepad.exe
+CreateProcess() failed with error code 2:
+The system cannot find the file specified.
+
+

What the hell happened? Help!

+

As I already wrote, NppExec is NOT cmd.exe. What does it mean? It means that NppExec, in particular, does NOT know what is %systemroot%. But cmd.exe knows it, right? So you can type the following:

+
+
cmd /c %systemroot%\notepad.exe
+
+

and Notepad will be run for you by cmd.exe (while cmd.exe itself is executing in NppExec).

+

I hope these basic examples were useful, but our goal is to compile/interpret/run something, isn't it? So we want to see an example of something like "<tool> <file> <arguments>", don't we?

+

OK, let's take some source file and try to run it. As I said, we could take any source file - it does not matter what language you are using. But, just for the example purposes, let's assume we have an .awk file with the following text:

+
+
BEGIN {
+  print "Hello!"
+}
+
+

Did you hear something about AWK or do you know something about it? No? That's great, because NppExec also does not!

+

Now I want to repeat: it does not matter what language you are using - it could be Pascal, Java, PHP, Ruby and so on, and so on - but the principle remains the same. NppExec DOES NOT know anything about this language and DOES NOT make any assumptions regarding it. You should exactly specify WHAT to interpret/compile/run (the source file) and WHO will do it (the interpreter/compiler).

+

So, we are assuming we have an opened file "program.awk" with the following text:

+
+
BEGIN {
+  print "Hello!"
+}
+
+

and we want to run it. Right now we are able to specify WHAT we want to run: it's our source file "program.awk". Notepad++ and NppExec provide the following variables which contain the current file name:

+
    +
  • $(FULL_CURRENT_PATH) : full pathname of the current file in Notepad++
  • +
  • $(FILE_NAME) : name and extension of the current file in Notepad++
  • +
+

Now, if you type "$(FULL_CURRENT_PATH)" and press Enter in NppExec's Console, you will see something like the following:

+
+
$(FULL_CURRENT_PATH)
+C:\Documents and Settings\User\My Documents\program.awk
+CreateProcess() failed with error code 193
+
+

If you search Google (or Bing, whatever) for "error code 193", you will find the following description: "%1 is not a valid Win32 application". This is exactly what we have discussed before: the system does not know how to run this file. So, it's our responsibility to specify a valid compiler/interpreter which is able to run it.

+

In our case of an .awk file, we should use ether GAWK or AWK95 interpreter. (In case of another file -- such as .cpp, .java, .php and so on -- you should use appropriate compiler/interpreter.) Let's assume you have downloaded the latest GAWK package and unpacked it to "C:\tools\GAWK". So the path to GAWK executable is "C:\tools\GAWK\gawk.exe".

+

Let's try to run it without parameters:

+
+
C:\tools\GAWK\gawk.exe
+Process started >>>
+Usage: gawk [POSIX or GNU style options] -f progfile [--] file ...
+(...)
+<<< Process finished.
+
+

So, what do we see? We see that we should specify "-f" between "gawk.exe" and the .awk source file.

+

Now let's try to run our file:

+
+
C:\tools\GAWK\gawk.exe -f $(FULL_CURRENT_PATH)
+C:\tools\GAWK\gawk.exe C:\Documents and Settings\User\My Documents\program.awk
+Process started >>>
+gawk: fatal: can't open source file `C:\Documents' for reading (No such file or directory)
+<<< Process finished.
+
+

What the hell happened? Help!

+

Well. If we look at the file pathname "C:\Documents and Settings\User\My Documents\program.awk", we can observe spaces there. What does it mean? According to default system behaviour, ALL file names with spaces should be enclosed in double quotes. Otherwise the system does not understand where is the end of file name and treats spaces as dividers between several file names.

+

So, let's try again:

+
+
"C:\tools\GAWK\gawk.exe" -f "$(FULL_CURRENT_PATH)"
+"C:\tools\GAWK\gawk.exe" -f "C:\Documents and Settings\User\My Documents\program.awk"
+Process started >>>
+Hello!
+<<< Process finished.
+
+

Success! We have successfully run our .awk program using gawk.exe. This illustrates our general principle which could be applied to ANY language: specify WHAT to run (the source file) and WHO will run it (the interpreter or compiler). Additional argument ("-f" in our case) included.

+

The path to the interpreter was also enclosed in double quotes because, in general, it also may contain spaces. Thus I'd recommend to always enclose paths to interpeter/compiler and source file in double quotes.

+
+
 
+
+

Phew!.. Are you still here, with me? ;)

+

What else to say?.. Not much, actually. Often it's better to write some NppExec's script [3.7] for running/compiling purposes, because a lot of actions (commands) may be required for this. You can see several examples under the sections [4.6] and [4.7].

+

And here is one more useful advice. Starting from NppExec v0.4.2, you can use run-time variables in your command aliases. For example, you can define the following alias:

+
+
npe_cmdalias g = "C:\tools\GAWK\gawk.exe" -f "$(FULL_CURRENT_PATH)"
+
+

Once you did it, you can type just "g" to run your current file using gawk.exe. Type "help npe_cmdalias" in NppExec's Console to learn more about the command aliases.

+
+
 
+
+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.1.html b/docs/NppExec_Manual/4.1.html similarity index 77% rename from NppExec/doc/NppExec/NppExec_Manual/4.1.html rename to docs/NppExec_Manual/4.1.html index 2f7cf32..a725be1 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.1.html +++ b/docs/NppExec_Manual/4.1.html @@ -1,40 +1,46 @@ - - - - - -4.1. NppExec's Console behaviour - - -

4.1. NppExec's Console behaviour

-

By default, NppExec's Console is automatically shown each time you execute some NppExec's script. The reason is simple: usually script execution assumes some output which is needed or at least may be usefull for user.

-

However, you may want some of your scripts to be executed silently (i.e. without showing NppExec's Console) or even want to force NppExec's Console to be closed. And NppExec allows you to do this using its command NPP_CONSOLE.

-

You can use

-
-
NPP_CONSOLE ?
-
-

in the beginning of your script in order to keep current Console's state. It means that hidden (closed) Console remains hidden and shown (opened) Console remains shown.

-

Also you can use

-
-
NPP_CONSOLE 0
-
-

to hide the Console, and

-
-
NPP_CONSOLE 1
-
-

to show the Console during script execution.

-

Type "help npp_console" in NppExec's Console for more details.

-

By default, NppExec's Console is automatically cleared each time you execute some NppExec's script. However, you can use

-
-
NPE_CONSOLE a+
-
-

to enable the "append" mode which keeps the previous Console's text and does not clear it.

-

Type "help npe_console" in NppExec's Console for more details.

-

To set the keyboard focus to NppExec's Console, use

-
-
NPP_SETFOCUS Con
-
-

Type "help npp_setfocus" in NppExec's Console for more details.

-

See also: NppExec's Console [3.5]; Console output redirection [4.5].

- - + + + + + +4.1. NppExec's Console behaviour + + + +

4.1. NppExec's Console behaviour

+

By default, NppExec's Console is automatically shown each time you execute some NppExec's script. The reason is simple: usually script execution assumes some output which is needed or at least may be usefull for user.

+

However, you may want some of your scripts to be executed silently (i.e. without showing NppExec's Console) or even want to force NppExec's Console to be closed. And NppExec allows you to do this using its command NPP_CONSOLE.

+

You can use

+
+
NPP_CONSOLE ?
+
+

in the beginning of your script in order to keep current Console's state. It means that hidden (closed) Console remains hidden and shown (opened) Console remains shown.

+

Also you can use

+
+
NPP_CONSOLE 0
+
+

to hide the Console, and

+
+
NPP_CONSOLE 1
+
+

to show the Console during script execution.

+

Type "help npp_console" in NppExec's Console for more details.

+

By default, NppExec's Console is automatically cleared each time you execute some NppExec's script. However, you can use

+
+
NPE_CONSOLE a+
+
+

to enable the "append" mode which keeps the previous Console's text and does not clear it.

+

Type "help npe_console" in NppExec's Console for more details.

+

To set the keyboard focus to NppExec's Console, use

+
+
NPP_SETFOCUS Con
+
+

Type "help npp_setfocus" in NppExec's Console for more details.

+

By default, when "Toggle NppExec Console" (Ctrl+~) switches from NppExec's Console to Notepad++'s editing window, the Console remains visible. If you want NppExec's Console to become hidden when switching to Notepad++'s editing window, do the following:

+
    +
  1. in NppExec's Console, press Ctrl+F or F7 to show the search pane;
  2. +
  3. in the search pane, check "Hide toggled Console".
  4. +
+

See also: NppExec's Console [3.5]; Console output redirection [4.5].

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.2.html b/docs/NppExec_Manual/4.2.html similarity index 77% rename from NppExec/doc/NppExec/NppExec_Manual/4.2.html rename to docs/NppExec_Manual/4.2.html index 672539b..2a85770 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.2.html +++ b/docs/NppExec_Manual/4.2.html @@ -1,76 +1,81 @@ - - - - - -4.2. Environment - - -

4.2. Environment

-

NppExec allows you to specify the environment (i.e. environment variables) for any program you start from NppExec. You can do it from NppExec's scripts or directly from NppExec's Console window. You can set or remove/restore such environment variables using NppExec's commands ENV_SET and ENV_UNSET.

-

For example, you can set your own value of PATH:

-
-
ENV_SET PATH = C:\temp  // modified
-
-

Now you can start cmd.exe (from - NppExec's script or NppExec's console) and type "echo %PATH%" to ensure that the value of PATH is now "C:\temp". Type "exit" to -exit cmd.exe and then execute this NppExec's command:

-
-
ENV_UNSET PATH  // restored
-
-

This command restores the initial value of PATH. NppExec does not remove the - PATH variable because this variable existed before it was modified with ENV_SET. - In the same time, you can create and remove new environment variables:

-
-
ENV_SET new_environment_variable = Hello  // created
-ENV_UNSET new_environment_variable        // removed
-
-

Such environment variables can be used (and modified) by any program you start from NppExec. Also, values of such variables can be used by NppExec in a form of $(SYS.variable_name). For example:

-
-
ENV_SET a = My Variable  // created:  a=My Variable
-echo $(SYS.a)            // prints:   My Variable
-ENV_SET a = aaa          // modified: a=aaa
-echo $(SYS.a)            // prints:   aaa
-ENV_UNSET a              // removed
-
-

I.e. you can use "$(SYS.variable_name)" to read the variable's value and use "ENV_SET variable_name = value" to -set the variables's value.

-

If there is a need to set/modify an environment variable temporarily (in the scope of the current NppExec's script), use "ENV_SET local <var> = <value>". Once the current NppExec's script ends, the previous value of <var> is restored automatically.

-

Type "help env_set" in NppExec's - Console -for more details.

-

Good way to set your environment is to do it inside NppExec's start-up script. You can specify your start-up script in NppExec's Advanced Options. This script will be executed each time Notepad++ starts. For example, you can create similar script:

-
-
// don't show NppExec's Console if it's hidden
-NPP_CONSOLE ?
-// set our environment variables
-ENV_SET NPPHOME = $(NPP_DIRECTORY)
-ENV_SET TCCHOME = C:\tools\tcc
-// restore initial value of PATH
-ENV_UNSET PATH
-// set our value of PATH
-ENV_SET PATH = $(SYS.NPPHOME);$(SYS.TCCHOME);$(SYS.PATH)
-// clear Console screen
-CLS
-
-

The first command ("NPP_CONSOLE ?") - forbids the Console to be shown if it's hidden - this is usefull at Notepad++'es -start-up.

-

The two following commands set new environment variables: NPPHOME and TCCHOME. These environment variables can be used by any program you start from NppExec.

-

The following command ("ENV_UNSET PATH") restores the initial value of PATH if it was previously modified by NppExec. Of course, it can not be modified by NppExec before its start-up script is executed, but you may execute the start-up script again (using NPP_EXEC or from the "Execute NppExec Script..." dialog), - so it may be important to restore the initial value of PATH before modifying - it. Otherwise, the value of PATH may grow again and again - each time you - call the start-up script explicitly or execute another script which modifies -the PATH variable.

-

The next command sets the new value - of the PATH variable. Now PATH includes both NPPHOME and TCCHOME, so you - can - type just "notepad++" or "tcc" in order to use Notepad++'es command line -switches or to run tcc.

-

Finally, the last command ("CLS") - clears NppExec's Console's output, so the Console will contain no text when - you -open it.

-

See also: Environment (heritable) variables [3.8.3].

- - + + + + + +4.2. Environment + + + +

4.2. Environment

+

NppExec allows you to specify the environment (i.e. environment variables) for any program you start from NppExec. You can do it from NppExec's scripts or directly from NppExec's Console window. You can set or remove/restore such environment variables using NppExec's commands ENV_SET and ENV_UNSET.

+

For example, you can set your own value of PATH:

+
+
ENV_SET PATH = C:\temp  // modified
+
+

Now you can start cmd.exe (from + NppExec's script or NppExec's console) and type "echo %PATH%" to ensure that the value of PATH is now "C:\temp". Type "exit" to +exit cmd.exe and then execute this NppExec's command:

+
+
ENV_UNSET PATH  // restored
+
+

This command restores the initial value of PATH. NppExec does not remove the + PATH variable because this variable existed before it was modified with ENV_SET. + In the same time, you can create and remove new environment variables:

+
+
ENV_SET new_environment_variable = Hello  // created
+ENV_UNSET new_environment_variable        // removed
+
+

Such environment variables can be used (and modified) by any program you start from NppExec. Also, values of such variables can be used by NppExec in a form of $(SYS.variable_name). For example:

+
+
ENV_SET a = My Variable  // created:  a=My Variable
+echo $(SYS.a)            // prints:   My Variable
+ENV_SET a = aaa          // modified: a=aaa
+echo $(SYS.a)            // prints:   aaa
+ENV_UNSET a              // removed
+
+

I.e. you can use "$(SYS.variable_name)" to read the variable's value and use "ENV_SET variable_name = value" to +set the variables's value.

+

If there is a need to set/modify an environment variable temporarily (in the scope of the current NppExec's script), use "ENV_SET local <var> = <value>". Once the current NppExec's script ends, the previous value of <var> is restored automatically.

+

Type "help env_set" in NppExec's + Console +for more details.

+

Good way to set your environment is to do it inside NppExec's start-up script. You can specify your start-up script in NppExec's Advanced Options. This script will be executed each time Notepad++ starts. For example, you can create similar script:

+
+
// don't show NppExec's Console if it's hidden
+NPP_CONSOLE ?
+// don't output anything within this NppExec's script
+NPP_CONSOLE local -
+// as we don't output anything, don't print "==== READY ===="
+NPE_CONSOLE local -- p-
+// set our environment variables
+ENV_SET NPPHOME = $(NPP_DIRECTORY)
+ENV_SET TCCHOME = C:\tools\tcc
+// restore initial value of PATH
+ENV_UNSET PATH
+// set our value of PATH
+ENV_SET PATH = $(SYS.NPPHOME);$(SYS.TCCHOME);$(SYS.PATH)
+// clear Console screen
+CLS
+
+

The first command ("NPP_CONSOLE ?") forbids the Console to be shown if it's hidden - this is usefull at Notepad++'es start-up.

+

The next command ("NPP_CONSOLE local -") disables any output to the Console within the current NppExec's script, thus making the script to be completely silent.

+

The next command ("NPE_CONSOLE local -- p-") disables the "==== READY ====" message within the current NppExec's script, so this message is not printed when the script has finished.

+

The two following commands set new environment variables: NPPHOME and TCCHOME. These environment variables can be used by any program you start from NppExec.

+

The following command ("ENV_UNSET PATH") restores the initial value of PATH if it has previously been modified by NppExec. Of course, it can not be modified by NppExec before its start-up script is executed, but you may execute the start-up script again (using NPP_EXEC or from the "Execute NppExec Script..." dialog), + so it may be important to restore the initial value of PATH before modifying + it. Otherwise, the value of PATH may grow again and again - each time you + call the start-up script explicitly or execute another script which modifies +the PATH variable.

+

The next command sets the new value + of the PATH variable. Now PATH includes both NPPHOME and TCCHOME, so you + can + type just "notepad++" or "tcc" in order to use Notepad++'es command line +switches or to run tcc.

+

Finally, the last command ("CLS") + clears NppExec's Console's output, so the Console will contain no text when + you +open it.

+

See also: Environment (heritable) variables [3.8.3].

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.3.html b/docs/NppExec_Manual/4.3.html similarity index 87% rename from NppExec/doc/NppExec/NppExec_Manual/4.3.html rename to docs/NppExec_Manual/4.3.html index a071c57..93c1972 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.3.html +++ b/docs/NppExec_Manual/4.3.html @@ -1,40 +1,41 @@ - - - - - -4.3. Run-time parameters - - -

4.3. Run-time parameters

-

NppExec supports several different ways to use run-time parameters which you can vary according to your needs.

-

The first line of each section below shows how the run-time parameter(s) can be set, and the second line shows how these parameters can be used.

-
    -
  1. Passing parameters to NppExec's script (to use them inside the script): -
    -
    NPP_EXEC "my script" "param 1" "param 2"
    --> $(ARGV), $(ARGV[1]), $(ARGV[2]), ...
    -
    -
  2. -
  3. Run-time input (sets NppExec's variable $(INPUT) and so on): -
    -
    INPUTBOX "Input some value:" : "default value"
    --> $(INPUT),$(INPUT[1]), $(INPUT[2]), ...
    -
    -
  4. -
  5. User's variables (internal NppExec's variables): -
    -
    SET variable = value
    --> $(variable)
    -
    -
  6. -
  7. Environment variables (can be modified also outside of NppExec) -
    -
    ENV_SET variable = value
    --> $(SYS.variable)
    -
    -
  8. -
-

See also: User (internal) variables [3.8.2]; Environment (heritable) variables [3.8.3].

- - + + + + + +4.3. Run-time parameters + + + +

4.3. Run-time parameters

+

NppExec supports several different ways to use run-time parameters which you can vary according to your needs.

+

The first line of each section below shows how the run-time parameter(s) can be set, and the second line shows how these parameters can be used.

+
    +
  1. Passing parameters to NppExec's script (to use them inside the script): +
    +
    NPP_EXEC "my script" "param 1" "param 2"
    +-> $(ARGV), $(ARGV[1]), $(ARGV[2]), ...
    +
    +
  2. +
  3. Run-time input (sets NppExec's variable $(INPUT) and so on): +
    +
    INPUTBOX "Input some value:" : "default value"
    +-> $(INPUT), $(INPUT[1]), $(INPUT[2]), ...
    +
    +
  4. +
  5. User's variables (internal NppExec's variables): +
    +
    SET variable = value
    +-> $(variable)
    +
    +
  6. +
  7. Environment variables (can be modified also outside of NppExec) +
    +
    ENV_SET variable = value
    +-> $(SYS.variable)
    +
    +
  8. +
+

See also: User (internal) variables [3.8.2]; Environment (heritable) variables [3.8.3].

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.4.html b/docs/NppExec_Manual/4.4.html similarity index 91% rename from NppExec/doc/NppExec/NppExec_Manual/4.4.html rename to docs/NppExec_Manual/4.4.html index 27bcf25..2094b83 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.4.html +++ b/docs/NppExec_Manual/4.4.html @@ -1,68 +1,69 @@ - - - - - -4.4. Using cmd.exe - - -

4.4. Using cmd.exe

-

NppExec by itself does not support - standard console commands such as "copy", "move", "mkdir", "for" etc. (*) Actually, - these commands are part of system's command interpreter (cmd.exe). So, you - can - use cmd.exe to perform such commands. For example, you can type the following -commands in NppExec's Console or inside NppExec's script:

-
-
// create a directory C:\Backup
-cmd /c mkdir C:\Backup
-// save current Notepad++'es file
-NPP_SAVE
-// copy current file to C:\Backup
-cmd /c copy "$(FULL_CURRENT_PATH)" "C:\Backup\$(FILE_NAME)" /Y 
-// change current directory
-cd C:\Backup
-// list all .txt files in C:\Backup
-cmd /c for %f in (*.txt) do @echo %f
-
-

NppExec by itself can not redirect console program's output into a text file. (*) And, again, you can do it via cmd.exe:

-
-
cmd /c program.exe >program.txt
-
-

or even

-
-
cmd /c for /? >for.txt
-
-

By the way, cmd.exe allows to execute several commands one after another while each previous command is completed successfully. For example:

-
-
cmd /c for /? >for.txt && type for.txt
-cmd /c C: && cd C:\Backup && for %f in (*.txt) do @echo %f
-
-

You can always type

-
-
cmd /?
-
-

for more details about cmd.exe and its commands. You'll be surprised how powerful it is :)

-

Don't forget you can execute .bat and .cmd files in the same way as executable files [3.3] - but the file extension (.bat or .cmd) can not be omitted in this case. (*) The batch files (.bat or .cmd) allow to implement sequences of commands with simple algorithms, so you can use them when single cmd's commands are not enough.

- -
-
 
-
- -

(*) Starting from NppExec ver. 0.6 RC3, it is possible to execute batch files (such as .bat and .cmd) without specifying their extension, as well as it is possible to avoid explicit usage of "cmd /C" to execute the command interpreter's commands. A new advanced option "ChildProcess_RunPolicy" was introduced for this. Set its value to 1 or 2 according to the desired behavior. Refer to "doc\NppExec\NppExec_TechInfo.txt" for further details.

- -
-
 
-
- -

Finally, a few words about the Delayed Expansion ( https://ss64.com/nt/delayedexpansion.html ). According to cmd's help, this option can be turned on by specifying

-
-
cmd /V:ON
-
-

Here is an example of running a batch file that relies on the Delayed Expansion (thus using /V:ON). This example assumes that the current document is a batch file (thus using "$(FULL_CURRENT_PATH)") and you want to run it in its own separate console window (thus using NPP_RUN):

-
-
NPP_RUN cmd /V:ON /C "$(FULL_CURRENT_PATH)"
-
-

See also: Do something (how-to) [3.3]; Console output redirection [4.5]; Grab date & time to NppExec variable [4.6.5]; Run and terminate PowerShell process [4.6.7]; Send several commands to external tool [4.6.9].

- - + + + + + +4.4. Using cmd.exe + + + +

4.4. Using cmd.exe

+

NppExec by itself does not support + standard console commands such as "copy", "move", "mkdir", "for" etc. (*) Actually, + these commands are part of system's command interpreter (cmd.exe). So, you + can + use cmd.exe to perform such commands. For example, you can type the following +commands in NppExec's Console or inside NppExec's script:

+
+
// create a directory C:\Backup
+cmd /c mkdir C:\Backup
+// save current Notepad++'es file
+NPP_SAVE
+// copy current file to C:\Backup
+cmd /c copy "$(FULL_CURRENT_PATH)" "C:\Backup\$(FILE_NAME)" /Y 
+// change current directory
+cd C:\Backup
+// list all .txt files in C:\Backup
+cmd /c for %f in (*.txt) do @echo %f
+
+

NppExec by itself can not redirect console program's output into a text file. (*) And, again, you can do it via cmd.exe:

+
+
cmd /c program.exe >program.txt
+
+

or even

+
+
cmd /c for /? >for.txt
+
+

By the way, cmd.exe allows to execute several commands one after another while each previous command is completed successfully. For example:

+
+
cmd /c for /? >for.txt && type for.txt
+cmd /c C: && cd C:\Backup && for %f in (*.txt) do @echo %f
+
+

You can always type

+
+
cmd /?
+
+

for more details about cmd.exe and its commands. You'll be surprised how powerful it is :)

+

Don't forget you can execute .bat and .cmd files in the same way as executable files [3.3] - but the file extension (.bat or .cmd) can not be omitted in this case. (*) The batch files (.bat or .cmd) allow to implement sequences of commands with simple algorithms, so you can use them when single cmd's commands are not enough.

+ +
+
 
+
+ +

(*) Starting from NppExec ver. 0.6 RC3, it is possible to execute batch files (such as .bat and .cmd) without specifying their extension, as well as it is possible to avoid explicit usage of "cmd /C" to execute the command interpreter's commands. A new advanced option "ChildProcess_RunPolicy" was introduced for this. Set its value to 1 or 2 according to the desired behavior. Refer to "doc\NppExec\NppExec_TechInfo.txt" for further details.

+ +
+
 
+
+ +

Finally, a few words about the Delayed Expansion ( https://ss64.com/nt/delayedexpansion.html ). According to cmd's help, this option can be turned on by specifying

+
+
cmd /V:ON
+
+

Here is an example of running a batch file that relies on the Delayed Expansion (thus using /V:ON). This example assumes that the current document is a batch file (thus using "$(FULL_CURRENT_PATH)") and you want to run it in its own separate console window (thus using NPP_RUN):

+
+
NPP_RUN cmd /V:ON /C "$(FULL_CURRENT_PATH)"
+
+

See also: Do something (how-to) [3.3]; Console output redirection [4.5]; Grab date & time to NppExec variable [4.6.5]; Run and terminate PowerShell process [4.6.7]; Send several commands to external tool [4.6.9].

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.5.html b/docs/NppExec_Manual/4.5.html similarity index 94% rename from NppExec/doc/NppExec/NppExec_Manual/4.5.html rename to docs/NppExec_Manual/4.5.html index 000247c..ac919af 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.5.html +++ b/docs/NppExec_Manual/4.5.html @@ -1,42 +1,43 @@ - - - - - -4.5. Console output redirection - - -

4.5. Console output redirection

-

By default, when you run some console program using NppExec, the program's output is shown in NppExec's Console. It is possible because the console program is started as a child process of NppExec. NppExec uses pipes to redirect child process'es output to NppExec's Console window and to redirect user's input from NppExec's Console window to child process'es input. Such approach has several known limitations:

-
-

- no output may be shown until child process ends (if this child process performs a lot of operations without explicit flushing of its output);

-

- no output may be shown while child process waits for initial input (this may happen with some interpreters, but does not happen with cmd.exe);

-

- stdout and stderr output may be mixed (stdout and stderr are redirected into the same pipe);

-

- no - output or incorrect output may happen when child process requires "real" console - screen buffer.

-
-

The advantages:

-
-

+ NppExec's Console supports ANSI (Windows), OEM (DOS) and UTF-8 output and input (the standard console usually supports just OEM or ANSI);

-

+ NppExec's Console allows to change the console output using NppExec's Exclude/Include and Replacing filters;

-

+ NppExec's Console allows to highlight warnings/errors and process them using NppExec's Highlight filters.

-
-

If you want your console program's output to be redirected into a text file, you can use something similar to the following:

-
-
cmd /c program.exe >C:\temp\out.txt
-
-

This will redirect the output of 'program.exe' into a text file 'out.txt' inside 'temp' folder on your drive C (this folder must exist).

-

Then you can open this text file in Notepad++:

-
-
NPP_OPEN C:\temp\out.txt
-
-

Thus, you can use the following NppExec's script:

-
-
SET local OUTFILE = C:\temp\out.txt
-cmd /c program.exe >$(OUTFILE)
-NPP_OPEN $(OUTFILE)
-
-

See also: NppExec's Console [3.5]; NppExec's Console behaviour [4.1]; Using cmd.exe [4.4].

- - + + + + + +4.5. Console output redirection + + + +

4.5. Console output redirection

+

By default, when you run some console program using NppExec, the program's output is shown in NppExec's Console. It is possible because the console program is started as a child process of NppExec. NppExec uses pipes to redirect child process'es output to NppExec's Console window and to redirect user's input from NppExec's Console window to child process'es input. Such approach has several known limitations:

+
+

- no output may be shown until child process ends (if this child process performs a lot of operations without explicit flushing of its output);

+

- no output may be shown while child process waits for initial input (this may happen with some interpreters, but does not happen with cmd.exe);

+

- stdout and stderr output may be mixed (stdout and stderr are redirected into the same pipe);

+

- no + output or incorrect output may happen when child process requires "real" console + screen buffer.

+
+

The advantages:

+
+

+ NppExec's Console supports ANSI (Windows), OEM (DOS) and UTF-8 output and input (the standard console usually supports just OEM or ANSI);

+

+ NppExec's Console allows to change the console output using NppExec's Exclude/Include and Replacing filters;

+

+ NppExec's Console allows to highlight warnings/errors and process them using NppExec's Highlight filters.

+
+

If you want your console program's output to be redirected into a text file, you can use something similar to the following:

+
+
cmd /c program.exe >C:\temp\out.txt
+
+

This will redirect the output of 'program.exe' into a text file 'out.txt' inside 'temp' folder on your drive C (this folder must exist).

+

Then you can open this text file in Notepad++:

+
+
NPP_OPEN C:\temp\out.txt
+
+

Thus, you can use the following NppExec's script:

+
+
SET local OUTFILE = C:\temp\out.txt
+cmd /c program.exe >$(OUTFILE)
+NPP_OPEN $(OUTFILE)
+
+

See also: NppExec's Console [3.5]; NppExec's Console behaviour [4.1]; Using cmd.exe [4.4].

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.6.1.html b/docs/NppExec_Manual/4.6.1.html similarity index 92% rename from NppExec/doc/NppExec/NppExec_Manual/4.6.1.html rename to docs/NppExec_Manual/4.6.1.html index 44f0676..146600b 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.6.1.html +++ b/docs/NppExec_Manual/4.6.1.html @@ -1,69 +1,70 @@ - - - - - -4.6.1. Applying external tool to selected text - - -

4.6.1. Applying external tool to selected text

-

Let's suppose you want to apply some AWK program to your selected text in Notepad++.

-

The first thing you require is NppExec plugin ;)

-

The second thing you require is - an AWK -executable, for example, "awk95.exe" or "gawk.exe".

-

When you want to apply some AWK - program to your selected text, this AWK program must exists, isn't it? So, - create -a file "do.awk" in your Notepad++'s folder. The full path to this file is "$(NPP_DIRECTORY)\do.awk".

-

OK, the file is created, now you - need some AWK program. Open the "do.awk" in Notepad++ and type your program, - for -example:

-
-
{ print $0 }
-
-

This simple AWK program will print each record (i.e. text line) from the input file given.

-

Now, open another file in Notepad++ and select some text (few lines, for example).

-

Now you have the selected text and a tool (awk95.exe or gawk.exe) you want to apply to this selected text.

-

The only thing remaining is NppExec's script which will allow you to do what you want.

-

Press F6 (or Plugins -> NppExec -> Execute NppExec Script...) -and type:

-
-
// full path to AWK executable 
-set local AWK_EXE = C:\tools\awk\awk95.exe 
-// this temporary file name will be used 
-set local TEMP_FILE = $(SYS.TEMP)\npp_sel.txt 
-// save current selection as ANSI text file 
-SEL_SAVETO $(TEMP_FILE) :a 
-// run do.awk for this file 
-"$(AWK_EXE)" -f "$(NPP_DIRECTORY)\do.awk" "$(TEMP_FILE)"
-
-

Save this script as "do.awk on selected text" or -whatever you want.

-

Press OK.

-

You will see the AWK's output in the NppExec's Console window. You can copy it from there with Ctrl+C.

-

As you understand, such approach can be used for any command-line external tool such as grep, php and so on.

-

Good luck!

-
-
 
-
-

P.S. By the way, if you have nothing selected and you want to select a word under the caret, the following script can be used:

-
-
// get current position...
-SCI_SENDMSG SCI_GETCURRENTPOS
-set local pos = $(MSG_RESULT)
-// get start of a word near the pos...
-SCI_SENDMSG SCI_WORDSTARTPOSITION $(pos) 1
-set local wordStart = $(MSG_RESULT)
-// get end of a word near the pos...
-SCI_SENDMSG SCI_WORDENDPOSITION $(pos) 1
-set local wordEnd = $(MSG_RESULT)
-// set selection
-SCI_SENDMSG SCI_SETSEL $(wordStart) $(wordEnd)
- 
-
-

If you combine this script with the previous one, you will be able to apply an external tool to a word under the caret. (I.e. first it will select a word under the caret, and then will apply an external tool to that selected word.) Also consider ability to use $(CURRENT_WORD) instead of SEL_SAVETO in this case (see [4.6.3]).

-

See also: Processing & replacing the selection [4.6.3].

- - + + + + + +4.6.1. Applying external tool to selected text + + + +

4.6.1. Applying external tool to selected text

+

Let's suppose you want to apply some AWK program to your selected text in Notepad++.

+

The first thing you require is NppExec plugin ;)

+

The second thing you require is + an AWK +executable, for example, "awk95.exe" or "gawk.exe".

+

When you want to apply some AWK + program to your selected text, this AWK program must exists, isn't it? So, + create +a file "do.awk" in your Notepad++'s folder. The full path to this file is "$(NPP_DIRECTORY)\do.awk".

+

OK, the file is created, now you + need some AWK program. Open the "do.awk" in Notepad++ and type your program, + for +example:

+
+
{ print $0 }
+
+

This simple AWK program will print each record (i.e. text line) from the input file given.

+

Now, open another file in Notepad++ and select some text (few lines, for example).

+

Now you have the selected text and a tool (awk95.exe or gawk.exe) you want to apply to this selected text.

+

The only thing remaining is NppExec's script which will allow you to do what you want.

+

Press F6 (or Plugins -> NppExec -> Execute NppExec Script...) +and type:

+
+
// full path to AWK executable 
+set local AWK_EXE = C:\tools\awk\awk95.exe 
+// this temporary file name will be used 
+set local TEMP_FILE = $(SYS.TEMP)\npp_sel.txt 
+// save current selection as ANSI text file 
+SEL_SAVETO $(TEMP_FILE) :a 
+// run do.awk for this file 
+"$(AWK_EXE)" -f "$(NPP_DIRECTORY)\do.awk" "$(TEMP_FILE)"
+
+

Save this script as "do.awk on selected text" or +whatever you want.

+

Press OK.

+

You will see the AWK's output in the NppExec's Console window. You can copy it from there with Ctrl+C.

+

As you understand, such approach can be used for any command-line external tool such as grep, php and so on.

+

Good luck!

+
+
 
+
+

P.S. By the way, if you have nothing selected and you want to select a word under the caret, the following script can be used:

+
+
// get current position...
+SCI_SENDMSG SCI_GETCURRENTPOS
+set local pos = $(MSG_RESULT)
+// get start of a word near the pos...
+SCI_SENDMSG SCI_WORDSTARTPOSITION $(pos) 1
+set local wordStart = $(MSG_RESULT)
+// get end of a word near the pos...
+SCI_SENDMSG SCI_WORDENDPOSITION $(pos) 1
+set local wordEnd = $(MSG_RESULT)
+// set selection
+SCI_SENDMSG SCI_SETSEL $(wordStart) $(wordEnd)
+ 
+
+

If you combine this script with the previous one, you will be able to apply an external tool to a word under the caret. (I.e. first it will select a word under the caret, and then will apply an external tool to that selected word.) Also consider ability to use $(CURRENT_WORD) instead of SEL_SAVETO in this case (see [4.6.3]).

+

See also: Processing & replacing the selection [4.6.3]; Modify selected text and save to file [4.6.17].

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.6.10.html b/docs/NppExec_Manual/4.6.10.html similarity index 70% rename from NppExec/doc/NppExec/NppExec_Manual/4.6.10.html rename to docs/NppExec_Manual/4.6.10.html index ed1a59f..1aa444f 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.6.10.html +++ b/docs/NppExec_Manual/4.6.10.html @@ -1,34 +1,35 @@ - - - - - -4.6.10. Running Lua - - -

4.6.10. Running Lua

- -

Depending on what exactly we want to achieve, here are the two NppExec's scripts that can be used to run Lua:

- -
-
// Lua in NppExec's Console
-set local Lua = C:\Lua\bin\lua.exe // <-- specify your path to Lua here!
-npp_save // saves the current .lua file
-"$(Lua)" "$(FULL_CURRENT_PATH)" // runs it
-
- -

and

- -
-
// Lua in a separate console window
-set local Lua = C:\Lua\bin\lua.exe // <-- specify your path to Lua here!
-npp_save // saves the current .lua file
-npp_run cmd /c ""$(Lua)" "$(FULL_CURRENT_PATH)" && pause" // runs it
-
- -
-
 
-
- - - + + + + + +4.6.10. Running Lua + + + +

4.6.10. Running Lua

+ +

Depending on what exactly we want to achieve, here are the two NppExec's scripts that can be used to run Lua:

+ +
+
// Lua in NppExec's Console
+set local Lua = C:\Lua\bin\lua.exe // <-- specify your path to Lua here!
+npp_save // saves the current .lua file
+"$(Lua)" "$(FULL_CURRENT_PATH)" // runs it
+
+ +

and

+ +
+
// Lua in a separate console window
+set local Lua = C:\Lua\bin\lua.exe // <-- specify your path to Lua here!
+npp_save // saves the current .lua file
+npp_run cmd /c ""$(Lua)" "$(FULL_CURRENT_PATH)" && pause" // runs it
+
+ +
+
 
+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.6.11.html b/docs/NppExec_Manual/4.6.11.html similarity index 80% rename from NppExec/doc/NppExec/NppExec_Manual/4.6.11.html rename to docs/NppExec_Manual/4.6.11.html index c221b43..9080045 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.6.11.html +++ b/docs/NppExec_Manual/4.6.11.html @@ -1,122 +1,123 @@ - - - - - -4.6.11. Clone current document to new editor pane - - -

4.6.11. Clone current document to new editor pane

- -

Let's consider the following scenario: you want to copy the whole content of the current document (opened in Notepad++) and paste it to a new editor pane.

-

The first implementation that comes to your mind is:

-
    -
  1. save the current position of the caret;
  2. -
  3. select all the text and copy it to the clipboard;
  4. -
  5. restore the position of the caret;
  6. -
  7. open a new editor pane and paste the text from the clipboard.
  8. -
-

As Notepad++ uses Scintilla component to handle the text and all the text operations, let's deal directly with Scintilla to implement all of the above. Let's refer to Scintilla's documentation to get an idea of how to do it:

-
    -
  • https://www.scintilla.org/ScintillaDoc.html#SelectionAndInformation
  • -
  • https://www.scintilla.org/ScintillaDoc.html#CutCopyAndPaste
  • -
-

Looking at the documentation, we may end up with the following NppExec script:

-
-
// saving the caret pos & anchor
-sci_sendmsg SCI_GETCURRENTPOS
-set local pos = $(MSG_RESULT)
-sci_sendmsg SCI_GETANCHOR
-set local anchor = $(MSG_RESULT)
-
-// selecting all
-sci_sendmsg SCI_SELECTALL
-
-// copying the selection to the clipboard
-sci_sendmsg SCI_COPY
-
-// restoring the caret pos & anchor
-sci_sendmsg SCI_SETSEL $(anchor) $(pos)
-
-// open new editor pane
-NPP_SENDMSG WM_COMMAND IDM_FILE_NEW
-
-// pasting the text from the clipboard
-sci_sendmsg SCI_PASTE
-
- -

Inspecting the Scintilla's documentation further, we can notice SCI_COPYRANGE that allows to simplify the whole script:

-
-
// getting the length of the document
-sci_sendmsg SCI_GETTEXTLENGTH
-set local textlength = $(MSG_RESULT)
-
-// copying the whole text to the clipboard
-sci_sendmsg SCI_COPYRANGE 0 $(textlength)
-
-// open new editor pane
-NPP_SENDMSG WM_COMMAND IDM_FILE_NEW
-
-// pasting the text from the clipboard
-sci_sendmsg SCI_PASTE
-
- -

Looking into "Notepad_plus_msgs.h" ("PowerEditor\src\MISC\PluginsManager\Notepad_plus_msgs.h"), we can implement an advanced version of this script that:

-
    -
  • applies the encoding of the current document to the new one;
  • -
  • applies the language (such as C++, JavaScript, XML, etc.) of the current document to the new one;
  • -
  • sets the same caret and anchor positions as in the current document.
  • -
-

Here is the final NppExec's script:

-
-
// getting the current buffer id
-npp_sendmsg NPPM_GETCURRENTBUFFERID
-set local originalBufferId = $(MSG_RESULT)
-
-// getting the current buffer encoding & lang type
-npp_sendmsg NPPM_GETBUFFERENCODING $(originalBufferId)
-set local bufEnc = $(MSG_RESULT)
-npp_sendmsg NPPM_GETBUFFERLANGTYPE $(originalBufferId)
-set local bufLangType = $(MSG_RESULT)
-
-// getting the caret pos & anchor
-sci_sendmsg SCI_GETCURRENTPOS
-set local pos = $(MSG_RESULT)
-sci_sendmsg SCI_GETANCHOR
-set local anchor = $(MSG_RESULT)
-sci_sendmsg SCI_GETFIRSTVISIBLELINE
-set local firstvisibleline = $(MSG_RESULT)
-
-// getting the length of the document
-sci_sendmsg SCI_GETTEXTLENGTH
-set local textlength = $(MSG_RESULT)
-
-// copying the whole text to the clipboard
-sci_sendmsg SCI_COPYRANGE 0 $(textlength)
-
-// opening a new editor pane (new document)
-NPP_SENDMSG WM_COMMAND IDM_FILE_NEW
-
-// getting the new buffer id
-npp_sendmsg NPPM_GETCURRENTBUFFERID
-set local newBufferId = $(MSG_RESULT)
-
-// setting the new buffer encoding & lang type
-npp_sendmsg NPPM_SETBUFFERENCODING $(newBufferId) $(bufEnc)
-npp_sendmsg NPPM_SETBUFFERLANGTYPE $(newBufferId) $(bufLangType)
-
-// pasting the text from the clipboard
-sci_sendmsg SCI_PASTE
-
-// setting the caret pos & anchor
-sci_sendmsg SCI_SETSEL $(anchor) $(pos)
-sci_sendmsg SCI_SETFIRSTVISIBLELINE $(firstvisibleline)
-
-

Note: in this last script, originally I was thinking to use SCI_GETCODEPAGE and SCI_SETCODEPAGE to deal with the text encoding. But it appeared that Notepad++ does not seem to be aware of the encoding change by SCI_SETCODEPAGE. So I've used the Notepad++'s way of dealing with encoding via NPPM_GETBUFFERENCODING and NPPM_SETBUFFERENCODING.

- -
-
 
-
- - - + + + + + +4.6.11. Clone current document to new editor pane + + + +

4.6.11. Clone current document to new editor pane

+ +

Let's consider the following scenario: you want to copy the entire content of the current document (opened in Notepad++) and paste it to a new editor pane.

+

The first implementation that comes to your mind is:

+
    +
  1. save the current position of the caret;
  2. +
  3. select all the text and copy it to the clipboard;
  4. +
  5. restore the position of the caret;
  6. +
  7. open a new editor pane and paste the text from the clipboard.
  8. +
+

As Notepad++ uses Scintilla component to handle the text and all the text operations, let's deal directly with Scintilla to implement all of the above. Let's refer to Scintilla's documentation to get an idea of how to do it:

+
    +
  • https://www.scintilla.org/ScintillaDoc.html#SelectionAndInformation
  • +
  • https://www.scintilla.org/ScintillaDoc.html#CutCopyAndPaste
  • +
+

Looking at the documentation, we may end up with the following NppExec script:

+
+
// saving the caret pos & anchor
+sci_sendmsg SCI_GETCURRENTPOS
+set local pos = $(MSG_RESULT)
+sci_sendmsg SCI_GETANCHOR
+set local anchor = $(MSG_RESULT)
+
+// selecting all
+sci_sendmsg SCI_SELECTALL
+
+// copying the selection to the clipboard
+sci_sendmsg SCI_COPY
+
+// restoring the caret pos & anchor
+sci_sendmsg SCI_SETSEL $(anchor) $(pos)
+
+// open new editor pane
+NPP_SENDMSG WM_COMMAND IDM_FILE_NEW
+
+// pasting the text from the clipboard
+sci_sendmsg SCI_PASTE
+
+ +

Inspecting the Scintilla's documentation further, we can notice SCI_COPYRANGE that allows to simplify the entire script:

+
+
// getting the length of the document
+sci_sendmsg SCI_GETTEXTLENGTH
+set local textlength = $(MSG_RESULT)
+
+// copying the entire text to the clipboard
+sci_sendmsg SCI_COPYRANGE 0 $(textlength)
+
+// open new editor pane
+NPP_SENDMSG WM_COMMAND IDM_FILE_NEW
+
+// pasting the text from the clipboard
+sci_sendmsg SCI_PASTE
+
+ +

Looking into "Notepad_plus_msgs.h" ("PowerEditor\src\MISC\PluginsManager\Notepad_plus_msgs.h"), we can implement an advanced version of this script that:

+
    +
  • applies the encoding of the current document to the new one;
  • +
  • applies the language (such as C++, JavaScript, XML, etc.) of the current document to the new one;
  • +
  • sets the same caret and anchor positions as in the current document.
  • +
+

Here is the final NppExec's script:

+
+
// getting the current buffer id
+npp_sendmsg NPPM_GETCURRENTBUFFERID
+set local originalBufferId = $(MSG_RESULT)
+
+// getting the current buffer encoding & lang type
+npp_sendmsg NPPM_GETBUFFERENCODING $(originalBufferId)
+set local bufEnc = $(MSG_RESULT)
+npp_sendmsg NPPM_GETBUFFERLANGTYPE $(originalBufferId)
+set local bufLangType = $(MSG_RESULT)
+
+// getting the caret pos & anchor
+sci_sendmsg SCI_GETCURRENTPOS
+set local pos = $(MSG_RESULT)
+sci_sendmsg SCI_GETANCHOR
+set local anchor = $(MSG_RESULT)
+sci_sendmsg SCI_GETFIRSTVISIBLELINE
+set local firstvisibleline = $(MSG_RESULT)
+
+// getting the length of the document
+sci_sendmsg SCI_GETTEXTLENGTH
+set local textlength = $(MSG_RESULT)
+
+// copying the entire text to the clipboard
+sci_sendmsg SCI_COPYRANGE 0 $(textlength)
+
+// opening a new editor pane (new document)
+NPP_SENDMSG WM_COMMAND IDM_FILE_NEW
+
+// getting the new buffer id
+npp_sendmsg NPPM_GETCURRENTBUFFERID
+set local newBufferId = $(MSG_RESULT)
+
+// setting the new buffer encoding & lang type
+npp_sendmsg NPPM_SETBUFFERENCODING $(newBufferId) $(bufEnc)
+npp_sendmsg NPPM_SETBUFFERLANGTYPE $(newBufferId) $(bufLangType)
+
+// pasting the text from the clipboard
+sci_sendmsg SCI_PASTE
+
+// setting the caret pos & anchor
+sci_sendmsg SCI_SETSEL $(anchor) $(pos)
+sci_sendmsg SCI_SETFIRSTVISIBLELINE $(firstvisibleline)
+
+

Note: in this last script, originally I was thinking to use SCI_GETCODEPAGE and SCI_SETCODEPAGE to deal with the text encoding. But it appeared that Notepad++ does not seem to be aware of the encoding change by SCI_SETCODEPAGE. So I've used the Notepad++'s way of dealing with encoding via NPPM_GETBUFFERENCODING and NPPM_SETBUFFERENCODING.

+ +
+
 
+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.6.12.html b/docs/NppExec_Manual/4.6.12.html similarity index 77% rename from NppExec/doc/NppExec/NppExec_Manual/4.6.12.html rename to docs/NppExec_Manual/4.6.12.html index 61e6557..205351e 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.6.12.html +++ b/docs/NppExec_Manual/4.6.12.html @@ -1,83 +1,84 @@ - - - - - -4.6.12. Passing multiple files to external tool - - -

4.6.12. Passing multiple files to external tool

- -

Sometimes you may want to pass multiple files to an external tool, especially when these multiple files are part of some project and the external tool is a compiler that compiles this project.

-

Usually some makefile is created for these purposes, and the path to the makefile is passed to the compiler.

-

But let's imagine we don't want to use a makefile and want to use NppExec's script for this. Let's say we want NppExec's script to look through the files opened in Notepad++ and create a list of files with a given file extension.

-

For example, the following NppExec's scripts collects all the opened files with .cpp extension and outputs them to NppExec's Console:

- -
-
npp_console local -        // disable output to the Console
-set local MatchExt = .cpp  // file extension to match
-set local FileList =       // output file list
-set local i = 1
-
-// iterating through all opened files...
-:NextOpenedFile
-set local file = $(#$(i))  // full path name
-if "$(file)" == "" goto OutOfOpenedFiles
-set local n ~ strrfind "$(file)" \
-if n == -1 then
-  set local n ~ strrfind "$(file)" /
-endif
-if n != -1 then
-  set local n ~ $(n) + 1
-  set local file ~ substr $(n) - $(file)  // file name (without path)
-endif
-set local n ~ strrfind "$(file)" .
-if n != -1 then
-  set local e ~ substr $(n) - $(file)  // file extension
-  if "$(e)" ~= "$(MatchExt)" then      // compare case-insensitively
-    set local FileList = $(FileList) "$(file)"
-  endif
-endif
-set local i ~ $(i) + 1
-goto NextOpenedFile
-
-:OutOfOpenedFiles
-npp_console local +  // enable output to the Console
-echo $(FileList)
-
- -

If your project consists of a lot of files, including files in subfolders, we may form a list of all these files using some additional tool such as Swiss File Knife ( https://sourceforge.net/projects/swissfileknife/files/ ).

-

Here is how Swiss File Knife (sfk) creates a list of all .cpp files starting from the current directory:

- -
-
sfk list -quot -dir . -file .cpp +xed "/[xwhite]/ /"
-
- -

Then, using sfk, the NppExec's script will look like the following:

- -
-
npp_console local -        // disable output to the Console
-set local MatchExt = .cpp  // file extension to match
-
-npe_console local v+
-sfk list -quot -dir . -file $(MatchExt) +xed "/[xwhite]/ /"
-set local FileList = $(OUTPUTL)
-
-npp_console local +  // enable output to the Console
-echo $(FileList)
-
- -

The only thing remaining is to call your compiler passing the $(FileList) to it. For example:

- -
-
g++ -c $(FileList)
-
- -

See also: Compiling [4.7].

- -
-
 
-
- - - + + + + + +4.6.12. Passing multiple files to external tool + + + +

4.6.12. Passing multiple files to external tool

+ +

Sometimes you may want to pass multiple files to an external tool, especially when these multiple files are part of some project and the external tool is a compiler that compiles this project.

+

Usually some makefile is created for these purposes, and the path to the makefile is passed to the compiler.

+

But let's imagine we don't want to use a makefile and want to use NppExec's script for this. Let's say we want NppExec's script to look through the files opened in Notepad++ and create a list of files with a given file extension.

+

For example, the following NppExec's scripts collects all the opened files with .cpp extension and outputs them to NppExec's Console:

+ +
+
npp_console local -        // disable output to the Console
+set local MatchExt = .cpp  // file extension to match
+set local FileList =       // output file list
+set local i = 1
+
+// iterating through all opened files...
+:NextOpenedFile
+set local file = $(#$(i))  // full path name
+if "$(file)" == "" goto OutOfOpenedFiles
+set local n ~ strrfind "$(file)" \
+if n == -1 then
+  set local n ~ strrfind "$(file)" /
+endif
+if n != -1 then
+  set local n ~ $(n) + 1
+  set local file ~ substr $(n) - $(file)  // file name (without path)
+endif
+set local n ~ strrfind "$(file)" .
+if n != -1 then
+  set local e ~ substr $(n) - $(file)  // file extension
+  if "$(e)" ~= "$(MatchExt)" then      // compare case-insensitively
+    set local FileList = $(FileList) "$(file)"
+  endif
+endif
+set local i ~ $(i) + 1
+goto NextOpenedFile
+
+:OutOfOpenedFiles
+npp_console local +  // enable output to the Console
+echo $(FileList)
+
+ +

If your project consists of a lot of files, including files in subfolders, we may form a list of all these files using some additional tool such as Swiss File Knife ( https://sourceforge.net/projects/swissfileknife/files/ ).

+

Here is how Swiss File Knife (sfk) creates a list of all .cpp files starting from the current directory:

+ +
+
sfk list -quot -dir . -file .cpp +xed "/[xwhite]/ /"
+
+ +

Then, using sfk, the NppExec's script will look like the following:

+ +
+
npp_console local -        // disable output to the Console
+set local MatchExt = .cpp  // file extension to match
+
+npe_console local v+
+sfk list -quot -dir . -file $(MatchExt) +xed "/[xwhite]/ /"
+set local FileList = $(OUTPUTL)
+
+npp_console local +  // enable output to the Console
+echo $(FileList)
+
+ +

The only thing remaining is to call your compiler passing the $(FileList) to it. For example:

+ +
+
g++ -c $(FileList)
+
+ +

See also: Compiling [4.7].

+ +
+
 
+
+ + + diff --git a/docs/NppExec_Manual/4.6.13.html b/docs/NppExec_Manual/4.6.13.html new file mode 100644 index 0000000..5016112 --- /dev/null +++ b/docs/NppExec_Manual/4.6.13.html @@ -0,0 +1,165 @@ + + + + + +4.6.13. Working with the Notepad++ 'Replace' dialog + + + +

4.6.13. Working with the Notepad++ 'Replace' dialog

+ +

Let's imagine you want to invoke the Notepad++ 'Replace' dialog, populate its 'Find what' and 'Replace with' fields with specific strings, check or uncheck the search-related checkboxes, and finally press the 'Find Next' button. And you want to do all of this programmatically.

+

The first tools that come to my mind to do such things are AutoIt ( https://www.autoitscript.com/ ) and AutoHotKey ( https://www.autohotkey.com/ ).

+

But let's consider something simpler. For example, NirCmd from NirSoft ( https://www.nirsoft.net/ ).

+

First, let's create the following NppExec script:

+ +
+
env_set local PATH = $(SYS.PATH);C:\tools\NirSoft  // TODO: specify path to the folder with nircmd.exe here!
+npp_sendmsg WM_COMMAND IDM_SEARCH_REPLACE  // showing the Replace dialog
+nircmd script "$(NPP_DIRECTORY)\replace.ncl"  // TODO: you may specify other folder than $(NPP_DIRECTORY)
+
+ +

Then, as the NppExec script above mentions "$(NPP_DIRECTORY)\replace.ncl", let's create a file named "replace.ncl" under your Notepad++ folder. It will be a simple non-Unicode text file with the following lines:

+ +
+
// set 'Find what' text:
+dlg "notepad++.exe" "Replace" settext 1601 "Find what"
+// set 'Replace with' text:
+dlg "notepad++.exe" "Replace" settext 1602 "Replace with"
+// uncheck 'Whole word' checkbox:
+win child title "Replace" sendmsg id 1603 0x00F1 0x0000 0
+// uncheck 'Match case' checkbox:
+win child title "Replace" sendmsg id 1604 0x00F1 0x0000 0
+// check 'Wrap around' checkbox:
+win child title "Replace" sendmsg id 1606 0x00F1 0x0001 0
+// uncheck 'Backward direction' checkbox:
+win child title "Replace" sendmsg id 1722 0x00F1 0x0000 0
+// click 'Regular expression' button:
+win child title "Replace" sendmsg id 1605 0x00F5 0 0
+// uncheck '. matches newline' checkbox:
+win child title "Replace" sendmsg id 1703 0x00F1 0x0000 0
+// click 'Find Next' button:
+win child title "Replace" sendmsg id 1 0x00F5 0 0
+
+ +

This file uses a hard-coded string "Replace" as the title of the Notepad++ 'Replace' dialog. If you are using a non-English localization, you will need to replace the word "Replace" with the localization-dependent title (such as "Remplacer" for French).

+

Also, this file uses several magic numbers such as 1601 and 1602, 0x00F1 and 0x00F5, 0x0000 and 0x0001. Let me explain what they mean.

+

To deal with controls (elements) of a dialog, we need to know the corresponding control identifiers (control IDs). Here is what we can see inside the Notepad++ source file https://github.com/notepad-plus-plus/notepad-plus-plus/blob/master/PowerEditor/src/ScintillaComponent/FindReplaceDlg_rc.h :

+
+
#define	IDFINDWHAT						1601
+#define	IDREPLACEWITH					1602
+#define	IDWHOLEWORD						1603
+#define	IDMATCHCASE						1604
+#define IDREGEXP						1605
+#define	IDWRAP							1606
+
+

I believe this explains where the magic numbers of 1601, 1602, and so on, came from. These are the control IDs. Another way to get these IDs is to use a specific program such as Property Edit ( https://mh-nexus.de/en/downloads.php?product=Property%20Edit ).

+

Now, knowing the control IDs, we want to send some specific messages to these controls. The BM_SETCHECK message is responsible for checking/unchecking a checkbox control; the BM_CLICK message is responsible for clicking a button. When we look inside a Windows header file, "winuser.h", we can see that BM_SETCHECK is defined as 0x00F1 and BM_CLICK is defined as 0x00F5.

+

Finally, the values of 0x0000 and 0x0001 in this context are parameters of the BM_SETCHECK (0x00F1) message. Their meanings with respect to the BM_SETCHECK message are: 0x0000 is BST_UNCHECKED and 0x0001 is BST_CHECKED. So, "0x00F1 0x0001 0" checks a checkbox control, whereas "0x00F1 0x0000 0" unchecks it. You may read more here: https://docs.microsoft.com/windows/win32/controls/bm-setcheck

+

Important note: as NppExec's scripts are executed in a separate thread, the script continues its execution when Notepad++'s dialog is shown. It allows to use NirCmd (as well as AutoHotKey or any other tool) to interact with the Notepad++'s dialog by pressing its buttons and so on. Correspondingly, it's also possible to close the dialog and then execute other commands from the same NppExec's script.

+ +
+
 
+
+ +

Now, after warming up, let's create a similar AutoHotKey script.

+

AutoHotKey provides more abilities and more control over what we are doing, so it is recommended. We will use AutoHotKey 2.0 (refer to https://www.autohotkey.com/docs/v2/v2-changes.htm for details).

+

The new NppExec script to invoke AutoHotKey will be quite similar to the one that invokes NirCmd. We will additionally pass a handle to the Notepad++ main window as an input parameter to the .ahk script. This is to ensure that we will be dealing with the current Notepad++ window (as there may be other running instances of Notepad++):

+ +
+
set local AutoHotKeyDir = C:\tools\AutoHotKey  // TODO: specify path to the AutoHotKey folder here!
+env_set local PATH = $(SYS.PATH);$(AutoHotKeyDir)  // adding to %PATH%
+npp_sendmsg WM_COMMAND IDM_SEARCH_REPLACE  // showing the Replace dialog
+AutoHotkey32.exe "$(AutoHotKeyDir)\NppReplace.ahk" $(NPP_HWND)  // TODO: you may place your .ahk script under a different folder
+
+
+ +

Now, let's write the .ahk script that will do all the magic. Let's create a file named "NppReplace.ahk" under the folder specified in the NppExec script above (in this example, it is "$(AutoHotKeyDir)\NppReplace.ahk"). This file uses the AutoHotKey 2.0 syntax:

+ +
+
if A_Args.Length < 1
+{
+  MsgBox("Usage: " A_ScriptName " <NPP_HWND>",, 0x30) ; 0x30 - exclamation
+  Exit
+}
+
+ReplaceDlgTitle := "Replace"
+idNppWnd := Integer(A_Args[1])
+idReplaceDlg := 0
+
+idDlgList := WinGetList(ReplaceDlgTitle " ahk_exe notepad++.exe")
+for idDlg in idDlgList
+{
+  idParent := DllCall("user32\GetParent", "Ptr", idDlg, "Ptr")
+  if idParent = idNppWnd
+  {
+    idReplaceDlg := idDlg
+    break
+  }
+}
+
+if idReplaceDlg = 0
+{
+  MsgBox("Could not find a dialog with a title `"" ReplaceDlgTitle "`" for NPP_HWND=" Format("0x{:X}", idNppWnd),, 0x10) ; 0x10 - error
+  Exit
+}
+
+GetDlgItem(idDlg, idItem)
+{
+  return DllCall("user32\GetDlgItem", "Ptr", idDlg, "Int", idItem, "Ptr")
+}
+
+ClickButton(idButton)
+{
+  SendMessage(0x00F5, 0, 0, idButton)
+}
+
+idFindWhat := GetDlgItem(idReplaceDlg, 1601)
+idReplaceWith := GetDlgItem(idReplaceDlg, 1602)
+idWholeWord := GetDlgItem(idReplaceDlg, 1603)
+idMatchCase := GetDlgItem(idReplaceDlg, 1604)
+idWrapAround := GetDlgItem(idReplaceDlg, 1606)
+idBackwardDirection := GetDlgItem(idReplaceDlg, 1722)
+idRegularExpression := GetDlgItem(idReplaceDlg, 1605)
+idDotMatchesNewline := GetDlgItem(idReplaceDlg, 1703)
+idFindNext := GetDlgItem(idReplaceDlg, 1)
+
+ControlSetText("Find What", idFindWhat)
+ControlSetText("Replace With", idReplaceWith)
+ControlSetChecked(0, idWholeWord)
+ControlSetChecked(0, idMatchCase)
+ControlSetChecked(1, idWrapAround)
+ControlSetChecked(0, idBackwardDirection)
+ClickButton(idRegularExpression)
+ControlSetChecked(0, idDotMatchesNewline)
+ClickButton(idFindNext)
+
+Exit
+
+
+ +
+
 
+
+ +

Note: If you want to find or replace some string programmatically without showing the Replace dialog, NppExec proposes the following commands for this: SCI_FIND and SCI_REPLACE. The actual behavior of these commands completely depend on the <flags> parameter specified. The description and examples are available by typing any of the following:

+ +
+
help sci_find
+help sci_replace
+help all
+
+ +
+
 
+
+ +

See also: Clipboard, keystrokes and much more [4.6.8].

+ +
+
 
+
+ + + diff --git a/docs/NppExec_Manual/4.6.14.html b/docs/NppExec_Manual/4.6.14.html new file mode 100644 index 0000000..19bd99c --- /dev/null +++ b/docs/NppExec_Manual/4.6.14.html @@ -0,0 +1,95 @@ + + + + + +4.6.14. Notepad++ as a Clipboard Monitor + + + +

4.6.14. Notepad++ as a Clipboard Monitor

+ +

Let's imagine you want Notepad++ to work as a Clipboard Monitor by gathering all the text copied to the Clipboard into a single file shown in Notepad++.

+

We may use a third-party tool such as AutoHotKey to do all the clipboard-related work, while Notepad++'s work will be to automatically refresh the file content once any text from the Clipboard has been added to this file.

+

At first, let's download and install AutoHotKey v2 ( https://www.autohotkey.com/ ).

+

Secondly, let's write an AutoHotKey v2 script that will monitor the Clipboard and append the new text data to a single file. Let's accept the path to that single file as an input argument of the script:

+ +
+
#SingleInstance Force
+
+if A_Args.Length < 1
+{
+    MsgBox "This script requires a path to an output text file as an argument!"
+    ExitApp
+}
+
+; TempDir := EnvGet("TEMP")
+; ClpbrdFilePath := TempDir "\clpbrd.txt"
+ClpbrdFilePath := A_Args[1]  ; reading file path as a command-line argument
+FileObj := FileOpen(ClpbrdFilePath, "w")  ; creating an empty file
+FileObj.Close()
+
+OnClipboardChange ClipboardChanged  ; clipboard callback function
+
+ClipboardChanged(DataType) {
+    if DataType = 1 {  ; text
+        FileObj := FileOpen(ClpbrdFilePath, "a")
+        FileObj.WriteLine(A_Clipboard)  ; appending to the file
+        FileObj.Close() 
+        ; ToolTip "Clipboard text: '" A_Clipboard "'"
+        ; Sleep 2000
+        ; ToolTip  ; Turn off the tip.
+    }
+}
+
+ProcessWaitClose("notepad++.exe")  ; be active while Notepad++ is active
+ExitApp
+
+ +

Let's save this script file as e.g. "C:\AutoHotkeyScripts\NppClipboardMonitor.ahk".

+

Now let's write NppExec's script that will use the AutoHotKey v2 script mentioned above. (If you don't have the NppExec plugin, install it via Plugins -> Plugins Admin... first). In Notepad++, select Plugins -> NppExec -> Execute NppExec Script... and type the following in the opened dialog:

+ +
+
npp_console ?
+set local cbfile = $(SYS.TEMP)\clpbrd.txt
+set local ah2script = C:\AutoHotkeyScripts\NppClipboardMonitor.ahk
+npp_run "C:\Program Files\AutoHotkey\v2\AutoHotkey32.exe" "$(ah2script)" "$(cbfile)"
+npp_close "$(cbfile)"
+npp_open "$(cbfile)"
+npp_menucommand View|Monitoring (tail -f)
+
+ +

This assumes AutoHotKey v2 was installed to "C:\Program Files\AutoHotkey\v2" and Notepad++'s interface uses English localization. If Notepad++'s localization is different than English, please change the line

+
+
npp_menucommand View|Monitoring (tail -f)
+
+

to the one corresponding to your Notepad++'s localization. Alternatively, you can use

+
+
npp_sendmsg NPPM_SETMENUITEMCHECK IDM_VIEW_MONITORING 1
+
+

to enable the monitoring, and

+
+
npp_sendmsg NPPM_SETMENUITEMCHECK IDM_VIEW_MONITORING 0
+
+

to disable the monitoring.

+ +

Let's save the NppExec's script above as "clipboard monitor". To do it, press the "Save..." button, type "clipboard monitor" (without the quotes) and press "Save".

+

Now you may want to assign a shortcut key to this NppExec's script. To do that, select Plugins -> NppExec -> Advanced Options... and click the "Associated script:" combo-box in the bottom part of the opened dialog. Select the "clipboard monitor" item in the drop-down list and press "Add/Modify". A new item "clipboard monitor :: clipboard monitor" will be added to the "Menu items" list. When you finally press "OK", there will be a message "Notepad++ must be restarted to apply some of the options". This is required to add a new menu item "clipboard monitor" to Notepad++.

+

When Notepad++ is restarted, a shortcut key can be assigned to the new menu item "clipboard monitor". In Notepad++, select Settings -> Shortcut Mapper... and click "Plugin commands". Find the "clipboard monitor" command that corresponds to "NppExec.dll" and assign a desired shortcut key to it.

+

Everything is ready!

+

Now either press the shortcut key assigned to the "clipboard monitor" menu item or select Plugins -> NppExec -> Execute NppExec Script... and then select "clipboard monitor" in the combo-box at the bottom of the opened dialog and finally press "OK". You'll see an empty file "clpbrd.txt" opened in Notepad++.

+

Now, copy any text to the Clipboard in any program - and that exact text should be appended to the "clpbrd.txt" file content shown in Notepad++.

+

Final words. If you close and/or reopen this file (the "clpbrd.txt" one) in Notepad++ or if you restart Notepad++, don't forget to run the "clipboard monitor" NppExec's script again in order to monitor the Clipboard. Otherwise the "clpbrd.txt" will be a simple text file. (Because in fact it is a simple text file). As we discussed above, all the clipboard monitoring work is done by AutoHotKey. Correspondingly, when the AutoHotKey v2 script is running, you may find the AutoHotKey's icon in the TaskBar, as well as right-click that icon and select "Exit" to exit AutoHotKey. In such case, you'll again have to run the "clipboard monitor" NppExec's script manually in order to monitor the Clipboard. No magic here, just dexterous hands :-)

+ +
+
 
+
+ +

See also: Clipboard, keystrokes and much more [4.6.8]; NppExec's Console as a Log Viewer [4.6.18].

+ +
+
 
+
+ + + diff --git a/docs/NppExec_Manual/4.6.15.html b/docs/NppExec_Manual/4.6.15.html new file mode 100644 index 0000000..5010630 --- /dev/null +++ b/docs/NppExec_Manual/4.6.15.html @@ -0,0 +1,159 @@ + + + + + +4.6.15. Triggering certain actions while saving a file + + + +

4.6.15. Triggering certain actions while saving a file

+ +

Probably you already thought of that: how useful it would be if NppExec allowed to trigger certain actions each time a file is saved. For example, you might want an external spell-checker to be run for text files; a code-formatting tool to be run for certain source files; also, you might want to do backups for some other files; and so on.

+

Some applications provide callback mechanisms or triggers for similar purpose. For example, there could be an "OnSave" callback/trigger that is invoked/triggered each time a file is saved. NppExec does not provide that, mostly because I don't see a good way to avoid deadlocks and/or infinite recursion. Here is an example of the latter: let's imagine we have a certain "OnSave" script triggered each time a file is saved. Now, let's imagine this "OnSave" script contains a command NPP_SAVE or NPP_SAVEALL. This embedded command will trigger another "OnSave" script, which, in its turn, will execute another NPP_SAVE or NPP_SAVEALL, and so on and so forth. Here is a different example: let's imagine the "OnSave" script starts a long-running external process, such as "cmd.exe" without arguments. By its nature, NppExec will wait until this process is finished - and it will be happening while saving the file. So, I'm not saying I don't want to implement this - all I'm saying there are certain problems for which I don't see a good solution yet.

+

Anyway, let's look at what we can do right now. As always, NppExec allows to do much more than can be expected, but it does not come out-of-the-box - we rather have to do everything manually. Well, let's do it! :-)

+

At first, let's see what is the alternative to a callback/trigger. It may not look obvious - but let's concentrate on what we usually do to save a file manually. We basically have two options for that: either press the "Save" button on the Toolbar or press Ctrl+S. The latter, Ctrl+S, is the one we are going to use. (Well, I'm aware of the auto-saving feature - and if you rely on it, I'm encouraging you to use Ctrl+S because, well, because it is required for all the further steps of this instruction :-) ).

+

The basic idea is this: what if we assign Ctrl+S to a certain NppExec's script rather than to the internal Notepad++'s "Save File" command? And once we have thought about that, the solution is immediately seen! Step one: create an NppExec's script that will be handling the file saving operation. Step two: create a menu item for this NppExec's script. Step three: assign a shortcut Ctrl+S to that menu item. Voila!

+

So, let's implement that step by step.

+

Let's start from a very simple NppExec's script, such as this one:

+ +
+
// npp_console ?
+npp_console local -
+npe_console local m- --
+npp_console local +
+
+echo Before saving a file "$(FULL_CURRENT_PATH)"
+
+npp_save // saving a file
+
+echo After saving a file "$(FULL_CURRENT_PATH)"
+
+ +

We intentionally use "npe_console local m- --" in the beginning of the script to make it less verbose. As the script may grow with time, it's a pretty good idea to abridge the output.

+

This simple script prints one message before a file is saved and another message after a file is saved. As the purpose of this script is to be executed on Ctrl+S, let's consider what would happen if we removed the "npp_save" command. Right, the file would have never be saved! Let's keep that in mind.

+

OK, let's save this script with a name "file_save". (I assume you are already familiar with the "Execute NppExec Script..." dialog [3.6] and NppExec's script [3.7]).

+

The step one (mentioned above) is done: the script has been created! Let's proceed to the step two.

+

From Notepad++'s main menu, select Plugins -> NppExec -> Advanced options... Now, in the Advanced Options dialog, click the "Associated script" combo-box, select "file_save" there and click the "Add/Modify" button. You'll see a new item "file_save :: file_save" in the "Menu items" list. Now press "OK" - and you'll see a message "Notepad++ must be restarted to apply some of the options". This is required to add a new menu item "file_save" to Notepad++. So, let's restart Notepad++. This will be the finish of the step two.

+

After Notepad++ is restarted, a shortcut key can be assigned to the new menu item "file_save". This is the step three. In Notepad++, select Settings -> Shortcut Mapper... and click "Plugin commands". Find the "file_save" command that corresponds to "NppExec.dll" and try to assign Ctrl+S to it. You will see: "CONFLICT FOUND! Main menu | Save ( Ctrl + S )". Oops! Looks like we need to disable this shortcut for the standard command first. OK, let's click the "Main menu" tab, find "Save | Ctrl+S" there, select it and press "Modify". Let's assign some non-used shortcut to it: for example, Ctrl+Alt+Shift+S or whatever you like unless it conflicts with any existing shortcut. After this is done, let's return to the "find_save" command in the "Plugin commands" tab and assign Ctrl+S to it. The step three is done!

+

Now let's test what we accomplished. Once you press Ctrl+S for any file, you should see these two messages in NppExec's Console: "Before saving a file" and "After saving a file".

+ +

Very good so far. Let's make our "file_save" script to do something more usefull. For example, let's backup a file if it is an XML file. Our updated NppExec's script may look like the following:

+ +
+
// npp_console ?
+npp_console local -
+npe_console local m- --
+npp_console local +
+
+echo Before saving a file "$(FULL_CURRENT_PATH)"
+if "$(EXT_PART)" ~= ".xml" then
+  set local f ~ fileexists $(FULL_CURRENT_PATH)
+  if $(f) != 0 then
+    set local bakfile = $(FULL_CURRENT_PATH).bak
+    cmd /C (if exist "$(bakfile)" del /F "$(bakfile)") & copy "$(FULL_CURRENT_PATH)" "$(bakfile)"
+  endif
+endif // ".xml"
+
+npp_save // saving a file
+
+echo After saving a file "$(FULL_CURRENT_PATH)"
+
+ +

Now let's assume we want to run XmlLint against the saved XML file and see the results in Notepad++. Also, let's comment out the unneeded messages:

+ +
+
// npp_console ?
+npp_console local -
+npe_console local m- --
+npp_console local +
+
+// echo Before saving a file "$(FULL_CURRENT_PATH)"
+if "$(EXT_PART)" ~= ".xml" then
+  set local f ~ fileexists $(FULL_CURRENT_PATH)
+  if $(f) != 0 then
+    set local bakfile = $(FULL_CURRENT_PATH).bak
+    cmd /C (if exist "$(bakfile)" del /F "$(bakfile)") & copy "$(FULL_CURRENT_PATH)" "$(bakfile)"
+  endif
+endif // ".xml"
+
+npp_save // saving a file
+
+// echo After saving a file "$(FULL_CURRENT_PATH)"
+if "$(EXT_PART)" ~= ".xml" then
+  "xmllint.exe" "$(FULL_CURRENT_PATH)" --output "$(FULL_CURRENT_PATH)"
+  npp_sendmsg NPPM_RELOADFILE 0 "$(FULL_CURRENT_PATH)"
+endif
+
+ +

This is almost perfect. Each time we press Ctrl+S, a backup copy of the previously saved XML file is created, the updated content is saved to the file and XmlLint is run against the saved file. You may need to specify a full path to "xmllint.exe" to make it work. Or, if you are not interested in XML, maybe you are doing something similar for e.g. C++ using the Artistic Style formatter - in such case you may need to specify a full path to "astyle.exe".

+

Let's actually add an example for C++ files as well. This requires additional modifications to the script:

+ +
+
// npp_console ?
+npp_console local -
+npe_console local m- --
+npp_console local +
+
+// echo Before saving a file "$(FULL_CURRENT_PATH)"
+set local isXml = 0
+set local isCpp = 0
+
+if "$(EXT_PART)" ~= ".xml" then
+  set local isXml = 1
+else if "$(EXT_PART)" ~= ".cpp" then
+  set local isCpp = 1
+else if "$(EXT_PART)" ~= ".cxx" then
+  set local isCpp = 1
+else if "$(EXT_PART)" ~= ".cc" then
+  set local isCpp = 1
+else if "$(EXT_PART)" ~= ".c" then
+  set local isCpp = 1
+else if "$(EXT_PART)" ~= ".hpp" then
+  set local isCpp = 1
+else if "$(EXT_PART)" ~= ".hxx" then
+  set local isCpp = 1
+else if "$(EXT_PART)" ~= ".hh" then
+  set local isCpp = 1
+else if "$(EXT_PART)" ~= ".h" then
+  set local isCpp = 1
+endif
+
+set local doBackup = 0
+if "$(isXml)" == "1" then
+  set local doBackup = 1
+else if "$(isCpp)" == "1" then
+  set local doBackup = 1
+endif
+
+if "$(doBackup)" == "1" then
+  set local f ~ fileexists $(FULL_CURRENT_PATH)
+  if $(f) != 0 then
+    set local bakfile = $(FULL_CURRENT_PATH).bak
+    cmd /C (if exist "$(bakfile)" del /F "$(bakfile)") & copy "$(FULL_CURRENT_PATH)" "$(bakfile)"
+  endif
+endif
+
+npp_save // saving a file
+
+// echo After saving a file "$(FULL_CURRENT_PATH)"
+if "$(isXml)" == "1" then
+  "xmllint.exe" "$(FULL_CURRENT_PATH)" --output "$(FULL_CURRENT_PATH)"
+  npp_sendmsg NPPM_RELOADFILE 0 "$(FULL_CURRENT_PATH)"
+else if "$(isCpp)" == "1" then
+  "astyle.exe" "$(FULL_CURRENT_PATH)"
+  npp_sendmsg NPPM_RELOADFILE 0 "$(FULL_CURRENT_PATH)"
+endif
+
+ +

After doing it, you can safely call yourself a guru of NppExec's scripting :-) What was started as a small draft is now a full-functional script that does a lot!

+

The only remaining thing is the message "This file has been modified by another program" shown each time the XML file is modified by XmlLint (or, in case of a C++ file, each time it is modified by AStyle). To deal with it, we need to modify one Notepad++'s option manually. Go to Settings -> Preferences... -> MISC. -> File Status Auto-Detection. Check the "Update silently" check-box. This will disable the message "This file has been modified by another program". (Ideally, I would prefer a programmatic way to disable and enable this message, but Notepad++ does not currently allow that. There is an internal message NPPM_INTERNAL_ENABLECHECKDOCOPT, though).

+

Finally, after this NppExec's script is debugged and adjusted enough to do exactly what you want, you can uncomment the very first line "// npp_console ?". After that, the NppExec's Console will not be automatically shown each time you press Ctrl+S.

+

Well done and good luck!

+ +
+
 
+
+ + + diff --git a/docs/NppExec_Manual/4.6.16.html b/docs/NppExec_Manual/4.6.16.html new file mode 100644 index 0000000..0b1ef0f --- /dev/null +++ b/docs/NppExec_Manual/4.6.16.html @@ -0,0 +1,104 @@ + + + + + +4.6.16. Open a file basing on the text selected in the editor + + + +

4.6.16. Open a file basing on the text selected in the editor

+ +

I was wondering whether NppExec allows to open a file, say, "C:\Program Files (x86)\Notepad++\change.log" when a text "Notepad++\change.log" is selected in the editor.

+

NppExec does allow this!

+

Here is NppExec's script required for this (please see the embedded comments for clarifications):

+ +
+
npp_console ?
+
+// process the selected text...
+sci_sendmsg SCI_GETSELTEXT 0 @""
+set local F = $(MSG_LPARAM) // the selected text
+if "$(F)" != "" then // something selected
+  // check current file name...
+  set local n ~ strfind "$(FILE_NAME)" "$(F)"
+  if $(n) == -1 then // current file name does not contain the selected text
+    // check already opened files...
+    set local prev_fpath = $(FULL_CURRENT_PATH)
+    npp_console local -
+    npp_switch $(F) // try to switch to another file
+    npp_console local +
+    if "$(FULL_CURRENT_PATH)" == "$(prev_fpath)" then // did not switch to another file
+      // check predefined directories...
+      npe_console local v+ --
+      C:\tools\findfile.bat "$(F)"
+      if "$(OUTPUT1)" != "" then // found in a predefined dir
+        set local F = $(OUTPUT1)
+      endif
+      npp_open $(F)
+    endif
+  endif
+endif
+
+ +

This NppExec's script uses external file "C:\tools\findfile.bat" which describes the set of predefined directories to be checked.

+

Here is a possible content of this "findfile.bat":

+ +
+
@echo off
+
+for /D %%d in (
+               "C:",
+               "C:\Program Files",
+               "C:\Program Files (x86)"
+              ) do (
+    if exist "%%~d\%~1" (
+        call :EchoUnquotedString "%%~d\%~1"
+    )
+)
+goto End
+
+:EchoUnquotedString
+    echo %~1
+goto End
+
+:End
+
+ +

The predefined directories in this example are: "C:", C:\Program Files" and "C:\Program Files (x86)". You can define your own set of directories here.

+

Here is how it works:

+
    +
  • the NppExec's statement C:\tools\findfile.bat "$(F)" invokes the external batch file, passing the selected text as an argument to it;
  • +
  • inside of "C:\tools\findfile.bat", when "%%~d\%~1" exists, its full path is printed to the console output;
  • +
  • then NppExec's statement if "$(OUTPUT1)" != "" checks whether the output from "C:\tools\findfile.bat" is empty or not;
  • +
  • if it is not empty, we take $(OUTPUT1) as the file name to be opened: set local F = $(OUTPUT1);
  • +
  • finally, the file is opened by npp_open $(F).
  • +
+ +

Basing on your needs, the batch file "findfile.bat" can be modified. For example, it can use the output of git ls-files :

+
+
@echo off
+
+set WorkDir=C:\Projects\notepad-plus-plus
+cd /D "%WorkDir%"
+
+for /F %%f in ('git ls-files -- *%1*') do (
+  call :EchoUnquotedString "%WorkDir%\%%~f"
+)
+goto End
+
+:EchoUnquotedString
+    echo %~1
+goto End
+
+:End
+
+
+ + +
+
 
+
+ + + diff --git a/docs/NppExec_Manual/4.6.17.html b/docs/NppExec_Manual/4.6.17.html new file mode 100644 index 0000000..b4e5c87 --- /dev/null +++ b/docs/NppExec_Manual/4.6.17.html @@ -0,0 +1,99 @@ + + + + + +4.6.17. Modify selected text and save to file + + + +

4.6.17. Modify selected text and save to file

+ +

Question:

+

I know that SEL_SAVETO will save the selected text to target file, but how to modify the selected text such as add one blank line and then save to target file?

+ +

Answer, option one:

+

I'd say the correct answer is to change the order of these operations:

+
    +
  1. save the selected text via SEL_SAVETO;
  2. +
  3. modify the saved file by some external tool.
  4. +
+

For example, sfk (Swiss File Knife) supports a lot of ways to modify a file, and, moreover, it supports commands chaining (i.e. it's possible to apply one modification, then apply another one to the result and so on), plus now it does support UTF-8 and UCS-2 files. So I'd recommend to try to use sfk for any additional file modifications.

+

Here are a few examples of how to append/insert text lines by means of sfk:

+
    +
  • To append several lines similar to +
    +
    cmd /c echo trailing line1>>myfile.txt
    +cmd /c echo trailing line2>>myfile.txt
    +
    + use the following: +
    +
    sfk echo -spat "trailing line1\ntrailing line2" +append myfile.txt
    +
    +
  • +
  • To insert some text before line 5: +
    +
    sfk filt -lnum myfile.txt +xed "/[lstart]005 /005 text to insert\n[all]/" +xed "_[lstart]* __" -tofile out.txt
    +
    +
  • +
  • To insert after a specific string (e.g. insert after a line that contains a string "insert something after me"): +
    +
    sfk xed myfile.txt "/[lstart]*insert something after me*[eol]/[all]the new text\n/" -tofile out.txt
    +
    +
  • +
+ +

Answer, option two:

+

It's possible to modify the original text by means of SCI_ commands, save the modified text and then undo the changes.

+

For example, we can append a string in the following way (this example works with the entire document rather than with the selected text):

+ +
+
set local str ~ strfromhex 0D 00 0A 00 "Some string" // first 4 bytes are \r\n
+set local str_len ~ strlensci $(str)
+sci_sendmsg SCI_APPENDTEXT $(str_len) "$(str)" // append a string to the end of document
+text_saveto $(SYS.TEMP)\out.txt // save to the output file
+sci_sendmsg SCI_UNDO // undo
+
+ +

Here is an example that appends a string to the existing selection, saves it to a file and then reverts the text (and selection) to the previous state:

+ +
+
// getting the current selection
+sci_sendmsg SCI_GETCURRENTPOS
+set local pos = $(MSG_RESULT)
+sci_sendmsg SCI_GETANCHOR
+set local anchor = $(MSG_RESULT)
+
+if $(pos) < $(anchor) then
+  set local pos1 = $(pos)
+  set local pos2 = $(anchor)
+else
+  set local pos1 = $(anchor)
+  set local pos2 = $(pos)
+endif
+
+// appending a string to the selection 
+set local str ~ strfromhex 0D 00 0A 00 "Some string" // first 4 bytes are \r\n
+set local str_len ~ strlensci $(str)
+sci_sendmsg SCI_INSERTTEXT $(pos2) "$(str)" // append a string to the end of selection
+set local pos2 ~ $(pos2) + $(str_len)
+sci_sendmsg SCI_SETSEL $(pos1) $(pos2) // update the selection
+sel_saveto $(SYS.TEMP)\out.txt // save to the output file
+sci_sendmsg SCI_UNDO // undo
+
+// restoring the original selection
+sci_sendmsg SCI_SETSEL $(anchor) $(pos)
+
+ +
+
 
+
+ +

See also: Applying external tool to selected text [4.6.1]; Processing & replacing the selection [4.6.3].

+ +
+
 
+
+ + + diff --git a/docs/NppExec_Manual/4.6.18.html b/docs/NppExec_Manual/4.6.18.html new file mode 100644 index 0000000..ea8d227 --- /dev/null +++ b/docs/NppExec_Manual/4.6.18.html @@ -0,0 +1,71 @@ + + + + + +4.6.18. NppExec's Console as a Log Viewer + + + +

4.6.18. NppExec's Console as a Log Viewer

+ +

[the idea was originally proposed by mischlrebl as "show and reload file content periodically" here: https://github.com/d0vgan/nppexec/issues/101]

+ +

[ mischlrebl: ]

+
+

I am wondering if it is possible to watch and track a log file in the Console - like the "Monitoring (tail -f)" function in Notepad++?

+

It would be very handy to work with split screen on the files and to see the messages below.

+
+ +

[ DV: ]

+
+

The closest built-in command in NppExec is con_load, though it loads an entire file into the Console window.

+

To achieve your goal, you may probably run some external log viewer/watcher implemented as a console application in NppExec's Console.

+

This version of tail works good in NppExec's Console: https://github.com/JavaScriptDude/cygtail
+ On the cygtail's project page, click the <>Code button and then click Download ZIP there.
+ After downloading and extracting the binaries, this command will do the job:

+
+
tail -f log.txt
+
+

+

BusyBox for Windows also works good in NppExec's Console: https://frippery.org/busybox/
+ Once downloaded, this command will do the job:

+
+
busybox tail -f log.txt
+
+
+ +
+
 
+
+ +

As I had never thought about NppExec in terms of log viewing, I asked mischlrebl for more details of this use-case.
+And here are the resulting images that speak for themselves:

+ +

+ + + +

+ + + +
+
 
+
+ +

It may also be useful to have one instance of NppExec working as a Log Viewer and another instance of NppExec handling commands and scripts.
+Refer to "Using several copies of NppExec" [2.4] for details.

+ +
+
 
+
+ +

See also: Clipboard, keystrokes and much more [4.6.8]; Notepad++ as a Clipboard Monitor [4.6.14].

+ +
+
 
+
+ + + diff --git a/docs/NppExec_Manual/4.6.19.html b/docs/NppExec_Manual/4.6.19.html new file mode 100644 index 0000000..f3788d2 --- /dev/null +++ b/docs/NppExec_Manual/4.6.19.html @@ -0,0 +1,58 @@ + + + + + +4.6.19. Auto-hide NppExec's Console after executing a script + + + +

4.6.19. Auto-hide NppExec's Console after executing a script

+ +

Let's imagine we want to use NppExec for file backup, and want NppExec's Console to be automatically shown at the beginning of the file backup and automatically hidden at the end.
+Thus, the Console will be just an informational window that is shown to reflect the progress of certain operations and then is hidden.

+

The file backup operations may be as simple as that:

+
+
set local backupDir = $(SYS.USERPROFILE)\OneDrive\  // the backup directory
+npp_save  // saving the current file
+cmd /C copy /B /Y "$(FULL_CURRENT_PATH)" "$(backupDir)"  // backing the current file up
+
+

By default, when NppExec executes a script, the Console is automatically shown, unless npp_console ? is explicitly specified at the very beginning of the script. Then, at the end of the script, a visible Console remains visible.
+For the purpose of auto-hiding the Console at the end of the script, we need to alter the default behavior. We need to use the npp_console command with the specific parameters:

+
+
npp_console local on
+
+

This command has the following effects: 1. If the Console is hidden, it is shown. 2. As this command is local, the previous state of the Console (before the script) is restored at the end of the script. I.e. if the Console was hidden before the script, it is shown during the script and then becomes hidden at the end of the script. This is the desired "Auto-hide" behavior. So, this is the exact command we want at the very beginning of our script.
+(Note: With this command, if the Console was shown before the script, it remains shown after the script. If you want the Console to be always hidden at the end of the script, use npp_console off at the end of the script).

+

As the Console will be auto-hidden, we may need some pause to read the Console's output while it is visible:

+
+
sleep 2000  // waiting for 2 seconds
+
+

Also, we may want to preserve the keyboard focus in the editing window rather than having the focus in the Console while it is visible:

+
+
npp_setfocus sci  // setting the focus to the Scintilla's editing window
+
+

Finally, it is a good idea to disable the output to the Console while the auxiliary commands are executed:

+
+
npp_console local -  // disabling the output to the Console
+
+ +

So, here is the full script:

+
+
npp_console local on  // showing the Console if it is hidden
+npp_console local -   // disabling the output to the Console
+set local backupDir = $(SYS.USERPROFILE)\OneDrive\  // the backup directory
+npp_setfocus sci      // setting the focus to the Scintilla's editing window
+npp_console local +   // enabling the output to the Console
+npp_save              // saving the current file
+cmd /C copy /B /Y "$(FULL_CURRENT_PATH)" "$(backupDir)"  // backing the current file up
+npp_console local -   // disabling the output to the Console
+sleep 2000            // waiting for 2 seconds
+
+ +
+
 
+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.6.2.html b/docs/NppExec_Manual/4.6.2.html similarity index 94% rename from NppExec/doc/NppExec/NppExec_Manual/4.6.2.html rename to docs/NppExec_Manual/4.6.2.html index f66c3df..09be02d 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.6.2.html +++ b/docs/NppExec_Manual/4.6.2.html @@ -1,65 +1,66 @@ - - - - - -4.6.2. Calculating - - -

4.6.2. Calculating

-

Of course, you can use external tools for calculations. All you need to do is to select the text which contains some mathematical expression and call NppExec's script which would allow to calculate it.

-

For example:

-
-
set AWK_EXE = C:\tools\gawk\gawk.exe
-"$(AWK_EXE)" "BEGIN { print $(CURRENT_WORD) }"
-
-

This simple script allows you to - calculate -such expressions as "1 + sin(3)/4" or "(2 + 0x10)*3" etc.

-

You can modify the file "do.awk" from - previous example [4.6.1] in order to calculate an average value of numbers -given as the following table:

-
-
1.  552
-2.  554
-3.  549
-4.  551
-
-

Here is the AWK script (i.e. the - content of "do.awk") which calculates an - average value of numbers in the second column:

-
-
BEGIN {
-   Sum = 0
-   N = 0
-}
-NF == 2 {
-   Sum += $2
-   ++N
-}
-END {
-   print "avg = " Sum/N " (Sum = " Sum ", N = " N ")"
-}
-
-

Now, all you have to do is to select - the given table (see above) in Notepad++ and execute NppExec's script "do.awk on selected text". - You will see the following output in NppExec's Console:

-
-
avg = 551.5 (Sum = 2206, N = 4)
-
-

Of course, you can use other external tools for calculations of selected expressions or table data. The output of such external tools will be shown in NppExec's Console. Also you can redirect such output into a text file and then open that text file in Notepad++ [4.5].

-

NppExec ver. 0.4 introduces built-in calculator abilities provided by Function Parser (fparser). For example:

-
-
// calculate math expression on the current line
-// usage: type math expression in the editor and run this script
-NPP_CONSOLE ?  // don't show the Console if it's hidden
-SCI_SENDMSG SCI_GETCURLINE 100000 @""  // get current line
-set ans ~ $(MSG_LPARAM)  // try to calculate
-SCI_SENDMSG SCI_LINEEND  // go to end of line
-SCI_SENDMSG SCI_REPLACESEL 0 " = $(ans)"  // add the result
-
-
-

Type "help set" for more details.

-

See also: Calculations, strlen and so on [3.8.4].

- - + + + + + +4.6.2. Calculating + + + +

4.6.2. Calculating

+

Of course, you can use external tools for calculations. All you need to do is to select the text which contains some mathematical expression and call NppExec's script which would allow to calculate it.

+

For example:

+
+
set AWK_EXE = C:\tools\gawk\gawk.exe
+"$(AWK_EXE)" "BEGIN { print $(CURRENT_WORD) }"
+
+

This simple script allows you to + calculate +such expressions as "1 + sin(3)/4" or "(2 + 0x10)*3" etc.

+

You can modify the file "do.awk" from + previous example [4.6.1] in order to calculate an average value of numbers +given as the following table:

+
+
1.  552
+2.  554
+3.  549
+4.  551
+
+

Here is the AWK script (i.e. the + content of "do.awk") which calculates an + average value of numbers in the second column:

+
+
BEGIN {
+   Sum = 0
+   N = 0
+}
+NF == 2 {
+   Sum += $2
+   ++N
+}
+END {
+   print "avg = " Sum/N " (Sum = " Sum ", N = " N ")"
+}
+
+

Now, all you have to do is to select + the given table (see above) in Notepad++ and execute NppExec's script "do.awk on selected text". + You will see the following output in NppExec's Console:

+
+
avg = 551.5 (Sum = 2206, N = 4)
+
+

Of course, you can use other external tools for calculations of selected expressions or table data. The output of such external tools will be shown in NppExec's Console. Also you can redirect such output into a text file and then open that text file in Notepad++ [4.5].

+

NppExec ver. 0.4 introduces built-in calculator abilities provided by Function Parser (fparser). For example:

+
+
// calculate math expression on the current line
+// usage: type math expression in the editor and run this script
+NPP_CONSOLE ?  // don't show the Console if it's hidden
+SCI_SENDMSG SCI_GETCURLINE 100000 @""  // get current line
+set ans ~ $(MSG_LPARAM)  // try to calculate
+SCI_SENDMSG SCI_LINEEND  // go to end of line
+SCI_SENDMSG SCI_REPLACESEL 0 " = $(ans)"  // add the result
+
+
+

Type "help set" for more details.

+

See also: Calculations, strlen and so on [3.8.4].

+ + diff --git a/docs/NppExec_Manual/4.6.20.html b/docs/NppExec_Manual/4.6.20.html new file mode 100644 index 0000000..94240b4 --- /dev/null +++ b/docs/NppExec_Manual/4.6.20.html @@ -0,0 +1,67 @@ + + + + + +4.6.20. Opening multiple files and switching between them + + + +

4.6.20. Opening multiple files and switching between them

+ +

To open multiple files by means of NppExec, use npp_open:

+ +
+
npp_open file_path_1
+npp_open file_path_2
+npp_open file_path_3
+
+ +

The example above opens 3 files in Notepad++ and the last opened file becomes active.

+

If you want to preserve the order of opening these files but activate the first one (instead of the last one), use npp_switch at the end:

+ +
+
npp_open file_path_1
+npp_open file_path_2
+npp_open file_path_3
+npp_switch file_path_1
+
+ +

Both npp_open and npp_switch accept full file paths and relative file paths.
+Moreover, npp_switch also supports partial file names. For example, npp_switch abc will switch to the first opened file that contains "abc" in its name.

+

It is possible to open multiple files by specifying a file mask. For example, this will open all .txt files from a given directory:

+ +
+
npp_open C:\some_dir\*.txt
+
+ +

In this case, if you want to switch to the very first file opened by npp_open, a few additional commands are needed.
+At first, we need to remember the number of opened files before npp_open. Let's say this number is N.
+Then we call npp_open to open multiple files.
+Finally, we switch to the (N+1)th opened file.

+

Here is the corresponding NppExec's script:

+ +
+
// 1. remembering the number of opened files
+npp_sendmsg NPPM_GETCURRENTSCINTILLA 0 @0
+set local view ~ $(MSG_LPARAM) + 1
+npp_sendmsg NPPM_GETNBOPENFILES 0 $(view)
+set local num_opened_files = $(MSG_RESULT)
+
+// 2. calling npp_open
+npp_open C:\some_dir\*.txt
+
+// 3. switching to the (num_opened_files + 1)th document
+set local file_idx ~ $(num_opened_files) + 1
+npp_switch $(#$(file_idx))
+
+ +

Just for information, npp_switch $(#$(file_idx)) becomes e.g. npp_switch $(#5) when the value of $(file_idx) is 5.
+This trick is called "indirect variable reference, e.g. $($(name))" and was added in NppExec v0.6.2.

+ +
+
 
+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.6.3.html b/docs/NppExec_Manual/4.6.3.html similarity index 84% rename from NppExec/doc/NppExec/NppExec_Manual/4.6.3.html rename to docs/NppExec_Manual/4.6.3.html index 137c6ff..67767f8 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.6.3.html +++ b/docs/NppExec_Manual/4.6.3.html @@ -1,94 +1,96 @@ - - - - - -4.6.3. Processing & replacing the selection - - -

4.6.3. Processing & replacing the selection

-

There are two ways (or forms) to get the text selected in Notepad++:

-
    -
  1. Using pre-defined [3.8.1] variable $(CURRENT_WORD) which can store limited number of selected characters;
  2. -
  3. Using SEL_SAVETO "FilePathName" to save the whole selected text into a text file specified.
  4. -
-

Then the selected text can be processed by some external tool as shown in [4.6.1].

-

There are two ways (or forms) to replace the selected text with the text you want:

-
    -
  1. Using SEL_SETTEXT "TextToReplaceWith" which can also use some variable as its argument e.g. SEL_SETTEXT $(FILE_NAME);
  2. -
  3. Using SEL_LOADFROM "FilePathName" to load the text from a text file specified.
  4. -
-

NppExec allows you to use both ways to process the selected text with some external tool and then to replace the text with the tool's output. Several steps are required:

-

1) Pass the selected text to the external tool. The selected text is the external tool's input:

-
-
-
// input: command line, output: command line
-tool.exe <args> "$(CURRENT_WORD)"
-
-

or

-
-
// input: command line, output: file
-cmd /c tool.exe <args> "$(CURRENT_WORD)" >$(SYS.TEMP)\out.txt
-
-

or

-
-
// input: file, output: command line
-SEL_SAVETO $(SYS.TEMP)\npp_sel.txt
-tool.exe <args> $(SYS.TEMP)\npp_sel.txt
-
-

or

-
-
// input: file, output: file
-SEL_SAVETO $(SYS.TEMP)\npp_sel.txt
-cmd /c tool.exe <args> C:\npp_sel.txt >$(SYS.TEMP)\out.txt
-
-
-

2) Replace the selected text with the tool's output:

-
-
-
// replace the selected text with the output file's content
-SEL_LOADFROM $(SYS.TEMP)\out.txt
-
-

or

-
-
// replace the selected text with the command line's output:
-SEL_SETTEXT $(OUTPUT)
-
-
-

The very last approach needs several additional steps. The $(OUTPUT) variable stores the whole external tool's output while NPE_CONSOLE V+ has been set. Let's see an example of such approach.

-

Let's assume you select a word such as "copy", "dir", "cd" etc. and want to replace this word with its description from cmd's help. You can use $(CURRENT_WORD) variable to pass the selected word to cmd.exe. Also you want to replace the selected word with cmd's output. You can use $(OUTPUT) variable to do it. Here is the full NppExec's script which allows you to get the desired result:

-
-
// enable $(OUTPUT) variable within the current NppExec's script
-NPE_CONSOLE local v+
-// run cmd.exe with the selected word as parameter
-cmd.exe /c $(CURRENT_WORD) /?
-// (optional) replace the selected text: previously selected word
-SEL_SETTEXT $(CURRENT_WORD)
-// (optional) replace the selected text: new line
-SEL_SETTEXT+ \n
-// replace the selected text: cmd's output
-SEL_SETTEXT $(OUTPUT)
-
-
-

That's all. Now try the following:

-
    -
  1. Create new file in Notepad++ (don't even save it yet)
  2. -
  3. Type, for example, "dir" (without quotes)
  4. -
  5. Select the word "dir" (without quotes)
  6. -
  7. Open NppExec's Execute window, select "<temporary script>"
  8. -
  9. Copy the script shown above to the Execute window's edit-box
  10. -
  11. Press OK
  12. -
  13. Enjoy the result :-)
  14. -
-

The $(OUTPUT) variable is disabled by default to minimize the memory usage as this variable stores the whole external process'es output when enabled.

-

You can clear this variable by assigning an empty value to it:

-
-
SET $(OUTPUT) =
-
-

To free the memory allocated for this variable, use the following:

-
-
UNSET $(OUTPUT)
-
-

See also: Applying external tool to selected text [4.6.1].

- - + + + + + +4.6.3. Processing & replacing the selection + + + +

4.6.3. Processing & replacing the selection

+

There are two ways (or forms) to get the text selected in Notepad++:

+
    +
  1. Using pre-defined [3.8.1] variable $(CURRENT_WORD) which can store limited number of selected characters;
  2. +
  3. Using pre-defined [3.8.1] variable $(SELECTED_TEXT) which can store any number of selected characters;
  4. +
  5. Using SEL_SAVETO "FilePathName" to save the entire selected text into a text file specified.
  6. +
+

Then the selected text can be processed by some external tool as shown in [4.6.1].

+

There are two ways (or forms) to replace the selected text with the text you want:

+
    +
  1. Using SEL_SETTEXT "TextToReplaceWith" which can also use some variable as its argument e.g. SEL_SETTEXT $(FILE_NAME);
  2. +
  3. Using SEL_LOADFROM "FilePathName" to load the text from a text file specified.
  4. +
+

NppExec allows you to use both ways to process the selected text with some external tool and then to replace the text with the tool's output. Several steps are required:

+

1) Pass the selected text to the external tool. The selected text is the external tool's input:

+
+
+
// input: command line, output: command line
+tool.exe <args> "$(CURRENT_WORD)"
+
+

or

+
+
// input: command line, output: file
+cmd /c tool.exe <args> "$(CURRENT_WORD)" >$(SYS.TEMP)\out.txt
+
+

or

+
+
// input: file, output: command line
+SEL_SAVETO $(SYS.TEMP)\npp_sel.txt
+tool.exe <args> $(SYS.TEMP)\npp_sel.txt
+
+

or

+
+
// input: file, output: file
+SEL_SAVETO $(SYS.TEMP)\npp_sel.txt
+cmd /c tool.exe <args> C:\npp_sel.txt >$(SYS.TEMP)\out.txt
+
+
+

2) Replace the selected text with the tool's output:

+
+
+
// replace the selected text with the output file's content
+SEL_LOADFROM $(SYS.TEMP)\out.txt
+
+

or

+
+
// replace the selected text with the command line's output:
+SEL_SETTEXT $(OUTPUT)
+
+
+

The very last approach needs several additional steps. The $(OUTPUT) variable stores the entire external tool's output while NPE_CONSOLE V+ has been set. Let's see an example of such approach.

+

Let's assume you select a word such as "copy", "dir", "cd" etc. and want to replace this word with its description from cmd's help. You can use $(CURRENT_WORD) variable to pass the selected word to cmd.exe. Also you want to replace the selected word with cmd's output. You can use $(OUTPUT) variable to do it. Here is the full NppExec's script which allows you to get the desired result:

+
+
// enable $(OUTPUT) variable within the current NppExec's script
+NPE_CONSOLE local v+
+// run cmd.exe with the selected word as parameter
+cmd.exe /c $(CURRENT_WORD) /?
+// (optional) replace the selected text: previously selected word
+SEL_SETTEXT $(CURRENT_WORD)
+// (optional) replace the selected text: new line
+SEL_SETTEXT+ \n
+// replace the selected text: cmd's output
+SEL_SETTEXT $(OUTPUT)
+
+
+

That's all. Now try the following:

+
    +
  1. Create new file in Notepad++ (don't even save it yet)
  2. +
  3. Type, for example, "dir" (without quotes)
  4. +
  5. Select the word "dir" (without quotes)
  6. +
  7. Open NppExec's Execute window, select "<temporary script>"
  8. +
  9. Copy the script shown above to the Execute window's edit-box
  10. +
  11. Press OK
  12. +
  13. Enjoy the result :-)
  14. +
+

The $(OUTPUT) variable is disabled by default to minimize the memory usage as this variable stores the entire external process'es output when enabled.

+

You can clear this variable by assigning an empty value to it:

+
+
SET $(OUTPUT) =
+
+

To free the memory allocated for this variable, use the following:

+
+
UNSET $(OUTPUT)
+
+

See also: Applying external tool to selected text [4.6.1]; Modify selected text and save to file [4.6.17].

+ + diff --git a/docs/NppExec_Manual/4.6.4.html b/docs/NppExec_Manual/4.6.4.html new file mode 100644 index 0000000..6749d5c --- /dev/null +++ b/docs/NppExec_Manual/4.6.4.html @@ -0,0 +1,128 @@ + + + + + +4.6.4. Running Python & wxPython + + + +

4.6.4. Running Python & wxPython

+ +

1. Interactive Python inside NppExec

+

Running "python -?" gives the following help information, in particular:

+
    +
  • -i : inspect interactively after running script, (also PYTHONINSPECT=x) and force prompts, even if stdin does not appear to be a terminal
  • +
  • -u : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x), see man page for details on internal buffering relating to '-u'
  • +
+

The text in italic exactly refers to what is stated in NppExec's Manual, sections 1.3 and 3.1 by "NppExec is not a console emulator".

+

So, by running "python -i -u" in NppExec's Console, you get the interactive Python inside Notepad++.

+

Here is an advanced example of NppExec's script to be used to test a Python's program interactively:

+
+
npp_console local -  // disable any output to the Console
+npp_save  // save current file (a .py file is expected)
+cd "$(CURRENT_DIRECTORY)"  // use the current file's dir
+set local @exit_cmd_silent = exit()  // allows to exit Python automatically
+env_set local PATH = $(SYS.PATH);C:\Python27  // using Python 2.7
+npp_setfocus con  // set the focus to the Console
+npp_console local +  // enable output to the Console
+python -i -u "$(FILE_NAME)"  // run Python's program interactively
+
+
+
+
 
+
+ +

2. Python and UTF-8

+

If your python's program contains some non-ASCII characters, you can get the following error from Python:

+
+
SyntaxError: Non-ASCII character
+
+

To be able to represent such non-ASCII characters correctly on any system, +such source file should be saved as UTF-8 (either without BOM or with BOM). +Though the error mentioned above still remains. +To avoid this error, acccording to https://peps.python.org/pep-0263/ , +you just need to specify

+
+
# coding=utf-8
+
+

or

+
+
# -*- coding: utf-8 -*-
+
+

at the beginning of your python's program.

+

Another thing is to output something to console as UTF-8. In this case, you can get something similar from Python:

+
+
UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-2: character maps to <undefined>
+
+

To fix this last one, it's enough to specify the environment variable PYTHONIOENCODING by setting it to "utf-8". I.e.

+
+
// within NppExec
+env_set local PYTHONIOENCODING=utf-8  // UTF-8 output for Python
+npe_console local -- o2 i2            // UTF-8 output/input for NppExec's Console
+python my_program.py
+
+
+
 
+
+ +

3. Running Python scripts using wxPython

+

[the text below has been originally posted by cioma in NppExec's forum]

+

[ cioma: ]

+
+

I use NPP as an IDE for Python. And I use NppExec to run scripts directly from NPP, highlight script syntax and runtime errors (if any) and link errors to a line of code.

+

Some time ago I started using wxPython GUI library and faced problems with running such scripts from within NppExec.

+

If I run this (in NppExec prompt):

+
+
python -t -B -u "$(FULL_CURRENT_PATH)" 
+
+

...then GUI part of wxPython is not shown. I guess the reason is that wxPython requires a "real" console buffer and NppExec doesn't provide that.

+

If I just run script over NPP "Run" dialog (no NppExec) then GUI is shown but if there are errors there is no way to easily relate them to line of code in NPP.

+

So I found this solution to work:

+

1. When creating wxPython application in the script make sure it's STDOUT is not redirected:

+
+
app = App(redirect=False) 
+
+

2. Run in NppExec:

+
+
cmd /C python -t -B -u "$(FULL_CURRENT_PATH)" 
+
+

Voila! We have both wxPython GUI running and its STDOUT redirected to NppExec.

+
+

[ DV: ]

+
+

Just one thing. For more details regarding runtime errors parsing (keyword: Highlight filters), refer to [4.7.4] and "help con_filter".

+
+
+
 
+
+ +

4. Running Pygame Code

+

[the text below has been originally posted by Ahmed A. in Notepad++'s forum]

+

I have NppExec set up with this script:

+
+
npp_save
+cd $(CURRENT_DIRECTORY)
+python -u $(FILE_NAME)
+
+

It runs most python code perfectly fine, I even tested out some of the example code that comes with python. Files using the turtle module work perfectly with opening windows etc.

+

However, when I run code using the Pygame module, everything works fine except that no window is opened. I see that the code is executing and I can print statements in the game loop and they show up in the console, but that is all.

+

Eventually I was able to get it to work. The issue was that NppExec was somehow blocking window creation in the case of Pygame. Using "cmd /c python" fixed the issue with the window:

+
+
npp_save
+cd "$(CURRENT_DIRECTORY)"
+cmd /c python -u "$(FILE_NAME)"
+
+

Here is the related comment from superuser.com ( https://superuser.com/questions/381942/stop-nppexec-from-trapping-console-output-until-program-finishes ) where I found the solution to this problem:

+

To prevent your python script's own windows being suppressed (not sure exactly what is going on here), run the call to Python as an argument to cmd by preprending "cmd /c". For example, I'm using

+
+
cmd /c python -u "$(FULL_CURRENT_PATH)"
+
+

so my Cocos2D window shows up.

+ +
+
 
+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.6.5.html b/docs/NppExec_Manual/4.6.5.html similarity index 94% rename from NppExec/doc/NppExec/NppExec_Manual/4.6.5.html rename to docs/NppExec_Manual/4.6.5.html index bba2906..6474288 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.6.5.html +++ b/docs/NppExec_Manual/4.6.5.html @@ -1,67 +1,68 @@ - - - - - -4.6.5. Grab date & time to NppExec variable - - -

4.6.5. Grab date & time to NppExec variable

- -

1. To grab current date to NppExec variable, you can create the following simple auxiliary script:

-
-
NPE_CONSOLE local v+
-cmd /c date /t
-set DATE = $(OUTPUTL)
-
-

and give it a name "date", for example.

-

Then you can use "NPP_EXEC date" or just "\date" to call this script which sets an internal environment variable $(DATE).

-

The same approach can be used for time: just replace "date /t" with "time /t".

- -

2. To grab date or time in user-specified format, some additional actions are needed. -First, go to Notepad++'s folder (where notepad++.exe is located) and create a file named "date.bat" with the following content:

-
-
@echo off
-for /f "tokens=1-3 delims=/.- " %%a in ('DATE /T') do set CUR_DATE=%%c%%b%%a
-echo %CUR_DATE%
-
-

Then create the following NppExec's script which will use this bat-file:

-
-
NPE_CONSOLE local v+
-"$(NPP_DIRECTORY)\date.bat"
-set DATE = $(OUTPUTL) // the bat-file's output
-
-

Now your date format is definitely determined by this line:

-
-
for /f "tokens=1-3 delims=/.- " %%a in ('DATE /T') do set CUR_DATE=%%c%%b%%a
-
-

and you can change it as you want, e.g.

-
-
for /f "tokens=1-3 delims=/.- " %%a in ('DATE /T') do set CUR_DATE=%%c-%%b-%%a
-
-

or

-
-
for /f "tokens=1-3 delims=/.- " %%a in ('DATE /T') do set CUR_DATE=%%c%%a%%b
-
-

or whatever you want.

- -

3. Finally, you can use the following bat-file which returns both date and time as one string:

-
-
@echo off
-for /f "tokens=1-3 delims=/.- " %%a in ('DATE /T') do set CUR_DATE=%%c%%b%%a
-for /f "tokens=1-2 delims=: " %%a in ('TIME /T') do set CUR_TIME=%%a%%b
-echo %CUR_DATE%_%CUR_TIME%
-
- -

4. Here is another version of the previous bat-file, now using cmd's environment variables %DATE% and %TIME% which supports also milliseconds:

-
-
@echo off
-for /f "tokens=1-3 delims=/.- " %%a in ("%DATE%") do set CUR_DATE=%%c%%b%%a
-for /f "tokens=1-4 delims=:., " %%a in ("%TIME%") do set CUR_TIME=%%a%%b%%c%%d
-echo %CUR_DATE%_%CUR_TIME%
-
- -

See also: Using cmd.exe [4.4].

- - - + + + + + +4.6.5. Grab date & time to NppExec variable + + + +

4.6.5. Grab date & time to NppExec variable

+ +

1. To grab current date to NppExec variable, you can create the following simple auxiliary script:

+
+
NPE_CONSOLE local v+
+cmd /c date /t
+set DATE = $(OUTPUTL)
+
+

and give it a name "date", for example.

+

Then you can use "NPP_EXEC date" or just "\date" to call this script which sets an internal environment variable $(DATE).

+

The same approach can be used for time: just replace "date /t" with "time /t".

+ +

2. To grab date or time in user-specified format, some additional actions are needed. +First, go to Notepad++'s folder (where notepad++.exe is located) and create a file named "date.bat" with the following content:

+
+
@echo off
+for /f "tokens=1-3 delims=/.- " %%a in ('DATE /T') do set CUR_DATE=%%c%%b%%a
+echo %CUR_DATE%
+
+

Then create the following NppExec's script which will use this bat-file:

+
+
NPE_CONSOLE local v+
+"$(NPP_DIRECTORY)\date.bat"
+set DATE = $(OUTPUTL) // the bat-file's output
+
+

Now your date format is definitely determined by this line:

+
+
for /f "tokens=1-3 delims=/.- " %%a in ('DATE /T') do set CUR_DATE=%%c%%b%%a
+
+

and you can change it as you want, e.g.

+
+
for /f "tokens=1-3 delims=/.- " %%a in ('DATE /T') do set CUR_DATE=%%c-%%b-%%a
+
+

or

+
+
for /f "tokens=1-3 delims=/.- " %%a in ('DATE /T') do set CUR_DATE=%%c%%a%%b
+
+

or whatever you want.

+ +

3. Finally, you can use the following bat-file which returns both date and time as one string:

+
+
@echo off
+for /f "tokens=1-3 delims=/.- " %%a in ('DATE /T') do set CUR_DATE=%%c%%b%%a
+for /f "tokens=1-2 delims=: " %%a in ('TIME /T') do set CUR_TIME=%%a%%b
+echo %CUR_DATE%_%CUR_TIME%
+
+ +

4. Here is another version of the previous bat-file, now using cmd's environment variables %DATE% and %TIME% which supports also milliseconds:

+
+
@echo off
+for /f "tokens=1-3 delims=/.- " %%a in ("%DATE%") do set CUR_DATE=%%c%%b%%a
+for /f "tokens=1-4 delims=:., " %%a in ("%TIME%") do set CUR_TIME=%%a%%b%%c%%d
+echo %CUR_DATE%_%CUR_TIME%
+
+ +

See also: Using cmd.exe [4.4].

+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.6.6.html b/docs/NppExec_Manual/4.6.6.html similarity index 86% rename from NppExec/doc/NppExec/NppExec_Manual/4.6.6.html rename to docs/NppExec_Manual/4.6.6.html index 7bcd8ba..efa96a3 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.6.6.html +++ b/docs/NppExec_Manual/4.6.6.html @@ -1,27 +1,28 @@ - - - - - -4.6.6. Grab Console output to new editor pane - - -

4.6.6. Grab Console output to new editor pane

- -

To open new editor pane, use "NPP_SENDMSG WM_COMMAND IDM_FILE_NEW".

-

To get the Console output, notice the usage of "NPE_CONSOLE v+" and "SEL_SETTEXT $(OUTPUT)" [4.6.3].

-

To sum up, the following NppExec script should be used:

- -
-
// enable the $(OUTPUT) variable for the current NppExec's script
-NPE_CONSOLE local v+
-// your command here... for example, let it be "cmd /?"
-cmd /?
-// open new editor pane
-NPP_SENDMSG WM_COMMAND IDM_FILE_NEW
-// set the text in the new editor pane
-SEL_SETTEXT $(OUTPUT)
-
- - - + + + + + +4.6.6. Grab Console output to new editor pane + + + +

4.6.6. Grab Console output to new editor pane

+ +

To open new editor pane, use "NPP_SENDMSG WM_COMMAND IDM_FILE_NEW".

+

To get the Console output, notice the usage of "NPE_CONSOLE v+" and "SEL_SETTEXT $(OUTPUT)" [4.6.3].

+

To sum up, the following NppExec script should be used:

+ +
+
// enable the $(OUTPUT) variable for the current NppExec's script
+NPE_CONSOLE local v+
+// your command here... for example, let it be "cmd /?"
+cmd /?
+// open new editor pane
+NPP_SENDMSG WM_COMMAND IDM_FILE_NEW
+// set the text in the new editor pane
+SEL_SETTEXT $(OUTPUT)
+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.6.7.html b/docs/NppExec_Manual/4.6.7.html similarity index 94% rename from NppExec/doc/NppExec/NppExec_Manual/4.6.7.html rename to docs/NppExec_Manual/4.6.7.html index f15bb82..548b1a5 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.6.7.html +++ b/docs/NppExec_Manual/4.6.7.html @@ -1,128 +1,129 @@ - - - - - -4.6.7. Run and terminate PowerShell process - - -

4.6.7. Run and terminate PowerShell process

- -

[Part 1: the following text is based on nppexec/issues/23 by LorneCash]

-

The problem #1: If you execute a PowerShell's script in NppExec's Console, the PowerShell process is not ended when the script is finished.

-

The solution #1: Use "cmd /c echo. | powershell" instead of "powershell" to emulate sending of the Enter key to PowerShell process.

-

The problem #2: PowerShell says: "File ... cannot be loaded because running scripts is disabled on this system".

-

The solution #2: Either use the command-line option "-ExecutionPolicy Unrestricted" (see the examples below) or set PowerShell's global ExecutionPolicy (see the second part of this article).

-

The problem #3: If a quoted file path is passed to the second instance of PowerShell, this second instance receives the file path without quotes.

-

The solution #3: Use escaped quotes \" \" instead of just " ".

-

Here is an example that illustrates this approach. Also it demonstrates how PowerShell's ExecutionPolicy can be applied to a single script. It is assumed that a .ps1 file is currently opened in Notepad++:

-
-
cmd /c echo. | PowerShell -ExecutionPolicy Unrestricted start-process PowerShell -ArgumentList '-ExecutionPolicy Unrestricted -File \"$(FULL_CURRENT_PATH)\"'
-
- -

And here is an example of PowerShell's command executed in NppExec's Console:

-
-
cmd /c echo. | PowerShell -Command Write-Host 'Hello, World!'
-
- -

Now let's consider the following scenario. When you are debugging PowerShell or batch scripts you usually run them a lot with pauses in them, so you end up with a lot of console windows that have to be closed manually. This can be automated by saving the PID (process id) of the last running process and then using this saved PID to close that process gracefully. Here is the corresponding NppExec's script that runs a PowerShell script file (.ps1) opened in Notepad++:

-
-
if "$(PS_ID)" != "" then
-  // closing the previous running process by its id...
-  cmd /C echo. | PowerShell -Command "get-process -Id $(PS_ID) -ErrorAction SilentlyContinue | ForEach-Object {$null = $_.CloseMainWindow()};"
-  unset PS_ID
-endif
-// running a new process and saving its id...
-npe_console local v+ --
-cmd /C echo. | PowerShell -ExecutionPolicy Unrestricted -Command "(start-process -PassThru PowerShell -ArgumentList '-File ""$(FULL_CURRENT_PATH)""').Id"
-set PS_ID = $(OUTPUT)
-
-
-

In case of a batch script file (.bat or .cmd), the NppExec's script will be slightly different:

-
-
if "$(PS_ID)" != "" then
-  // closing the previous running process by its id...
-  cmd /C echo. | PowerShell -Command "get-process -Id $(PS_ID) -ErrorAction SilentlyContinue | ForEach-Object {$null = $_.CloseMainWindow()};"
-  unset PS_ID
-endif
-// running a new process and saving its id...
-npe_console local v+ --
-cmd /C echo. | PowerShell -Command "(start-process -PassThru cmd -ArgumentList '/c ""$(FULL_CURRENT_PATH)""').Id"
-set PS_ID = $(OUTPUT)
-
-
-

Finally, we can merge these two NppExec's scripts into a new NppExec's script that will take care of both PowerShell and batch script files:

-
-
npp_console ?  // don't show the Console if it's hidden
-npp_save       // save the current file
-if "$(PS_ID)" != "" then
-  // closing the previous running process by its id...
-  cmd /C echo. | PowerShell -Command "get-process -Id $(PS_ID) -ErrorAction SilentlyContinue | ForEach-Object {$null = $_.CloseMainWindow()};"
-  unset PS_ID
-endif
-// is it a batch file?..
-set local IS_BATCH_FILE = false
-if "$(EXT_PART)" ~= ".bat" then
-  set local IS_BATCH_FILE = true
-else if "$(EXT_PART)" ~= ".cmd" then
-  set local IS_BATCH_FILE = true
-endif
-// running a new process and saving its id...
-npe_console local v+ --
-if "$(IS_BATCH_FILE)" == "true" then
-  cmd /C echo. | PowerShell -Command "(start-process -PassThru cmd -ArgumentList '/c ""$(FULL_CURRENT_PATH)""').Id"
-  set PS_ID = $(OUTPUT)
-else if "$(EXT_PART)" ~= ".ps1" then
-  cmd /C echo. | PowerShell -ExecutionPolicy Unrestricted -Command "(start-process -PassThru PowerShell -ArgumentList '-File ""$(FULL_CURRENT_PATH)""').Id"
-  set PS_ID = $(OUTPUT)
-else
-  messagebox "File type has not been configured in NppExec's 'Run' script" : "NppExec: Run - Unknown File Type" : warn
-endif
-
-
- -
-
 
-
- -

[Part 2: the text below was originally posted in NppExec's forum]

-

The problem: if you execute a PowerShell's script in NppExec's Console, the PowerShell process is not ended when the script is finished.

-

The solution: use "cmd /c echo. | powershell" instead of "powershell" to emulate sending of the Enter key to PowerShell process.

-

Here is an example of the full NppExec's script that uses the currently selected text as a PowerShell's program:

- -
-
// path to PowerShell.exe
-set local PS_EXE = C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe
-// temporary file
-set local TEMP_FILE = $(SYS.TEMP)\ps_sel.ps1
-// save selected text from current file to a temporary ANSI file
-SEL_SAVETO $(TEMP_FILE) :a
-// execute the temporary file in PowerShell and exit
-cmd /c echo. | "$(PS_EXE)" -nologo "$(TEMP_FILE)"
-
- -

Note:

-

If PowerShell unexpectedly says something like

-
-
File "test.ps1" cannot be loaded because running scripts is disabled on this system
-
-

it could be related to the fact that there are 32-bit and 64-bit instances on 64-bit systems, and they can have different settings. According to https://stackoverflow.com/questions/4037939/powershell-says-execution-of-scripts-is-disabled-on-this-system , the following should help:

-
-
x86 (32 bit)
-Open "C:\Windows\SysWOW64\cmd.exe"
-Run the command: "powershell Set-ExecutionPolicy RemoteSigned"
-
-x64 (64 bit)
-Open "C:\Windows\system32\cmd.exe"
-Run the command: "powershell Set-ExecutionPolicy RemoteSigned"
-
-You can check the bitness using
-- In CMD: echo %PROCESSOR_ARCHITECTURE%
-- In Powershell: [Environment]::Is64BitProcess
-
-
- -

See also: Using cmd.exe [4.4].

- - - + + + + + +4.6.7. Run and terminate PowerShell process + + + +

4.6.7. Run and terminate PowerShell process

+ +

[Part 1: the following text is based on nppexec/issues/23 by LorneCash]

+

The problem #1: If you execute a PowerShell's script in NppExec's Console, the PowerShell process is not ended when the script is finished.

+

The solution #1: Use "cmd /c echo. | powershell" instead of "powershell" to emulate sending of the Enter key to PowerShell process.

+

The problem #2: PowerShell says: "File ... cannot be loaded because running scripts is disabled on this system".

+

The solution #2: Either use the command-line option "-ExecutionPolicy Unrestricted" (see the examples below) or set PowerShell's global ExecutionPolicy (see the second part of this article).

+

The problem #3: If a quoted file path is passed to the second instance of PowerShell, this second instance receives the file path without quotes.

+

The solution #3: Use escaped quotes \" \" instead of just " ".

+

Here is an example that illustrates this approach. Also it demonstrates how PowerShell's ExecutionPolicy can be applied to a single script. It is assumed that a .ps1 file is currently opened in Notepad++:

+
+
cmd /c echo. | PowerShell -ExecutionPolicy Unrestricted start-process PowerShell -ArgumentList '-ExecutionPolicy Unrestricted -File \"$(FULL_CURRENT_PATH)\"'
+
+ +

And here is an example of PowerShell's command executed in NppExec's Console:

+
+
cmd /c echo. | PowerShell -Command Write-Host 'Hello, World!'
+
+ +

Now let's consider the following scenario. When you are debugging PowerShell or batch scripts you usually run them a lot with pauses in them, so you end up with a lot of console windows that have to be closed manually. This can be automated by saving the PID (process id) of the last running process and then using this saved PID to close that process gracefully. Here is the corresponding NppExec's script that runs a PowerShell script file (.ps1) opened in Notepad++:

+
+
if "$(PS_ID)" != "" then
+  // closing the previous running process by its id...
+  cmd /C echo. | PowerShell -Command "get-process -Id $(PS_ID) -ErrorAction SilentlyContinue | ForEach-Object {$null = $_.CloseMainWindow()};"
+  unset PS_ID
+endif
+// running a new process and saving its id...
+npe_console local v+ --
+cmd /C echo. | PowerShell -ExecutionPolicy Unrestricted -Command "(start-process -PassThru PowerShell -ArgumentList '-File ""$(FULL_CURRENT_PATH)""').Id"
+set PS_ID = $(OUTPUT)
+
+
+

In case of a batch script file (.bat or .cmd), the NppExec's script will be slightly different:

+
+
if "$(PS_ID)" != "" then
+  // closing the previous running process by its id...
+  cmd /C echo. | PowerShell -Command "get-process -Id $(PS_ID) -ErrorAction SilentlyContinue | ForEach-Object {$null = $_.CloseMainWindow()};"
+  unset PS_ID
+endif
+// running a new process and saving its id...
+npe_console local v+ --
+cmd /C echo. | PowerShell -Command "(start-process -PassThru cmd -ArgumentList '/c ""$(FULL_CURRENT_PATH)""').Id"
+set PS_ID = $(OUTPUT)
+
+
+

Finally, we can merge these two NppExec's scripts into a new NppExec's script that will take care of both PowerShell and batch script files:

+
+
npp_console ?  // don't show the Console if it's hidden
+npp_save       // save the current file
+if "$(PS_ID)" != "" then
+  // closing the previous running process by its id...
+  cmd /C echo. | PowerShell -Command "get-process -Id $(PS_ID) -ErrorAction SilentlyContinue | ForEach-Object {$null = $_.CloseMainWindow()};"
+  unset PS_ID
+endif
+// is it a batch file?..
+set local IS_BATCH_FILE = false
+if "$(EXT_PART)" ~= ".bat" then
+  set local IS_BATCH_FILE = true
+else if "$(EXT_PART)" ~= ".cmd" then
+  set local IS_BATCH_FILE = true
+endif
+// running a new process and saving its id...
+npe_console local v+ --
+if "$(IS_BATCH_FILE)" == "true" then
+  cmd /C echo. | PowerShell -Command "(start-process -PassThru cmd -ArgumentList '/c ""$(FULL_CURRENT_PATH)""').Id"
+  set PS_ID = $(OUTPUT)
+else if "$(EXT_PART)" ~= ".ps1" then
+  cmd /C echo. | PowerShell -ExecutionPolicy Unrestricted -Command "(start-process -PassThru PowerShell -ArgumentList '-File ""$(FULL_CURRENT_PATH)""').Id"
+  set PS_ID = $(OUTPUT)
+else
+  messagebox "File type has not been configured in NppExec's 'Run' script" : "NppExec: Run - Unknown File Type" : warn
+endif
+
+
+ +
+
 
+
+ +

[Part 2: the text below was originally posted in NppExec's forum]

+

The problem: if you execute a PowerShell's script in NppExec's Console, the PowerShell process is not ended when the script is finished.

+

The solution: use "cmd /c echo. | powershell" instead of "powershell" to emulate sending of the Enter key to PowerShell process.

+

Here is an example of the full NppExec's script that uses the currently selected text as a PowerShell's program:

+ +
+
// path to PowerShell.exe
+set local PS_EXE = C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe
+// temporary file
+set local TEMP_FILE = $(SYS.TEMP)\ps_sel.ps1
+// save selected text from current file to a temporary ANSI file
+SEL_SAVETO $(TEMP_FILE) :a
+// execute the temporary file in PowerShell and exit
+cmd /c echo. | "$(PS_EXE)" -nologo "$(TEMP_FILE)"
+
+ +

Note:

+

If PowerShell unexpectedly says something like

+
+
File "test.ps1" cannot be loaded because running scripts is disabled on this system
+
+

it could be related to the fact that there are 32-bit and 64-bit instances on 64-bit systems, and they can have different settings. According to https://stackoverflow.com/questions/4037939/powershell-says-execution-of-scripts-is-disabled-on-this-system , the following should help:

+
+
x86 (32 bit)
+Open "C:\Windows\SysWOW64\cmd.exe"
+Run the command: "powershell Set-ExecutionPolicy RemoteSigned"
+
+x64 (64 bit)
+Open "C:\Windows\system32\cmd.exe"
+Run the command: "powershell Set-ExecutionPolicy RemoteSigned"
+
+You can check the bitness using
+- In CMD: echo %PROCESSOR_ARCHITECTURE%
+- In Powershell: [Environment]::Is64BitProcess
+
+
+ +

See also: Using cmd.exe [4.4].

+ + + diff --git a/docs/NppExec_Manual/4.6.8.html b/docs/NppExec_Manual/4.6.8.html new file mode 100644 index 0000000..cf54f27 --- /dev/null +++ b/docs/NppExec_Manual/4.6.8.html @@ -0,0 +1,27 @@ + + + + + +4.6.8. Clipboard, keystrokes and much more + + + +

4.6.8. Clipboard, keystrokes and much more

+ +

You can always extend NppExec's functionality by using different external tools.

+

For example:

+
    +
  • NirCmd ( https://www.nirsoft.net/ ) allows to work with the clipboard, send keystrokes to the system, modify the Registry and ini-files - and much more;
  • +
  • Swiss File Knife - sfk ( https://sourceforge.net/projects/swissfileknife/ ) allows various operations on text and binary files;
  • +
  • BusyBox for Windows ( https://frippery.org/busybox/ ) is a single binary that contains many common Unix tools;
  • +
  • wget ( https://eternallybored.org/misc/wget/ ) allows to download from the network;
  • +
  • winapiexec ( https://ramensoftware.com/winapiexec ) allows to run WinAPI functions through command line parameters;
  • +
  • gawk ( for Windows: https://sourceforge.net/projects/ezwinports/ ) allows to write special-purpose programs (scripts) for simple data-reformatting jobs.
  • +
+

The list of such useful programs can go on and on - and the main idea here is the ability of "communication" between these programs and NppExec. As you can use different tools with different parameters and then retrieve and process the produced output, there theoretically is no limit of what you can achieve by this approach. This reminds us the section [3.1]: "So, generally speaking, NppExec is a tool" - and what this tool can do for you depends on how you use it. So use it wisely :)

+ +

See also: Working with the Notepad++ 'Replace' dialog [4.6.13]; Notepad++ as a Clipboard Monitor [4.6.14]; NppExec's Console as a Log Viewer [4.6.18].

+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.6.9.html b/docs/NppExec_Manual/4.6.9.html similarity index 90% rename from NppExec/doc/NppExec/NppExec_Manual/4.6.9.html rename to docs/NppExec_Manual/4.6.9.html index 4761750..2113811 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.6.9.html +++ b/docs/NppExec_Manual/4.6.9.html @@ -1,37 +1,38 @@ - - - - - -4.6.9. Send several commands to external tool - - -

4.6.9. Send several commands to external tool

- -

A piping technique can be used to send several commands to external tool.

-

Let's take the standard "cmd" as an example. Let's assume you have a text file with a list of commands you want cmd to execute. Let's name this file "c.txt" and have the following lines in it:

-
-
ECHO Let's execute DIR command...
-DIR
-ECHO Done!
-ECHO Now let's see some help for CD command...
-CD /?
-ECHO Done!
-
-
-
-

Note: Don't forget to press Enter to have end-of-line (CR/LF) after the very last line! As far as I understand, the last command ("ECHO Done!" in our case) may be incorrectly understood if there's no new line after it.

-

Now execute the following from NppExec's Console:

-
-
cmd /C type c.txt | cmd
-
-

I believe the same technique should work with external tool as well - e.g.:

-
-
cmd /C type c.txt | external_tool
-
-

unless the external tool itself does not accept piping. But generally this approach should work.

- -

See also: Using cmd.exe [4.4].

- - - + + + + + +4.6.9. Send several commands to external tool + + + +

4.6.9. Send several commands to external tool

+ +

A piping technique can be used to send several commands to external tool.

+

Let's take the standard "cmd" as an example. Let's assume you have a text file with a list of commands you want cmd to execute. Let's name this file "c.txt" and have the following lines in it:

+
+
ECHO Let's execute DIR command...
+DIR
+ECHO Done!
+ECHO Now let's see some help for CD command...
+CD /?
+ECHO Done!
+
+
+
+

Note: Don't forget to press Enter to have end-of-line (CR/LF) after the very last line! As far as I understand, the last command ("ECHO Done!" in our case) may be incorrectly understood if there's no new line after it.

+

Now execute the following from NppExec's Console:

+
+
cmd /C type c.txt | cmd
+
+

I believe the same technique should work with external tool as well - e.g.:

+
+
cmd /C type c.txt | external_tool
+
+

unless the external tool itself does not accept piping. But generally this approach should work.

+ +

See also: Using cmd.exe [4.4].

+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.6.html b/docs/NppExec_Manual/4.6.html similarity index 63% rename from NppExec/doc/NppExec/NppExec_Manual/4.6.html rename to docs/NppExec_Manual/4.6.html index 38ac997..158d678 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.6.html +++ b/docs/NppExec_Manual/4.6.html @@ -1,11 +1,12 @@ - - - - - -4.6. Using external tools - - -

4.6. Using external tools

- - + + + + + +4.6. Using external tools + + + +

4.6. Using external tools

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.7.1.html b/docs/NppExec_Manual/4.7.1.html similarity index 83% rename from NppExec/doc/NppExec/NppExec_Manual/4.7.1.html rename to docs/NppExec_Manual/4.7.1.html index bb10fcb..f748e4d 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.7.1.html +++ b/docs/NppExec_Manual/4.7.1.html @@ -1,63 +1,69 @@ - - - - - -4.7.1. Compiling simple C and Pas-programs - - -

4.7.1. Compiling simple C and Pas-programs

-

1. You can edit, compile & run - simple -C-programs directly from Notepad++. All you need is the following:

-
-

1) download tcc (tcc is a freeware C-compiler, about 1 MB in archive)

-

2) unpack - tcc to "C:\tools\tcc" or create "tcc" subfolder in your Notepad++ folder (for example, "C:\Program Files\Notepad++\tcc") - and unpack tcc there

-

3) run - Notepad++ and call the "Execute NppExec Script..." dialog (Plugins -> NppExec -> Execute NppExec Script... - - or just press F6).

-

4) type - these commands in the "Execute NppExec Script..." dialog:

-
-

4.1) if tcc is placed in C:\tools\tcc

-
-
// save current file 
-NPP_SAVE 
-// compile & run with tcc 
-C:\tools\tcc\tcc.exe -run "$(FULL_CURRENT_PATH)"
-
-
-
-

4.2) if tcc is placed in $(NPP_DIRECTORY)\tcc

-
-
// save current file 
-NPP_SAVE 
-// compile & run with tcc 
-"$(NPP_DIRECTORY)\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)"
-
-
-

5) - save these commands: press Save... button, type "tcc-run" (this is - a name of your script) and press Save.

-
-

Now, when you have a C source file - opened in Notepad++, you can call the "Execute NppExec Script..." dialog, select "tcc-run" and press OK to compile & run this C-file. -

-

In this case tcc works as an interpreter for your C source file (its option "-run" does it: use "tcc -?" to learn more). If you need to produce the output .exe file, just remove the "-run" option.

-
-
 
-
- -

2. By the similar technique, you can compile Pascal files using Free Pascal (FPC):

-
-
NPP_SAVE // save current file
-set local PathToFpcExe = C:\FPC\2.6.0\bin\i386-win32 // path to fpc.exe
-env_set local PATH = $(SYS.PATH);$(PathToFpcExe) // add the path to fpc.exe to %PATH%
-cd $(CURRENT_DIRECTORY) // go to directory of the current file
-fpc "$(FILE_NAME)" // use fpc.exe to compile
-
- - - + + + + + +4.7.1. Compiling simple C and Pas-programs + + + +

4.7.1. Compiling simple C and Pas-programs

+

1. You can edit, compile & run + simple +C-programs directly from Notepad++. All you need is the following:

+
+

1) download tcc (Tiny C Compiler is a freeware C-compiler, about 1 MB in archive)

+

2) unpack + tcc to "C:\tools\tcc" or create "tcc" subfolder in your Notepad++ folder (for example, "C:\Program Files\Notepad++\tcc") + and unpack tcc there

+

3) run + Notepad++ and call the "Execute NppExec Script..." dialog (Plugins -> NppExec -> Execute NppExec Script... + - or just press F6).

+

4) type + these commands in the "Execute NppExec Script..." dialog:

+
+

4.1) if tcc is placed in C:\tools\tcc

+
+
// save current file 
+NPP_SAVE
+// enable the built-in error highlight filter locally
+NPE_CONSOLE local -- x+
+// compile & run with tcc 
+C:\tools\tcc\tcc.exe -run "$(FULL_CURRENT_PATH)"
+
+
+
+

4.2) if tcc is placed in $(NPP_DIRECTORY)\tcc

+
+
// save current file 
+NPP_SAVE
+// enable the built-in error highlight filter locally
+NPE_CONSOLE local -- x+
+// compile & run with tcc 
+"$(NPP_DIRECTORY)\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)"
+
+
+

5) + save these commands: press Save... button, type "tcc-run" (this is + a name of your script) and press Save.

+
+

Now, when you have a C source file + opened in Notepad++, you can call the "Execute NppExec Script..." dialog, select "tcc-run" and press OK to compile & run this C-file. +

+

In this case tcc works as an interpreter for your C source file (its option "-run" does it: use "tcc -?" to learn more). If you need to produce the output .exe file, just remove the "-run" option.

+
+
 
+
+ +

2. By the similar technique, you can compile Pascal files using Free Pascal (FPC):

+
+
NPP_SAVE // save current file
+set local PathToFpcExe = C:\FPC\2.6.0\bin\i386-win32 // path to fpc.exe
+env_set local PATH = $(SYS.PATH);$(PathToFpcExe) // add the path to fpc.exe to %PATH%
+cd $(CURRENT_DIRECTORY) // go to directory of the current file
+NPE_CONSOLE local -- x+ // enable the built-in error highlight filter locally
+fpc "$(FILE_NAME)" // use fpc.exe to compile
+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.7.2.html b/docs/NppExec_Manual/4.7.2.html similarity index 69% rename from NppExec/doc/NppExec/NppExec_Manual/4.7.2.html rename to docs/NppExec_Manual/4.7.2.html index 603d982..7c8293d 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.7.2.html +++ b/docs/NppExec_Manual/4.7.2.html @@ -1,45 +1,49 @@ - - - - - -4.7.2. Compiling Java - - -

4.7.2. Compiling Java

-

[This article uses some text - originally posted by Sam (sammi101082) in Notepad++'es Help forum.]

-

[ Sam: ]

-
-

To compile a Java file, all you have to do is the following:

-
    -
  1. Navigate to Plugins -> NppExec -> Execute. (Default Shortcut key is F6)
  2. -
  3. In the new popup window, type this
  4. -
    -
    cmd /c cd "$(CURRENT_DIRECTORY)" && "%JAVA_HOME%\bin\javac" "$(FULL_CURRENT_PATH)"  
    -
    -
  5. Click on "Save" and give it a name say "Java Compile".
  6. -
  7. Bingo. You are there. Now any Java file you are editing in Notepad++ - can be compiled by pressing F6 and choosing this script "Java Compile". - It will compile the Java class for you. This is irrespective of which - directory - you are in.
  8. -
-

The NppExec plugin can be used to execute any executable as you would from a command prompt. For running the compiled Java class, the script is:

-
-
cmd /k cd "$(CURRENT_DIRECTORY)" && "%JAVA_HOME%\bin\java" "$(NAME_PART)" && exit 
-
-

P.S. Remember to set the JAVA_HOME environment variable. To check if it is set, open a command prompt and type java.

-
-

[ DV: ]

-
-

Actually, the same thing can be done without explicit usage of 'cmd.exe'. You can use several commands (one command per line) in NppExec's script, and these commands will be executed one by one. For example:

-
-
cd "$(CURRENT_DIRECTORY)" 
-"$(SYS.JAVA_HOME)\bin\javac" "$(FULL_CURRENT_PATH)" 
-
-

Also you can use ENV_SET to set environment variables such as PATH or JAVA_HOME for any process (program) you start from Notepad++ [4.2].

-
- - - + + + + + +4.7.2. Compiling Java + + + +

4.7.2. Compiling Java

+

[This article uses some text + originally posted by Sam (sammi101082) in Notepad++'es Help forum.]

+

[ Sam: ]

+
+

To compile a Java file, all you have to do is the following:

+
    +
  1. Navigate to Plugins -> NppExec -> Execute. (Default Shortcut key is F6)
  2. +
  3. In the new popup window, type this +
    +
    NPE_CONSOLE local -- x+ // enable the built-in error highlight filter locally
    +cmd /c cd "$(CURRENT_DIRECTORY)" && "%JAVA_HOME%\bin\javac" "$(FULL_CURRENT_PATH)"  
    +
    +
  4. +
  5. Click on "Save" and give it a name say "Java Compile".
  6. +
  7. Bingo. You are there. Now any Java file you are editing in Notepad++ + can be compiled by pressing F6 and choosing this script "Java Compile". + It will compile the Java class for you. This is irrespective of which + directory you are in.
  8. +
+

The NppExec plugin can be used to execute any executable as you would from a command prompt. For running the compiled Java class, the script is:

+
+
NPE_CONSOLE local -- x+ // enable the built-in error highlight filter locally
+cmd /k cd "$(CURRENT_DIRECTORY)" && "%JAVA_HOME%\bin\java" "$(NAME_PART)" && exit 
+
+

P.S. Remember to set the JAVA_HOME environment variable. To check if it is set, open a command prompt and type java.

+
+

[ DV: ]

+
+

Actually, the same thing can be done without explicit usage of 'cmd.exe'. You can use several commands (one command per line) in NppExec's script, and these commands will be executed one by one. For example:

+
+
NPE_CONSOLE local -- x+ // enable the built-in error highlight filter locally
+cd "$(CURRENT_DIRECTORY)" 
+"$(SYS.JAVA_HOME)\bin\javac" "$(FULL_CURRENT_PATH)" 
+
+

Also you can use ENV_SET to set environment variables such as PATH or JAVA_HOME for any process (program) you start from Notepad++ [4.2].

+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.7.3.html b/docs/NppExec_Manual/4.7.3.html similarity index 76% rename from NppExec/doc/NppExec/NppExec_Manual/4.7.3.html rename to docs/NppExec_Manual/4.7.3.html index 239c4ce..3d584df 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.7.3.html +++ b/docs/NppExec_Manual/4.7.3.html @@ -1,113 +1,130 @@ - - - - - -4.7.3. Using Visual Studio's compiler (cl.exe) - - - -

4.7.3. Using Visual Studio's compiler (cl.exe)

-

If you want to run 'cl.exe' from NppExec, it requires some additional environment. Such environment can be set using a batch file or using NppExec's command ENV_SET [4.2].

-

1. Using a batch file (simple)

-

To use a simple batch file, create a file 'cl.cmd' with similar text:

- -
-
-REM cl.cmd
-REM Visual Studio 2017 Community Edition
-@echo off
-call "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86
-cl.exe %*
-
-
-

Now, use something similar to

-
-
-cl.cmd "$(FULL_CURRENT_PATH)"
-
-
-

to compile your source file(s).

-

2. Using a batch file (advanced)

-

To use an advanced batch file, create a file 'cl.cmd' with similar text:

- -
-
-REM cl.cmd
-REM Visual Studio 8.0 (2005) Express
-@echo off
-Set VCDIR=C:\Program Files\Microsoft Visual Studio 8\VC
-Set VSCOMMON=C:\Program Files\Microsoft Visual Studio 8\Common7\IDE
-Set MSSDK=C:\Program Files\Microsoft Platform SDK for Windows Server 2003
-Set PATH=%VCDIR%\bin;%MSSDK%\bin;%VSCOMMON%;%PATH%
-Set INCLUDE=%MSSDK%\include;%VCDIR%\include;%INCLUDE%
-Set LIB=%MSSDK%\lib;%VCDIR%\lib;%LIB%
-cl.exe %*
-
-
-

Now, use something similar to

-
-
-cl.cmd "$(FULL_CURRENT_PATH)"
-
-
-

to compile your source file(s).

-

As you can see, the VC's environment is handled inside the 'cl.cmd' in this case. I.e. it is handled by the system (well, by cmd.exe) and not by NppExec.

-

3. Using ENV_SET

-

The initialization of environment variables for VC will look similar to the following:

-
-
// setting NppExec's internal (user) variables
-SET local VCDIR = C:\Program Files\Microsoft Visual Studio 8\VC
-SET local VSCOMMON = C:\Program Files\Microsoft Visual Studio 8\Common7\IDE
-SET local MSSDK = C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2
-
-// setting NppExec's child process'es environment variables
-// (due to "local", the previous values of the environment
-//  variables will be restored when this script ends)
-ENV_SET local PATH = $(VCDIR)\bin;$(MSSDK)\bin;$(VSCOMMON);$(SYS.PATH)
-ENV_SET local INCLUDE = $(MSSDK)\include;$(VCDIR)\include;$(SYS.INCLUDE)
-ENV_SET local LIB = $(MSSDK)\lib;$(VCDIR)\lib;$(SYS.LIB)
-
-// executing the child process with specified environment variables 
-rc /r /Fo"$(CURRENT_DIRECTORY)\Resources.res" "$(CURRENT_DIRECTORY)\Resources.rc"
-cl.exe "$(FULL_CURRENT_PATH)"
-
-
-

Don't forget that ENV_SET does not understand -such form of existing environment variables as "%PATH%" because NppExec does not accept such declaration. "$(SYS.PATH)" should be used instead of "%PATH%".

-

In general, it's not a good idea to set and then restore the environment every time it is needed by some tool. Instead, you can set all the required environment in NppExec's start-up script [4.2]. Such approach would allow you to use any of your tools without further specifying of full paths or additional environment variables.

-

4. Using ENV_SET, VS 10 + clang

-

[The text below was originally posted by Suman Kar in NppExec's forum.]

-

I have spent a good couple of hours getting this to work. Finally, I was able to coax NppExec, clang and Visual Studio to work together and let me compile my C snippets. The following script (along with "compile_or_run" described in the documentation [4.7.4]) worked for me:

-
-
// run@.cpp.txt
-
-// setting NppExec's internal (user) variables
-SET local VCBASE=C:\Program Files\Microsoft Visual Studio 10.0
-SET local VCDIR = $(VCBASE)\VC
-SET local VSCOMMON = $(VCBASE)\Common7\IDE
-SET local MSSDK = C:\Program Files\Microsoft SDKs\Windows\v7.0A
-
-// setting NppExec's child process'es environment variables
-// (due to "local", the previous values of the environment
-//  variables will be restored when this script ends)
-ENV_SET local PATH = $(VCDIR)\bin;$(MSSDK)\bin;$(VSCOMMON);$(SYS.PATH)
-ENV_SET local INCLUDE = $(MSSDK)\include;$(VCDIR)\include;$(SYS.INCLUDE)
-ENV_SET local LIB = $(MSSDK)\lib;$(VCDIR)\lib;$(SYS.LIB)
-
-// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-///! NOTE: change the following to the folder where your clang binary resides
-SET local clangc = D:\llvm_workspace\llvm\build\bin\Debug\clang.exe
-// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-SET local obj = $(CURRENT_DIRECTORY)\$(NAME_PART)
-
-// run clang
-"$(clangc)" "$(FULL_CURRENT_PATH)" -o "$(obj).exe"
-cmd /c "$(obj).exe"
-
-
-

Things to note: I am using Visual Studio 2010 (installed in C:\Program Files\) on a 32-bit Windows 7 box with NppExec 0.4.2.1 and my clang 3.0 binaries reside at D:\llvm_workspace\llvm\build\bin\Debug\ (built with Visual Studio 2010). You will need to change the appropriate paths in the script of course depending on your installation.

-

 

- - + + + + + +4.7.3. Using Visual Studio's compiler (cl.exe) + + + + +

4.7.3. Using Visual Studio's compiler (cl.exe)

+

If you want to run 'cl.exe' from NppExec, it requires some additional environment. Such environment can be set using a batch file or using NppExec's command ENV_SET [4.2].

+

1. Using a batch file (simple)

+

To use a simple batch file, create a file 'cl.cmd' with similar text:

+ +
+
+REM cl.cmd
+REM Visual Studio 2017 Community Edition
+@echo off
+call "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86
+cl.exe %*
+
+
+

Now, use NppExec's script similar to

+
+
NPE_CONSOLE local -- x+ // enable the built-in error highlight filter locally
+cl.cmd "$(FULL_CURRENT_PATH)"
+
+
+

to compile your source file(s).

+

2. Using a batch file (advanced)

+

To use an advanced batch file, create a file 'cl.cmd' with similar text:

+ +
+
+REM cl.cmd
+REM Visual Studio 8.0 (2005) Express
+@echo off
+Set VCDIR=C:\Program Files\Microsoft Visual Studio 8\VC
+Set VSCOMMON=C:\Program Files\Microsoft Visual Studio 8\Common7\IDE
+Set MSSDK=C:\Program Files\Microsoft Platform SDK for Windows Server 2003
+Set PATH=%VCDIR%\bin;%MSSDK%\bin;%VSCOMMON%;%PATH%
+Set INCLUDE=%MSSDK%\include;%VCDIR%\include;%INCLUDE%
+Set LIB=%MSSDK%\lib;%VCDIR%\lib;%LIB%
+cl.exe %*
+
+
+

Now, use NppExec's script similar to

+
+
NPE_CONSOLE local -- x+ // enable the built-in error highlight filter locally
+cl.cmd "$(FULL_CURRENT_PATH)"
+
+
+

to compile your source file(s).

+

As you can see, the VC's environment is handled inside the 'cl.cmd' in this case. I.e. it is handled by the system (well, by cmd.exe) and not by NppExec.

+

3. Using a running (interactive) VS Developer Command Prompt

+

The following NppExec's script can be used to run the Developer Command Prompt for VS 2022 in NppExec's Console:

+
+
set local @exit_cmd = exit  // sends "exit" when NppExec's Console is closed
+cmd /K "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x86
+
+

Now, while the VS Developer Command Prompt is running in NppExec's Console, it is possible to e.g. compile the current file via the following command in NppExec's Console:

+
+
cd /D "$(CURRENT_DIRECTORY)" && cl "$(FILE_NAME)"
+
+

4. Using ENV_SET

+

The initialization of environment variables for VC will look similar to the following:

+
+
// setting NppExec's internal (user) variables
+SET local VCDIR = C:\Program Files\Microsoft Visual Studio 8\VC
+SET local VSCOMMON = C:\Program Files\Microsoft Visual Studio 8\Common7\IDE
+SET local MSSDK = C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2
+
+// setting NppExec's child process'es environment variables
+// (due to "local", the previous values of the environment
+//  variables will be restored when this script ends)
+ENV_SET local PATH = $(VCDIR)\bin;$(MSSDK)\bin;$(VSCOMMON);$(SYS.PATH)
+ENV_SET local INCLUDE = $(MSSDK)\include;$(VCDIR)\include;$(SYS.INCLUDE)
+ENV_SET local LIB = $(MSSDK)\lib;$(VCDIR)\lib;$(SYS.LIB)
+
+// enabling the built-in error highlight filter locally
+NPE_CONSOLE local -- x+
+
+// executing the child process with specified environment variables 
+rc /r /Fo"$(CURRENT_DIRECTORY)\Resources.res" "$(CURRENT_DIRECTORY)\Resources.rc"
+cl.exe "$(FULL_CURRENT_PATH)"
+
+
+

Don't forget that ENV_SET does not understand +such form of existing environment variables as "%PATH%" because NppExec does not accept such declaration. "$(SYS.PATH)" should be used instead of "%PATH%".

+

In general, it's not a good idea to set and then restore the environment every time it is needed by some tool. Instead, you can set all the required environment in NppExec's start-up script [4.2]. Such approach would allow you to use any of your tools without further specifying of full paths or additional environment variables.

+

5. Using ENV_SET, VS 10 + clang

+

[The text below was originally posted by Suman Kar in NppExec's forum.]

+

I have spent a good couple of hours getting this to work. Finally, I was able to coax NppExec, clang and Visual Studio to work together and let me compile my C snippets. The following script (along with "compile_or_run" described in the documentation [4.7.4]) worked for me:

+
+
// run@.cpp.txt
+
+// setting NppExec's internal (user) variables
+SET local VCBASE=C:\Program Files\Microsoft Visual Studio 10.0
+SET local VCDIR = $(VCBASE)\VC
+SET local VSCOMMON = $(VCBASE)\Common7\IDE
+SET local MSSDK = C:\Program Files\Microsoft SDKs\Windows\v7.0A
+
+// setting NppExec's child process'es environment variables
+// (due to "local", the previous values of the environment
+//  variables will be restored when this script ends)
+ENV_SET local PATH = $(VCDIR)\bin;$(MSSDK)\bin;$(VSCOMMON);$(SYS.PATH)
+ENV_SET local INCLUDE = $(MSSDK)\include;$(VCDIR)\include;$(SYS.INCLUDE)
+ENV_SET local LIB = $(MSSDK)\lib;$(VCDIR)\lib;$(SYS.LIB)
+
+// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+///! NOTE: change the following to the folder where your clang binary resides
+SET local clangc = D:\llvm_workspace\llvm\build\bin\Debug\clang.exe
+// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+SET local obj = $(CURRENT_DIRECTORY)\$(NAME_PART)
+
+// enabling the built-in error highlight filter locally
+NPE_CONSOLE local -- x+
+
+// run clang
+"$(clangc)" "$(FULL_CURRENT_PATH)" -o "$(obj).exe"
+cmd /c "$(obj).exe"
+
+
+

Things to note: I am using Visual Studio 2010 (installed in C:\Program Files\) on a 32-bit Windows 7 box with NppExec 0.4.2.1 and my clang 3.0 binaries reside at D:\llvm_workspace\llvm\build\bin\Debug\ (built with Visual Studio 2010). You will need to change the appropriate paths in the script of course depending on your installation.

+

 

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.7.4.html b/docs/NppExec_Manual/4.7.4.html similarity index 80% rename from NppExec/doc/NppExec/NppExec_Manual/4.7.4.html rename to docs/NppExec_Manual/4.7.4.html index 91bcd86..16dff60 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.7.4.html +++ b/docs/NppExec_Manual/4.7.4.html @@ -1,23 +1,22 @@ - - - - - -4.7.4. Compiling ANY source file - - -

4.7.4. Compiling ANY source file

-

Compiling any source file using NppExec assumes the following:

-
-

- usage of external compilers/interpreters to compile (and run) your source file(s);

-

- creating specific NppExec's scripts for compiling (and running) specific source files;

-

- creating general NppExec's script which would allow to use different compilers/interpreters for different source files;

-

- usage of NppExec's Highlight filters to parse the compiler's/interpreter's output (warnings, errors etc).

-
-

You can find all this information - inside the file "NppExec_Guide.txt". Please - refer -to.

-

(But, before you proceed, be sure you do understand the section [4.0].)

- - + + + + + +4.7.4. Compiling ANY source file + + + +

4.7.4. Compiling ANY source file

+

Compiling any source file using NppExec assumes the following:

+
+

- usage of external compilers/interpreters to compile (and run) your source file(s);

+

- creating specific NppExec's scripts for compiling (and running) specific source files;

+

- creating general NppExec's script which would allow to use different compilers/interpreters for different source files;

+

- usage of NppExec's Highlight filters to parse the compiler's/interpreter's output (warnings, errors etc).

+
+

You can find all this information + inside the "NppExec_Guide". Please refer to.

+

(But, before you proceed, be sure you do understand the section [4.0].)

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.7.html b/docs/NppExec_Manual/4.7.html similarity index 60% rename from NppExec/doc/NppExec/NppExec_Manual/4.7.html rename to docs/NppExec_Manual/4.7.html index 3bea1ba..e0bc324 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.7.html +++ b/docs/NppExec_Manual/4.7.html @@ -1,11 +1,12 @@ - - - - - -4.7. Compiling - - -

4.7. Compiling

- - + + + + + +4.7. Compiling + + + +

4.7. Compiling

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.8.1.html b/docs/NppExec_Manual/4.8.1.html similarity index 95% rename from NppExec/doc/NppExec/NppExec_Manual/4.8.1.html rename to docs/NppExec_Manual/4.8.1.html index 785ca8a..4a18be3 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.8.1.html +++ b/docs/NppExec_Manual/4.8.1.html @@ -1,89 +1,90 @@ - - - - - -4.8.1. Logging - - -

4.8.1. Logging

-

According to "doc\NppExec\NppExec_TechInfo.txt", NppExec's logging can be enabled by specifying a 'LogsDir' parameter under the [Options] section of the "NppExec.ini".

-

The full path to the "NppExec.ini" configuration file can be obtained via

-
-
echo $(PLUGINS_CONFIG_DIR)
-
-

or even

-
-
npp_open $(PLUGINS_CONFIG_DIR)\NppExec.ini
-
-

To enable the logging, just add something similar to

-
-
LogsDir="NppExecLogs"
-
-

under the [Options] section of the "NppExec.ini".

-

Once it's done, restart Notepad++ and go to the folder "%TEMP%\NppExecLogs". It will contain a subfolder "NppExec" and a subfolder with the current date under it. You'll find the NppExec's log files there.

-

Here is a typical beginning of NppExec's log file:

-
-
22:00:17.618  7388  Log start >>
-22:00:17.618  7388  ; CNppExec::ReadOptions - start
-22:00:17.619  7388  ; CNppExec::ReadOptions - end
-22:00:17.619  7388  ; CNppExecCommandExecutor - started
-22:00:17.699  7388  ; NPPN_READY - start
-
-

The first column is the time in the format of hours:minutes:seconds.milliseconds. -The second column is the thread identifier (NppExec uses different threads to perform different activities, such as processing GUI commands, running collateral scripts, etc).

-

Here is a typical ending of NppExec's log file:

-
-
22:01:26.454  7388  ; NPPN_SHUTDOWN - end
-22:01:26.465  7388  ; CNppExecCommandExecutor: waiting for the ExecuteThreadDoneEvent...
-22:01:26.465  7388  ; CNppExecCommandExecutor - stopped
-22:01:26.467  7388  Log exit.
-
-

The absence of "Log exit." at the end of NppExec's log file (assuming Notepad++ had exited) would mean that either NppExec itself or Notepad++ in whole hung or crashed. -Such crash or hang could be caused by some other Notepad++'s plugin or, in more rare cases, by NppExec or Notepad++ itself. -If it was NppExec's fault, the last line of the log file at least shows the last successful activity before the hang or crash.

-

Note: NppExec's logger internally calls fflush() after each logged line. It may look excessive, but in case of a hang or a crash it helps to ensure that the log file does contain everything that could have been logged. -So it would definitely help with the investigation.

-

In general, NppExec's logging is a great help when something goes wrong or does not go as it was expected. -That is why there is a special command NPE_DEBUGLOG that enables NppExec's "logging" directly into NppExec's Console window. -This command does not create an output log file (unless the 'LogsDir' parameter is specified in the "NppExec.ini") - instead it prints detailed information about each NppExec's command activity to NppExec's Console. -This information is quite similar to what is (or would be) written to NppExec's log file, though NppExec's log file usually contains a little bit more information.

-

To enable this "debug logging", use

-
-
npe_debuglog on
-
-

or just

-
-
npe_debug 1
-
-

In this mode, NppExec also shows additional information when NppExec's hot-key is pressed and also when a line in NppExec's Console is double-clicked. -The latter allows to "debug" the Console Highlight Filters - as it shows the matched filter (if any) for the double-clicked line.

-

Example:

-
    -
  1. in Plugins -> NppExec -> Console Output Filters, specify e.g. "*error* : %FILE%" as one of the HighLight masks, check it to enable it, and press OK;
  2. -
  3. type "echo Some error : Some file name" in NppExec's Console and press Enter;
  4. -
  5. type "npe_debug 1" in NppExec's Console and press Enter;
  6. -
  7. double-click the previously printed line "Some error : Some file name".
  8. -
-

As the result, Notepad++ says that the file "Some file name" does not exist and proposes to create it. -Obviously you don't need to create this file as it was just a test :) -And here is what NppExec's Console shows:

-
-
; Console's line double-clicked
-; WarningAnalyzer info
-; {
-;    Input line: "Some error : Some file name"
-;    Match result: true
-;    Active filter: "*error* : %FILE%"
-;    * Parsed File Name: "Some file name"
-;    * Parsed Line Number: 
-;    * Parsed Char Position: 
-; }
-
- -
-
 
-
- - - + + + + + +4.8.1. Logging + + + +

4.8.1. Logging

+

According to "doc\NppExec\NppExec_TechInfo.txt", NppExec's logging can be enabled by specifying a 'LogsDir' parameter under the [Options] section of the "NppExec.ini".

+

The full path to the "NppExec.ini" configuration file can be obtained via

+
+
echo $(PLUGINS_CONFIG_DIR)
+
+

or even

+
+
npp_open $(PLUGINS_CONFIG_DIR)\NppExec.ini
+
+

To enable the logging, just add something similar to

+
+
LogsDir="NppExecLogs"
+
+

under the [Options] section of the "NppExec.ini".

+

Once it's done, restart Notepad++ and go to the folder "%TEMP%\NppExecLogs". It will contain a subfolder "NppExec" and a subfolder with the current date under it. You'll find the NppExec's log files there.

+

Here is a typical beginning of NppExec's log file:

+
+
22:00:17.618  7388  Log start >>
+22:00:17.618  7388  ; CNppExec::ReadOptions - start
+22:00:17.619  7388  ; CNppExec::ReadOptions - end
+22:00:17.619  7388  ; CNppExecCommandExecutor - started
+22:00:17.699  7388  ; NPPN_READY - start
+
+

The first column is the time in the format of hours:minutes:seconds.milliseconds. +The second column is the thread identifier (NppExec uses different threads to perform different activities, such as processing GUI commands, running collateral scripts, etc).

+

Here is a typical ending of NppExec's log file:

+
+
22:01:26.454  7388  ; NPPN_SHUTDOWN - end
+22:01:26.465  7388  ; CNppExecCommandExecutor: waiting for the ExecuteThreadDoneEvent...
+22:01:26.465  7388  ; CNppExecCommandExecutor - stopped
+22:01:26.467  7388  Log exit.
+
+

The absence of "Log exit." at the end of NppExec's log file (assuming Notepad++ had exited) would mean that either NppExec itself or Notepad++ in whole hung or crashed. +Such crash or hang could be caused by some other Notepad++'s plugin or, in more rare cases, by NppExec or Notepad++ itself. +If it was NppExec's fault, the last line of the log file at least shows the last successful activity before the hang or crash.

+

Note: NppExec's logger internally calls fflush() after each logged line. It may look excessive, but in case of a hang or a crash it helps to ensure that the log file does contain everything that could have been logged. +So it would definitely help with the investigation.

+

In general, NppExec's logging is a great help when something goes wrong or does not go as it was expected. +That is why there is a special command NPE_DEBUGLOG that enables NppExec's "logging" directly into NppExec's Console window. +This command does not create an output log file (unless the 'LogsDir' parameter is specified in the "NppExec.ini") - instead it prints detailed information about each NppExec's command activity to NppExec's Console. +This information is quite similar to what is (or would be) written to NppExec's log file, though NppExec's log file usually contains a little bit more information.

+

To enable this "debug logging", use

+
+
npe_debuglog on
+
+

or just

+
+
npe_debug 1
+
+

In this mode, NppExec also shows additional information when NppExec's hot-key is pressed and also when a line in NppExec's Console is double-clicked. +The latter allows to "debug" the Console Highlight Filters - as it shows the matched filter (if any) for the double-clicked line.

+

Example:

+
    +
  1. in Plugins -> NppExec -> Console Output Filters, specify e.g. "*error* : %FILE%" as one of the HighLight masks, check it to enable it, and press OK;
  2. +
  3. type "echo Some error : Some file name" in NppExec's Console and press Enter;
  4. +
  5. type "npe_debug 1" in NppExec's Console and press Enter;
  6. +
  7. double-click the previously printed line "Some error : Some file name".
  8. +
+

As the result, Notepad++ says that the file "Some file name" does not exist and proposes to create it. +Obviously you don't need to create this file as it was just a test :) +And here is what NppExec's Console shows:

+
+
; Console's line double-clicked
+; WarningAnalyzer info
+; {
+;    Input line: "Some error : Some file name"
+;    Match result: true
+;    Active filter: "*error* : %FILE%"
+;    * Parsed File Name: "Some file name"
+;    * Parsed Line Number: <none>
+;    * Parsed Char Position: <none>
+; }
+
+ +
+
 
+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.8.2.html b/docs/NppExec_Manual/4.8.2.html similarity index 95% rename from NppExec/doc/NppExec/NppExec_Manual/4.8.2.html rename to docs/NppExec_Manual/4.8.2.html index 962502b..43d7f51 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.8.2.html +++ b/docs/NppExec_Manual/4.8.2.html @@ -1,270 +1,271 @@ - - - - - -4.8.2. Collateral scripts - - -

4.8.2. Collateral scripts

- -

I think, the subject of collateral scripts in NppExec (introduced in NppExec v0.6) deserves a separate article. So let's do it. We'll start with simple examples, explain their background and then proceed to technical details of how it is implemented in NppExec.

-

Let's start from something easy. Type the following in NppExec's Console:

-
-
cmd
-
- -

and press Enter.

-

The cmd.exe is now running in NppExec's Console.

-

If now you type "cmd" once again, you'll have the first cmd.exe executing the second cmd.exe. But let's try something different. Now, with cmd.exe running, type the following in NppExec's Console:

-
-
nppexec:cmd
-
- -

The "nppexec:" prefix instructs NppExec to not pass this command to the running process (to cmd.exe in our case), but to execute it as NppExec's own command instead. Thus "nppexec:cmd" (executed from within an already running cmd.exe) differs from just "cmd" in the following way:

-
    -
  • just "cmd" is executed by means of the running process (i.e. by cmd.exe in our example);
  • -
  • "nppexec:cmd" is executed by NppExec itself;
  • -
  • just "cmd" makes the running instance of cmd.exe to start a new instance of cmd.exe and wait until this second instance is finished;
  • -
  • "nppexec:cmd" runs a _parallel_ instance of cmd.exe, while the previous instance of cmd.exe is still active in the background. This is what is called "collateral" in NppExec.
  • -
- -

Let's look at another, more advanced, example.

-

Consider the following Python program:

-
-
import time
-
-def run():
-    for i in xrange(5):
-        time.sleep(3)
-        print i
-
-run()
-
- -

This program is basically a cycle where integers from 0 to 4 are printed with an interval of 3 seconds.

-

Here is an equivalent program in C:

-
-
#include <stdio.h>
-#include <windows.h>
-
-void run()
-{
-    int i;
-    for (i = 0; i < 5; ++i)
-    {
-        Sleep(3000);
-        printf("%d\n", i);
-        fflush(stdout); // important! otherwise the output may be buffered inside a pipe
-    }
-}
-
-int main()
-{
-    run();
-    return 0;
-}
-
- -

The comment about a possible buffering inside a pipe relates to NppExec - because NppExec uses pipes to redirect the console process'es output and input. As I stated before, and I am still stating now, this "feature" of buffering in pipes is not something infused by or incorrectly handled by NppExec - it is a core "feature" of pipes as they were implemented by Microsoft. This is known for years - and still it has not been fixed. So do use fflush() whenever a program is expected to be run without a real console window (e.g. when it is run in NppExec).

-

Surely you need either Python or a C compiler installed on you machine to proceed. Or just create a similar program using any other language you prefer.

-

In case of Python, please be sure that the path to python.exe has been added to the PATH environment variable. In case of C, please ensure the path to a C compiler (such as Tiny C Compiler or GCC) has been added to the PATH environment variable. If you are not sure how to deal with the PATH environment variable, please search internet for this and ensure you do understand it prior to any further reading of this article. Here are a few links related to %PATH%, just in case:

-
-
https://en.wikipedia.org/wiki/PATH_(variable)
-https://ss64.com/nt/path.html
-
-

Also, be sure to check "Follow $(CURRENT_DIRECTORY)" in NppExec: select "Plugins" in Notepad++'s main menu, then "NppExec", then check "Follow $(CURRENT_DIRECTORY)".

- -

Now, in case of Python, type:

-
-
nppexec:python -u "$(FILE_NAME)"
-
- -

in NppExec's Console to run the Python program mentioned above. (I assume the Python program has been saved into a file, e.g. "test.py", and this file is currently opened in Notepad++.)

- -

In case of Tiny C Compiler, type:

-
-
nppexec:tcc -run "$(FILE_NAME)"
-
- -

In case of GCC, type:

-
-
nppexec:cmd /c gcc "$(FILE_NAME)" -o "$(NAME_PART).exe" && "$(NAME_PART).exe"
-
- -

And again, I assumed the C program has been saved into a file, e.g. "test.c", and this file is currently opened in Notepad++.

-

The "nppexec:" prefix here does not have any special meaning while nothing is currently running in NppExec's Console. But we'll need this prefix a little bit later. For the moment, though, you can just imagine this prefix is not present - or just do not type it actually.

-

Once you type one of the previously mentioned commands (or any other command applicable to another programming language you are using) and press Enter in NppExec's Console, here is the expected output:

- -
-
0
-1
-2
-3
-4
-================ READY ================
-
- -

Now, let's think about the following. There is an interval of 3 seconds between each output - and what if you want to run another NppExec's command during that time? This is where NppExec's collateral scripts come in handy.

-

Remember the initial command with the "nppexec:" prefix? Now here is the meaning of it: when there is an already running process in NppExec, and you want NppExec to execute NppExec's command _while working with this running process_, the "nppexec:" prefix tells NppExec to pass (give) this command to NppExec itself rather than to the running process. As this command will be executed at the same time as the running process is executing, it is a collateral command.

-

Let's do it in practice. Follow these steps:

-
    -
  1. Copy the command to the clipboard (e.g. the 'nppexec:python -u "$(FILE_NAME)"' command in case of Python);
  2. -
  3. Paste this command to NppExec's Console (via Ctrl+V) and press Enter;
  4. -
  5. Wait until "0" and "1" have been printed;
  6. -
  7. Now paste the same command again (via Ctrl+V) and press Enter.
  8. -
- -

As the interval between the output of the integers is 3 seconds, you need to be hurry with these last Ctrl+V and Enter.

-

Basically, this was the reason why I mentioned the "nppexec:" prefix before: to be able to copy the command to the clipboard in advance, and then just paste it from the clipboard.

-

The expected output will be similar to (in case of Python):

-
-
nppexec:python -u "$(FILE_NAME)"
-python -u "test.py"
-Process started (PID=1620) >>>
-0
-1
-nppexec:python -u "$(FILE_NAME)"
-python -u "test.py"
-Process started (PID=1776) >>>
-0
-1
-2
-3
-4
-<<< Process finished (PID=1776). (Exit code 0)
-2
-3
-4
-<<< Process finished (PID=1620). (Exit code 0)
-================ READY ================
-
- -

This is the output with "No internal messages" unchecked - in such way it's more clear where each process'es output is.

-

We can notice the following things here:

-
    -
  1. The first process'es output was not available in NppExec's Console while the second (collateral) process was running.
  2. -
  3. Once the second process has finished, the rest of the first process'es output was printed. This is what I call a "postponed output" - the output of a process that was running in the background.
  4. -
- -

You can run as many embedded collateral commands (with the "nppexec:" prefix) as you need. In terms of the example above, just press Ctrl+V and Enter while the second process is running, then press Ctrl+V and Enter while the third process is running, and so on. NppExec has no limitation in this.

-

NppExec's built-in help provides some other examples with the "nppexec:" prefix. Type one of the following in NppExec's Console:

- -
-
help npe_queue
-help proc_signal
-help @exit_cmd
-
- -

Now here is an interesting hint. In case of two running processes (as in the last example with Python above), it's clear that once the second process has printed "2", the first process in the background had already printed "4" and finished. And if you call the "Execute NppExec Script..." (F6 by default) now, NppExec allows you to do that even though the second process is still running in NppExec's Console! It's because only the first process was a "regular" command in terms of NppExec, whereas the second process was "collateral". And after the "regular" process has finished, the "Execute NppExec Script..." becomes available, disregarding the running "collateral" process. (Though, it may be changed in the future :))

-

So now let's discuss how it can be possible and how collateral commands are implemented in NppExec.

-

From NppExec v0.6, the core of NppExec is the CommandExecutor (the CNppExecCommandExecutor class). The CommandExecutor is responsible for execution of any CommandExecutor's Command (sounds logical, isn't it? ;)). In terms of the CommandExecutor, a Command is anything that can be initiated from the UI (user interface) and from NppExec's Plugin Interface. For example, an attempt to run any command in NppExec's Console is a CommandExecutor's Command; an attempt to run the "Execute NppExec Script..." (F6 by default) is also CommandExecutor's Command; an attempt to close NppExec's Console or to exit Notepad++ is also a CommandExecutor's Command. I'm writing "Command" from the capital letter to not confuse it with a command that can be entered in NppExec's Console or be a part of NppExec's script (by this "command" from the small letter I mean anything like "cmd", "help", "npp_console off" and so on).

-

Any CommandExecutor's Command has two methods: Execute() and Expire(). The method Expire() is called when the Command can not be started during ChildScript_SyncTimeout_ms time interval (it is 200 ms by default, refer to "NppExec_TechInfo.txt"). This can happen when another script or command is already running in NppExec's Console. The method Expire() invokes the method CanStartScriptOrCommand() that checks whether a running process (if any) can be exited. If it's possible, the method Execute() will be called. Otherwise the Command is marked as "expired" and will not be executed.

-

Here is how NppExec's log file looks like in case of a regular (non-collateral) command:

- -
-
; @Input Command: cmd
-; RunScriptCommand - create (instance = 0x320CBA8 @ 20:21:20.588)
-; RunScriptCommand - executing (instance = 0x320CBA8 @ 20:21:20.588)
-; CScriptEngine - create (instance = 0x32589B8 @ 20:21:20.589)
-; CScriptEngine::Run - start (instance = 0x32589B8 @ 20:21:20.589)
-
- -

Let's explain this. The RunScriptCommand is the CommandExecutor's Command responsible for running (executing) anything (any command) from NppExec's Console. This RunScriptCommand creates a CScriptEngine instance and delegates the actual execution of the command to it. It's because NppExec operates with NppExec's scripts, and even a single command is a NppExec's script (that consists of this single command). Another source of NppExec's scripts is the "Execute NppExec Script..." (F6 by default) that leads to the following in NppExec's log file:

- -
-
; Hot-key: executing function [0], "Execute NppExec Script..."
-; ExecDlgCommand - create (instance = 0xA53D50 @ 20:27:45.520)
-; ExecDlgCommand - executing (instance = 0xA53D50 @ 20:27:45.520)
-GetCmdType() { ... }
-; CScriptEngine - create (instance = 0xA59AC0 @ 20:27:51.815)
-; CScriptEngine::Run - start (instance = 0xA59AC0 @ 20:27:51.815)
-
- -

In this case we have the ExecDlgCommand responsible for the "Execute NppExec Script..." dialog. Also we have several extra lines related to "GetCmdType()" that pre-processes the NppExec's script obtained from the "Execute" dialog. But anyway, we do have a Command instance and a CScriptEngine instance.

-

CScriptEngine is responsible for the actual execution of the given NppExec's script (remember, NppExec's script can contain either several commands or a single command). So, what CScriptEngine does is it recognizes the command itself (via its getCmdType method), preprocesses the command arguments (via its modifyCommandLine method) and invokes one of its specific methods to finally execute the command of a known type.

-

So, let's repeat: in case of a regular (non-collateral) Command, the corresponding Command instance is created first (to initiate the execution of something), and then a CScriptEngine instance is created to execute the NppExec's script. Surely, we do not have a CScriptEngine instance in case of CloseConsoleCommand or NppExitCommand since these Commands are not associated with NppExec's script to be executed, but let's concentrate on the Commands that do.

-

By the way, as we already mentioned NppExec's log files here, let's say how to get them. Please refer to "NppExec_TechInfo.txt" and [4.8.1] for details.

-

Now, returning to our Commands and NppExec's scripts, let's see how NppExec's log file looks like in case of a collateral (non-regular) command:

- -
-
; @Child Process'es Input: nppexec:cmd
-CheckCmdAliases() { ... }
-; Executing a collateral script...
-; CScriptEngine - create (instance = 0xA59AC0 @ 20:50:10.710)
-; CScriptEngine::Run - start (instance = 0xA59AC0 @ 20:50:10.710)
-
- -

Did you notice that? Only an instance of a CScriptEngine is created, without any Command! It's because the collateral commands and scripts do not wait for the previous command/script to be finished - they are executed in parallel. To allow this, the CommandExecutor's method ExecuteCollateralScript() does the following:

-
    -
  1. creates a CScriptEngine instance (to execute NppExec's script);
  2. -
  3. executes this CScriptEngine instance in a separate thread.
  4. -
- -

Thus, the more collateral scripts, the more separate threads are running in NppExec, with its own instance of CScriptEngine in each thread.

-

Talking about threads, they are created in NppExec on demand. If no script/command was executed in NppExec yet, no thread is created.

-
    -
  • Once any Command needs to be executed, a thread for CNppExecCommandExecutor::BackgroundExecuteThreadFunc is created.
  • -
  • Once any Command is about to expire, a thread for CNppExecCommandExecutor::BackgroundExpiredThreadFunc is created.
  • -
  • Once any NppExec's script needs to send a notification via NppExec's Plugin Interface, a thread for BackgroundSendMsgThreadFunc is created.
  • -
  • Once NPEM_EXECUTE_COLLATERAL or NPEM_EXECUTE_QUEUED is received through NppExec's Plugin Interface, a thread for BackgroundExecAsyncCmdThreadFunc is created.
  • -
-

Too many threads, you might say. Probably, but the last 3 spend most of their time in WaitForMultipleObjects(2, waitEvents, FALSE, INFINITE) - i.e. in sleeping.

-

The BackgroundExecuteThreadFunc is the most active one, it is the place where Command->Execute() is called. Consequently, this is where a CScriptEngine instance is running for regular NppExec's scripts. And, as it was mentioned before, collateral NppExec's scripts are running in their own, separate, threads.

-

I think that's basically all about the collateral and regular scripts in NppExec.

- -
-
 
-
- -

Part 2. The prefixes "nppexec:" and "nppexec::".

- -

Now let's compare the prefixes "nppexec:" and "nppexec::" and highlight the differences between them.

- -

The prefix "nppexec:"

-
    -
  1. executes NppExec's scripts either normally (when nothing is currently running by NppExec) or in parallel (creating a new thread, when e.g. a child process is currently running by NppExec);
  2. -
  3. shares local variables with its parent NppExec's script.
  4. -
-

Thus, it's possible to do e.g.

-
-
nppexec:set local x = 10
-
-

from within a running instance of cmd.exe (in NppExec's Console), and then

-
-
nppexec:set local x
-
-

prints "local $(X) = 10". So such local variable is actually local for the parent NppExec's script, not for the collateral one.

-

And these are the main 2 differences between collateral scripts created via the "nppexec:" prefix and -via the NPEM_EXECUTE_COLLATERAL message (from NppExec's plugin interface):

-
    -
  1. NPEM_EXECUTE_COLLATERAL always executes NppExec's scripts in parallel (creating a new thread);
  2. -
  3. NPEM_EXECUTE_COLLATERAL never shares its local variables.
  4. -
-

And this is the exact description of what the "nppexec::" prefix (with double "::") does. The "nppexec::" prefix

-
    -
  1. always executes NppExec's scripts in parallel (creating a new thread);
  2. -
  3. never shares its local variables.
  4. -
-

In other words, the "nppexec::" prefix mirrors the behavior of the NPEM_EXECUTE_COLLATERAL message.

-

Thus, typing

-
-
nppexec::set local x = 10
-
-

and then

-
-
nppexec::set local x
-
-

prints "no user-defined local variables", and

-
-
set local x
-
-

prints "no such user's local variable: $(X)".

- -
-
 
-
- - - - + + + + + +4.8.2. Collateral scripts + + + +

4.8.2. Collateral scripts

+ +

I think, the subject of collateral scripts in NppExec (introduced in NppExec v0.6) deserves a separate article. So let's do it. We'll start with simple examples, explain their background and then proceed to technical details of how it is implemented in NppExec.

+

Let's start from something easy. Type the following in NppExec's Console:

+
+
cmd
+
+ +

and press Enter.

+

The cmd.exe is now running in NppExec's Console.

+

If now you type "cmd" once again, you'll have the first cmd.exe executing the second cmd.exe. But let's try something different. Now, with cmd.exe running, type the following in NppExec's Console:

+
+
nppexec:cmd
+
+ +

The "nppexec:" prefix instructs NppExec to not pass this command to the running process (to cmd.exe in our case), but to execute it as NppExec's own command instead. Thus "nppexec:cmd" (executed from within an already running cmd.exe) differs from just "cmd" in the following way:

+
    +
  • just "cmd" is executed by means of the running process (i.e. by cmd.exe in our example);
  • +
  • "nppexec:cmd" is executed by NppExec itself;
  • +
  • just "cmd" makes the running instance of cmd.exe to start a new instance of cmd.exe and wait until this second instance is finished;
  • +
  • "nppexec:cmd" runs a _parallel_ instance of cmd.exe, while the previous instance of cmd.exe is still active in the background. This is what is called "collateral" in NppExec.
  • +
+ +

Let's look at another, more advanced, example.

+

Consider the following Python program:

+
+
import time
+
+def run():
+    for i in xrange(5):
+        time.sleep(3)
+        print i
+
+run()
+
+ +

This program is basically a cycle where integers from 0 to 4 are printed with an interval of 3 seconds.

+

Here is an equivalent program in C:

+
+
#include <stdio.h>
+#include <windows.h>
+
+void run()
+{
+    int i;
+    for (i = 0; i < 5; ++i)
+    {
+        Sleep(3000);
+        printf("%d\n", i);
+        fflush(stdout); // important! otherwise the output may be buffered inside a pipe
+    }
+}
+
+int main()
+{
+    run();
+    return 0;
+}
+
+ +

The comment about a possible buffering inside a pipe relates to NppExec - because NppExec uses pipes to redirect the console process'es output and input. As I stated before, and I am still stating now, this "feature" of buffering in pipes is not something infused by or incorrectly handled by NppExec - it is a core "feature" of pipes as they were implemented by Microsoft. This is known for years - and still it has not been fixed. So do use fflush() whenever a program is expected to be run without a real console window (e.g. when it is run in NppExec).

+

Surely you need either Python or a C compiler installed on you machine to proceed. Or just create a similar program using any other language you prefer.

+

In case of Python, please be sure that the path to python.exe has been added to the PATH environment variable. In case of C, please ensure the path to a C compiler (such as Tiny C Compiler or GCC) has been added to the PATH environment variable. If you are not sure how to deal with the PATH environment variable, please search internet for this and ensure you do understand it prior to any further reading of this article. Here are a few links related to %PATH%, just in case:

+
    +
  • https://en.wikipedia.org/wiki/PATH_(variable)
  • +
  • https://ss64.com/nt/path.html
  • +
+

Also, be sure to check "Follow $(CURRENT_DIRECTORY)" in NppExec: select "Plugins" in Notepad++'s main menu, then "NppExec", then check "Follow $(CURRENT_DIRECTORY)".

+ +

Now, in case of Python, type:

+
+
nppexec:python -u "$(FILE_NAME)"
+
+ +

in NppExec's Console to run the Python program mentioned above. (I assume the Python program has been saved into a file, e.g. "test.py", and this file is currently opened in Notepad++.)

+ +

In case of Tiny C Compiler, type:

+
+
nppexec:tcc -run "$(FILE_NAME)"
+
+ +

In case of GCC, type:

+
+
nppexec:cmd /c gcc "$(FILE_NAME)" -o "$(NAME_PART).exe" && "$(NAME_PART).exe"
+
+ +

And again, I assumed the C program has been saved into a file, e.g. "test.c", and this file is currently opened in Notepad++.

+

The "nppexec:" prefix here does not have any special meaning while nothing is currently running in NppExec's Console. But we'll need this prefix a little bit later. For the moment, though, you can just imagine this prefix is not present - or just do not type it actually.

+

Once you type one of the previously mentioned commands (or any other command applicable to another programming language you are using) and press Enter in NppExec's Console, here is the expected output:

+ +
+
0
+1
+2
+3
+4
+================ READY ================
+
+ +

Now, let's think about the following. There is an interval of 3 seconds between each output - and what if you want to run another NppExec's command during that time? This is where NppExec's collateral scripts come in handy.

+

Remember the initial command with the "nppexec:" prefix? Now here is the meaning of it: when there is an already running process in NppExec, and you want NppExec to execute NppExec's command _while working with this running process_, the "nppexec:" prefix tells NppExec to pass (give) this command to NppExec itself rather than to the running process. As this command will be executed at the same time as the running process is executing, it is a collateral command.

+

Let's do it in practice. Follow these steps:

+
    +
  1. Copy the command to the clipboard (e.g. the 'nppexec:python -u "$(FILE_NAME)"' command in case of Python);
  2. +
  3. Paste this command to NppExec's Console (via Ctrl+V) and press Enter;
  4. +
  5. Wait until "0" and "1" have been printed;
  6. +
  7. Now paste the same command again (via Ctrl+V) and press Enter.
  8. +
+ +

As the interval between the output of the integers is 3 seconds, you need to be hurry with these last Ctrl+V and Enter.

+

Basically, this was the reason why I mentioned the "nppexec:" prefix before: to be able to copy the command to the clipboard in advance, and then just paste it from the clipboard.

+

The expected output will be similar to (in case of Python):

+
+
nppexec:python -u "$(FILE_NAME)"
+python -u "test.py"
+Process started (PID=1620) >>>
+0
+1
+nppexec:python -u "$(FILE_NAME)"
+python -u "test.py"
+Process started (PID=1776) >>>
+0
+1
+2
+3
+4
+<<< Process finished (PID=1776). (Exit code 0)
+2
+3
+4
+<<< Process finished (PID=1620). (Exit code 0)
+================ READY ================
+
+ +

This is the output with "No internal messages" unchecked - in such way it's more clear where each process'es output is.

+

We can notice the following things here:

+
    +
  1. The first process'es output was not available in NppExec's Console while the second (collateral) process was running.
  2. +
  3. Once the second process has finished, the rest of the first process'es output was printed. This is what I call a "postponed output" - the output of a process that was running in the background.
  4. +
+ +

You can run as many embedded collateral commands (with the "nppexec:" prefix) as you need. In terms of the example above, just press Ctrl+V and Enter while the second process is running, then press Ctrl+V and Enter while the third process is running, and so on. NppExec has no limitation in this.

+

NppExec's built-in help provides some other examples with the "nppexec:" prefix. Type one of the following in NppExec's Console:

+ +
+
help npe_queue
+help proc_signal
+help @exit_cmd
+
+ +

Now here is an interesting hint. In case of two running processes (as in the last example with Python above), it's clear that once the second process has printed "2", the first process in the background had already printed "4" and finished. And if you call the "Execute NppExec Script..." (F6 by default) now, NppExec allows you to do that even though the second process is still running in NppExec's Console! It's because only the first process was a "regular" command in terms of NppExec, whereas the second process was "collateral". And after the "regular" process has finished, the "Execute NppExec Script..." becomes available, disregarding the running "collateral" process. (Though, it may be changed in the future :))

+

So now let's discuss how it can be possible and how collateral commands are implemented in NppExec.

+

From NppExec v0.6, the core of NppExec is the CommandExecutor (the CNppExecCommandExecutor class). The CommandExecutor is responsible for execution of any CommandExecutor's Command (sounds logical, isn't it? ;)). In terms of the CommandExecutor, a Command is anything that can be initiated from the UI (user interface) and from NppExec's Plugin Interface. For example, an attempt to run any command in NppExec's Console is a CommandExecutor's Command; an attempt to run the "Execute NppExec Script..." (F6 by default) is also CommandExecutor's Command; an attempt to close NppExec's Console or to exit Notepad++ is also a CommandExecutor's Command. I'm writing "Command" from the capital letter to not confuse it with a command that can be entered in NppExec's Console or be a part of NppExec's script (by this "command" from the small letter I mean anything like "cmd", "help", "npp_console off" and so on).

+

Any CommandExecutor's Command has two methods: Execute() and Expire(). The method Expire() is called when the Command can not be started during ChildScript_SyncTimeout_ms time interval (it is 200 ms by default, refer to "NppExec_TechInfo.txt"). This can happen when another script or command is already running in NppExec's Console. The method Expire() invokes the method CanStartScriptOrCommand() that checks whether a running process (if any) can be exited. If it's possible, the method Execute() will be called. Otherwise the Command is marked as "expired" and will not be executed.

+

Here is how NppExec's log file looks like in case of a regular (non-collateral) command:

+ +
+
; @Input Command: cmd
+; RunScriptCommand - create (instance = 0x320CBA8 @ 20:21:20.588)
+; RunScriptCommand - executing (instance = 0x320CBA8 @ 20:21:20.588)
+; CScriptEngine - create (instance = 0x32589B8 @ 20:21:20.589)
+; CScriptEngine::Run - start (instance = 0x32589B8 @ 20:21:20.589)
+
+ +

Let's explain this. The RunScriptCommand is the CommandExecutor's Command responsible for running (executing) anything (any command) from NppExec's Console. This RunScriptCommand creates a CScriptEngine instance and delegates the actual execution of the command to it. It's because NppExec operates with NppExec's scripts, and even a single command is a NppExec's script (that consists of this single command). Another source of NppExec's scripts is the "Execute NppExec Script..." (F6 by default) that leads to the following in NppExec's log file:

+ +
+
; Hot-key: executing function [0], "Execute NppExec Script..."
+; ExecDlgCommand - create (instance = 0xA53D50 @ 20:27:45.520)
+; ExecDlgCommand - executing (instance = 0xA53D50 @ 20:27:45.520)
+GetCmdType() { ... }
+; CScriptEngine - create (instance = 0xA59AC0 @ 20:27:51.815)
+; CScriptEngine::Run - start (instance = 0xA59AC0 @ 20:27:51.815)
+
+ +

In this case we have the ExecDlgCommand responsible for the "Execute NppExec Script..." dialog. Also we have several extra lines related to "GetCmdType()" that pre-processes the NppExec's script obtained from the "Execute" dialog. But anyway, we do have a Command instance and a CScriptEngine instance.

+

CScriptEngine is responsible for the actual execution of the given NppExec's script (remember, NppExec's script can contain either several commands or a single command). So, what CScriptEngine does is it recognizes the command itself (via its getCmdType method), preprocesses the command arguments (via its modifyCommandLine method) and invokes one of its specific methods to finally execute the command of a known type.

+

So, let's repeat: in case of a regular (non-collateral) Command, the corresponding Command instance is created first (to initiate the execution of something), and then a CScriptEngine instance is created to execute the NppExec's script. Surely, we do not have a CScriptEngine instance in case of CloseConsoleCommand or NppExitCommand since these Commands are not associated with NppExec's script to be executed, but let's concentrate on the Commands that do.

+

By the way, as we already mentioned NppExec's log files here, let's say how to get them. Please refer to "NppExec_TechInfo.txt" and [4.8.1] for details.

+

Now, returning to our Commands and NppExec's scripts, let's see how NppExec's log file looks like in case of a collateral (non-regular) command:

+ +
+
; @Child Process'es Input: nppexec:cmd
+CheckCmdAliases() { ... }
+; Executing a collateral script...
+; CScriptEngine - create (instance = 0xA59AC0 @ 20:50:10.710)
+; CScriptEngine::Run - start (instance = 0xA59AC0 @ 20:50:10.710)
+
+ +

Did you notice that? Only an instance of a CScriptEngine is created, without any Command! It's because the collateral commands and scripts do not wait for the previous command/script to be finished - they are executed in parallel. To allow this, the CommandExecutor's method ExecuteCollateralScript() does the following:

+
    +
  1. creates a CScriptEngine instance (to execute NppExec's script);
  2. +
  3. executes this CScriptEngine instance in a separate thread.
  4. +
+ +

Thus, the more collateral scripts, the more separate threads are running in NppExec, with its own instance of CScriptEngine in each thread.

+

Talking about threads, they are created in NppExec on demand. If no script/command was executed in NppExec yet, no thread is created.

+
    +
  • Once any Command needs to be executed, a thread for CNppExecCommandExecutor::BackgroundExecuteThreadFunc is created.
  • +
  • Once any Command is about to expire, a thread for CNppExecCommandExecutor::BackgroundExpiredThreadFunc is created.
  • +
  • Once any NppExec's script needs to send a notification via NppExec's Plugin Interface, a thread for BackgroundSendMsgThreadFunc is created.
  • +
  • Once NPEM_EXECUTE_COLLATERAL or NPEM_EXECUTE_QUEUED is received through NppExec's Plugin Interface, a thread for BackgroundExecAsyncCmdThreadFunc is created.
  • +
+

Too many threads, you might say. Probably, but the last 3 spend most of their time in WaitForMultipleObjects(2, waitEvents, FALSE, INFINITE) - i.e. in sleeping.

+

The BackgroundExecuteThreadFunc is the most active one, it is the place where Command->Execute() is called. Consequently, this is where a CScriptEngine instance is running for regular NppExec's scripts. And, as it was mentioned before, collateral NppExec's scripts are running in their own, separate, threads.

+

I think that's basically all about the collateral and regular scripts in NppExec.

+ +
+
 
+
+ +

Part 2. The prefixes "nppexec:" and "nppexec::".

+ +

Now let's compare the prefixes "nppexec:" and "nppexec::" and highlight the differences between them.

+ +

The prefix "nppexec:"

+
    +
  1. executes NppExec's scripts either normally (when nothing is currently running by NppExec) or in parallel (creating a new thread, when e.g. a child process is currently running by NppExec);
  2. +
  3. shares local variables with its parent NppExec's script.
  4. +
+

Thus, it's possible to do e.g.

+
+
nppexec:set local x = 10
+
+

from within a running instance of cmd.exe (in NppExec's Console), and then

+
+
nppexec:set local x
+
+

prints "local $(X) = 10". So such local variable is actually local for the parent NppExec's script, not for the collateral one.

+

And these are the main 2 differences between collateral scripts created via the "nppexec:" prefix and +via the NPEM_EXECUTE_COLLATERAL message (from NppExec's plugin interface):

+
    +
  1. NPEM_EXECUTE_COLLATERAL always executes NppExec's scripts in parallel (creating a new thread);
  2. +
  3. NPEM_EXECUTE_COLLATERAL never shares its local variables.
  4. +
+

And this is the exact description of what the "nppexec::" prefix (with double "::") does. The "nppexec::" prefix

+
    +
  1. always executes NppExec's scripts in parallel (creating a new thread);
  2. +
  3. never shares its local variables.
  4. +
+

In other words, the "nppexec::" prefix mirrors the behavior of the NPEM_EXECUTE_COLLATERAL message.

+

Thus, typing

+
+
nppexec::set local x = 10
+
+

and then

+
+
nppexec::set local x
+
+

prints "no user-defined local variables", and

+
+
set local x
+
+

prints "no such user's local variable: $(X)".

+ +
+
 
+
+ + + + diff --git a/docs/NppExec_Manual/4.8.3.html b/docs/NppExec_Manual/4.8.3.html new file mode 100644 index 0000000..a9f153b --- /dev/null +++ b/docs/NppExec_Manual/4.8.3.html @@ -0,0 +1,218 @@ + + + + + +4.8.3. Console child process workflow + + + +

4.8.3. Console child process workflow

+ +

Well, let's follow all the steps of a child console process'es execution.

+ +

(1) In the beginning, there was an NppExec's script. The script's commands (which will be executed) are located inside `g_nppExec.m_ScriptCmdList` - bidirectional list of strings. Each string is a separate command.

+ +

(2) The CmdList (list of commands) is passed to the CNppExecCommandExecutor:

+ +
+
...
+CNppExecCommandExecutor::ScriptableCommand * pCommand =
+  new CNppExecCommandExecutor::DoRunScriptCommand(tstr(), CmdList, nRunFlags);
+GetCommandExecutor().ExecuteCommand(pCommand);
+...
+
+ +

and the method ExecuteCommand() simply adds the given Command to the queue:

+ +
+
m_ExecuteQueue.push_back( std::shared_ptr<Command>(cmd) );
+...
+m_ExecuteCmdEvent.Set();
+
+ +

(3) The thread BackgroundExecuteThreadFunc monitors the m_ExecuteQueue and executes the given command in this thread (thus, not in the main thread):

+ +
+
...
+auto& ExecuteQueue = pCommandExecutor->m_ExecuteQueue;
+isExecuteQueueEmpty = ExecuteQueue.empty();
+if ( !isExecuteQueueEmpty )
+    pCommand = ExecuteQueue.front();
+...
+if ( !isExecuteQueueEmpty )
+{
+    if ( pCommand )
+    {
+        if ( !pCommand->IsExpired() )
+            pCommand->Execute(); // pCommand contains the CmdList
+    }
+    ...
+}
+
+ +

(4) The pCommand->Execute() eventually calls CScriptEngine::Run() where all the commands from the CmdList are finally executed. You can ensure it by looking at the brief code of this method:

+ +
+
...
+CListItemT<tstr>* p = m_CmdList.GetFirst(); // first list item
+while ( p && ContinueExecution() )
+{
+    ...
+    S = p->GetItem(); // extract a string
+    if (S.length() > 0)
+    {
+        ...
+        nCmdType = ModifyCommandLine(this, S, ifState);
+        ...
+    }
+    p = (m_execState.pScriptLineNext == INVALID_TSTR_LIST_ITEM) ?
+      p->GetNext() : m_execState.pScriptLineNext; // next list item
+}
+...
+
+ +

The following line:

+ +
+
nCmdType = ModifyCommandLine(this, S, ifState);
+
+ +

returns an identifier of an internal command such as NPP_EXEC, NPP_RUN and so on. Also, it expands (substitutes the corresponding values) the variables such as $(FILE_NAME), $(NPP_DIRECTORY) and so on. And here is how the command `S` is executed:

+ +
+
m_nCmdType = nCmdType;
+...
+m_sCmdParams = S;
+EXECFUNC pCmdExecFunc = m_CommandRegistry.GetCmdExecFunc(m_nCmdType);
+nCmdResult = pCmdExecFunc(this, S);
+
+ +

(5) When the `nCmdType` is 0 (i.e. CMDTYPE_UNKNOWN), it means the following: the current string does not contain any internal NppExec's command, so it is interpreted as an external command - i.e. as a path to some executable file. Let's look at the corresponding method to which pCmdExecFunc points to in this case:

+ +
+
CScriptEngine::eCmdResult CScriptEngine::Do(const tstr& params)
+{
+    ...
+    std::shared_ptr<CChildProcess> proc(new CChildProcess(this));
+    ...
+    proc->Create(m_pNppExec->GetConsole().GetDialogWnd(), params.c_str())
+    ...
+}
+
+ +

As you can see, it calls the method CChildProcess::Create, where the `params` parameter is the passed value of `S` mentioned above. So, let's refer to CChildProcess::Create.

+ +

(6) The first intelligible thing inside CChildProcess::Create is a creation of the input/output pipes (m_hStd Input/Output Read/Write Pipe). These pipes are "information channels" between the NppExec plugin and a child process which will be created soon. Don't forget about the pipes - we'll return to them later. The second intelligible thing is actually the creation of a child process. Here is the corresponding code:

+ +
+
// initialize STARTUPINFO struct
+ZeroMemory(&si, sizeof(STARTUPINFO));
+si.cb = sizeof(STARTUPINFO);
+si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
+si.wShowWindow = SW_HIDE;
+si.hStdInput = m_hStdInReadPipe;    // pipe for user's input (stdin)
+si.hStdOutput = m_hStdOutWritePipe; // pipe for process'es stdout
+si.hStdError = m_hStdOutWritePipe;  // pipe for process'es stderr
+
+...
+tstr sCmdLine = cszCommandLine;
+...
+if ( ::CreateProcess(NULL, sCmdLine.c_str(), ...) )
+{
+    ...
+}
+
+ +

The second parameter of CChildProcess::Create (this parameter corresponds to `params` and `S` mentioned above) is passed to the system's function CreateProcess. This parameter is a path to an executable which will be run as a child process of the plugin.

+ +

(7) Now the child process is created. Let's assume it is a console process. As you remember, the whole CScriptEngine::Run() method is running in another thread, so this child process is created and handled in that thread also. The NppExec Console serves as the child console process'es output and input while this process is running. I.e. when you type some string in the ConsoleDlg's RichEdit control and press Enter, this string will be passed to the child process. You can find the corresponding code inside the "ConsoleDlg::OnNotify" function inside "DlgConsole.cpp". Search for "GetCommandExecutor().ExecuteChildProcessCommand". But let's return to the capturing of the child process'es output.

+ +

(8) This is the code of the capturing:

+ +
+
CStrT<char>  bufLine;  // a buffer for child process'es output
+bool         bPrevLineEmpty = false;
+bool         bDoOutputNext = true;
+int          nPrevState = 0;
+DWORD        dwRead = 0;
+...
+do
+{
+    dwRead = readPipesAndOutput(bufLine, bPrevLineEmpty, nPrevState, false, bDoOutputNext);
+    ...
+}
+while ( (isConsoleProcessRunning = (::WaitForSingleObject(m_ProcessInfo.hProcess, dwCycleTimeOut) == WAIT_TIMEOUT))
+         && m_pScriptEngine->ContinueExecution() && !isBreaking() );
+    // NOTE: time-out inside WaitForSingleObject() prevents from 100% CPU usage!
+
+if ( m_pScriptEngine->ContinueExecution() && (!isBreaking()) && !m_pScriptEngine->GetTriedExitCmd() )
+{
+    // maybe the child process is exited but not all its data is read
+    readPipesAndOutput(bufLine, bPrevLineEmpty, nPrevState, true, bDoOutputNext);
+}
+
+ +

We try to read data from the console process (by means of pipes) while the process is not finished and while the plugin's ConsoleDlg is visible. The "readPipesAndOutput" method actually does all the work about the capturing of the child console process'es output and showing this output in the ConsoleDlg.

+ +

(9) The whole "readPipesAndOutput" method can drive you crazy (I wrote this method by parts ;-)) but, in brief, it's very simple:

+ +
+
...
+do
+{
+    Sleep(10);  // it prevents from 100% CPU usage while reading!
+    dwBytesRead = 0;
+    if ( !::PeekNamedPipe(m_hStdOutReadPipe, NULL, 0, NULL, &dwBytesRead, NULL) )
+    {
+        dwBytesRead = 0;
+    }
+    ...
+    if ( (dwBytesRead > 0) || bOutputAll )
+    {
+        // some data is in the Pipe or bOutputAll==true
+
+        bool bContainsData = (dwBytesRead > 0) ? true : false;
+        // without bContainsData==true the ReadFile operation will never return
+
+        if ( bContainsData )
+            ::ZeroMemory(Buf, CONSOLEPIPE_BUFSIZE);
+        dwBytesRead = 0;
+        if ( (bContainsData
+              && ::ReadFile(m_hStdOutReadPipe, Buf, (CONSOLEPIPE_BUFSIZE-1)*sizeof(char), &dwBytesRead, NULL)
+              && (dwBytesRead > 0)) || bOutputAll )
+        {
+            // some data has been read from the Pipe or bOutputAll==true
+            ...
+        }
+    }
+}
+while ( (dwBytesRead > 0) && m_pScriptEngine->ContinueExecution() && !isBreaking() );
+
+ +

As you can see, at first we verify if there is something in the pipe:

+ +
+
::PeekNamedPipe(..., &dwBytesRead, ...)
+...
+bool bContainsData = (dwBytesRead > 0) ? true : false;
+
+ +

then we read the data:

+ +
+
ReadFile(...)
+
+ +

And here is the problem. Sometimes PeekNamedPipe returns FALSE or returns dwBytesRead == 0 though some data must be in the output pipe already.

+

As of July 2023, this issue with PeekNamedPipe is still relevant. PeekNamedPipe still sometimes returns FALSE or returns dwBytesRead == 0 when some data has already been written by the console child process to its output - and thus this data is expected to be present in the output pipe. But no, PeekNamedPipe returns FALSE or dwBytesRead == 0. And if we call ReadFile at that point, it just does not return until the pipe internally "decides" to give its data away. (And usually it happens when the child process either exits or calls fflush() internally. Unfortunately, NppExec can't control that from its side of the pipe).

+

This is relevant for Windows 2000, XP, Vista, 7, 8, 8.1, 10 and 11. Microsoft even introduced so-called PseudoConsole in Windows 10, but still has not fixed this buggy implementation of PeekNamedPipe.

+

This is the only reason of why sometimes you don't see any output in NppExec's Console while some output is expected. The data is inside the pipe's internal buffer and there is no way to get it from there. Sad but true.

+ + +
+
 
+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.8.html b/docs/NppExec_Manual/4.8.html similarity index 62% rename from NppExec/doc/NppExec/NppExec_Manual/4.8.html rename to docs/NppExec_Manual/4.8.html index e0a8b22..417836a 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.8.html +++ b/docs/NppExec_Manual/4.8.html @@ -1,11 +1,12 @@ - - - - - -4.8. Advanced details - - -

4.8. Advanced details

- - + + + + + +4.8. Advanced details + + + +

4.8. Advanced details

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/4.html b/docs/NppExec_Manual/4.html similarity index 54% rename from NppExec/doc/NppExec/NppExec_Manual/4.html rename to docs/NppExec_Manual/4.html index fb69f5f..d5b02cd 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/4.html +++ b/docs/NppExec_Manual/4.html @@ -1,11 +1,13 @@ - - - - - - - -

4. Advanced usage

-

 

- - + + + + + +4. Advanced usage + + + +

4. Advanced usage

+

 

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/5.html b/docs/NppExec_Manual/5.html similarity index 54% rename from NppExec/doc/NppExec/NppExec_Manual/5.html rename to docs/NppExec_Manual/5.html index 8faaf22..a3e972b 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/5.html +++ b/docs/NppExec_Manual/5.html @@ -1,11 +1,13 @@ - - - - - - - -

5. Other

-

 

- - + + + + + +5. Other + + + +

5. Other

+

 

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/About.html b/docs/NppExec_Manual/About.html similarity index 68% rename from NppExec/doc/NppExec/NppExec_Manual/About.html rename to docs/NppExec_Manual/About.html index c3a7bf2..004d1ff 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/About.html +++ b/docs/NppExec_Manual/About.html @@ -1,45 +1,55 @@ - - - - - -About - - -

About

- - - - - - - - - - - - - -
NppExecA plugin for Notepad++, developed by DV <dvv81 @ ukr.net>.
User Manual

The user manual for NppExec written by DV. Initially converted to the CHM format by Greg Webb.

-

Version history:

-
    -
  • 1.0 - April 2009
  • -
  • 1.1 - January 2010 (sections 4.6.3 and 4.6.4 added)
  • -
  • 1.2 - April 2010 (sections 3.7, 4.1 and 4.6.2 updated)
  • -
  • 1.3 - July 2010 (4.5, 4.6.2 and 4.6.3 updated; 4.6.5 and 4.6.6 added)
  • -
  • 1.4 - November 2011 (3.1, 3.4, 4.6.1 and 4.7.4 updated; 3.8.4, 4.0 and 4.6.7 added)
  • -
  • 1.5 - May 2012 (3.1 and 4.7.3 updated)
  • -
  • 1.6 - April 2013 (3.8.4 and About updated; 4.6.8 added)
  • -
  • 1.7 - January 2014 (2.1, 2.3, 3.1, 3.8.2, 4.6.1, 4.6.4, 4.7.1, 4.7.3, 'About' and 'NppExec_Guide' updated)
  • -
  • 1.8 - November 2014 (corrections in 3.7, 3.8.1, 4.2, 4.7.1)
  • -
  • 1.9 - February 2015 (3.4 updated; 4.6.9 added)
  • -
  • 2.0 - September 2015 (uses "style.css" now)
  • -
  • 2.1 - May 2018 (various sections slightly updated)
  • -
  • 2.2 - June 2018 (3.3, 4.4, 4.6.7 slightly updated; 4.6.10, 4.8.1 and 4.8.2 added)
  • -
  • 2.3 - April 2019 (clickable links, various sections slightly updated)
  • -
  • 2.4 - September 2020 (several "See also" references added; 1.1, 2.3, 2.5, 4.6.7 and 4.7.3 updated)
  • -
  • 2.5 - July 2021 (reflecting the latest changes; 'NppExec_Guide' updated; 3.8.5, 4.6.11 and 4.6.12 added)
  • -
Notepad++A generic source editor (text editor with advanced features for programmers) created by Don HO.
-

 

- - + + + + + +About + + + +

About

+ + + + + + + + + + + + + +
NppExecA plugin for Notepad++, developed by DV <dvv81 @ ukr.net>.
User Manual

The user manual for NppExec written by DV. Initially converted to the CHM format by Greg Webb.

+

Version history:

+
    +
  • 1.0 - April 2009
  • +
  • 1.1 - January 2010 (sections 4.6.3 and 4.6.4 added)
  • +
  • 1.2 - April 2010 (sections 3.7, 4.1 and 4.6.2 updated)
  • +
  • 1.3 - July 2010 (4.5, 4.6.2 and 4.6.3 updated; 4.6.5 and 4.6.6 added)
  • +
  • 1.4 - November 2011 (3.1, 3.4, 4.6.1 and 4.7.4 updated; 3.8.4, 4.0 and 4.6.7 added)
  • +
  • 1.5 - May 2012 (3.1 and 4.7.3 updated)
  • +
  • 1.6 - April 2013 (3.8.4 and About updated; 4.6.8 added)
  • +
  • 1.7 - January 2014 (2.1, 2.3, 3.1, 3.8.2, 4.6.1, 4.6.4, 4.7.1, 4.7.3, 'About' and 'NppExec_Guide' updated)
  • +
  • 1.8 - November 2014 (corrections in 3.7, 3.8.1, 4.2, 4.7.1)
  • +
  • 1.9 - February 2015 (3.4 updated; 4.6.9 added)
  • +
  • 2.0 - September 2015 (uses "style.css" now)
  • +
  • 2.1 - May 2018 (various sections slightly updated)
  • +
  • 2.2 - June 2018 (3.3, 4.4, 4.6.7 slightly updated; 4.6.10, 4.8.1 and 4.8.2 added)
  • +
  • 2.3 - April 2019 (clickable links, various sections slightly updated)
  • +
  • 2.4 - September 2020 (several "See also" references added; 1.1, 2.3, 2.5, 4.6.7 and 4.7.3 updated)
  • +
  • 2.5 - July 2021 (reflecting the latest changes; 'NppExec_Guide' updated; 3.8.5, 4.6.11 and 4.6.12 added)
  • +
  • 2.6 - February 2022 ('NppExec_Guide.txt' converted to HTML and updated; 3.4, 4.2, 4.6.8, 4.7.1, 4.7.2, 4.7.3 updated)
  • +
  • 2.7 - April 2022 (1.2 and 3.5 updated)
  • +
  • 2.8 - June 2022 (4.6.13 added; 4.6.8 updated; `META NAME="Generator"` removed)
  • +
  • 2.9 - June 2023 (3.8.5 updated; `!DOCTYPE` nodes added, `lang` attribute added for `HTML` nodes)
  • +
  • 3.0 - August 2023 (4.6.14, 4.6.15 and 4.8.3 added; 4.6.3, 4.6.4, 4.7.1 and NppExec_Guide updated)
  • +
  • 3.1 - September 2023 (2.4, 3.7, 3.8.4, 4.1, 4.6.4 and 4.7.3 updated; 4.6.16 and 4.6.17 added)
  • +
  • 3.2 - January 2024 (FAQ added)
  • +
  • 3.3 - June 2025 (4.6.18 added; 4.6.8 updated)
  • +
  • 3.4 - October 2025 (3.9, 4.6.19 and 4.6.20 added)
  • +
Notepad++A generic source editor (text editor with advanced features for programmers) created by Don HO.
+

 

+ + diff --git a/NppExec/doc/NppExec/NppExec_Manual/Acknowledgment.html b/docs/NppExec_Manual/Acknowledgment.html similarity index 63% rename from NppExec/doc/NppExec/NppExec_Manual/Acknowledgment.html rename to docs/NppExec_Manual/Acknowledgment.html index c5ef07f..2b99081 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/Acknowledgment.html +++ b/docs/NppExec_Manual/Acknowledgment.html @@ -1,16 +1,18 @@ - - - - - -Acknowledgment - - -

Acknowledgments

-
    -
  1. This CHM file has been created with HTML Help Workshop.
  2. -
  3. Thanks to Greg Webb for converting the original text (ver.1.0) from Keynote to CHM.
  4. -
  5. Thanks to NppExec's users who inspired some parts of this Manual.
  6. -
- - + + + + + +Acknowledgment + + + +

Acknowledgments

+
    +
  1. This CHM file has been created with HTML Help Workshop.
  2. +
  3. Thanks to Greg Webb for converting the original text (ver.1.0) from Keynote to CHM.
  4. +
  5. Thanks to NppExec's users who inspired some parts of this Manual.
  6. +
  7. Thanks to Joseph Samuel and rdipardo for bringing the Manual online: https://d0vgan.github.io/nppexec/
  8. +
+ + diff --git a/docs/NppExec_Manual/FAQ.html b/docs/NppExec_Manual/FAQ.html new file mode 100644 index 0000000..cbd31cc --- /dev/null +++ b/docs/NppExec_Manual/FAQ.html @@ -0,0 +1,120 @@ + + + + + +FAQ (Frequently Asked Questions) + + + + +

FAQ (Frequently Asked Questions)

+ +

Q1. Why program output is wrong in NppExec?

+

To answer this question, let's mention the most common problems one may face in NppExec's Console first:

+
    +
  • NppExec's Console does not show any output until a program exits;
  • +
  • NppExec's Console does not show any prompt when a program waits for user input;
  • +
  • NppExec's Console shows program's output with incorrect indentations or colors;
  • +
  • NppExec's Console shows program's output with unexpected characters;
  • +
  • NppExec's Console shows program's output with stdout and stderr mixed.
  • +
+

Looking at this list, you are surely thinking: quite a few problems, man! Why have you introduced them?

+

Well, I can assure you: this is not something intended. This is a limitation of the technique that NppExec uses to capture program's output.

+

In short, NppExec does not use a real console (also known as "terminal"). Instead, NppExec uses pipes to "communicate" with an external program. And sometimes, depending on a program, these pipes do not work as expected. Technical details are explained in [4.8.3], from the point (6).

+

Fortunately, there are workarounds for these issues which are explained below, in Q3.

+

 

+ +

Q2. Why NppExec does not use real console (terminal)?

+

Very good question!

+

I'll try to give a good answer.

+

The main purpose of NppExec is its deep integration with Notepad++. NppExec achieves it by:

+
    +
  • supporting Notepad++'s and own variables such as $(FILE_NAME), $(CWD) and so on;
  • +
  • supporting various commands such as npp_save, sci_sendmsg and so on;
  • +
  • working with the text in Notepad++'s editing window (also with the selected text);
  • +
  • invoking external programs to alter the text in Notepad++'s editing window;
  • +
  • highlighting warnings and errors in a program's output;
  • +
  • automate certain actions in Notepad++ by means of NppExec's scripts.
  • +
+

All of the above is not possible in a real console. Because there is no connection between a real console and Notepad++. A real console does not know anything about $(FILE_NAME); it can't save a file in Notepad++; it can not alter the text selected in Notepad++; it can not produce clickable warnings and errors allowing to go to the corresponding file and line in Notepad++. And so on. Different tools, different abilities.

+

So, NppExec provides some benefits with respect to integration with Notepad++, but lacks some benefits of the real console. Well, some sort of trade-off.

+

 

+ +

Q3. How can I get proper program output in NppExec?

+

The short answer is: run this program using the system's command-line interpreter which is cmd.exe. As NppExec lacks the features of the real console, the logical solution is to execute a program in a separate console window.

+

There are two ways to achieve this:

+

1. Using npp_run:

+
+
npp_run program.exe
+
+

This runs a program program.exe in a separate window (not in NppExec's Console). In this case, NppExec does not have any control over the program.exe - it does not know if the program is running or has it finished.

+

To run the program with arguments such as arg1 and arg 2, use:

+
+
npp_run program.exe arg1 "arg 2"
+
+

2. Using cmd /C start /wait:

+
+
cmd /C start /wait "some title" program.exe
+
+

In this case, cmd itself is running within NppExec's Console, so NppExec waits until the cmd is finished. In the same time, start /wait instructs the cmd to run the program.exe in a separate window and wait until the program.exe is finished.

+

Correspondingly, we have the program.exe running in its own window and NppExec's Console waiting for the program.exe to finish. This is the advantage of cmd /C start /wait over npp_run.

+

The "some title" is the title of the console window started by the cmd /C start /wait.

+

To run the program with arguments such as arg1 and arg 2, use:

+
+
cmd /C start /wait "some title" program.exe arg1 "arg 2"
+
+

Now, what if program.exe exits too fast - and, instead, we want its console output to remain until we read it? In such case, we are adding another explicit usage of cmd /C, this time calling it with pause:

+
+
cmd /C start /wait "some title" cmd /C "program.exe arg1 "arg 2" && pause"
+
+

Finally, let's consider a more complicated scenario. What if we want to compile a file currently opened in Notepad++ and then to run the produced executable with some arguments? To do that, the following commands can be used:

+
+
npp_save  // save the current file
+cd $(CURRENT_DIRECTORY)  // cd to the directory of the current file
+npe_console local -- x+  // enable the built-in error highlight filter
+compiler.exe "$(FILE_NAME)"  // compile the current file in NppExec's Console
+if $(EXITCODE) != 0 then  // check the compiler's exit code
+  exit  // the compiler did not succeed, no sense to continue
+endif
+cmd /C start /wait "$(NAME_PART)" "$(NAME_PART).exe" arg1 "arg 2"  // run the compiled file
+npp_setfocus con  // return the focus back to NppExec's Console
+
+

The sequence of the commands above is called NppExec's script [3.7].

+

To run the compiled file (executable) and preserve its console output, use the same technique with cmd /C and pause as shown above:

+
+
cmd /C start /wait "$(NAME_PART)" cmd /C ""$(NAME_PART).exe" arg1 "arg 2" && pause"
+
+

 

+ +

Q4. Why output redirection and command chaining do not work in NppExec?

+

They actually work by means of the system's command-line interpreter which is cmd.exe.

+

For example:

+
+
cmd /C program.exe >program.txt
+
+

and also:

+
+
cmd /C start /wait "example" cmd /C "echo Hello world! && pause"
+
+

See more examples in [4.4].

+

 

+ +

Q5. How can I compile my source code in NppExec?

+

In short, you need two things: a proper compiler for your programming language and a proper way of using this compiler by means of NppExec.

+

In general, each programming language and each compiler requires its own approach. The Q3 above briefly mentions a template of NppExec's script [3.7] that compiles the current file and runs the produced executable.

+

Please refer to other sections of the NppExec Manual to get an idea of how to compile the source code for the programming language you are interested in. In particular:

+
    +
  • Introduction to compiling/interpreting/etc. [4.0];
  • +
  • Running Python & wxPython [4.6.4];
  • +
  • Run and terminate PowerShell process [4.6.7];
  • +
  • Running Lua [4.6.10];
  • +
  • Compiling simple C and Pas-programs [4.7.1];
  • +
  • Compiling Java [4.7.2];
  • +
  • Using Visual Studio's compiler (cl.exe) [4.7.3];
  • +
  • Compiling ANY source file [4.7.4].
  • +
+

 

+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/NppExec Manual.html b/docs/NppExec_Manual/NppExec Manual.html similarity index 68% rename from NppExec/doc/NppExec/NppExec_Manual/NppExec Manual.html rename to docs/NppExec_Manual/NppExec Manual.html index 18c7f15..0df33e5 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/NppExec Manual.html +++ b/docs/NppExec_Manual/NppExec Manual.html @@ -1,12 +1,14 @@ - - - - - -NppExec Manual - - -

NppExec Manual

-

 

- - + + + + + + +NppExec Manual + + + +

NppExec Manual

+

 

+ + diff --git a/docs/NppExec_Manual/NppExec_Guide.html b/docs/NppExec_Manual/NppExec_Guide.html new file mode 100644 index 0000000..03459fc --- /dev/null +++ b/docs/NppExec_Manual/NppExec_Guide.html @@ -0,0 +1,397 @@ + + + + + +Guide: Using NppExec to compile sources with associated compilers + + + +

Guide: Using NppExec to compile sources with associated compilers

+ + +

As a Notepad++ user, did you ever think about ability to compile your source +file with its associated compiler in a single action?

+

You may use the NppExec plugin to perform certain actions on your files, but +what about the automatization? What if you want your .c files to be compiled +with tcc, .cpp files to be compiled with g++ and .awk files to be interpretted +with gawk automatically, without explicit call to required compiler or +interpreter? Is it possible?

+

Yes, NppExec already allows you to do this. All you need is some imagination +and several things to do. And I'm about to tell what is needed.

+ +
+ +

Let's begin with several theoretical questions.

+

At first, how can NppExec understand which compiler/interpreter is required +by your current source file? NppExec is not a compiler, it does not have +any information about your file and does not know what to do with it.

+

Moreover, Notepad++ itself is not such IDE as Visual Studio or Dev-C++, +it does not include any compiler and also does not know what to do with your +source file.

+

So, the only way to compile your source file with required compiler is to tell +Notepad++ (to tell NppExec in our case) which compiler to use and how to +use it.

+

This is the solution which you may use already - explicit usage of certain +compiler/interpreter with certain source file. For example, you may want to +compile and run your .c source file with tcc (Tiny C Compiler). A simple NppExec's script can +be created for this purpose:

+ +
+
"C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)"
+
+ +

The full path "C:\tools\tcc\tcc.exe" specifies a path to required compiler; +Notepad++'es environment variable "$(FULL_CURRENT_PATH)" specifies full path +name to your current source file; and "-run" in tcc's command line means +"run compiled source". The full path was given in quotes, because, in general, +it can contain spaces.

+

Now, we are talking about NppExec's script. This assumes the script has been +created and saved with some name which identified that script. If you are +not sure about NppExec's script creation & saving, let me guide you.

+ +
+ +

To create & save some NppExec's script, do the following:

+

1) Open the "Execute NppExec Script..." window: press the hotkey (F6) or + select (main menu) Plugins -> NppExec -> Execute NppExec Script...

+

2) Type the text of your script in the "Execute NppExec Script..." window. + For example:

+ +
+
"C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)"
+
+ +

3) Save this new script: press the "Save..." button, type your script name + (for example, type "run@.c") and press Save.

+ +
+ +

Now you can compile & run any single .c file opened in Notepad++. To do it, +press F6 (default hotkey for the "Execute NppExec Script..." window), select +"run@.c" in the combo-box and press OK.

+

You can press Ctrl+F6 (by default) to execute the same script again without +showing the "Execute NppExec Script..." window.

+ +
+ +

As you can see, currently you have to call the "run@.c" script explicitly +in order to compile & run your .c source file. Thus, to compile & run +another source file (.cpp, .asm, .php, .lua, ...) you also have to call +corresponding script explicitly. [The last sentence assumes you have created +separate scripts for every language you use (.cpp, .asm, .php, .lua, ...)].

+

However, we don't want to call required script explicitly. We want NppExec +to call the "run@.c" script for a .c file and call different script required +for different (.cpp, .asm, .php, .lua, ...) file automatically.

+

So, a question: how can we do it?

+

The first part of the answer is in your source file's extension. There is +such environment varible as $(EXT_PART) which contains the extension of +current file opened in Notepad++.

+

The second part of the answer is in NppExec's internal command NPP_EXEC. +As you probably know already, this command expects an existing script name +or a script file name as its first argument. The purpose of this command is +to execute specified NppExec's script.

+

Thus, if you use NPP_EXEC command, and its first argument (a script to be +executed) depends on current file's extension, you can call different scripts +for different file types from one starting script!

+

Let's examine it in more detail.

+ +
+ +

We are about to create a general NppExec's script which would allow us to +call different scripts for different source files depending on their extension. +In other words, we use the NPP_EXEC command to call required script, and the +script name depends on current file's extension.

+

The name of the script above, +"run@.c", consists of two parts: the prefix "run@" and the extension ".c".

+

As the file's extension can be got from Notepad++, we can write general form +of this script's name: "run@$(EXT_PART)".

+

It's not hard to understand that this script's name transforms to "run@.cpp" +for .cpp source file, "run@.lua" for .lua source file and so on.

+

So, let's create our general compile-or-run script which will be called each +time you want to compile or run any source file:

+ +
+
// save current file
+NPP_SAVE
+// construct the script name to be called
+SET Compiler = run@$(EXT_PART)
+// enable the built-in error highlight filter locally
+NPE_CONSOLE local -- x+
+// call the script
+NPP_EXEC "$(Compiler)"
+
+ +

Save this script as "compile_or_run". Now this is your only starting script +which will allow you to compile or run any source file. I.e. press F6, select +the "compile_or_run" and press OK in order to compile or run any source file.

+

However, don't forget that this script requires existing scripts for every +source file you want to compile. Thus, "run@.cpp" must exist to compile a .cpp +file, "run@.php" must exist to compile a .php file and so on.

+

You can see several examples of such scripts below:

+ +
+
// run@.c
+"C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)"
+
+// run@.cpp
+SET local g++ = C:\Dev-Cpp\bin\g++.exe
+SET local obj = $(CURRENT_DIRECTORY)\$(NAME_PART)
+"$(g++)" -c "$(FULL_CURRENT_PATH)" -o "$(obj).o"
+"$(g++)" "$(obj).o" -o "$(obj).exe"
+NPP_RUN "$(obj).exe"
+
+// run@.awk
+"C:\tools\gawk\gawk.exe" -f "$(FULL_CURRENT_PATH)"
+
+ +

All of these scripts will be started automatically from the "compile_or_run" +script for .c, .cpp and .awk files. You can create more "run@..." scripts to +support any source file extension you use.

+ +
+ +

Now, let's return to our "compile_or_run" script. It uses the NPP_EXEC command +which supports a script file name as its first argument. What does it mean?

+

It means you can execute NppExec's script from a file.

+

As you can see, current implementation of the "compile_or_run" script requires +a lot of additional "run@..." scripts to exist together with other scripts +which you may want to call explicitly. In the same time, you do not call the +"run@..." scripts explicitly. So, the "run@..." scripts may be undesired in +the NppExec's script combo-box (in the "Execute NppExec Script..." window).

+

Thus, you may modify the "compile_or_run" script in order to call script files +instead of internal scripts. For example:

+ +
+
// compile_or_run
+NPP_SAVE
+SET Compiler = C:\tools\NppExec Scripts\run@$(EXT_PART).txt
+NPE_CONSOLE local -- x+
+NPP_EXEC "$(Compiler)"
+
+ +

Now you need to create a directory "C:\tools\NppExec Scripts" which will contain +the following files: "run@.c.txt", "run@.cpp.txt", "run@.awk.txt"and so on.

+

The text of these files will be exactly the same as in the scripts "run@.c", +"run@.cpp" and "run@.awk" above.

+

E.g. the file "C:\tools\NppExec Scripts\run@.awk.txt" must contain

+ +
+
"C:\tools\gawk\gawk.exe" -f "$(FULL_CURRENT_PATH)"
+
+ +

and so on for other file extensions (.c, .cpp, ...).

+

Similarly, the path to your NppExec Scripts can be relative to Notepad++.

+

For example:

+ +
+
// compile_or_run
+NPP_SAVE
+SET Compiler = $(NPP_DIRECTORY)\NppExec Scripts\run@$(EXT_PART).txt
+NPE_CONSOLE local -- x+
+NPP_EXEC "$(Compiler)"
+
+ +

or

+ +
+
// compile_or_run
+NPP_SAVE
+SET Compiler = $(PLUGINS_CONFIG_DIR)\NppExec Scripts\run@$(EXT_PART).txt
+NPE_CONSOLE local -- x+
+NPP_EXEC "$(Compiler)"
+
+ +

Such approach allows to use external text files as the NppExec Scripts, while +they are always available since they reside in Notepad++'s folder.

+

To read more information about the NPP_EXEC command, open the NppExec's +Console in Notepad++, and type:

+ +
+
help npp_exec
+
+ +

and press Enter.

+

To read more information about the NPE_CONSOLE command, type:

+ +
+
help npe_console
+
+ +

and press Enter.

+

To get general NppExec's help information, type just

+ +
+
help
+
+ +

and press Enter.

+ +
+ +

You may have noticed, that the script "compile_or_run" uses a non-local +variable $(Compiler), such as:

+ +
+
SET Compiler = run@$(EXT_PART)
+
+ +

Though, in general, it is recommended to use a local variable, e.g.

+ +
+
SET local Compiler = run@$(EXT_PART)
+
+ +

Local variables, unlike non-local ones, are automatically deleted at the end +of the script where they were created. (So you don't have to use the UNSET +command for local variables at the end of your script.)

+

So, why the variable $(Compiler) is not a local one?

+

Consider a situation when the "run@..." script does not do what you expected +it to. In such case, you probably want to examine this script and correct it, +right? And here is when the existing variable $(Compiler) becomes useful! As +this variable holds the name of (or the path to) the just executed "run@..." +script, it's easy to see what exact "run@..." script needs to be examined.

+

Just type one the following in NppExec's Console:

+ +
+
// to show the "run@..." script's name:
+echo $(Compiler)
+
+// to open the "run@..." script from a physical file:
+NPP_OPEN $(Compiler)
+
+ +
+ +

Starting from NppExec v0.6 alpha 1, IF...ELSE IF...ELSE...ENDIF sequences are +supported in NppExec's scripts (see "help if").

+

It means we can create a single NppExec's script that will deal with all the +file types we want.

+

For example:

+ +
+
// setting internal messages off, error highlight filter on
+NPE_CONSOLE local m- x+ --
+// saving current file
+NPP_SAVE
+// file extension in lower case
+set local ext ~ strlower $(EXT_PART)
+// compiling/running...
+if $(ext) == .c
+  "C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)"
+else if $(ext) == .cpp
+  env_set local PATH = $(path);C:\mingw32\bin;
+  set local obj = $(CURRENT_DIRECTORY)\$(NAME_PART)
+  cmd /C del "$(obj).o" 2>nul & del "$(obj).exe" 2>nul
+  echo Compiling...
+  "g++" -c "$(FULL_CURRENT_PATH)"
+  if $(EXITCODE) == 0
+    "g++" "$(obj).o" -o "$(obj).exe"
+    echo Running...
+    NPP_RUN cmd /C if exist "$(obj).exe" "$(obj).exe" && echo. && pause
+  endif
+else if $(ext) == .awk
+  "C:\tools\gawk\gawk.exe" -f "$(FULL_CURRENT_PATH)"
+else
+  messagebox "Unknown file type!"
+endif
+
+ +

Such a single script includes everything in one place. On the one hand, it's nice to have everything in one place. On the other hand, it will create issues with maintenance and performance in the future.

+

Maintenance. As time goes by, more and more file types (languages) will be added to this single script. The script will grow - and it will be harder and harder to find some exact things within the script. Moreover, if different parts of the script will share some common functionality (or, at least, some common variables) and you'll decide to make changes to the common functionality at some point, it will most likely lead to unexpected effects in different places. (For example, you may want some change to affect only certain languages, but in fact it will affect more of them). So, the bigger the script will become, the more accurate you'll need to be with each single change within the script.

+

Performance. The bigger the script will become, the more time NppExec will need to process the entire script. The good thing is: NppExec's engine is internally fast enough to handle very big scripts without a noticeable delay. The bad thing is: NppExec's user interface (the NppExec Console) is very slow when there are a lot of messages to be printed. Here are the good news: it's easy to reduce the number of messages to be printed in NppExec's Console - and thus to enhance the overall performance. The presense of "NPE_CONSOLE local m-" in the beginning of the script already reduces the number of messages NppExec prints to its Console. Going further, you can explicitly specify when to disable and enable NppExec's output, thus having a complete manual control of when NppExec prints something to its Console and when it does not. Just notice that you'll need to update each IF-ELSE block to achieve that:

+ +
+
// disabling any output to NppExec's Console
+NPP_CONSOLE local -
+// setting internal messages off, error highlight filter on
+NPE_CONSOLE local m- x+ --
+// saving current file
+NPP_SAVE
+// file extension in lower case
+set local ext ~ strlower $(EXT_PART)
+// compiling/running...
+if $(ext) == .c
+  NPP_CONSOLE local +  // enabling output to NppExec's Console
+  "C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)"
+else if $(ext) == .cpp
+  env_set local PATH = $(path);C:\mingw32\bin;
+  set local obj = $(CURRENT_DIRECTORY)\$(NAME_PART)
+  cmd /C del "$(obj).o" 2>nul & del "$(obj).exe" 2>nul
+  NPP_CONSOLE local +  // enabling output to NppExec's Console
+  echo Compiling...
+  "g++" -c "$(FULL_CURRENT_PATH)"
+  if $(EXITCODE) == 0
+    "g++" "$(obj).o" -o "$(obj).exe"
+    echo Running...
+    NPP_RUN cmd /C if exist "$(obj).exe" "$(obj).exe" && echo. && pause
+  endif
+else if $(ext) == .awk
+  NPP_CONSOLE local +  // enabling output to NppExec's Console
+  "C:\tools\gawk\gawk.exe" -f "$(FULL_CURRENT_PATH)"
+else
+  NPP_CONSOLE local +  // enabling output to NppExec's Console
+  messagebox "Unknown file type!"
+endif
+
+ +
+ +

One more thing regarding NppExec usage.

+

Compiler/interpreter's output is shown +in NppExec's Console and can be parsed by NppExec. It means that different +error/warning messages can be shown using different colours, and you can jump +to corresponding line in the source file by double-clicking such warning +or error message in the NppExec's Console.

+

To enable such parsing, you must tell NppExec what form do these error/warning +messages have (i.e. specify the message mask). You can configure it from +(main menu) Plugins -> NppExec -> Console Output Filters... -> HighLight.

+

That window contains an example of parsing (highlighting) masks for GCC:

+ +
+
Example 1: %ABSFILE%:%LINE%: warning:* => detects the warning lines from gcc
+Example 2: %ABSFILE%:%LINE%: error:* => detects the error lines from gcc
+
+ +

I.e. to enable detection (parsing) of GCC errors in NppExec, you must specify +the mask of the compiler's error line ("%ABSFILE%:%LINE%: error:*") and, +optionally, specify Red, Green and Blue components of the line to be +highlighted and, also optionally, this line can be shown using Italic, Bold +and/or Underlined font typeface. And, of course, corresponding check-box must +be checked to enable this parsing mask.

+

For example, if you want to see GCC's errors as Bold lines with Red colour +and GCC's warnings as Italic lines with Blue colour, it will look similar to +the following:

+ +
+
[v] [%ABSFILE%:%LINE%: error:*       ]  0x80 0x00 0x00  [ ] [v] [ ]
+[v] [%ABSFILE%:%LINE%: warning:*     ]  0x00 0x00 0x80  [v] [ ] [ ]
+
+ +

You can find some more notes and hints by typing

+ +
+
help con_filter
+
+ +
+ +

Well, seems it's time to finish the guide.

+

I hope this guide was usefull for +you, because otherwise it was waste of time for both of us: the reader (you) +and the writer (me). Anyway, thank you for your time and for your interest!

+

If you like this guide, I hope it will inspire you to find your own usefull +application of NppExec's functions, and maybe to share it with us.

+ +
+
 
+
+ +

See also: NppExec's Console as a Log Viewer [4.6.18].

+ +
+
 
+
+ + + diff --git a/NppExec/doc/NppExec/NppExec_Manual/NppExec_Guide.txt b/docs/NppExec_Manual/NppExec_Guide.txt similarity index 73% rename from NppExec/doc/NppExec/NppExec_Manual/NppExec_Guide.txt rename to docs/NppExec_Manual/NppExec_Guide.txt index 4db7d7a..b9c554a 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/NppExec_Guide.txt +++ b/docs/NppExec_Manual/NppExec_Guide.txt @@ -1,270 +1,338 @@ -Guide: Using NppExec to compile sources with associated compilers - -As a Notepad++ user, did you ever think about ability to compile your source -file with its associated compiler in a single action? -You may use the NppExec plugin to perform certain actions on your files, but -what about the automatization? What if you want your .c files to be compiled -with tcc, .cpp files to be compiled with g++ and .awk files to be interpretted -with gawk automatically, without explicit call to required compiler or -interpreter? Is it possible? -Yes, NppExec ALREADY allows you to do this. All you need is some imagination -and several things to do. And I'm about to tell what is needed. - -Let's begin with several theoretical questions. -At first, how can NppExec understand which compiler/interpreter is required -by your current source file? NppExec is not a compiler, it does not have -any information about your file and does not know what to do with it. -Moreover, Notepad++ itself is not such IDE as Visual C++ Express or Dev-C++, -it does not include any compiler and also does not know what to do with your -source file. -So, the only way to compile your source file with required compiler is to tell -Notepad++ (to tell NppExec in our case) _which_ compiler to use and _how_ to -use it. -This is the solution which you may use already - explicit usage of certain -compiler/interpreter with certain source file. For example, you may want to -compile and run your .c source file with tcc. A simple NppExec's script can -be created for this purpose: - - "C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)" - -The full path "C:\tools\tcc\tcc.exe" specifies a path to required compiler; -Notepad++'es environment variable "$(FULL_CURRENT_PATH)" specifies full path -name to your current source file; and "-run" in tcc's command line means -"run compiled source". The full path was given in quotes, because, in general, -it can contain spaces. -Now, we are talking about NppExec's script. It assumes the script has been -created and saved with some name which identified that script. If you are -not sure about NppExec's script creation & saving, let me guide you. - -To create & save some NppExec's script, do the following: -1) Open the "Execute NppExec Script..." window: press the hotkey (F6) or - select (main menu) Plugins -> NppExec -> Execute NppExec Script... -2) Type the text of your script in the "Execute NppExec Script..." window. - For example: - - "C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)" - -3) Save this new script: press the "Save..." button, type your script name - (for example, type "run@.c") and press Save. - -Now you can compile & run any single .c file opened in Notepad++. To do it, -press F6 (default hotkey for the "Execute NppExec Script..." window), select -"run@.c" in the combo-box and press OK. -You can press Ctrl+F6 (by default) to execute the same script again without -showing the "Execute NppExec Script..." window. - -As you can see, currently you have to call the "run@.c" script explicitly -in order to compile & run your .c source file. Thus, to compile & run -another source file (.cpp, .asm, .php, .lua, ...) you also have to call -corresponding script explicitly. [The last sentence assumes you have created -separate scripts for every language you use (.cpp, .asm, .php, .lua, ...)] -However, we don't want to call required script explicitly. We want NppExec -to call the "run@.c" script for a .c file and call different script required -for different (.cpp, .asm, .php, .lua, ...) file automatically. -So, a question: how can we do it? -The first part of the answer is in your source file's extension. There is -such environment varible as $(EXT_PART) which contains the extension of -current file opened in Notepad++. -The second part of the answer is in NppExec's internal command NPP_EXEC. -As you probably know already, this command expects an existing script name -or a script file name as its first argument. The purpose of this command is -to execute specified NppExec's script. -Thus, if you use NPP_EXEC command, and its first argument (a script to be -executed) depends on current file's extension, you can call different scripts -for different file types from one starting script! -Let's examine it in more detail. - -We are about to create a general NppExec's script which would allow us to -call different scripts for different source files depending on their extension. -In other words, we use the NPP_EXEC command to call required script, and the -script name depends on current file's extension. The name of the script above, -"run@.c", consists of two parts: the prefix "run@" and the extension ".c". -As the file's extension can be got from Notepad++, we can write general form -of this script's name: "run@$(EXT_PART)". -It's not hard to understand that this script's name transforms to "run@.cpp" -for .cpp source file, "run@.lua" for .lua source file and so on. -So, let's create our general compile-or-run script which will be called each -time you want compile or run ANY source file: - - // save current file - NPP_SAVE - // construct the script name to be called - SET Compiler = run@$(EXT_PART) - // call the script - NPP_EXEC "$(Compiler)" - -Save this script as "compile_or_run". Now this is your only starting script -which will allow you to compile or run ANY source file. I.e. press F6, select -the "compile_or_run" and press OK in order to compile or run ANY source file. -However, don't forget that this script requires existing scripts for every -source file you want to compile. Thus, "run@.cpp" must exist to compile a .cpp -file, "run@.php" must exist to compile a .php file and so on. -You can see several examples of such scripts below: - - // run@.c - "C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)" - - // run@.cpp - SET local g++ = C:\Dev-Cpp\bin\g++.exe - SET local obj = $(CURRENT_DIRECTORY)\$(NAME_PART) - "$(g++)" -c "$(FULL_CURRENT_PATH)" -o "$(obj).o" - "$(g++)" "$(obj).o" -o "$(obj).exe" - NPP_RUN "$(obj).exe" - - // run@.awk - "C:\tools\gawk\gawk.exe" -f "$(FULL_CURRENT_PATH)" - -All of these scripts will be started automatically from the "compile_or_run" -script for .c, .cpp and .awk files. You can create more "run@..." scripts to -support any source file extension you use. - -Now, let's return to our "compile_or_run" script. It uses the NPP_EXEC command -which supports a script file name as its first argument. What does it mean? -It means you can execute NppExec's script from a file. -As you can see, current implementation of the "compile_or_run" script requires -a lot of additional "run@..." scripts to exist together with other scripts -which you may want to call explicitly. In the same time, you do not call the -"run@..." scripts explicitly. So, the "run@..." scripts may be undesired in -the NppExec's script combo-box (in the "Execute NppExec Script..." window). -Thus, you may modify the "compile_or_run" script in order to call script files -instead of internal scripts. For example: - - // compile_or_run - NPP_SAVE - SET Compiler = C:\tools\NppExec Scripts\run@$(EXT_PART).txt - NPP_EXEC "$(Compiler)" - -Now you must create a directory "C:\tools\NppExec Scripts" which contains -the following files: "run@.c.txt", "run@.cpp.txt", "run@.awk.txt" and so on. -The text of these files must be exactly the same as in the scripts "run@.c", -"run@.cpp" and "run@.awk" above. -E.g. the file "C:\tools\NppExec Scripts\run@.awk.txt" must contain - - "C:\tools\gawk\gawk.exe" -f "$(FULL_CURRENT_PATH)" - -and so on for other file extensions (.c, .cpp, ...). -Similarly, the path to your NppExec Scripts can be relative to Notepad++. -For example: - - // compile_or_run - NPP_SAVE - SET Compiler = $(NPP_DIRECTORY)\NppExec Scripts\run@$(EXT_PART).txt - NPP_EXEC "$(Compiler)" - -or - - // compile_or_run - NPP_SAVE - SET Compiler = $(PLUGINS_CONFIG_DIR)\NppExec Scripts\run@$(EXT_PART).txt - NPP_EXEC "$(Compiler)" - -Such approach allows to use external text files as the NppExec Scripts, while -they are always available since they reside in Notepad++'s folder. -To read more information about the NPP_EXEC command, open the NppExec's -Console in Notepad++, and type: - - help npp_exec - -and press Enter. -To get general NppExec's help information, type just - - help - -and press Enter. - -You may have noticed, that the script "compile_or_run" uses a non-local -variable $(Compiler), such as: - - SET Compiler = run@$(EXT_PART) - -Though, in general, it is recommended to use a local variable, e.g. - - SET local Compiler = run@$(EXT_PART) - -Local variables, unlike non-local ones, are automatically deleted at the end -of the script where they were created. (So you don't have to use the UNSET -command for local variables at the end of your script.) -So, why the variable $(Compiler) is not a local one? -Consider a situation when the "run@..." script does not do what you expected -it to. In such case, you probably want to examine this script and correct it, -right? And here is when the existing variable $(Compiler) becomes useful! As -this variable holds the name of (or the path to) the just executed "run@..." -script, it's easy to see what exact "run@..." script needs to be examined. -Just type one the following in NppExec's Console: - - // to show the "run@..." script's name: - echo $(Compiler) - - // to open the "run@..." script from a physical file: - NPP_OPEN $(Compiler) - - -Starting from NppExec v0.6 alpha 1, IF...ELSE IF...ELSE...ENDIF sequences are -supported in NppExec's scripts (see "help if"). -It means we can create a single NppExec's script that will deal with all the -file types we want. -For example: - - // setting internal messages off - npe_console local m- -- - // saving current file - NPP_SAVE - // file extension in lower case - set local ext ~ strlower $(EXT_PART) - // compiling/running... - if $(ext) == .c - "C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)" - else if $(ext) == .cpp - env_set local PATH = $(path);C:\mingw32\bin; - set local obj = $(CURRENT_DIRECTORY)\$(NAME_PART) - cmd /C del "$(obj).o" 2>nul & del "$(obj).exe" 2>nul - echo Compiling... - "g++" -c "$(FULL_CURRENT_PATH)" - if $(EXITCODE) == 0 - "g++" "$(obj).o" -o "$(obj).exe" - echo Running... - NPP_RUN cmd /C if exist "$(obj).exe" "$(obj).exe" && echo. && pause - endif - else if $(ext) == .awk - "C:\tools\gawk\gawk.exe" -f "$(FULL_CURRENT_PATH)" - else - messagebox "Unknown file type!" - endif - - -One more thing regarding NppExec usage. Compiler/interpreter's output is shown -in NppExec's Console and can be parsed by NppExec. It means that different -error/warning messages can be shown using different colours, and you can jump -to corresponding line in the source file by double-clicking on such warning -or error message in the NppExec's Console. -To enable such parsing, you must tell NppExec what form do these error/warning -messages have (i.e. specify the message mask). You can configure it from -(main menu) Plugins -> NppExec -> Console Output Filters... -> HighLight. -That window contains an example of parsing (highlighting) masks for GCC: - - Example 1: %ABSFILE%:%LINE%: warning:* => detects the warning lines from gcc - Example 2: %ABSFILE%:%LINE%: error:* => detects the error lines from gcc - -I.e. to enable detection (parsing) of GCC errors in NppExec, you must specify -the mask of the compiler's error line ("%ABSFILE%:%LINE%: error:*") and, -optionally, specify Red, Green and Blue components of the line to be -highlighted and, also optionally, this line can be shown using Italic, Bold -and/or Underlined font typeface. And, of course, corresponding check-box must -be checked to enable this parsing mask. -For example, if you want to see GCC's errors as Bold lines with Red colour -and GCC's warnings as Italic lines with Blue colour, it will look similar to -the following: - - [v] [%ABSFILE%:%LINE%: error:* ] 0x80 0x00 0x00 [ ] [v] [ ] - [v] [%ABSFILE%:%LINE%: warning:* ] 0x00 0x00 0x80 [v] [ ] [ ] - -You can find some more notes and hints by typing - - help con_filter - - -Well, seems it's time to finish the guide. I hope this guide was usefull for -you, because otherwise it was waste of time for both of us: the reader (you) -and the writer (me). -If you like this guide, I hope it will inspire you to find your own usefull -application of NppExec's functions, and maybe to share it with us. +Guide: Using NppExec to compile sources with associated compilers + +As a Notepad++ user, did you ever think about ability to compile your source +file with its associated compiler in a single action? +You may use the NppExec plugin to perform certain actions on your files, but +what about the automatization? What if you want your .c files to be compiled +with tcc, .cpp files to be compiled with g++ and .awk files to be interpretted +with gawk automatically, without explicit call to required compiler or +interpreter? Is it possible? +Yes, NppExec ALREADY allows you to do this. All you need is some imagination +and several things to do. And I'm about to tell what is needed. + +Let's begin with several theoretical questions. +At first, how can NppExec understand which compiler/interpreter is required +by your current source file? NppExec is not a compiler, it does not have +any information about your file and does not know what to do with it. +Moreover, Notepad++ itself is not such IDE as Visual Studio or Dev-C++, +it does not include any compiler and also does not know what to do with your +source file. +So, the only way to compile your source file with required compiler is to tell +Notepad++ (to tell NppExec in our case) _which_ compiler to use and _how_ to +use it. +This is the solution which you may use already - explicit usage of certain +compiler/interpreter with certain source file. For example, you may want to +compile and run your .c source file with tcc. A simple NppExec's script can +be created for this purpose: + + "C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)" + +The full path "C:\tools\tcc\tcc.exe" specifies a path to required compiler; +Notepad++'es environment variable "$(FULL_CURRENT_PATH)" specifies full path +name to your current source file; and "-run" in tcc's command line means +"run compiled source". The full path was given in quotes, because, in general, +it can contain spaces. +Now, we are talking about NppExec's script. It assumes the script has been +created and saved with some name which identified that script. If you are +not sure about NppExec's script creation & saving, let me guide you. + +To create & save some NppExec's script, do the following: +1) Open the "Execute NppExec Script..." window: press the hotkey (F6) or + select (main menu) Plugins -> NppExec -> Execute NppExec Script... +2) Type the text of your script in the "Execute NppExec Script..." window. + For example: + + "C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)" + +3) Save this new script: press the "Save..." button, type your script name + (for example, type "run@.c") and press Save. + +Now you can compile & run any single .c file opened in Notepad++. To do it, +press F6 (default hotkey for the "Execute NppExec Script..." window), select +"run@.c" in the combo-box and press OK. +You can press Ctrl+F6 (by default) to execute the same script again without +showing the "Execute NppExec Script..." window. + +As you can see, currently you have to call the "run@.c" script explicitly +in order to compile & run your .c source file. Thus, to compile & run +another source file (.cpp, .asm, .php, .lua, ...) you also have to call +corresponding script explicitly. [The last sentence assumes you have created +separate scripts for every language you use (.cpp, .asm, .php, .lua, ...)] +However, we don't want to call required script explicitly. We want NppExec +to call the "run@.c" script for a .c file and call different script required +for different (.cpp, .asm, .php, .lua, ...) file automatically. +So, a question: how can we do it? +The first part of the answer is in your source file's extension. There is +such environment varible as $(EXT_PART) which contains the extension of +current file opened in Notepad++. +The second part of the answer is in NppExec's internal command NPP_EXEC. +As you probably know already, this command expects an existing script name +or a script file name as its first argument. The purpose of this command is +to execute specified NppExec's script. +Thus, if you use NPP_EXEC command, and its first argument (a script to be +executed) depends on current file's extension, you can call different scripts +for different file types from one starting script! +Let's examine it in more detail. + +We are about to create a general NppExec's script which would allow us to +call different scripts for different source files depending on their extension. +In other words, we use the NPP_EXEC command to call required script, and the +script name depends on current file's extension. The name of the script above, +"run@.c", consists of two parts: the prefix "run@" and the extension ".c". +As the file's extension can be got from Notepad++, we can write general form +of this script's name: "run@$(EXT_PART)". +It's not hard to understand that this script's name transforms to "run@.cpp" +for .cpp source file, "run@.lua" for .lua source file and so on. +So, let's create our general compile-or-run script which will be called each +time you want to compile or run ANY source file: + + // save current file + NPP_SAVE + // construct the script name to be called + SET Compiler = run@$(EXT_PART) + // enable the built-in error highlight filter locally + NPE_CONSOLE local -- x+ + // call the script + NPP_EXEC "$(Compiler)" + +Save this script as "compile_or_run". Now this is your only starting script +which will allow you to compile or run ANY source file. I.e. press F6, select +the "compile_or_run" and press OK in order to compile or run ANY source file. +However, don't forget that this script requires existing scripts for every +source file you want to compile. Thus, "run@.cpp" must exist to compile a .cpp +file, "run@.php" must exist to compile a .php file and so on. +You can see several examples of such scripts below: + + // run@.c + "C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)" + + // run@.cpp + SET local g++ = C:\Dev-Cpp\bin\g++.exe + SET local obj = $(CURRENT_DIRECTORY)\$(NAME_PART) + "$(g++)" -c "$(FULL_CURRENT_PATH)" -o "$(obj).o" + "$(g++)" "$(obj).o" -o "$(obj).exe" + NPP_RUN "$(obj).exe" + + // run@.awk + "C:\tools\gawk\gawk.exe" -f "$(FULL_CURRENT_PATH)" + +All of these scripts will be started automatically from the "compile_or_run" +script for .c, .cpp and .awk files. You can create more "run@..." scripts to +support any source file extension you use. + +Now, let's return to our "compile_or_run" script. It uses the NPP_EXEC command +which supports a script file name as its first argument. What does it mean? +It means you can execute NppExec's script from a file. +As you can see, current implementation of the "compile_or_run" script requires +a lot of additional "run@..." scripts to exist together with other scripts +which you may want to call explicitly. In the same time, you do not call the +"run@..." scripts explicitly. So, the "run@..." scripts may be undesired in +the NppExec's script combo-box (in the "Execute NppExec Script..." window). +Thus, you may modify the "compile_or_run" script in order to call script files +instead of internal scripts. For example: + + // compile_or_run + NPP_SAVE + SET Compiler = C:\tools\NppExec Scripts\run@$(EXT_PART).txt + NPE_CONSOLE local -- x+ + NPP_EXEC "$(Compiler)" + +Now you need to create a directory "C:\tools\NppExec Scripts" which will +contain the following files: "run@.c.txt", "run@.cpp.txt", "run@.awk.txt" +and so on. +The text of these files will be exactly the same as in the scripts "run@.c", +"run@.cpp" and "run@.awk" above. +E.g. the file "C:\tools\NppExec Scripts\run@.awk.txt" must contain + + "C:\tools\gawk\gawk.exe" -f "$(FULL_CURRENT_PATH)" + +and so on for other file extensions (.c, .cpp, ...). +Similarly, the path to your NppExec Scripts can be relative to Notepad++. +For example: + + // compile_or_run + NPP_SAVE + SET Compiler = $(NPP_DIRECTORY)\NppExec Scripts\run@$(EXT_PART).txt + NPE_CONSOLE local -- x+ + NPP_EXEC "$(Compiler)" + +or + + // compile_or_run + NPP_SAVE + SET Compiler = $(PLUGINS_CONFIG_DIR)\NppExec Scripts\run@$(EXT_PART).txt + NPE_CONSOLE local -- x+ + NPP_EXEC "$(Compiler)" + +Such approach allows to use external text files as the NppExec Scripts, while +they are always available since they reside in Notepad++'s folder. +To read more information about the NPP_EXEC command, open the NppExec's +Console in Notepad++, and type: + + help npp_exec + +and press Enter. +To read more information about the NPE_CONSOLE command, type: + + help npe_console + +and press Enter. +To get general NppExec's help information, type just + + help + +and press Enter. + +You may have noticed, that the script "compile_or_run" uses a non-local +variable $(Compiler), such as: + + SET Compiler = run@$(EXT_PART) + +Though, in general, it is recommended to use a local variable, e.g. + + SET local Compiler = run@$(EXT_PART) + +Local variables, unlike non-local ones, are automatically deleted at the end +of the script where they were created. (So you don't have to use the UNSET +command for local variables at the end of your script.) +So, why the variable $(Compiler) is not a local one? +Consider a situation when the "run@..." script does not do what you expected +it to. In such case, you probably want to examine this script and correct it, +right? And here is when the existing variable $(Compiler) becomes useful! As +this variable holds the name of (or the path to) the just executed "run@..." +script, it's easy to see what exact "run@..." script needs to be examined. +Just type one the following in NppExec's Console: + + // to show the "run@..." script's name: + echo $(Compiler) + + // to open the "run@..." script from a physical file: + NPP_OPEN $(Compiler) + + +Starting from NppExec v0.6 alpha 1, IF...ELSE IF...ELSE...ENDIF sequences are +supported in NppExec's scripts (see "help if"). +It means we can create a single NppExec's script that will deal with all the +file types we want. +For example: + + // setting internal messages off, error highlight filter on + NPE_CONSOLE local m- x+ -- + // saving current file + NPP_SAVE + // file extension in lower case + set local ext ~ strlower $(EXT_PART) + // compiling/running... + if $(ext) == .c + "C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)" + else if $(ext) == .cpp + env_set local PATH = $(path);C:\mingw32\bin; + set local obj = $(CURRENT_DIRECTORY)\$(NAME_PART) + cmd /C del "$(obj).o" 2>nul & del "$(obj).exe" 2>nul + echo Compiling... + "g++" -c "$(FULL_CURRENT_PATH)" + if $(EXITCODE) == 0 + "g++" "$(obj).o" -o "$(obj).exe" + echo Running... + NPP_RUN cmd /C if exist "$(obj).exe" "$(obj).exe" && echo. && pause + endif + else if $(ext) == .awk + "C:\tools\gawk\gawk.exe" -f "$(FULL_CURRENT_PATH)" + else + messagebox "Unknown file type!" + endif + +Such a single script includes everything in one place. On the one hand, it's +nice to have everything in one place. On the other hand, it will create issues +with maintenance and performance in the future. +_Maintenance_. As time goes by, more and more file types (languages) will be +added to this single script. The script will grow - and it will be harder and +harder to find some exact things within the script. Moreover, if different +parts of the script will share some common functionality (or, at least, some +common variables) and you'll decide to make changes to the common functionality +at some point, it will most likely lead to unexpected effects in different +places. (For example, you may want some change to affect only certain languages, +but in fact it will affect more of them). So, the bigger the script will become, +the more accurate you'll need to be with each single change within the script. +_Performance_. The bigger the script will become, the more time NppExec will +need to process the entire script. The good thing is: NppExec's engine is +internally fast enough to handle very big scripts without a noticeable delay. +The bad thing is: NppExec's user interface (the NppExec Console) is very slow +when there are a lot of messages to be printed. Here are the good news: it's +easy to reduce the number of messages to be printed in NppExec's Console - and +thus to enhance the overall performance. The presense of "NPE_CONSOLE local m-" +in the beginning of the script already reduces the number of messages NppExec +prints to its Console. Going further, you can explicitly specify when to +disable and enable NppExec's output, thus having a complete manual control of +when NppExec prints something to its Console and when it does not. Just notice +that you'll need to update _each_ IF-ELSE block to achieve that: + + // disabling any output to NppExec's Console + NPP_CONSOLE local - + // setting internal messages off, error highlight filter on + NPE_CONSOLE local m- x+ -- + // saving current file + NPP_SAVE + // file extension in lower case + set local ext ~ strlower $(EXT_PART) + // compiling/running... + if $(ext) == .c + NPP_CONSOLE local + // enabling output to NppExec's Console + "C:\tools\tcc\tcc.exe" -run "$(FULL_CURRENT_PATH)" + else if $(ext) == .cpp + env_set local PATH = $(path);C:\mingw32\bin; + set local obj = $(CURRENT_DIRECTORY)\$(NAME_PART) + cmd /C del "$(obj).o" 2>nul & del "$(obj).exe" 2>nul + NPP_CONSOLE local + // enabling output to NppExec's Console + echo Compiling... + "g++" -c "$(FULL_CURRENT_PATH)" + if $(EXITCODE) == 0 + "g++" "$(obj).o" -o "$(obj).exe" + echo Running... + NPP_RUN cmd /C if exist "$(obj).exe" "$(obj).exe" && echo. && pause + endif + else if $(ext) == .awk + NPP_CONSOLE local + // enabling output to NppExec's Console + "C:\tools\gawk\gawk.exe" -f "$(FULL_CURRENT_PATH)" + else + NPP_CONSOLE local + // enabling output to NppExec's Console + messagebox "Unknown file type!" + endif + + +One more thing regarding NppExec usage. Compiler/interpreter's output is shown +in NppExec's Console and can be parsed by NppExec. It means that different +error/warning messages can be shown using different colours, and you can jump +to corresponding line in the source file by double-clicking on such warning +or error message in the NppExec's Console. +To enable such parsing, you must tell NppExec what form do these error/warning +messages have (i.e. specify the message mask). You can configure it from +(main menu) Plugins -> NppExec -> Console Output Filters... -> HighLight. +That window contains an example of parsing (highlighting) masks for GCC: + + Example 1: %ABSFILE%:%LINE%: warning:* => detects the warning lines from gcc + Example 2: %ABSFILE%:%LINE%: error:* => detects the error lines from gcc + +I.e. to enable detection (parsing) of GCC errors in NppExec, you must specify +the mask of the compiler's error line ("%ABSFILE%:%LINE%: error:*") and, +optionally, specify Red, Green and Blue components of the line to be +highlighted and, also optionally, this line can be shown using Italic, Bold +and/or Underlined font typeface. And, of course, corresponding check-box must +be checked to enable this parsing mask. +For example, if you want to see GCC's errors as Bold lines with Red colour +and GCC's warnings as Italic lines with Blue colour, it will look similar to +the following: + + [v] [%ABSFILE%:%LINE%: error:* ] 0x80 0x00 0x00 [ ] [v] [ ] + [v] [%ABSFILE%:%LINE%: warning:* ] 0x00 0x00 0x80 [v] [ ] [ ] + +You can find some more notes and hints by typing + + help con_filter + + +Well, seems it's time to finish the guide. I hope this guide was usefull for +you, because otherwise it was waste of time for both of us: the reader (you) +and the writer (me). Anyway, thank you for your time and for your interest! +If you like this guide, I hope it will inspire you to find your own usefull +application of NppExec's functions, and maybe to share it with us. diff --git a/NppExec/doc/NppExec/NppExec_Manual/NppExec_Manual.hhc b/docs/NppExec_Manual/NppExec_Manual.hhc similarity index 80% rename from NppExec/doc/NppExec/NppExec_Manual/NppExec_Manual.hhc rename to docs/NppExec_Manual/NppExec_Manual.hhc index 812d876..4048b1d 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/NppExec_Manual.hhc +++ b/docs/NppExec_Manual/NppExec_Manual.hhc @@ -1,250 +1,294 @@ - - - - - - -
    -
  • - - - -
  • - - -
      -
    • - - - -
    • - - - -
    • - - - -
    -
  • - - -
      -
    • - - - -
    • - - - -
    • - - - -
    • - - - -
    • - - - -
    -
  • - - -
      -
    • - - - -
    • - - - -
    • - - - -
    • - - - -
    • - - - -
    • - - - -
    • - - - -
    • - - -
        -
      • - - - -
      • - - - -
      • - - - -
      • - - - -
      • - - - -
      -
    -
  • - - -
      -
    • - - - -
    • - - - -
    • - - - -
    • - - - -
    • - - - -
    • - - - -
    • - - -
        -
      • - - - -
      • - - - -
      • - - - -
      • - - - -
      • - - - -
      • - - - -
      • - - - -
      • - - - -
      • - - - -
      • - - - -
      • - - - -
      • - - - -
      -
    • - - -
        -
      • - - - -
      • - - - -
      • - - - -
      • - - - -
      -
    • - - -
        -
      • - - - -
      • - - - -
      -
    -
  • - - -
      -
    • - - - -
    • - - - -
    • - - - -
    • - - - -
    -
- + + + + + + +
    +
  • + + + +
  • + + +
      +
    • + + + +
    • + + + +
    • + + + +
    +
  • + + +
      +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    +
  • + + +
      +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    • + + +
        +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      +
    • + + + +
    +
  • + + +
      +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    • + + +
        +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      +
    • + + +
        +
      • + + + +
      • + + + +
      • + + + +
      • + + + +
      +
    • + + +
        +
      • + + + +
      • + + + +
      • + + + +
      +
    +
  • + + +
      +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    +
+ diff --git a/NppExec/doc/NppExec/NppExec_Manual/NppExec_Manual.hhp b/docs/NppExec_Manual/NppExec_Manual.hhp similarity index 95% rename from NppExec/doc/NppExec/NppExec_Manual/NppExec_Manual.hhp rename to docs/NppExec_Manual/NppExec_Manual.hhp index 8c12c89..a625a27 100644 --- a/NppExec/doc/NppExec/NppExec_Manual/NppExec_Manual.hhp +++ b/docs/NppExec_Manual/NppExec_Manual.hhp @@ -1,14 +1,14 @@ -[OPTIONS] -Auto Index=Yes -Compatibility=1.1 or later -Compiled file=NppExec_Manual.chm -Contents file=NppExec_Manual.hhc -Default topic=0. Title Page.html -Display compile progress=No -Full-text search=Yes -Language=0x409 English (United States) -Title=NppExec - - -[INFOTYPES] - +[OPTIONS] +Auto Index=Yes +Compatibility=1.1 or later +Compiled file=NppExec_Manual.chm +Contents file=NppExec_Manual.hhc +Default topic=0. Title Page.html +Display compile progress=No +Full-text search=Yes +Language=0x409 English (United States) +Title=NppExec + + +[INFOTYPES] + diff --git a/docs/NppExec_Manual/Questions_suggestions.html b/docs/NppExec_Manual/Questions_suggestions.html new file mode 100644 index 0000000..129a898 --- /dev/null +++ b/docs/NppExec_Manual/Questions_suggestions.html @@ -0,0 +1,19 @@ + + + + + +Questions/suggestions? + + + +

Questions/suggestions?

+

Did not find an answer for your question? You can try the following:

+
    +
  1. Read this manual once again ;)
  2. +
  3. Visit https://sourceforge.net/projects/npp-plugins/ and search NppExec's forum for the answer or ask your question there.
  4. +
  5. Visit https://github.com/d0vgan/nppexec/issues/ and search the closed and open issues.
  6. +
+

Have a suggestion? Visit NppExec's forum and let me know.

+ + diff --git a/docs/NppExec_Manual/images/4_6_18_Console_Highlight_Filters.png b/docs/NppExec_Manual/images/4_6_18_Console_Highlight_Filters.png new file mode 100644 index 0000000..a40f1fe Binary files /dev/null and b/docs/NppExec_Manual/images/4_6_18_Console_Highlight_Filters.png differ diff --git a/docs/NppExec_Manual/images/4_6_18_NppExec_Console.png b/docs/NppExec_Manual/images/4_6_18_NppExec_Console.png new file mode 100644 index 0000000..6c7321e Binary files /dev/null and b/docs/NppExec_Manual/images/4_6_18_NppExec_Console.png differ diff --git a/docs/NppExec_Manual/index.html b/docs/NppExec_Manual/index.html new file mode 100644 index 0000000..e9d944d --- /dev/null +++ b/docs/NppExec_Manual/index.html @@ -0,0 +1,98 @@ + + + + + +NppExec Manual: Index + + +

NppExec Manual: Index

+

Title Page

+

1. What is NppExec

+ +

2. Installation

+ +

3. Basic Usage

+ +

4. Advanced Usage

+ +

5. Other

+ + + diff --git a/docs/NppExec_Manual/show_matches.js b/docs/NppExec_Manual/show_matches.js new file mode 100644 index 0000000..ba9d5d0 --- /dev/null +++ b/docs/NppExec_Manual/show_matches.js @@ -0,0 +1,27 @@ +window.onload = function() { + if (!(document.createRange && location.search)) + return; + var query = location.search + var param = 'contains=' + var value = query.slice(query.indexOf(param) + param.length) + var encodedChars = value.match(/%[0-9A-Fa-f]{2}/g) + if (encodedChars) { + encodedChars.forEach(function(ch) { + value = value.replace(ch, String.fromCharCode(parseInt(ch.slice(1), 16))) + }) + } + while (window.find(value)) { + var sel = window.getSelection() + var txtRng = sel.getRangeAt(0) + var selSpan = document.createElement('span') + selSpan.classList += 'match' + selSpan.style.backgroundColor = 'rgb(0,127,255)' + selSpan.style.color = 'white' + selSpan.innerText = txtRng.extractContents().textContent + txtRng.insertNode(selSpan) + } + window.getSelection().empty() + var matches = document.querySelectorAll('.match') + // anchor viewport to first matching string + if (matches.length) matches[0].scrollIntoView() +} diff --git a/docs/NppExec_Manual/style.css b/docs/NppExec_Manual/style.css new file mode 100644 index 0000000..c904e90 --- /dev/null +++ b/docs/NppExec_Manual/style.css @@ -0,0 +1,82 @@ +h1 { + font-family: Arial, Helvetica, sans-serif; +} + +h3 { + font-family: Arial, Helvetica, sans-serif; +} + +li { + font-family: Arial, Helvetica, sans-serif; +} + +p, label { + font-family: Arial, Helvetica, sans-serif; +} + +td { + font-family: Arial, Helvetica, sans-serif; +} + +pre { + font-family: "Courier New", Courier, mono; +} + +button#goto-doc { + margin-left: 0.25rem; +} + +@media screen and (max-width:350px) { + html, blockquote { + white-space: normal; + word-break: break-word; + } + + pre, code { + white-space: pre-wrap; + } + + a, a:active, a:focus, a:visited { + text-decoration: none; + } + + input, button, button#goto-doc { + display: block; + margin: 0.5rem 0; + padding: 0.25rem; + width: 100%; + } + + select { + padding: 0.5rem 0; + } + + button { + border-radius: 15px; + } + + blockquote, ol, ul, li { + margin: 0; + padding: 0; + } + + ol, ul, li, p { + font-size: smaller; + } + + ol, ul { + list-style: none; + } + + li { + padding: 0.125rem 0; + } + + td { + white-space: nowrap; + } +} + +code { + font-family: "Courier New", Courier, mono; +} diff --git a/docs/NppExec_Manual/toc.html b/docs/NppExec_Manual/toc.html new file mode 100644 index 0000000..2819a99 --- /dev/null +++ b/docs/NppExec_Manual/toc.html @@ -0,0 +1,120 @@ + + + + + +NppExec Manual: Index + + + + + +

NppExec Manual: Index

+
+ +

+
+

Title Page

+

1. What is NppExec

+ +

2. Installation

+ +

3. Basic Usage

+ +

4. Advanced Usage

+ +

5. Other

+ + + diff --git a/NppExec/doc/NppExec/NppExec_TechInfo.txt b/docs/NppExec_TechInfo.txt similarity index 84% rename from NppExec/doc/NppExec/NppExec_TechInfo.txt rename to docs/NppExec_TechInfo.txt index eb296d2..fc907eb 100644 --- a/NppExec/doc/NppExec/NppExec_TechInfo.txt +++ b/docs/NppExec_TechInfo.txt @@ -1,6 +1,7 @@ **************************************************************************** - * NppExec plugin ver. 0.7.1 for Notepad++ - * by DV , December 2006 - August 2021 + * NppExec plugin ver. 0.8.10 for Notepad++ + * by DV , December 2006 - October 2025 + * https://github.com/d0vgan/nppexec **************************************************************************** @@ -22,12 +23,14 @@ | ChildProcess_KillTimeout_ms | 500 | int | | ChildProcess_RunPolicy | 0 | int | | ChildProcess_ComSpecSwitches | /C | string | + | ChildProcess_PseudoConsole | 0 | BOOL | | ChildScript_SyncTimeout_ms | 200 | int | | ExitScript_Timeout_ms | 4000 | int | | Path_AutoDblQuotes | 0 (FALSE) | BOOL | | CmdHistory_MaxItems | 256 | int | | Exec_MaxCount | 100 | int | | GoTo_MaxCount | 10000 | int | + | ExecText_MaxCount | 500 | int | | RichEdit_MaxTextLength | 4194304 (4 MB) | int | | SendMsg_MaxBufLength | 4194304 (4 MB) | int | | Calc_Precision | 0.000001 | float | @@ -48,19 +51,27 @@ | NppExec_Cmd_Prefix | nppexec: | string | | UTF8_Detect_Length | 16384 | int | | AnsiEscapeSequences | 0 | int | + | ExecClipTextMode | 60 | int | + | ExecSelTextMode | 60 | int | + | KillProcTree | 1 (TRUE) | BOOL | | Cd_UnnamedFile | 1 | int | | | | | | [Options] | | | | HotKey | F6 | string | | ToolbarBtn | 1 | int | | WatchScriptFile | 1 (TRUE) | BOOL | + | SaveLastScript | 1 (TRUE) | BOOL | | ScriptNppStart | (empty) | string | | ScriptNppExit | (empty) | string | | HelpFile | doc\NppExec\NppExec_Manual.chm | string | | TempScriptFile | npes_temp.txt | string | + | LastScriptFile | npes_last.txt | string | | SavedScriptsFile | npes_saved.txt | string | | LogsDir | (empty) | string | | AutoSave_Seconds | 0 | int | + | | | | + | [ConsoleOutputFilter] | | | + | CompilerErrors | 0 (FALSE) | BOOL | | | | | ----------------------------------------------------------------------------- @@ -73,10 +84,12 @@ HotKey=F6 ToolbarBtn=1 WatchScriptFile=1 + SaveLastScript=1 ScriptNppStart= ScriptNppExit= HelpFile=doc\NppExec\NppExec_Manual.chm TempScriptFile=npes_temp.txt + LastScriptFile=npes_last.txt SavedScriptsFile=npes_saved.txt LogsDir= AutoSave_Seconds=0 @@ -94,12 +107,14 @@ ChildProcess_KillTimeout_ms=500 ChildProcess_RunPolicy=0 ChildProcess_ComSpecSwitches=/C + ChildProcess_PseudoConsole=0 ChildScript_SyncTimeout_ms=200 ExitScript_Timeout_ms=4000 Path_AutoDblQuotes=0 CmdHistory_MaxItems=256 Exec_MaxCount=100 GoTo_MaxCount=10000 + ExecText_MaxCount=500 RichEdit_MaxTextLength=4194304 SendMsg_MaxBufLength=4194304 Calc_Precision=0.000001 @@ -116,8 +131,14 @@ NppExec_Cmd_Prefix=nppexec: UTF8_Detect_Length=16384 AnsiEscapeSequences=0 + ExecClipTextMode=60 + ExecSelTextMode=60 + KillProcTree=1 Cd_UnnamedFile=1 + [ConsoleOutputFilter] + CompilerErrors=0 + ChildProcess_StartupTimeout_ms ------------------------------ @@ -232,6 +253,15 @@ The default value is "/C". + ChildProcess_PseudoConsole + -------------------------- + Specifies whether to use PseudoConsole when a child process is created. + (PseudoConsole is available since Windows 10 October 2018 Update, ver. 1809. + PseudoConsole deals with ANSI escape sequences and uses UTF-8 encoding). + This option is experimental. + Can be enabled/disabled via "npe_console u+/u-". + + ChildScript_SyncTimeout_ms -------------------------- When a new NppExec's script is about to be started while another one is @@ -306,6 +336,23 @@ You always can close the Console window to stop the running script. + ExecText_MaxCount + ----------------- + Specifies maximum number of NPP_EXECTEXT calls within one script. + This value is needed to prevent the infinite loop of the commands + such as: + + npp_exectext 0 $(SELECTED_TEXT) + + when the selected text itself contains the same command + + npp_exectext 0 $(SELECTED_TEXT) + + The same applies to the following command placed to the clipboard: + + npp_exectext 0 $(CLIPBOARD_TEXT) + + RichEdit_MaxTextLength ---------------------- Specifies maximum number of characters which can be stored or @@ -366,6 +413,7 @@ is printed in the Console after an NppExec's script is executed. If this option is disabled (set to 0), a message "==== READY ====" is not printed. + Can be enabled/disabled via "npe_console p+/p-". See also: CustomMsgReady. @@ -570,6 +618,27 @@ AnsiEscapeSequences = 1 - removes ANSI escape characters (the output text will not contain extra characters from the escape sequences). + Can be enabled/disabled via "npe_console e1/e0". + + ExecClipTextMode + ---------------- + Specifies the text processing mode for Execute Clipboard Text. + See the "c" parameter of NPE_CONSOLE ("help npe_console") for details. + + + ExecSelTextMode + --------------- + Specifies the text processing mode for Execute Selected Text. + See the "s" parameter of NPE_CONSOLE ("help npe_console") for details. + + + KillProcTree + ------------ + Kill process tree on/off. + When this option is on (set to 1), killing a running child process (the one + that runs in NppExec's Console) also kills any processes that were started + from this running child process. + Can be enabled/disabled via "npe_console j+/j-". Cd_UnnamedFile @@ -593,6 +662,7 @@ ToolbarBtn = 1 - the toolbar button shows the Console window; ToolbarBtn = 2 - the toolbar button calls the "Execute..." dialog. ToolbarBtn = 3 - the toolbar button directly executes last script. + ToolbarBtn = 4 - the toolbar button executes the selected text. WatchScriptFile @@ -604,6 +674,17 @@ the file time stamp and does not reread this file. + SaveLastScript + -------------- + When this option is enabled (set to 1), the plugin saves the last + executed script to "npes_saved.txt" and restores it when Notepad++ + starts. (So it can be run by Execute Previous NppExec Script). + If this option is disabled (set to 0), the plugin does not save the + last executed script and does not read "npes_saved.txt" when Notepad++ + starts. + See also: LastScriptFile. + + ScriptNppStart -------------- You can specify here a name of existing script which you want to be @@ -639,6 +720,14 @@ $(SYS.TEMP) $(NPP_DIRECTORY) $(PLUGINS_CONFIG_DIR) + This can also be a URL that points to the online version of the Manual: + HelpFile=https://d0vgan.github.io/nppexec/ + To start with a specific topic of the online Manual, use "?q=", such as: + HelpFile=https://d0vgan.github.io/nppexec/?q=FAQ + or: + HelpFile=https://d0vgan.github.io/nppexec/?q=4.0 + This can also be a path to the local HTML version of the Manual, e.g.: + HelpFile=C:\github\nppexec\docs\index.html TempScriptFile @@ -647,6 +736,13 @@ The default file name is "npes_temp.txt". + LastScriptFile + -------------- + Name of a file where NppExec stores its last executed script. + The default file name is "npes_last.txt". + See also: SaveLastScript. + + SavedScriptsFile ---------------- Name of a file where NppExec stores its saved scripts. @@ -686,3 +782,11 @@ 5 minutes). The value of 0 disables the auto-saving. + + CompilerErrors + -------------- + Enables or disables the built-in highlight filter that catches and + highlights most of compilers' errors. This filter has lower priority + than the user-defined highlight masks. + Can be enabled/disabled via "npe_console x+/x-". + diff --git a/NppExec/doc/NppExec/fparser.html b/docs/fparser.html similarity index 100% rename from NppExec/doc/NppExec/fparser.html rename to docs/fparser.html diff --git a/docs/index-local.html b/docs/index-local.html new file mode 100644 index 0000000..401b33b --- /dev/null +++ b/docs/index-local.html @@ -0,0 +1,27 @@ + + + + + + + + NppExec Manual: Index + + + + + + + + diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..c9df8c7 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,40 @@ + + + + + + + + NppExec Manual: Index + + + + + + + + + diff --git a/docs/search.js b/docs/search.js new file mode 100644 index 0000000..bb819ae --- /dev/null +++ b/docs/search.js @@ -0,0 +1,135 @@ +window.onload = function() { + "use strict"; + /* The search result container */ + var searchResults = document.getElementById('search-results'); + /* The topic heading */ + var searchBox = document.getElementById('topic-search-box'); + /* Shows the page mapped to the active */ + var findTopics = function(keyEvent) { + if (keyEvent.isComposing) // Don't react to CTRL, ALT, SHIFT, etc. + return; + + try { + /* The to be filled with topic headings */ + var topicHeadings = document.getElementById('topic-headings'); + + /* The 'value' property is an empty string when the has been + * emptied (by DEL, BACKSPACE, CTRL+X, etc.). But the boxes are never blank */ + helpTopics.selectedIndex = 0; + helpTopics.addEventListener('change', clickToView, { 'passive': false }); + helpTopics.addEventListener('focus', + /* Selecting the first